【问题标题】:Confusing behavior of Python for statementPython for 语句的令人困惑的行为
【发布时间】:2013-04-14 22:18:38
【问题描述】:

我有以下 python 代码:

x = range(0,10)
print x

for number in x: 
    print(number)
    if number%2<> 0: 
        x.remove(number)

print x

奇怪的是,输出是这样的:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
0
1
3
5
7
9
[0, 2, 4, 6, 8]

第一行和最后一行是对的,但是为什么2、4、6、8没有打印出来呢? print 语句不在 if 语句中!

我在 Windows 7 上使用 python(x,y)。另外,我是 Python 新手...我习惯于 C++

【问题讨论】:

  • 我第一次看到有人使用帕斯卡&lt;&gt;。说真的,从现在开始使用!=&lt;&gt; 在 Python 3 中消失了,除非你 from __future__ import barry_as_FLUFL
  • 不要使用&lt;&gt;;它很久以前就被弃用了,并且从 Python 3 中消失了。请改用!=
  • 谢谢,我知道!=,我正在尝试不同的东西,因为它没有按照我想要的方式工作。 (我是 python 新手)

标签: python windows if-statement for-loop


【解决方案1】:

您在迭代列表 (for number in x) 时从列表中删除项目 (x.remove)。

for-in 单独维护一个索引,这就是修改列表会产生意外行为的原因。

【讨论】:

  • 谢谢,要修复它,我只需将要删除的列表收集到列表中,然后在循环后将其删除。
【解决方案2】:

列表使用其索引进行迭代,但是当您删除元素时会跳过一些索引。

例如:

[0,1,2,...] # (iterator is at second - print 1)

删除

[0,2,3,...] # (iterator is still at second)

迭代器前进

[0,2,3,...] # (iterator is at third - print 3)

【讨论】:

  • 很好地解释了它
【解决方案3】:

为了清楚起见,添加一些print 语句:

x = range(10)

for index, number in enumerate(x):
    print "x is      ", x
    print "element is", number
    print "index is  ", index
    print

    if number % 2 == 0: 
        x.remove(number)

还有输出:

x is       [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
element is 0
index is   0

x is       [1, 2, 3, 4, 5, 6, 7, 8, 9]
element is 2
index is   1

x is       [1, 3, 4, 5, 6, 7, 8, 9]
element is 4
index is   2

x is       [1, 3, 5, 6, 7, 8, 9]
element is 6
index is   3

x is       [1, 3, 5, 7, 8, 9]
element is 8
index is   4

如您所见,index 继续上升1,即使您从列表中删除元素。这就是导致循环跳过元素的原因。

正如其他人所指出的,遍历列表并从中删除元素并不是一个好主意。而是循环复制一个副本:

for number in x[:]:

或者:

for number in list(x):

更好的是,使用列表理解创建一个新列表:

[number for number in x if number % 2 == 0]

【讨论】:

  • 这是这里最全面的答案:解释、解决方案和更好的选择。
【解决方案4】:

基本上,当您在删除某些内容的同时迭代某些内容时,您可能会出现奇怪的行为。发生的情况是您跳过了一些值,因为它们被转移到您已经迭代过的索引。

做你想做的事(过滤掉一些项目)的更好方法是使用列表推导,例如:

[x for x in range(10) if x%2==0]

您可以简单地使用range 步骤仅创建偶数,但上述解决方案让您在任何条件下都可以过滤掉。

有些数字没有被打印出来的原因是,当你循环和删除它们时,这些值会改变位置。当你删除1时,你可以想象所有的值都被移动了一个位置,迭代器指向2曾经所在的位置,但现在那里的值是3,所以2是从未印刷过。其余的值也是如此。

【讨论】:

  • 很好地使用列表理解过滤器
【解决方案5】:

正如 Mark Rushakoff 所提到的,您不应该在迭代某些内容时对其进行修改。将您的for number in x 更改为for number in x[:],它会按您的预期工作。在这种情况下,您正在迭代一个副本。

【讨论】:

    【解决方案6】:

    不要修改您正在迭代的列表。其他人建议复制列表或收集要删除的新列表。相反,请收集您想要留下的那些。这比复制列表并从未迭代的副本中删除要快,并且比收集要删除的列表然后删除它们要快。

        evens = []
        for number in x:
            if number%2 == 0:
                evens += [number]
        print(evens)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-08-31
      • 1970-01-01
      • 2015-07-11
      • 2017-01-17
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 2011-11-09
      相关资源
      最近更新 更多