2013-04-28 52 views
7

在通過重新編譯腳本更新類定義之後,pickle拒絕序列化該類的先前實例化的對象,並給出錯誤:「Can not pickle object:它不是相同的對象「Python pickle:處理更新的類定義

有沒有辦法告訴泡菜它應該忽略這種情況?要僅按名稱識別類別,請忽略哪個內部唯一ID導致不匹配?

我一定會歡迎作爲一個答案的建議,替代,等效模塊,以方便和強大的方式解決這個問題。


供參考,這是我的動機:

我創建一個高效率,快速迭代開發環境中的Python腳本編輯直播。腳本被重複編譯,但數據在編譯時仍然存在。作爲生產力目標的一部分,我嘗試使用pickle進行序列化,以避免爲不斷變化的數據結構編寫和更新顯式序列化代碼的成本。

大多是我序列化內置類型。我非常小心地避免了我在醃製的類中發生的有意義的更改,並且在必要時我使用copy_reg.pickle機制對unpickle執行上變頻。

即使類定義沒有真正改變(或者只是以一種良性的方式進行改變),腳本重新編譯也可以防止酸洗對象。

+1

我還沒有花太多時間,但這可能是有用的:http://docs.python.org/2/library/pickle.html#pickling-and-unpickling-normal-class-instances – mgilson 2013-04-28 23:21:25

回答

0

兩種解決方案進入我的腦海:

  1. 你泡菜可以設置object.__class__

    >>> class X(object): 
        pass 
    
    >>> class Y(object): 
        pass 
    
    >>> x = X() 
    >>> x.__class__ = Y 
    >>> type(x) 
    <class '__main__.Y'> 
    

    也許你可以使用persistent_id這是因爲每一個對象傳遞給它。

  2. 定義__reduce__做的和鹹菜完全一樣。 (看看pickle.py本)

6

除非你能解開類定義的早期版本,參考泡菜需要轉儲和裝載情況已經不復存在了。所以這是「不可能的」。

但是,如果你確實想這樣做,你可以保存你的類定義的以前的版本......然後它只是你必須欺騙鹹菜參考你的舊/保存的類定義,而不是使用最新的 - 這可能只是編輯obj.__class__obj.__module__指向您的舊類。在你的類實例中還可能有一些其他奇怪的東西,它們也引用了你必須處理的舊類定義。另外,如果添加或刪除類方法,則可能會遇到一些意外結果,或者必須相應地更新實例。另一個有趣的轉折是你可以讓unpickler總是使用你班級的最新版本。

我的序列化程序包dill有一些方法可以將編譯源從實時代碼對象轉儲到臨時文件,然後使用該臨時文件進行序列化。它是包裝中較新的部分之一,所以它不如蒔蘿的其餘部分。另外,你的用例不是我考慮的用例,但我可以看到它是一個很好的功能。

+0

好吧,我已經添加了這個功能來修改github上的最新版本。用比我想象的要少得多的技巧來實現......只是用pickle和序列化類定義。 – 2013-11-08 14:33:53