我正在寻找复制发生器的代码,然后继续使用新的生成器。它就像发电机的分叉。
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
应用程序本身要复杂得多,这只是一个代码示例。
重要(仅适用于我自己)是一种语义上美观的解决方案,对第三方来说非常易读。效率不是那么重要
答案 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()
会更快。