python3 分叉生成器

python3 bifurcated generator

我正在寻找一个代码来复制生成器,然后继续使用新的生成器。它就像发电机的分叉。

def Generator():
    myNumbers=range(3)
    for i in myNumbers:
        yield i

for i in Generator():
    bifurcatedGenerator = Generator
    for j in bifurcatedGenerator():
        print (i, j)

此代码作为输出给出:

0 0
0 1
0 2
1 0
1 1
1 2 <- wrong
2 0
2 1 <- wrong
2 2 <- wrong

而不同的输出应该是:(分叉生成器需要是一个新实例,但在旧生成器停止的同一点继续。)

0 0
0 1
0 2
1 1
1 2
2 2

应用程序本身要复杂得多,这里只是一个代码示例。

重要的(只对我自己而言)是一个语义优美的解决方案,对第三者来说很好读 parties.Efficiency 不是那么重要

有些人会告诉你使用 itertools.tee。不要使用 itertools.tee.

使用 list

要跟踪生成器之前的状态,您需要将之前生成的值存储在 list 中。这就是函数 itertools.tee 在复制生成器时所做的事情。

不幸的是,这消除了使用生成器的所有内存优势。所以你最好使用 list.

def generator():
    yield from range(3)

lst = list(generator())

for i in range(len(lst)):
    for j in range(i, len(lst)):
        print(lst[i], lst[j])

输出:

0 0
0 1
0 2
1 1
1 2
2 2

那为什么不使用 itertools.tee

仍然可以使用 itertools.tee,但你不应该使用。

from itertools import tee

def generator():
    yield from range(3)

lst = list(generator())

main_gen, bif_gen = tee(generator())

for i in main_gen:
    for j in bif_gen:
        print(i, j)
    _, bif_gen = tee(main_gen) # Yes, you *must* use the second item here

前面代码工作的原因很微妙,实际上与以下事实有关:itertools.tee returns 当给定 [=22= 时,第一个输出值是相同的 tee 对象] 目的。这就是应该使用第二个生成器的原因。

这与 doc 明确指定 list 在这种情况下更好的事实相结合,表明必须首选第一个解决方案:

This itertool may require significant auxiliary storage (depending on how much temporary data needs to be stored). In general, if one iterator uses most or all of the data before another iterator starts, it is faster to use list() instead of tee().

为什么不使用带有启动参数的生成器(并在使用时使用停止参数)?

def Generator(start=0, stop=3):
    for i in range(start, stop):
        yield i

for i in Generator():
    for j in Generator(start=i):
        print (i, j)

同时给出输出:

0 0
0 1
0 2
1 1
1 2
2 2