itertools.tee是如何工作的?可以复制'tee'以保存其“状态”吗?

9
以下是关于 itertools.tee 的一些测试:
    li = [x for x in range(10)]
    ite = iter(li)
==================================================
    it = itertools.tee(ite, 5)
    >>> type(ite)
    <type 'listiterator'>
    >>> type(it)
    <type 'tuple'>
    >>> type(it[0])
    <type 'itertools.tee'>
    >>> 

    >>> list(ite)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[0])          # here I got nothing after 'list(ite)', why?
    []
    >>> list(it[1])
    []
====================play again===================
    >>> ite = iter(li)
    it = itertools.tee(ite, 5)
    >>> list(it[1])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[2])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[3])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[4])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(ite)
    []                       # why I got nothing? and why below line still have the data?   
    >>> list(it[0])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[0])
    []
====================play again===================    
    >>> ite = iter(li)
    itt = itertools.tee(it[0], 5)    # tee the iter's tee[0].
    >>> list(itt[0])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(itt[1])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(it[0])
    []                               # why this has no data?
    >>> list(it[1])
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    >>> list(ite)
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]  

我的问题是

  1. tee是如何工作的,为什么有时原始迭代器“有数据”,而其他时间则没有?
  2. 我能否将一个迭代器的深拷贝作为“状态种子”保留以保持原始迭代器状态,并在稍后使用tee?
  3. 我可以交换两个迭代器或两个itertools.tee吗?

谢谢!


我不确定我是否理解了你的问题,但是我认为在使用itertools.tee复制迭代器后,您不应该触摸原始迭代器。您应该从tee中获取n+1个迭代器,并使用其中一个作为“原始”来“跟踪状态”,无论您所指的是什么。 - Kimvais
1个回答

16

tee 接管了原始迭代器;一旦你使用 tee 对一个迭代器进行操作,就应该抛弃原始迭代器,因为 tee 已经拥有它了(除非你真的知道自己在做什么)。

你可以使用 copy 模块来复制 tee:

import copy, itertools
it = [1,2,3,4]
a, b = itertools.tee(it)
c = copy.copy(a)

你可以通过调用a.copy()a.__copy__()来复制一个对象。

请注意,tee通过跟踪从原始迭代器中消耗的所有迭代值来工作,这些值可能仍然被副本消耗。

例如:

a = [1,2,3,4]
b, c = itertools.tee(a)
next(b)

此时,bc底层的tee对象已经读取了一个值1,它会将其存储在内存中,因为它必须记住它以便c进行迭代。它必须一直保留每个值,直到所有副本的tee被消耗。

这意味着,通过复制该tee来“保存状态”时需要小心。如果您实际上没有从“保存状态”的tee中消耗任何值,那么您将导致tee永远将迭代器返回的每个值都保留在内存中(直到被丢弃和收集为止)。


谢谢#Glenn,那么可以将tee视为数据缓冲区,可以作为迭代器进行操作,对于大型数据集可能不太适用,是否有一种方法可以复制单个序列的“纯”迭代器?我知道深度复制无法在迭代器上工作。 - user478514
2
不,通常情况下无法复制迭代器。迭代器可以像tee实例一样公开__copy__,但通常不会这样做。 - Glenn Maynard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接