Skip to content
Advertisement

Python 3 alternatives for __getinitargs__

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.

User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement