2017-08-24 72 views
1

的子類下面的語句:酸洗的OrderedDict

import pickle 
from collections import OrderedDict as Odict 

class A(Odict): 
    def __init__(self, items): 
     super().__init__(items) 

items = Odict((('a',1), ('b', 2))) 
a = A(items) 

with open('test.pickle','wb') as fout: 
    pickle.dump(a, fout) 

with open('test.pickle','rb') as fin: 
    pickle.load(fin) 

導致這個錯誤:

Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
TypeError: __init__() missing 1 required positional argument: 'items' 

但做工精細搭配素色dict而非OrderedDict。我知道在這種情況下,我不需要__init__,但是這個問題阻止了將多處理模塊與更復雜的OrderedDict的子類一起使用,其中其他參數作爲屬性存儲,我不能避免擁有它。 (我用python 3.4.6)。

+0

我想我可能已經想出了一個解決方案,我認爲這可能對其他人有用。添加: – Tom

回答

1

OrderedDict覆蓋__reduce__,如果覆蓋__init____new__方法和/或要存儲其他屬性,則需要覆蓋它。

在你的情況,你所作出的參數爲__init__強制(不強制對dictOrderedDict),所以你需要重寫__reduce__

import collections 

class OD(collections.OrderedDict): 
    def __init__(self, items): 
     super().__init__(items) 

    def __reduce__(self): 
     state = super().__reduce__() 
     # OrderedDict.__reduce__ returns a 5 tuple 
     # the first and last can be kept 
     # the fourth is None and needs to stay None 
     # the second must be set to an empty sequence 
     # the third can be used to store attributes 
     newstate = (state[0], 
        ([],), 
        None, 
        None, 
        state[4]) 
     return newstate 

這現在可以毫無問題地酸菜

import pickle 

a = OD((('a',1), ('b', 2))) 

with open('test.pickle','wb') as fout: 
    pickle.dump(a, fout) 

with open('test.pickle','rb') as fin: 
    pickle.load(fin) 

但是,如果你想要在你的__init__中未設置的屬性,這將無法正確工作:

a = OD((('a',1), ('b', 2))) 
a.a = 10 

with open('test.pickle','wb') as fout: 
    pickle.dump(a, fout) 

with open('test.pickle','rb') as fin: 
    b = pickle.load(fin) 

b.a # AttributeError: 'OD' object has no attribute 'a' 

爲了做到這一點,您需要更改上述__reduce__函數以返回第三個參數。例如,你可以簡單地返回__dict__

class OD(collections.OrderedDict): 
    def __init__(self, items): 
     super().__init__(items) 

    def __reduce__(self): 
     state = super().__reduce__() 
     newstate = (state[0], 
        ([],), 
        self.__dict__, 
        None, 
        state[4]) 
     return newstate 

有了這個上面的例子可以正常工作。


很多設計取決於你希望你的子類的行爲。在某些情況下,最好通過第二個參數(傳遞給__init__)傳遞項目。至於你如何設置你的屬性:有時足夠使用self.__dict__,但在其他情況下,使用__setstate__會更安全/更好。您一定要閱讀documentation of the pickle module並檢查哪種方法最適合您。