为什么我的自定义异常解除失败的简化版本。
我正在尝试腌制一个“简单”异常子类。它腌制还可以,但是当腌制时会掉下来:
import pickle class ABError(Exception): def __init__(self, a, b): self.a = a self.b = b ab_err = ABError("aaaa", "bbbb") pickled = pickle.dumps(ab_err) original = pickle.loads(pickled) # Fails
错误:
Traceback (most recent call last): File "p.py", line 12, inoriginal = pickle.loads(pickled) # Fails File "/usr/lib/python2.7/pickle.py", line 1388, in loads return Unpickler(file).load() File "/usr/lib/python2.7/pickle.py", line 864, in load dispatch[key](self) File "/usr/lib/python2.7/pickle.py", line 1139, in load_reduce value = func(*args) TypeError: __init__() takes exactly 3 arguments (1 given)
较早的注释建议该问题是因为内置Exception
类提供了一种__setstate_()
方法。但是,我不清楚这是否是预期的行为-这肯定令人惊讶,因为使用Works的子类执行相同的操作object
还可以。
在BaseException
类定义的自定义__reduce__
在方法exceptions.c,它返回的参数传递到列表中__init__
。确切的代码是
if (self->args && self->dict) return PyTuple_Pack(3, Py_TYPE(self), self->args, self->dict); else return PyTuple_Pack(2, Py_TYPE(self), self->args);
根据__reduce__
文档,
元组的第一项是可调用的调用。在这里,这将是异常类。
第二项是传递给可调用对象的参数的元组。在这里,将是self.args
。
第三项是将合并为的命令self.__dict__
。
因此,由此,BaseException.__reduce__
可以使给定参数调用异常的构造函数。
您有两个选择:覆盖__reduce__
,或者直接或通过让父类来将所需的参数放在self.args中:
import pickle class ABError(Exception): def __init__(self, a, b): self.a = a self.b = b # self.args = (a, b) # maybe better, let base class's __init__ do it => super(ABError, self).__init__(a, b) ab_err = ABError("aaaa", "bbbb") pickled = pickle.dumps(ab_err) original = pickle.loads(pickled) # no longer fails
请注意,最初的问题来自BaseException
泡菜处理的幼稚方式。它已在最新的python3版本中修复。例如,您问题的原始代码在python 3.5上运行良好。