考虑以下Python(3.5版(代码:
import pickle
from types import SimpleNamespace
class MyClass1(list):
def __init__(self, x):
self.append(x)
class MyClass2(SimpleNamespace):
def __init__(self, x):
self.x = x
a0 = SimpleNamespace(x=99)
a1 = MyClass1(99)
a2 = MyClass2(99)
print('* SimpleNamespace:', pickle.loads(pickle.dumps(a0)))
print('* MyClass1:', pickle.loads(pickle.dumps(a1)))
print('* MyClass2:', pickle.loads(pickle.dumps(a2)))
这对前两个(a0和a1(来说很好,但在处理a2时,我得到了一个错误:
* SimpleNamespace: namespace(x=99)
* MyClass1: [99]
Traceback (most recent call last):
File "./picktest.py", line 20, in <module>
print('* MyClass2:', pickle.loads(pickle.dumps(a2)))
TypeError: __init__() missing 1 required positional argument: 'x'
观察结果:
SimpleNamespace
可以进行腌制- 从不同类型(
list
(派生的类可以(取消(腌制 - 如果从
SimpleNamespace
派生的类具有需要参数的__init__
,则无法取消拾取该类。(错误发生在pickle.loads
中(
请注意,我尝试用pass
替换self.x = x
,但这并没有改变任何内容。
除了在没有继承的情况下重新实现MyClass2之外,还有什么方法可以实现这一点吗?
问题是SimpleNamespace
定义了一个__reduce__
,pickle
使用它来取消拾取对象。但是,SimpleNamespace
中定义的__reduce__
与您的__init__
不一致。你可以定义你自己的__reduce__
来绕过这个:
import pickle
from types import SimpleNamespace
class MyClass1(list):
def __init__(self, x):
self.append(x)
class MyClass2(SimpleNamespace):
def __init__(self, x):
self.x = x
def __reduce__(self):
return (self.__class__, (self.x,))
a0 = SimpleNamespace(x=99)
a1 = MyClass1(99)
a2 = MyClass2(99)
print('* SimpleNamespace:', pickle.loads(pickle.dumps(a0)))
print('* MyClass1:', pickle.loads(pickle.dumps(a1)))
print('* MyClass2:', pickle.loads(pickle.dumps(a2)))