【问题标题】:Unexpected behavior when copying iterators using tee使用 tee 复制迭代器时的意外行为
【发布时间】:2021-01-03 21:26:01
【问题描述】:

如果您在 for 循环中复制迭代器,则迭代会恢复正常。例如:

ita = iter(range(5))
for a in ita:
    print(a)
    if a == 2:
        ita, itb = tee(ita)

打印0 1 2 3 4。但是,如果您迭代第二个副本,原始迭代器也会耗尽:

ita = iter(range(5))
for a in ita:
    print(a)
    if a == 2:
        ita, itb = tee(ita)
        for b in itb:
            pass

只打印0 1 2

据我了解,对复制的迭代器进行迭代不应该影响原始迭代器,所以我不知道为什么会这样。任何帮助将不胜感激

【问题讨论】:

  • (1) 尽管您在 for 循环中设置了 ita,但这不会影响 for a in ita 中的 ita,因为它仅在循环首先进入。 (2) tee 返回的迭代器相互独立,但tee 在读取返回的迭代器之一时必须从其输入迭代器中读取以填充其返回的迭代器。
  • 这可以是一个答案..

标签: python loops iterator


【解决方案1】:

tee 从一个迭代器创建两个迭代器。这两个创建的迭代器中的每一个都可以独立使用,即消耗其中一个不会消耗另一个。

但是,必须使用原始迭代器。例如:

a = iter(range(5))
b, c = tee(a)
for value in b:
    pass

此时,b 被消耗。通过消费ba也被消费了,但c还没有被消费。见:

>>> list(a)
[]
>>> list(b)
[]
>>> list(c)
[0, 1, 2, 3, 4]

现在,在原始代码中,相同的变量名用于两件事:

ita, itb = tee(ita)

这里有 3 个迭代器,但其中两个使用变量名 ita。这就是混乱的原因。新的 ita 迭代器不会与 itb 一起使用,但旧的迭代器会。

请注意,for a in ita: 中使用的是原始ita,而不是新的。这是因为它 ita 变量仅在第一次执行 for 行时被读取,然后将其他内容分配给 ita 不会影响循环。

添加这一行可以看到新的ita没有被消耗:

ita = iter(range(5))
for a in ita:
    print(a)
    if a == 2:
        ita, itb = tee(ita)
        for b in itb:
            pass
        print(list(ita))  # dded line

打印:

0
1
2
[3, 4]

【讨论】:

    【解决方案2】:

    documentation for tee states:

    一旦tee() 进行了拆分,原来的iterable 不应该在其他任何地方使用;否则,iterable 可以在不通知 tee 对象的情况下前进。

    您触发的行为与文档中讨论的行为相反(tee 正在推进迭代器而不通知ita其他 消费者[for 循环]) ,但它会导致完全相同的问题。

    换一种说法,tee 假定它拥有传入的迭代器(“用于学习目的”实现中的伪 Python 也显示了同样多的内容)——并且由于 iter 的迭代器是有状态的,当tee 使用 ita 中的剩余元素,它会在您的 for 循环的下一轮之前清空 ita 中的剩余条目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-08
      • 1970-01-01
      • 2011-09-11
      • 2012-05-09
      • 2013-02-11
      • 2020-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多