考虑这段 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
可以 pickle。- 派生自不同类型 (
list
) 的类可以被(取消)pickled。 - 如果派生自
SimpleNamespace
的类具有需要参数的__init__
,则无法对其进行 unpickled。 (错误发生在pickle.loads
)
请注意,我尝试将 self.x = x
替换为 pass
并且没有任何改变。
除了在没有继承的情况下重新实现 MyClass2 之外,还有其他方法可以使这项工作正常进行吗?
最佳答案
问题是 SimpleNamespace
定义了一个 __reduce__
,pickle
使用它来取消 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)))
关于python - 使用从 SimpleNamespace 派生的类的 pickle.load 上的 TypeError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51519351/