对OrderedDict派生对象进行序列化
我创建了一个标准类 collections.OrderedDict 的子类。当我尝试反序列化(unpickle)这个类的对象时,出现了以下错误:
Traceback (most recent call last):
File "pickle.py", line 29, in <module>
print cPickle.load(f)
TypeError: ('__init__() takes exactly 1 argument (2 given)', <class '__main__.ConfiguratorsDict'>, ([['toto', 20]],))
为了弄清楚为什么会出现这样的情况,我简化了 collections.OrderedDict 的代码,得到了以下最小代码,这段代码会引发之前提到的错误。代码如下:
import cPickle
class OrderedDict(dict):
def __reduce__(self):
items = [[k, self[k]] for k in self]
inst_dict = vars(self).copy()
for k in vars(OrderedDict()):
inst_dict.pop(k, None)
if inst_dict:
return (self.__class__, (items,), inst_dict)
return self.__class__, (items,)
class ConfiguratorsDict(OrderedDict):
def __init__(self):
OrderedDict.__init__(self)
self._myspec = "blabla"
if __name__ == "__main__":
f = open("test.pickle","wb")
c = ConfiguratorsDict()
c["toto"] = 20
cPickle.dump(c,f)
f.close()
f = open("test.pickle","rb")
print cPickle.load(f)
f.close()
到目前为止,我真的不明白问题出在哪里。是我对 pickle 机制理解错了,还是与 OrderedDict 有关的问题?
非常感谢你的帮助
1 个回答
3
你没有仔细阅读__reduce__
的文档:
当返回一个元组时,它的长度必须在两个到五个元素之间。可选的元素可以省略,或者可以用
None
来表示。这个元组的内容会像平常一样被序列化,用于在反序列化时重建对象。每个元素的含义是:
- 一个可调用的对象,它会被用来创建对象的初始版本。元组的下一个元素将提供这个可调用对象的参数,后面的元素则提供额外的状态信息,这些信息会在之后完全重建序列化的数据时使用。
你返回了类作为可调用对象,并且第二个元素是items
,所以在反序列化时,它试图把items
传给这个类,从而调用__init__
,但你的__init__
并不接受任何参数,因此你会遇到错误。
你要么修改__init__
以接受参数,要么避免把items
作为第二个元素,而是用一个空元组代替。