pickle.load上的TypeError与派生自SimpleNamespace的类

时间:2018-07-25 12:50:51

标签: python python-3.x inheritance pickle

考虑以下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中)

请注意,我尝试仅将self.x = x替换为pass,但没有任何改变。

除了通过不继承而重新实现MyClass2之外,还有其他方法可以使这项工作吗?

1 个答案:

答案 0 :(得分:2)

问题是SimpleNamespace定义了__reduce__用于解开对象的pickle。但是,__reduce__中定义的SimpleNamespace与您的__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)))