I'm working on making some cython objects pickeable and have a question about using __setstate_
vs __reduce__
. It seems that when you pickle.loads()
an object with a __setstate__
method and also a __cinit__
method, the __cinit__
DOES get called (unlike if it were an __init__
). Is there a way to prevent this or pass a default argument or should I just use __reduce__
?
Here's a toy problem to illustrate (code modified from this blog).
in test.pyx
I have three classes:
cdef class Person:
cdef public str name
cdef public int age
def __init__(self,name,age):
print('in Person.__init__')
self.name = name
self.age = age
def __getstate__(self):
return (self.name, self.age,)
def __setstate__(self, state):
name, age = state
self.name = name
self.age = age
cdef class Person2:
cdef public str name
cdef public int age
def __cinit__(self,name,age):
print('in Person2.__cinit__')
self.name = name
self.age = age
def __getstate__(self):
return (self.name, self.age,)
def __setstate__(self, state):
name, age = state
self.name = name
self.age = age
cdef class Person3:
cdef public str name
cdef public int age
def __cinit__(self,name,age):
print('in Person3.__cinit__')
self.name = name
self.age = age
def __reduce__(self):
return (newPerson3,(self.name, self.age))
def newPerson3(name,age):
return Person3(name,age)
After building with python setup.py build_ext --inplace
, pickling Person
works as expected (because __init__
does not get called):
import test
import pickle
p = test.Person('timmy',12)
p_l = pickle.loads(pickle.dumps(p))
Pickling Person2
fails:
p2 = test.Person2('timmy',12)
p_l = pickle.loads(pickle.dumps(p2))
with
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "test.pyx", line 25, in test.Person2.__cinit__
print('in Person2.__cinit__')
TypeError: __cinit__() takes exactly 2 positional arguments (0 given)
So __cinit__
gets called....
The __reduce__
method in Person3
works as expected:
p3 = test.Person3('timmy',12)
p_l = pickle.loads(pickle.dumps(p3))
So is there a way to use __setstate__
to pickle Person2
?
In my actual problem, the classes are more complex and using __setstate__
would be more straightforward, but maybe I have to use __reduce__
here? I'm new to cython and custom pickling (and also don't know C well......), so may be missing something obvious...