2013-02-03 48 views
1

我正在嘗試使用pickle來保存自定義類;非常類似於下面的代碼(儘管在類中定義了一些方法,還有幾個字符等用於數據)。然而,經常當我運行這個,pickle然後unpickle時,我失去了類中的所有數據,並且就好像我創建了一個新的空白實例。Unpickle有時會產生空白對象

import pickle 
class MyClass: 
    VERSION = 1 
    some_data = {} 
    more_data = set() 

    def save(self,filename): 
     with open(filename, 'wb') as f: 
      p = pickle.Pickler(f) 
      p.dump(self) 

    def load(filename): 
     with open(filename,'rb') as ifile: 
      u = pickle.Unpickler(ifile) 
      obj = u.load() 
      return obj 

我想知道這是否與鹹菜類的備忘錄有關,但我不覺得它應該。當它不工作,我看我生成的文件,它看起來是這樣的:(顯然並不意味着是可讀的,但它顯然不包含任何數據)

 
€c__main__ 
MyClass 
q

不管怎麼說,我希望這是足夠的有人瞭解這裏可能會發生什麼,或者看什麼。

+1

你是否在'pickle.dumps'和'pickle.loads'之間改變你的代碼?因爲,我認爲pickle協議不會對代碼更改產生影響。 –

+0

你的課應該實現[pickle protocol](http://docs.python.org/2/library/pickle.html#pickle-protocol),以確保它能夠像你期望的那樣工作。 – Wessie

+0

你是否將實例的數據保存在'some_data'和'more_data'類變量中?那些不會被'pickle'保存,因爲它們不是實例本身的一部分。您應該使用'__init__'方法創建它們,而不是將它們保存在類中。 – Blckknght

回答

6

您遇到的問題是您使用可變類變量來保存數據,而不是將數據放入實例變量中。

pickle模塊僅保存直接存儲在實例上的數據,而不保存可通過self訪問的類變量。當你發現你的unpickled實例沒有數據時,這可能意味着這個類沒有保存上一次運行的數據,所以這些實例不能再訪問它。

使用類變量的方式也可能會導致其他問題,因爲數據將由類的所有實例共享!以下是說明問題的Python控制檯會話代碼:

>>> class Foo(object): 
     class_var = [] 
     def __init__(self, value): 
      self.class_var.append(value) 

>>> f1 = Foo(1) 
>>> f1.class_var 
[1] 
>>> f2 = Foo(2) 
>>> f2.class_var 
[1, 2] 

這可能不是您想要的。但它變得更糟!

>>> f1.class_var 
[1, 2] 

你認爲已經屬於f1數據已通過建立的f2改變。實際上,f1.class_varf2.class_var的對象非常相似(它也可以直接通過Foo.class_var獲得,而根本沒有經過任何實例)。

所以,使用類變量幾乎肯定不是你想要的。相反,寫的類的__init__方法是創建一個新的值,並將其保存爲一個實例變量:

>>> class Bar(object): 
     def __init__(self, value): 
      self.instance_var = [] # creates a separate list for each instance! 
      self.instance_var.append(value) 

>>> b1 = Bar(1) 
>>> b1.instance_var 
[1] 
>>> b2 = Bar(2) 
>>> b2.instance_var # doesn't include value from b1 
[2] 
>>> b1.instance_var # b1's data is unchanged 
[1] 

味酸會像您期望的處理此類。它的所有數據都在實例中,所以當你解開時,你永遠不應該得到一個空的實例。