Why does my custom Exception class below not serialize/unserialize correctly using the pickle module?
import pickle
class MyException(Exception):
def __ini
The current answers break down if you're using both arguments to construct an error message to pass to the parent Exception class. I believe the best way is to simply override the __reduce__
method in your exception. The __reduce__
method should return a two item tuple. The first item in the tuple is your class. The second item is a tuple containing the arguments to pass to your class's __init__
method.
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
More info about __reduce__
here.
I like Martijn's answer, but I think a better way is to pass all arguments to the Exception
base class:
class MyException(Exception):
def __init__(self, arg1, arg2):
super(MyException, self).__init__(arg1, arg2)
self.arg1 = arg1
self.arg2 = arg2
The base Exception
class' __reduce__
method will include all the args. By not making all of the extra arguments optional, you can ensure that the exception is constructed correctly.
I simply do this
class MyCustomException(Exception):
def __init__(self):
self.value = 'Message about my error'
def __str__(self):
return repr(self.value)
... somewhere in code ...
raise MyCustomException
Make arg2
optional:
class MyException(Exception):
def __init__(self, arg1, arg2=None):
self.arg1 = arg1
self.arg2 = arg2
super(MyException, self).__init__(arg1)
The base Exception
class defines a .__reduce__() method to make the extension (C-based) type picklable and that method only expects one argument (which is .args
); see the BaseException_reduce() function in the C source.
The easiest work-around is making extra arguments optional. The __reduce__
method also includes any additional object attributes beyond .args
and .message
and your instances are recreated properly:
>>> e = MyException('foo', 'bar')
>>> e.__reduce__()
(<class '__main__.MyException'>, ('foo',), {'arg1': 'foo', 'arg2': 'bar'})
>>> pickle.loads(pickle.dumps(e))
MyException('foo',)
>>> e2 = pickle.loads(pickle.dumps(e))
>>> e2.arg1
'foo'
>>> e2.arg2
'bar'