为啥带有pop-method(或del语句)的for循环不会遍历所有列表元素

Posted

技术标签:

【中文标题】为啥带有pop-method(或del语句)的for循环不会遍历所有列表元素【英文标题】:Why does a for-loop with pop-method (or del statement) not iterate over all list elements为什么带有pop-method(或del语句)的for循环不会遍历所有列表元素 【发布时间】:2012-12-06 00:50:47 【问题描述】:

我是 Python 新手,正在尝试使用列表 我在 linux2 上使用 Python 3.2.3(默认,2012 年 10 月 19 日,20:13:42),[GCC 4.6.3]

这是我的示例代码

>>> l=[1,2,3,4,5,6]
>>> for i in l:
...     l.pop(0)
...     print(l)
... 

我希望得到以下输出

1
[2, 3, 4, 5, 6]
2
[3, 4, 5, 6]
3
[4, 5, 6]
4
[5, 6]
5
[6]
6
[]

相反,我得到了这个

1
[2, 3, 4, 5, 6]
2
[3, 4, 5, 6]
3
[4, 5, 6]

for 循环在 3 圈后停止迭代。谁能解释一下原因?

【问题讨论】:

Modifying list while iterating的可能重复 @NedBatchelder:虽然根本原因相同,但问题却大不相同。调用pop 的原因甚至不一样(链接试图跳过,这个不是)。 【参考方案1】:

展开一点(插入符号 (^) 位于循环“索引”处):

your_list = [1,2,3,4,5,6]
             ^

弹出第一个项目后:

your_list = [2,3,4,5,6]
             ^

现在继续循环:

your_list = [2,3,4,5,6]
               ^

现在弹出第一个项目:

your_list = [3,4,5,6]
               ^

现在继续循环:

your_list = [3,4,5,6]
                 ^

现在弹出第一个项目:

your_list = [4,5,6]
                 ^

现在继续循环——等等,我们完成了。 :-)


>>> l = [1,2,3,4,5,6]
>>> for x in l:
...     l.pop(0)
... 
1
2
3
>>> print l
[4, 5, 6]

【讨论】:

第二次迭代的打印如何显示弹出值 2?由于在第一次迭代结束时指针为 2,那么下一次迭代指针应为 3。所以它不应该打印 3 而不是 2? 不,因为我总是弹出0th 元素,而不是当前列表迭代器指针索引处的元素。【参考方案2】:

您可以为此任务使用while 循环而不是for 循环。

while len(some_list)>0 :
    some_list.pop(0)

for 循环实际上会遍历列表中的每个项目,这将不起作用,因为列表中的索引会随着每次删除而改变,并且您最终不会得到所有项目。

但是,while 循环会在每次运行循环时检查一个条件,如果仍然为真,则再次运行代码。这里我们指定列表的长度必须大于0,即列表中必须有内容。

【讨论】:

你应该解释一下投反对票。这个答案是正确的。 这是处理提问者面临的问题的一个很好的答案,但它不是原始问题的计算机科学答案。 :P 我确实用它来解决我的问题。【参考方案3】:

尝试修改正在迭代的集合时必须小心。在这种情况下,列表使用简单的整数索引来跟踪“当前位置”。当您使用pop() 时,所有内容都会更改索引,因此会跳过元素。

在循环的第一次迭代中,i 是 l[0]。然后弹出列表,然后访问 l[1],它最初位于 l[2]。然后弹出列表,下一次迭代访问 l[2],这就是以前在 l[4] 的位置,等等。

无论如何都不需要在这段代码中弹出元素,大概你在真实代码中做了一些更复杂的事情。

【讨论】:

【参考方案4】:

Python 不支持在迭代列表时更改列表的长度。处理副本或改用list comprehension。

想想 Python 实际上是如何执行 for 循环的 - 它通过元素进行计数,返回当前索引处的项目。当您删除一个时,索引意味着不同的元素。

【讨论】:

在一种情况下它可能会起作用。在每次迭代中弹出最后一个元素时。 在某些情况下它可能会起作用。这不是你应该依赖的东西,但是有更好的方法。 Python 确实支持在迭代列表时修改列表,一旦您了解正在发生的事情,它就会以一致且可预测的方式工作。顺便说一句,对于某些用例,另一个有用的解决方法是以相反的顺序对列表进行操作。 可以做某事和应该做某事之间有很大的区别;-)。您绝对可以在迭代列表时修改它,但我认为大多数时候,您可能不应该【参考方案5】:

代码

l = [1,2,3,4,5,6]
for i in range(len(l)):
    l.pop(0)
    print(l)

退货

[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]

【讨论】:

【参考方案6】:
li = [1, 2, 3, 4, 5]

while li:
    # For descending order
    # print(li.pop())

    # For ascending order
    print(li.pop(0))

【讨论】:

以上是关于为啥带有pop-method(或del语句)的for循环不会遍历所有列表元素的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用带有 SqlTransaction 的 using 语句?

python中del 语句的用法?

python -使用del语句删除对象引用

带有项目的地图中的返回语句:在 Flutter DropdownButton 中,为啥以及如何工作

为啥带有 some 方法的三元运算符会使此语句为假?

为啥 C++ 不需要“new”语句来初始化 std::vector?