如何使用多个init args pickleable创建自定义异常类

时间:2013-04-26 20:44:13

标签: python exception serialization

为什么下面的自定义Exception类没有使用pickle模块正确序列化/反序列化?

import pickle

class MyException(Exception):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

        super(MyException, self).__init__(arg1)

e = MyException("foo", "bar")

str = pickle.dumps(e)
obj = pickle.loads(str)

此代码抛出以下错误:

Traceback (most recent call last):
File "test.py", line 13, in <module>
   obj = pickle.loads(str)
File "/usr/lib/python2.7/pickle.py", line 1382, in loads
   return Unpickler(file).load()
File "/usr/lib/python2.7/pickle.py", line 858, in load
   dispatch[key](self)
File "/usr/lib/python2.7/pickle.py", line 1133, in load_reduce
   value = func(*args)
TypeError: __init__() takes exactly 3 arguments (2 given)

我确信这个问题源于我对如何使课堂泡菜友好缺乏了解。有趣的是,当我的类没有扩展Exception时,不会发生这个问题。

感谢您的帮助。 凯尔

编辑:修复我对超级shx2的调用 编辑:清理标题/内容

4 个答案:

答案 0 :(得分:24)

如果您使用两个参数构造错误消息以传递给父Exception类,则当前答案会中断。我认为最好的方法是简单地覆盖异常中的__reduce__方法。 __reduce__方法应返回两项元组。元组中的第一项是你的班级。第二项是一个元组,其中包含传递给类的__init__方法的参数。

import pickle

class MyException(Exception):
    def __init__(self, arg1, arg2):
        self.arg1 = arg1
        self.arg2 = arg2

        super(MyException, self).__init__('arg1: {}, arg2: {}'.format(arg1, arg2))

    def __reduce__(self):
        return (MyException, (self.arg1, self.arg2))


original = MyException('foo', 'bar')
print repr(original)
print original.arg1
print original.arg2

reconstituted = pickle.loads(pickle.dumps(original))
print repr(reconstituted)
print reconstituted.arg1
print reconstituted.arg2

有关__reduce__ here的更多信息。

答案 1 :(得分:22)

arg2可选:

class MyException(Exception):
    def __init__(self, arg1, arg2=None):
        self.arg1 = arg1
        self.arg2 = arg2
        super(MyException, self).__init__(arg1)

基类Exception类定义.__reduce__() method以使扩展(基于C)类型可选择,并且该方法仅需要一个参数({{1} });请参阅BaseException_reduce() function in the C source

最简单的解决方法是使额外的参数可选。 .args方法包括__reduce__.args之外的任何其他对象属性,并且您的实例会正确重新创建:

.message

答案 2 :(得分:10)

我喜欢Martijn的答案,但我认为更好的方法是将所有参数传递给Exception基类:

class MyException(Exception):
    def __init__(self, arg1, arg2):
        super(MyException, self).__init__(arg1, arg2)        
        self.arg1 = arg1
        self.arg2 = arg2

基础Exception类'__reduce__方法将包含所有参数。通过不使所有额外参数可选,您可以确保正确构造异常。

答案 3 :(得分:0)

我只是这样做

class MyCustomException(Exception):
    def __init__(self):
        self.value = 'Message about my error'

    def __str__(self):
        return repr(self.value)

... somewhere in code ...
raise MyCustomException