首页 > 解决方案 > 带有派生自 SimpleNamespace 的类的 pickle.load 上的 TypeError

问题描述

考虑这个 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'

观察:

请注意,我尝试用self.x = xjust替换pass,但这并没有改变任何东西。

除了在没有继承的情况下重新实现 MyClass2 之外,还有其他方法可以完成这项工作吗?

标签: pythonpython-3.xinheritancepickle

解决方案


问题是它SimpleNamespace定义了一个__reduce__用来pickle解开你的对象的。但是,__reduce__定义的 inSimpleNamespace与您的__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)))

推荐阅读