为什么我不能在同一个迭代器上迭代两次?如何“重置”迭代器或重用数据?

新手上路,请多包涵

考虑代码:

 def test(data):
    for row in data:
        print("first loop")
    for row in data:
        print("second loop")

data迭代器 时,例如列表迭代器或生成器表达式* ,这不起作用:

 >>> test(iter([1, 2]))
first loop
first loop
>>> test((_ for _ in [1, 2]))
first loop
first loop

这会打印 first loop 几次,因为 data 是非空的。但是,它 打印 second loop为什么迭代 data 第一次有效,但第二次无效?我怎样才能让它第二次工作?

除了 for 循环,同样的问题似乎发生在任何类型的迭代中:list/set/dict comprehensions, passing the iterator to list() , sum() or reduce()

另一方面,如果 data 是另一种 可迭代 的,例如 listrange --- :

 >>> test([1, 2])
first loop
first loop
second loop
second loop
>>> test(range(2))
first loop
first loop
second loop
second loop


\* 更多示例:


有关一般理论和术语解释,请参阅 什么是迭代器、可迭代和迭代? .

检测 输入是迭代器还是“可重用”可迭代对象,请参阅 确保参数可以迭代两次

原文由 JSchwartz 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1k
2 个回答

迭代器只能使用一次。例如:

 lst = [1, 2, 3]
it = iter(lst)

next(it)
# => 1
next(it)
# => 2
next(it)
# => 3
next(it)
# => StopIteration

当迭代器被提供给 for 循环时,最后一个 StopIteration 将导致它第一次退出。尝试在另一个 for 循环中使用相同的迭代器将导致 StopIteration 立即再次出现,因为迭代器已被消耗。

解决这个问题的一个简单方法是将所有元素保存到一个列表中,可以根据需要多次遍历该列表。例如:

 data = list(data)

但是,如果迭代器将迭代许多元素,则最好使用 tee() 创建独立的迭代器:

 import itertools
it1, it2 = itertools.tee(data, 2) # create as many as needed

现在每个都可以依次迭代:

 for e in it1:
    print("first loop")

for e in it2:
    print("second loop")

原文由 Óscar López 发布,翻译遵循 CC BY-SA 4.0 许可协议

迭代器(例如,来自调用 iter ,来自生成器表达式,或来自 yield 的生成器函数)是有状态的,只能使用一次。

Óscar López 的回答 对此进行了解释,但是,出于性能原因,该回答建议使用 itertools.tee(data) 而不是 list(data) 的建议具有误导性。在大多数情况下,你想要遍历整个 data 然后再次遍历整个它, tee 比简单地消耗整个迭代器需要更多的时间和使用更多的内存进入一个列表,然后迭代它两次。 tee 如果您只使用每个迭代器的前几个元素,或者如果您将交替使用一个迭代器的几个元素和另一个迭代器的几个元素,则可能是首选。

原文由 kaya3 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题