2011-08-24 50 views
27

Python的鹹菜(我說的是標準的Python 2.5/2.6/2.7在這裏)不能鹹菜鎖,文件對象等爲什麼發電機不能酸洗?

這還不能泡菜發電機和lambda表達式(或任何其他匿名代碼),因爲泡菜真的只存儲名稱引用。

在鎖和操作系統相關功能的情況下,原因爲什麼你不能pickle他們是顯而易見的,是有道理的。

但是爲什麼你不能泡菜發電機?


:只是爲了清楚起見, - 我有興趣的根本原因(或假設和進入該設計決策選擇)爲什麼,而不是「,因爲它給你一個味酸錯誤」。

我意識到這個問題有點廣泛,所以下面是你回答它的一個經驗法則:「如果提出這些假設,或者允許的發生器的類型更受限制,酸洗髮生器會再次工作嗎?」

+1

什麼時候泡泡發生器會有意義? – NullUserException

+10

@NullUser:想象不難;你正在遍歷一個,你想停止你的程序,以後再恢復你以後離開的地方。 –

+3

...或者同時恢復,但是來自不同的程序(=序列化也用於網絡傳輸) – Radim

回答

39

有很多這方面的信息可用。對於這個問題的「官方話」,請閱讀(closed) Python bugtracker issue

核心推理,通過誰決定的人之一,是詳細的this blog

由於發電機本質上是各式的功能,我們需要保存它的字節碼,這是不保證在Python版本和它的框架之間向後兼容,框架保存發生器的狀態,如局部變量,閉包和指令指針。而後者完成起來相當麻煩,因爲它基本上需要使整個解釋器可供選擇。所以,對酸洗髮生器的任何支持都需要對CPython核心進行大量的更改。

現在,如果一個對象在一個生成器的局部變量中不受pickle支持(例如文件句柄,套接字,數據庫連接等),那麼無論pickle支持什麼,該生成器都不會被自動醃製我們可能會實施的發電機。所以在這種情況下,您仍然需要提供自定義的__getstate____setstate__方法。這個問題使發電機的酸洗支持受到限制。

和兩個建議的解決方法中提到:

無論如何,如果你需要一個這樣的特徵,然後看看無堆棧的Python它做上述所有。由於Stackless的解釋器是可挑選的,您還可以免費獲得流程遷移。這意味着您可以中斷一個tasklet(Stackless的綠色線程的名稱),醃製它,將pickle發送到另一臺機器,取出它,恢復tasklet,並且您剛剛遷移了一個進程。這真是太酷了!

但在我看來,這個問題的最好的解決方案是將發生器重寫爲簡單的迭代器(即使用__next__方法)。由於迭代器的狀態是明確的,所以迭代器在空間上很容易和高效。但是,您仍然需要明確處理代表某種外部狀態的對象;你無法繞過這個。

+0

優秀的答案,謝謝。我找到了「generator_tools」,這是一個聲稱可以做到這一點的純Python包。雖然我不能讓它工作,所以我想你(和亞歷山大)是正確的... – Radim

+0

該包在http://metaoptimize.com/blog/2009/12/22/why-cant-you上提及-pickle-generators-in-python-workaround-pattern-for-saving-training-state /其中還有另一種解決方法模式。 – agf

+1

如何提供答案並同時投票「關閉」?現在我好奇地等待着「辯論,辯論和擴展討論」:-) – Radim

19

你實際上可以,取決於實施。​​3210和Stackless Python都允許這種(在一定程度上是這樣):

Python 2.7.1 (dcae7aed462b, Aug 17 2011, 09:46:15) 
[PyPy 1.6.0 with GCC 4.0.1] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
And now for something completely different: ``Not your usual analyses.'' 
>>>> import pickle 
>>>> gen = (x for x in range(100)) 
>>>> next(gen) 
0 
>>>> pickled = pickle.dumps(gen) 
>>>> next(pickle.loads(pickled)) 
1 

在CPython中它也可以創建一個iterator object模擬揀選發電機。

+0

-1:都是真的,但回答了一個不同的問題。 – Radim

+1

@Radim它回答了我的問題。 –