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.