类型通过定义一组(相当大的)方法中的一个或多个来定义它的实例如何被腌制。每个人都有自己微妙的行为。见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__ 方法采用 optional 可调用的,默认为 list,或者您可以只使用函数而不是类:
def listdict():
return collections.defaultdict(list)