2013-07-02 29 views
1

正如我所理解的,您可以在文件和項目之間發送物體,只要這些物體都存在於兩個名稱空間中即可。我有兩個應用程序,這將傳遞一個Prime對象。更改醃漬物體的功能

class Prime(): 
    def __init__(self): 
     self.a = 1 
    def func(self): 
     print(self.a) 

這兩個應用程序都以上面的素數版本開始。但第一個應用程序將不得不改變Prime的功能,例如func將會打印(「hello world」)。然後,第二個應用程序將收到總理的第一次的版本通過泡菜和使用這樣的:

Second.py:

i = Prime 
i.func() 
with open("temp.txt", "r") as text: 
    o = pickle.load(text) 
    o.func() 

輸出:

1 
hello world 

我的2部分的問題這是。如果第二個應用程序在其名稱空間中只有原始版本的Prime,那麼只要函數名稱沒有更改,它就可以使用第一個應用程序。如果是的話,我該如何去改變Prime.func的功能?

+1

首先,你的意思是'我= Prime()'? – abarnert

+0

其次,你真的不能使用'pickle'在不同的應用程序之間發送具有不同模塊和類名的相同名稱的對象,而沒有很多詭異的解決方法。你是否特別要問如何爲你的特定案例做這些黑客行爲?即使你知道這通常是一個壞主意,因爲你確定在這種情況下它不是? – abarnert

+1

最後,通常'pickle'永遠不會真正地醃製函數對象,只是[完全限定引用它們的名字](http://docs.python。組織/ 2 /庫/ pickle.html#什麼,可待醃-和拆封)。解決這個問題的唯一方法是實現你自己的'__reduce__'和朋友,他們會做一些事情,像pickle'co_code'和其他需要從另一邊重新構建代碼和函數的信息(並檢查它是否適合Python版本,作爲.pyc文件)。如果這對你來說聽起來像是希臘語,你甚至不應該考慮這一點。 – abarnert

回答

1

唯一辦法做到這一點是讓這​​兩個應用程序使用的任何模塊定義了Prime類,在完全相同的限定名導入的版本完全相同。由於What can be pickled and unpickled?解釋爲:

...函數(內置的和用戶定義的)由「完全限定」名稱引用而不是按值賦值。這意味着只有函數名稱被醃漬,以及定義該函數的模塊的名稱。該函數的代碼及其任何函數屬性都不會被醃製。因此,定義模塊必須可以在取消環境中導入,並且模塊必須包含指定的對象,否則將引發異常。

換句話說,當你在第二個應用程序unpickle一個Prime對象,這將是第二個應用程序的版本Prime類的實例,即使從第一個應用程序來。


更一般地,酸洗被設計爲序列數據要被讀回在同一應用程序,或至少在一個非常緊密耦合的應用程序共享所有相關代碼。如果您想要更多的分離交換機制,請考慮使用JSON或YAML。


但是,假設你知道了這一切,而你確實想醃出於某種原因的方法實現。你能做到嗎?

當然可以。這只是一個很大的工作,而且有點冒險。既然你正在試圖做一些Python顯式地不想做的事情,那麼你必須期待這一點。

首先,你需要編寫一個代碼pickler來傳遞足夠的信息,你可以用它來調用types.CodeType的構造函數。這是在實施細節與只是語言的一個深層部分,所以唯一可以看到構造函數參數的地方是在交互式控制檯上鍵入help,並且唯一可以通過查看the table in the inspect docs並且猜測哪個參數發生變化來告訴那些參數意思是的方法與成員一起。 (這很簡單 - argcountco_argcount等)

你會注意到,一些code成員可能實際上沒有意義。例如,如果接收器不打算將這些文件放在文件系統的相同路徑中,是否真的想通過co_filenameco_firstlineno? (這會導致產生回溯的錯誤,而不僅僅是沒有源信息的回溯。)

無論如何,pickler只是創建並醃製你想要的任何成員的元組,而unpickler則會相反。但是你可能想在這裏填入sys.version_info或其他標記,所以你不要試圖解除字節碼,你不能運行。 (看看.pyc文件如何處理細節。)

接下來,你必須對函數類型做同樣的事情 - 當然,它會爲其代碼對象調用code pickler。

所以,現在你有代碼可以pickle和unickle一個函數(包括它的代碼)。你有什麼好處?

當您編寫您的Primes.__getstate__和/或Primes.__reduce__時,您可以覆蓋正常的酸洗機制,以將func方法的實現視爲對象狀態的一部分。

如果你真的願意,你可以泡製元類,所以func方法可以醃製作爲類的狀態,而不是,這意味着你會在類字典正常的實例方法描述符結束的一部分而不是綁定到對象字典中的綁定方法。但如果你可以同時擁有「本地」和未取消的對象Primes,那麼這將不起作用。

1

第一個問題:不。這不是酸洗的工作原理。 但是對於你的第二個問題,有一個簡單的方法來做到這一點。 您可以使用一個名爲marshal的模塊,它允許您序列化函數的代碼,並且可以將其與某個對象的副本一起存儲。

import marshal 
import pickle 
class A: 
    def __init__(self): 
     self.a = 1 
    def func(self): 
     print self.a 
firstA = A() 
s = pickle.dumps(firstA) 
sf = marshal.dumps(A.func.func_code) 

別的地方,你有不同的A類:

class A: 
    def __init__(self): 
     self.a = 2 
    def func(self): 
     print "Hello world" 

當加載剛對象,它仍然會使用不正確的功能:

secondA = pickle.loads(s) 
secondA.func() #prints "Hello world" 

然後,您可以使用函數代碼的值調用正確的函數:

#change the function to match what was stored 
secondA.func.__func__.func_code = marshal.loads(sf) 
secondA.func() #prints 1