Python itertools tee,克隆和缓存

use*_*818 0 python python-itertools

假设:使用python时itertools.tee(),所有重复的迭代器都引用原始迭代器,并缓存原始文件以提高性能.

我在以下调查中主要关注的是关于预期/正确缓存行为的我的IDEA .
编辑:我对正确缓存的想法是基于有缺陷的功能假设.最终需要一个围绕tee的小包装(这可能会对缓存产生影响).


题:

假设我使用tee创建3个迭代器克隆:a, b, c = itertools.tee(myiter,3).还假设在这一点上,我删除了对原始的所有引用,myiter(意思是,我的代码没有很好的方式可以在下文中引用回原文).

在代码的某个后期,如果我决定要另一个克隆myiter,我可以重新发布()我的一个副本吗?(正确缓存回原来的缓存myiter)

换句话说,在稍后的某个时刻,我希望我曾用过这个: a, b, c, d = itertools.tee(myiter,4).但是,既然我已经放弃了对原作的所有引用myiter,那么我能够最好的就是: copytee = itertools.tee(a, 1) #where 'a' is from a previous tee()

tee()知道我想要什么吗?(我真的想要创建一个基于原始myiter克隆的克隆,而不是中间克隆a(可能部分消耗))

Tim*_*ers 6

什么都没有什么神奇之处tee.它只是聪明;-)在任何时候,tee克隆迭代器传递给它.这意味着克隆的迭代器将从此时产生由传入的迭代器生成的值.但它不可能为他们重现值分别产生之前 tee被调用.

让我们用比你的例子简单得多的东西来展示它:

>>> it = iter(range(5))
>>> next(it)
0
Run Code Online (Sandbox Code Playgroud)

0现在已经消失了 - 永远. tee()无法取回它:

>>> a, b = tee(it)
>>> next(a)
1
Run Code Online (Sandbox Code Playgroud)

所以a推动it产生下一个价值.这是缓存的值,以便其他克隆也可以重现它:

>>> next(b)
1
Run Code Online (Sandbox Code Playgroud)

为了获得该结果,it未触及 - 从内部缓存中检索到1.现在所有的it,a并且b已经生产了1,1,也永远消失了.

我不知道这是否能回答你的问题 - 回答"tee()知道我想要什么吗?" 似乎需要心灵感应;-)也就是说,我不知道你的意思是"适当的缓存".如果您提供了您希望的输入/输出行为的确切示例,那将是最有帮助的.

除此之外,Python文档提供了相当于tee()的Python代码,也许正在研究能够回答你问题的代码:

def tee(iterable, n=2):
    it = iter(iterable)
    deques = [collections.deque() for i in range(n)]
    def gen(mydeque):
        while True:
            if not mydeque:             # when the local deque is empty
                newval = next(it)       # fetch a new value and
                for d in deques:        # load it to all the deques
                    d.append(newval)
            yield mydeque.popleft()
    return tuple(gen(d) for d in deques)
Run Code Online (Sandbox Code Playgroud)

您可以从见,例如,一无所知的迭代器的内部状态缓存-所有这些被缓存的生产值传入的迭代器,从时间开始tee()被调用.每个克隆都有自己的deque(FIFO列表)到目前为止生成的传入迭代器的值,并且所有克隆都知道传入的迭代器.所以对于你真正希望的任何东西来说,这可能太简单了.