1
a = [0,1,2,3,4,5]
for b in a:
  print ":"+str(b)
  a.pop(0)

认为这可以按顺序遍历整个列表及其所有项目,我运行了此代码并期望这一点。

:0
0
:1
1
:2
2
:3
3
:4
4
:5
5

相反,我得到了这个:

:0
0
:2
1
:4
2

现在我明白为什么会发生这种情况,但这是python中的错误吗?它不应该仍然遍历所有原始对象而不是当前列表的长度吗?为什么这没有抛出和越界错误?IE:它不应该已经完成​​了吗:

:0
0
:1
2
:2
4
:3
Error
:4
Error
:5
Error
4

4 回答 4

5

这完全是“预期的”和记录的行为。当您遍历列表时,您基本上是在遍历内存位置。当您从列表中弹出某些内容时,列表中的所有内容都会将 1 个索引移到更靠近列表开头的位置。因此,您最终会跳过项目。当您到达列表末尾时,迭代停止。

通常,在执行此类操作时,您希望遍历列表的副本:

for b in a[:]:
    ...

如评论中所示,如果您以相反的顺序遍历列表:

for b in reversed(a):
    a.pop()

这可以按预期工作,因为您不断地拉出最终元素,因此您不会改变您尚未看到的任何元素列表中的位置。

于 2013-01-22T18:37:10.027 回答
4

您正在循环列表并同时更改它。通过使用.pop(),您正在缩短列表,但迭代器指针不会更新。

请改用副本:

for b in list(a):

或者

for b in a[:]:

其中[:]切片表示法返回列表副本。

另一种方法是使用while循环代替:

while a:
    print a.pop(0)

因为空列表测试为 boolean False

pythonfor循环使用它的参数作为迭代器,它本身并不保留索引。循环无法for“知道”您删除了元素。相反,它list()是保留该指针的迭代器:

>>> a = [0,1,2,3,4,5]
>>> itera = iter(a)
>>> itera.next()  # index 0 -> a[0] is 0
0
>>> a.pop(0)
0
>>> a
[1,2,3,4,5]
>>> itera.next()  # index 1 -> a[1] is 2
2

该迭代器保留一个计数器,每次调用next()迭代器时,它都会为您提供下一个索引处的值,无论该值可能是什么,直到计数器等于列表的当前长度。

于 2013-01-22T18:36:57.097 回答
0

如果你想.pop()在循环中使用,一个常见的习惯用法是使用它while

a = [0,1,2,3,4,5]
while a:
  print ":{}".format(a.pop(0))

或者,如果您想要那里的印刷图案:

a = [0,1,2,3,4,5]
while a:
    print ":{}\n{}".format(a[0],a.pop(0))

印刷

:0
0
:1
1
:2
2
:3
3
:4
4
:5
5
于 2013-01-22T18:42:34.350 回答
0

在循环的每次迭代中,for我们必须检查条件b in a所以当你开始时:

a = [0,1,2,3,4,5]
for b in a:
  print ":"+str(b)
  a.pop(0)

b = 0in a(意思是a中的元素)是5。现在打印字符串化版本,a[b]然后删除数组的第一个元素。因此迭代二变为:

a = [1, 2, 3, 4, 5]
b = 1 (it incremented)
size of a = 4 (it shrank)

接下来它们将是b=2,a 的大小变为 3。最后一次迭代会产生您所期望的越界错误,因为b它将大于数组的大小,所以我们完成了。

于 2013-01-22T18:56:03.663 回答