For 循环的迭代次数少于我在 Python 中的预期
Posted
技术标签:
【中文标题】For 循环的迭代次数少于我在 Python 中的预期【英文标题】:For loop iterates less times than I expected in Python 【发布时间】:2019-10-17 05:40:27 【问题描述】:我希望下面的循环迭代六次,而不是使用 python3 迭代三次。我不明白这种行为。 我知道当我删除元素时列表会发生变化,但我不知道这会如何影响 for 循环条件。 为什么循环迭代不到六次?
a = [1, 2, 3, 4, 5, 6]
for elem in a:
del a[0]
print(a)
【问题讨论】:
提示:列表迭代器提供第一个、第二个、第三个...项。 根据经验,如果您在迭代期间修改要迭代的集合,您将注定失败 【参考方案1】:CPython 中的list
迭代器通过迭代列表的位置 工作。你可以认为它是这样工作的:
def list_iter(items: list):
index = 0
while True:
yield items[index]
index += 1
换句话说,迭代在 0 处提供项目,然后是 1,然后是 2,依此类推。没有预取项目 - 需要时从列表中查找项目。
当您在每个步骤中删除第一项时,列表在每个步骤中都会缩短 1。由于您从 6 个项目的列表开始,因此在第三次迭代中它减少到 3 个项目 - 这意味着第四次迭代无法查找项目。因此,您的迭代将在三个步骤后完成。
您可以在打印每个循环中的当前元素时看到这一点。要可视化效果,请使用enumerate
获取迭代的索引。请注意,它前进了一个索引,但值也移动了两个总偏移量:
>>> a = [1, 2, 3, 4, 5, 6]
... for idx, elem in enumerate(a):
... print(elem, 'from', a)
... print(' ', ' '*idx, '^')
... del a[0]
...
1 from [1, 2, 3, 4, 5, 6]
^
3 from [2, 3, 4, 5, 6]
^
5 from [3, 4, 5, 6]
^
在迭代容器时修改容器通常没有明确定义。你应该迭代一个副本:
a = [1, 2, 3, 4, 5, 6]
for elem in a.copy():
del a[0]
print(a)
【讨论】:
很好的解释。谢谢@MisterMiyagi!一个问题——如果第一个代码是sn-p,最后一行应该是index += 1
吗?
@SupratimHaldar 是的,感谢您发现错误。修好了。【参考方案2】:
您将在循环的每次迭代中删除第一个元素 del a[0]
,因此迭代器分 3 步清空,因为它会移动到您在下一次迭代中删除的元素之后的元素。
您可以检查迭代器当前所在的元素,以及下面代码中的列表状态
a = [1, 2, 3, 4, 5, 6]
for elem in a:
print(elem)
del a[0]
print(a)
输出是
1
[2, 3, 4, 5, 6]
3
[3, 4, 5, 6]
5
[4, 5, 6]
你可以把它想象成一个指向列表第一个元素的指针,每次迭代删除第一个元素时,指针会跳转2步,6个元素只能跳转3次。
通常,修改您正在迭代的同一个列表是一个坏主意。
但是如果你真的想要,你可以遍历列表的副本a[:]
如果你真的想删除项目
a = [1, 2, 3, 4, 5, 6]
for elem in a[:]:
del a[0]
print(a)
输出是
[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
【讨论】:
嗯,好的,我想我明白了,谢谢。因此,在每次迭代之前都会检查列表 a。三次迭代后,列表中将只剩下三个元素,因此没有第四个元素要获取。起初我没有得到“迭代器在 3 个步骤中清空”的表达,但我知道我想我明白了。谢谢。 把它想象成一个指向列表第一个元素的指针,每次迭代删除第一个元素时,指针会跳转2步,6个元素只能跳转3次@Zois 谢谢!此外,del [0]
、a
上的小错字也不见了。它不允许我编辑它。【参考方案3】:
迭代和同时从列表中删除元素是很棘手的。管理它的一种方法是反向遍历列表:
a = [1, 2, 3, 4, 5, 6]
for elem in reversed(a):
print(a)
del a[0]
print(a)
它会打印出来:
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[3, 4, 5, 6]
[4, 5, 6]
[5, 6]
[6]
[]
【讨论】:
有趣。您能否添加几行来解释这里发生了什么?我只是好奇,为什么reverse(a)
在这种情况下有效。
倒退不会破坏迭代器,@MisterMiyagi 在他的回答中更好地解释了这一点。
好的。谢谢@Óscar López!以上是关于For 循环的迭代次数少于我在 Python 中的预期的主要内容,如果未能解决你的问题,请参考以下文章