Is there a short enough way to call the __init__ constructor of a class during unpickling in Python 3? The usual way to do this was using __getinitargs__ like so
from __future__ import print_function
import pickle
class Car:
def __init__(self, model, number):
self.model = model
self.number = number
print("constructed with", model, number)
# many other things to do
def __getstate__(self):
# intentionally returns None
pass
def __setstate__(self, state):
pass
def __getinitargs__(self):
# save some information when pickling
# (will be passed to the constructor upon unpickling)
return self.model, self.number
c = Car("toyota", 1234)
d = pickle.loads(pickle.dumps(c))
print("reconstructed with", d.model, d.number)
However, the __getinitargs__ will be ignored in new style classes and in Python 3+, all classes can only be new style classes. There is the __getnewargs__ but it will pass the arguments only to the __new__ class method which is not the same. A python 2 call of the above illustrative example will result in
>> constructed with toyota 1234 >> constructed with toyota 1234 >> reconstructed with toyota 1234
while a python 3 call will error out
>> constructed with toyota 1234
Traceback (most recent call last):
File "test.py", line 26, in <module>
print("reconstructed with", d.model, d.number)
AttributeError: 'Car' object has no attribute 'model'
and ignore the __getinitargs__ method.
I don’t think Python 3 will easily regress in that regard so hopefully I am missing something obvious.
EDIT: Replacing __getinitargs__ with __getnewargs__ does not solve the issue.
Advertisement
Answer
If you want pickle to unpickle your object by calling Car(self.model, self.number), going through __init__ for initialization the same way a normal call to Car would, then tell it to do so in a __reduce__ method:
def __reduce__(self):
return (Car, (self.model, self.number))
Demo.