以下陈述:
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
子类,其他参数作为属性存储,我可以& #39;避免拥有它。 (我使用的是python 3.4.6)。
答案 0 :(得分:2)
OrderedDict
会覆盖__reduce__
,如果您覆盖__init__
或__new__
方法和/或想要存储其他属性,则需要覆盖它。
在您的情况下,您强制要求__init__
的参数(dict
或OrderedDict
不强制要求),因此您需要覆盖__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并检查哪种方法最适合你。