我有一个继承自defaultdict
的类:
class listdict(defaultdict):
def __init__(self):
defaultdict.__init__(self, list)
我可以腌制它,但当我取消它时,会发生这种情况:
('__init__() takes exactly 1 argument (2 given)', <class 'listdict'>, (<type 'list'>,))
该类没有定义pickle协议的任何特殊方法。普通defaultdict(list)
的酸洗和去除工作符合预期。谁能开导我?
答案 0 :(得分: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)
答案 1 :(得分:-1)
该错误表明你的'listdict'类需要一个参数(隐式self),但有两个参数。
您的类继承自defaultdict,并定义了初始化程序。这个初始化程序调用defaultdict的初始化程序并将'list'传递给它,在这种情况下可以是函数或类。 (我不能打扰检查)。
你可能意味着这样做:
class listdict(defaultdict):
def __init__(self, list):
defaultdict.__init__(self, list)
现在,当listdict使用给定列表初始化时,它会将THAT列表传递给defaultdict的构造函数,而不是将引用传递给全局列表。
(也就是说,使用与普通全局方法和类相同的名称(例如'str','list'等)被认为是错误的样式,原因与您感到困惑的原因相同。)