2010-10-04 47 views
10

我有一個從defaultdict繼承這樣的類:如何清理和取消從defaultdict繼承的類的實例?

class listdict(defaultdict): 
    def __init__(self): 
     defaultdict.__init__(self, list) 

我可以泡製它,但是當我unpickle它,出現這種情況:

('__init__() takes exactly 1 argument (2 given)', <class 'listdict'>, (<type 'list'>,)) 

類沒有定義的任何特殊方法泡菜協議。酸洗和取消正常的defaultdict(list)按預期工作。任何人都可以啓發我嗎?

+0

您使用'pickle'或' cpickle'? – aaronasterling 2010-10-04 13:10:22

+0

我正在使用'cPickle'。 – 2010-10-04 13:10:48

回答

8

類型通過定義一個或多個(相當大)的一組方法來定義它的實例如何被清理。每個人都有自己的微妙行爲。見the docs on the pickle protocol。在collections.defaultdict的情況下,它使用__reduce__方法:

>>> l = collections.defaultdict(list) 
>>> l.__reduce__() 
(<type 'collections.defaultdict'>, (<type 'list'>,), None, None, <dictionary-itemiterator object at 0x7f031fb3c470>) 

在元組中的第一項有類型,並且第二項是自變量的元組實例化時傳遞到的類型。如果您不覆蓋__reduce__,則第一項將正確更改爲您的類型,但第二項不會。這會導致您看到的錯誤。你怎麼能把它修好粗例如:

>>> import collections 
>>> import pickle 
>>> class C(collections.defaultdict): 
...  def __init__(self): 
...   collections.defaultdict.__init__(self, list) 
...  def __reduce__(self): 
...   t = collections.defaultdict.__reduce__(self) 
...   return (t[0],()) + t[2:] 
... 
>>> c = C() 
>>> c[1].append(2) 
>>> c[2].append(3) 
>>> c2 = pickle.loads(pickle.dumps(c)) 
>>> c2 == c 
True 

這只是粗略的例子,因爲有更多的酸洗(如__reduce_ex__),這一切都相當複雜。在這種情況下,使用__getinitargs__可能會更方便。

或者,你可以讓你的類的__init__方法採取可選調用,默認爲list,或者你可以只用而不是類的函數:

def listdict(): 
    return collections.defaultdict(list) 
+0

謝謝!我決定採用默認參數,因爲這似乎是最簡單和最穩定的選擇。 – 2010-10-04 13:33:27

+0

真的嗎?該功能* *更簡單:) – 2010-10-04 13:38:21

+0

謝謝。這幫助我解決了使用'[0] * self._size'作爲默認值的問題,並且在酸洗過程中持續使用'_size'參數。 – 2012-02-10 12:14:02

-1

該錯誤表明您的'listdict'類預計會接受一個參數(隱式自我),但有兩個參數。

你的類繼承自defaultdict,並且定義了一個初始化器。該初始化程序調用defaultdict的初始化程序並將「列表」傳遞給它,在這種情況下,它可能是函數或類。 (我不能打擾檢查)。

你大概的意思是要做到這一點:

class listdict(defaultdict): 
    def __init__(self, list): 
     defaultdict.__init__(self, list) 

現在,當listdict與給定列表初始化,它傳遞該列表到defaultdict的構造函數,而不是傳遞一個參考全局列表。 (這就是說,使用與常見全局方法和類相同的名稱(例如'str','list'等)的名稱被認爲是不好的風格,原因與您感到困惑的相同)。

+1

'list'是一個類。 OP沒有通過一個特定的列表,而是作爲一個可調用的類的一個類,它是defaultdict的構造函數作爲參數的一個工廠函數。讓'listdict'把'list'作爲參數會影響'defaultdict'子類化的目的。 – aaronasterling 2010-10-04 13:05:52

+0

@Aaron說得對。 – 2010-10-04 13:07:14

+0

它一定會不時發生 – aaronasterling 2010-10-04 13:08:42