从 SimpleNamespace 派生的 class 上的 pickle.load 类型错误
TypeError on pickle.load with class derived from SimpleNamespace
考虑这个 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
) 的 class 可以被(未)腌制。
- 从
SimpleNamespace
派生的 class 如果它有一个需要参数的 __init__
则不能被解封。 (错误发生在pickle.loads
)
请注意,我尝试将 self.x = x
替换为 pass
,但没有任何改变。
除了在没有继承的情况下重新实现 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)))
考虑这个 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
) 的 class 可以被(未)腌制。 - 从
SimpleNamespace
派生的 class 如果它有一个需要参数的__init__
则不能被解封。 (错误发生在pickle.loads
)
请注意,我尝试将 self.x = x
替换为 pass
,但没有任何改变。
除了在没有继承的情况下重新实现 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)))