python - 无法解开异常子类

标签 python

Why is my custom exception unpickle failing 的简化版本.

我正在尝试挑选一个“简单”的异常子类。它可以腌制,但在去除腌制时它会掉落:

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, in <module>
    original = 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_() 方法。但是,我不清楚这是否是预期的行为 - 这看起来确实令人惊讶,因为对 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__ 将使 unpickle 使用给定的参数调用异常的构造函数。

您有两个选择:要么覆盖 __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 pickle 处理的相当幼稚的方式。它在最新的 python3 版本中得到修复。例如,您问题的原始代码在 python 3.5 上运行良好。

关于python - 无法解开异常子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41808912/

相关文章:

python pip 指定一个库目录和一个包含目录

python - 为什么使用 numpy.ndarray.astype 将 numpy.ndarray 转换为自定义数据类型会使我的数据相乘?

python - (gclalcli) 错误 : could not create 'build/bdist.linux-x86_64/egg' : Permission denied

python - post_save信号未调用

python - python,del或delattr哪个更好?

python - 单个 for 循环中的多个计数器 : Python

python - 我应该默认使用原始字符串吗?

python - OpenSlide.read_region 函数有问题吗?

python - 在 Python 中有效地匹配字典的正则表达式

python正则表达式,正向看后面