Python新手,试图理解这个旨在从列表中删除所有项目的迭代循环是如何处理列表中的索引以及为什么它停在它所在的位置......
为什么会循环:
foo = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
for i in foo:
foo.remove(i)
print foo
停在这里?
['b', 'd', 'f', 'h']
而不是在这里?
['H']
此外,这里有索引的“引擎盖下”发生了什么?
每次迭代时,Python都会同时跟踪下一个索引,一旦项目被删除,右边的项目会向左移动一个索引(这就是为什么它会跳过其他项目)?
答案 0 :(得分:3)
从索引零开始,删除那里的“A”。然后它移动到索引1,删除那里的“D”。 (不是“C”,因为此时它在索引零处。)然后列表中只剩下两个项目,因此无法继续进行索引2,循环结束。
也许代替for
循环,您可以使用while
循环,直到列表为空。
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 :(得分:2)
要理解为什么会这样,让我们一步一步地了解内部发生的事情。
第1步:
>>> foo = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
此处,创建了一个新的列表对象,并将其分配给foo
。
第2步:
>>> for i in foo:
现在,迭代开始了。 i
循环变量被指定为索引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
应指向索引4 处的项目,但由于原始列表已减少为4个元素,因此执行将在此处停止。
>>> foo
['b', 'd', 'f', 'h']
以上是执行后的最终清单。
一些结论:
永远不会改变列表的长度。简单来说,在执行迭代时不要修改原始列表。
当迭代地在列表中执行.remove()
时,循环变量将使用索引而不是原始列表中的实际项来引用列表项。