以下语句:
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)。
最佳答案
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
现在可以毫无问题地 pickle :
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并检查哪种方法最适合您。
关于python - pickle OrderedDict 的子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45860040/