2014-01-23 139 views
15

发电机我使用发电机功能,说:现在深拷贝在Python

def foo(): 
    i=0 
    while (i<10): 
     i+=1 
     yield i 

,我想任何数量的迭代后,发电机复制选项,从而使新副本保留内部状态(在示例中将具有相同的'i'),但现在将独立于原始状态(即,对副本的迭代不应改变原始状态)。

我一直在使用copy.deepcopy尝试,但我得到的错误:

"TypeError: object.__new__(generator) is not safe, use generator.__new__()" 

很显然,我可以解决这个使用常规的功能与计数器的例子。 但我真的在寻找使用生成器的解决方案。

+5

我不*认为*这是可能的。如果你只需要对结果进行两次迭代,那么读到'list'并多次迭代'list',或者'itertools.tee'可能会有所帮助。它不会复制生成器,但它只是将结果存储在队列中,并稍后再将它们吐出。因此,当你阅读“复制”(这可能是你想要从一个生成器的真正克隆中想要的)时,你的函数的任何副作用都不会再被执行,并且如果你从“复制”中读取它*将推进底层的发电机 - 一旦你已经注意到你基本上需要所有的读者使用T恤,而不是原装。 –

+0

你真的想解决什么问题?有多种可能的答案。 –

+1

您可能已经知道这一点,但“Define”不是合法的python。正确的关键字是'def' – SethMMorton

回答

8

有三种情况,我能想到的:

  • 发电机没有副作用,你只是想能够回头看看你已经捕获的结果。你可以考虑一个cached generator而不是一个真正的发电机。您也可以共享缓存的生成器,并且如果有客户走到您还没有访问过的项目,它会前进。这与tee()方法类似,但是在生成器/缓存本身中实现了TEE功能,而不需要客户端来完成。

  • 发电机有副作用,但没有历史记录,您希望能够在任何地方重新启动。考虑将其编写为coroutine,您可以随时传入值以启动。

  • 发生器具有副作用和历史,这意味着G(x)处的发生器的状态取决于G(x-1)的结果,因此您不能只将x传回到它以开始任何地方。在这种情况下,我认为你需要更具体地了解你想要做什么,因为结果不仅取决于生成器,还取决于其他数据的状态。在这种情况下,可能有更好的方法来做到这一点。

4

itertools.tee的评论也是我的第一个猜测。因为,你不应该使用开球后不再前进原来发电机的警告,我可能会写这样的分拆副本:

>>> from itertools import tee 
>>> 
>>> def foo(): 
... i = 0 
... while i < 10: 
...  i += 1 
...  yield i 
... 
>>> 
>>> it = foo() 
>>> it.next() 
1 
>>> it, other = tee(it) 
>>> it.next() 
2 
>>> other.next() 
2 
+1

不应使用名称'new',因为它也是模块名称。 – leewz

+0

@leewangzhong - 修正了,谢谢。 –