【发布时间】:2015-07-02 08:48:26
【问题描述】:
假设我有一个这样的生成器
def gen():
a = yield "Hello World"
a_ = a + 1 #Imagine that on my computer "+ 1" is an expensive operation
print "a_ = ", a_
b = yield a_
print "b =", b
print "a_ =", a_
yield b
现在假设我愿意
>>> g = gen()
>>> g.next()
>>> g.send(42)
a_ = 43
43
现在我们计算出a_。现在我想像这样克隆我的生成器。
>>> newG = clonify(g)
>>> newG.send(7)
b = 7
a_ = 43
7
但我原来的g 仍然有效。
>>> g.send(11)
b = 11
a_ = 43
11
具体来说,clonify 获取生成器的状态,并复制它。我可以将我的生成器重置为像旧的一样,但这需要计算a_。另请注意,我不想广泛修改生成器。理想情况下,我可以从库中获取一个生成器对象并 clonify 它。
注意:itertools.tee 不起作用,因为它不处理发送。
注意:我只关心通过在函数中放置 yield 语句创建的生成器。
【问题讨论】:
-
这并不像听起来那么容易。如果生成器使用无法克隆的文件或网络流怎么办?虽然看看
itertools.tee -
简短的回答是您不能在 Python 中克隆生成器。但至少在理论上可以添加自己的生成器克隆支持,如果您不关心实现之间的可移植性,这意味着您可以自己做出所有决定(文件共享、复制还是提升?是否共享闭包变量? 你是深拷贝还是浅拷贝本地人?)。如果您有兴趣这样做,您可以提出很多很好的问题,但只是“我该如何做整个事情”可能太宽泛了。
-
@user2357112:实际上,即使是这样,也是通过编译然后调用带有
yield x+1语句的隐藏函数来实现的…… -
@PyRulez:不,这实际上不是生成器。尽管它几乎可以在任何地方替代生成器,因此您可以将其称为“类似生成器的对象”,但它不会传递
inspect.isgenerator或isinstance(g, types.GeneratorType),并且它没有gi_frame属性。 -
@JoranBeasley:虽然他的玩具示例并不是将生成器用于协程的有用示例,但那里有很多很好的示例,它们都会遇到这个问题。 (如果没有,Guido 会拒绝添加
send的 PEP,而不是成为它的合著者并确保它在 2.5 之前完成......)
标签: python python-2.7 clone generator coroutine