'Why is my custom exception unpickle failing
import pickle
class ABError(Exception):
def __init__(self, a, b):
super(ABError, self).__init__(a)
self.a = a
self.b = b
class ABCDError(ABError):
def __init__(self, a, b, c, d):
super(ABCDError, self).__init__(a, b)
self.c = c
self.d = d
err = ABCDError("aaaaa", "bbbbb", "ccccc", "ddddd")
pickled_err = pickle.dumps(err)
original_err = pickle.loads(pickled_err) # Fails
I get the following traceback:
Traceback (most recent call last):
File "pickle_pain.py", line 19, in <module>
original_err = pickle.loads(pickled_err) # 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 5 arguments (2 given)
I've done some googling, but struggling to find a good answer for why this happens, and not desperate to start learning the pickle serialisation format in order to step through this :-/
Edit: The behaviour is the same in python3, though the error message is slightly nicer:
Traceback (most recent call last):
File "pickle_pain.py", line 19, in <module>
original_err = pickle.loads(pickled_err) # Fails
TypeError: __init__() missing 3 required positional arguments: 'b', 'c', and 'd'
Solution 1:[1]
I was answering a different question that linked to this one and they are kind of the same. reduce will return how to recreate the object and it bases it off of whats in self.args. Since you aren't passing all the args to Exception it breaks. If you need to be able to access the custom fields without doing e.args[0] for a and e.args[1] for b etc, just make properties. Notice the Extended class still calls the Exception init not ABError.init.
import pickle
class ABError(Exception):
def __init__(self, a, b):
super(ABError, self).__init__(a, b)
@property
def a(self):
return self.args[0]
@property
def b(self):
return self.args[1]
class ABCDError(ABError):
def __init__(self, a, b, c, d):
super(ABError, self).__init__(a, b, c, d)
@property
def c(self):
return self.args[2]
@property
def d(self):
return self.args[3]
err = ABCDError("aaaaa", "bbbbb", "ccccc", "ddddd")
pickled_err = pickle.dumps(err)
original_err = pickle.loads(pickled_err) # Fails
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nathan Buckner |
