2014-01-23 194 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 - 修正了,謝謝。 –