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
答案 0 :(得分:5)
这完全是“预期的”并记录在案的行为。当您遍历列表时,您基本上是在内存位置上进行迭代。当您从列表中弹出一些内容时,列表中的所有内容会将1个索引移动到更靠近列表开头的位置。因此,您最终会跳过项目。当您到达列表末尾时,迭代停止。
通常在执行此类操作时,您希望迭代列表的副本:
for b in a[:]:
...
如评论中所示,如果以相反的顺序迭代列表:
for b in reversed(a):
a.pop()
这是按预期工作的,因为你不断拉出最后一个元素,因此你不会改变你尚未看到的任何元素列表中的位置。
答案 1 :(得分:4)
您正在遍历列表并同时更改它。通过使用.pop()
缩短列表,但迭代器指针不会更新。
改为使用副本:
for b in list(a):
或
for b in a[:]:
其中[:]
切片表示法返回列表副本。
另一种方法是使用while
循环代替:
while a:
print a.pop(0)
因为空列表测试为布尔值False
。
python for
循环使用它的参数作为迭代器,它本身不保留索引。 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()
时,它会在下一个索引处给出值,该值可能,直到计数器为止等于列表的当前长度。
答案 2 :(得分: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
答案 3 :(得分:0)
在for
循环的每次迭代中,我们必须检查条件b in a
所以当你开始时:
a = [0,1,2,3,4,5]
for b in a:
print ":"+str(b)
a.pop(0)
b = 0
和in 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
会更大比数组的大小,所以我们已经完成了。