无法腌制递归嵌套的defaultdict
Can't pickle recursive nested defaultdict
我有一个递归嵌套 defaultdict
class 定义为
from collections import defaultdict
class NestedDict(defaultdict):
def __init__(self):
super().__init__(self.__class__)
坐在 nested_dict.py
文件中。
当我尝试腌制它时,例如
import pickle
from nested_dict import NestedDict
d = NestedDict()
pickle.loads(pickle.dumps(d))
我得到 TypeError: __init__() takes 1 positional argument but 2 were given
。
这里到底发生了什么?
defaultdict
class 实现了一个 object.__reduce__()
method ,其中返回的元组的第二个元素(构造函数的参数)始终是工厂对象:
>>> d = NestedDict()
>>> d.__reduce__()
(<class '__main__.NestedDict'>, (<class '__main__.NestedDict'>,), None, None, <dict_itemiterator object at 0x110df59a8>)
然后将该参数传递给 NestedDict()
调用以重新构建对象。抛出异常是因为 NestedDict
class 不接受参数。
您可以在您的 subclass:
中覆盖 __reduce__
方法
class NestedDict(defaultdict):
def __init__(self):
super().__init__(self.__class__)
def __reduce__(self):
return (type(self), (), None, None, iter(self.items()))
以上生成完全相同的元素 defaultdict.__reduce__()
returns,只是第二个元素现在是一个空元组。
您也可以只接受并忽略一个参数:
class NestedDict(defaultdict):
def __init__(self, _=None): # accept a factory and ignore it
super().__init__(self.__class__)
_
这个名字通常用来表示我忽略这个值。
另一种实现可以只是子class dict
并提供自定义 __missing__
method;为不在字典中的键调用此方法:
class NestedDict(dict):
def __missing__(self, key):
nested = self[key] = type(self)()
return nested
def __repr__(self):
return f'{type(self).__name__}({super().__repr__()})'
这与您的版本完全一样,但不需要额外的 pickle 支持方法:
>>> d = NestedDict()
>>> d['foo']
NestedDict({})
>>> d['foo']['bar']
NestedDict({})
>>> d
NestedDict({'foo': NestedDict({'bar': NestedDict({})})})
>>> pickle.loads(pickle.dumps(d))
NestedDict({'foo': NestedDict({'bar': NestedDict({})})})
我有一个递归嵌套 defaultdict
class 定义为
from collections import defaultdict
class NestedDict(defaultdict):
def __init__(self):
super().__init__(self.__class__)
坐在 nested_dict.py
文件中。
当我尝试腌制它时,例如
import pickle
from nested_dict import NestedDict
d = NestedDict()
pickle.loads(pickle.dumps(d))
我得到 TypeError: __init__() takes 1 positional argument but 2 were given
。
这里到底发生了什么?
defaultdict
class 实现了一个 object.__reduce__()
method ,其中返回的元组的第二个元素(构造函数的参数)始终是工厂对象:
>>> d = NestedDict()
>>> d.__reduce__()
(<class '__main__.NestedDict'>, (<class '__main__.NestedDict'>,), None, None, <dict_itemiterator object at 0x110df59a8>)
然后将该参数传递给 NestedDict()
调用以重新构建对象。抛出异常是因为 NestedDict
class 不接受参数。
您可以在您的 subclass:
中覆盖__reduce__
方法
class NestedDict(defaultdict):
def __init__(self):
super().__init__(self.__class__)
def __reduce__(self):
return (type(self), (), None, None, iter(self.items()))
以上生成完全相同的元素 defaultdict.__reduce__()
returns,只是第二个元素现在是一个空元组。
您也可以只接受并忽略一个参数:
class NestedDict(defaultdict):
def __init__(self, _=None): # accept a factory and ignore it
super().__init__(self.__class__)
_
这个名字通常用来表示我忽略这个值。
另一种实现可以只是子class dict
并提供自定义 __missing__
method;为不在字典中的键调用此方法:
class NestedDict(dict):
def __missing__(self, key):
nested = self[key] = type(self)()
return nested
def __repr__(self):
return f'{type(self).__name__}({super().__repr__()})'
这与您的版本完全一样,但不需要额外的 pickle 支持方法:
>>> d = NestedDict()
>>> d['foo']
NestedDict({})
>>> d['foo']['bar']
NestedDict({})
>>> d
NestedDict({'foo': NestedDict({'bar': NestedDict({})})})
>>> pickle.loads(pickle.dumps(d))
NestedDict({'foo': NestedDict({'bar': NestedDict({})})})