python3分叉发电机

时间:2018-06-07 16:54:40

标签: python python-3.x algorithm generator yield

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

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

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

重要(仅适用于我自己)是一种语义上美观的解决方案,对第三方来说非常易读。效率不是那么重要

2 个答案:

答案 0 :(得分:2)

为什么不使用带有启动参数的发生器(当你在它时使用停止参数)?

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

答案 1 :(得分:1)

有些人会告诉您使用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在给定tee对象时返回与第一个输出值相同的tee对象的事实相关联。这就是应该使用第二台发电机的原因。

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

  

这个itertool可能需要大量的辅助存储(取决于   需要存储多少临时数据)。一般来说,如果一个   迭代器在另一个迭代器启动之前使用大部分或全部数据,   使用list()而不是tee()会更快。