为什么迭代循环删除列表中的项目停止

Why iterative loop to remove items in list stops

Python 的新手,试图理解这个旨在从列表中删除所有项目的迭代循环是如何处理列表中的索引的,以及为什么它在它执行的位置停止...

为什么会出现这个循环:

foo = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
for i in foo:
    foo.remove(i)
    print foo

到此为止?

['b', 'd', 'f', 'h']

而不是这里?

['H']

此外,"under the hood" 这里的索引发生了什么?

在每次迭代中,Python 都会跟踪下一个索引,同时,一旦删除了一个项目,其右侧的项目就会向左移动一个索引(这就是它跳过的原因每一项)?

它从索引零开始,删除那里的 "A"。然后它移动到索引一,删除那里的 "D" 。 (不是 "C",因为此时它的索引为零。)然后列表中只剩下两个项目,所以它不能移动到索引二,循环结束。

也许您可以使用 while 循环来代替 for 循环,该循环一直持续到列表为空。

foo = ['A', 'C', 'D', 'E']
while foo:
    foo.pop(0)
    print foo

... 或者您可以遍历列表的副本,当您修改 foo 时,它不会从您下面更改。当然,这会占用一些额外的内存。

foo = ['A', 'C', 'D', 'E']
for i in foo[:]:
    foo.remove(i)
    print foo

要了解为什么会发生这种情况,让我们逐步了解内部发生的情况。

第 1 步:

>>> foo = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

这里创建了一个新的列表对象,并赋值给foo

第 2 步:

>>> for i in foo:

现在,迭代开始了。 i 循环变量被赋值为 index 0 处的项目值,即 'a'.

第 3 步:

>>> foo.remove(i)
>>> print foo
['b', 'c', 'd', 'e', 'f', 'g', 'h']

现在,.remove(i) 显然执行 .remove(foo[0]) 而不是 .remove('a')。新列表现在在索引 0 处有 'b',在索引 1 处有 'c',依此类推。

第 4 步:

>>> for i in foo:

对于下一次迭代,i 循环变量被赋予索引 1 处项目的值,当前为 'c'

第 5 步:

>>> foo.remove(i)
>>> print foo
['b', 'd', 'e', 'f', 'g', 'h']

这一次,.remove(i) 执行 .remove(foo[1]),从列表中删除 'c'。当前列表现在在索引 0 处有 'b',在索引 1 处有 'd',依此类推。

第 6 步:

>>> for i in foo:

对于下一次迭代,i 循环变量被赋予 索引 2 处的项目值,当前为 'e'.

第 7 步:

>>> foo.remove(i)
>>> print foo
['b', 'd', 'f', 'g', 'h']

这一次,.remove(i) 执行 .remove(foo[2]),从列表中删除 'e'。类似地,项目的索引在上面的步骤 5 中得到更改。

第 8 步:

>>> for i in foo:

对于下一次迭代,i 循环变量被赋予 索引 3 处的项目值,当前为 'g'.

第 9 步:

>>> foo.remove(i)
>>> print foo
['b', 'd', 'f', 'h']

这一次,.remove(i) 执行 .remove(foo[3]),从列表中删除 'g'

第 10 步:

>>> for i in foo:

现在,i 应该指向 index 4 处的项目,但由于原始列表已减少到 4 个元素,因此执行将在此处停止。

>>> foo
['b', 'd', 'f', 'h']

以上是执行后的最终列表。

一些结论:

  • 在对列表进行迭代时切勿更改列表的长度。简而言之,在对其进行迭代时不要修改原始列表。

  • 在列表中迭代执行.remove()时,循环变量将使用索引引用列表项,而不是原始列表中的实际项。