Eric Jonas <[EMAIL PROTECTED]> writes:
>
> Hello! I've been successfully using cython for the root objects in a
> class hierarchy to make some common operations much faster. I eventually
> figured out how to implement __reduce__ in these objects to support
> pickling. Unfortunately, when I inherit (in python) from my cython
> classes, and pickle an instance of the resulting derived object, the
> unpickle only appears to restore the base (cython) object. Does anyone
> know of any workarounds for this pickle? (bad pun)
>
> Thanks,
> ...Eric
>
>
Hi,
I had to walk up this hill for pex, a preprocessor for cython, that among other
things generates pickling code for cdef classes. If you have the following code:
------------
cdef class base:
cdef int i
cdef double d
cdef class derived(base):
cdef char c
cdef object ob
------------
here is an excerpt of what pex generates (sorry, it's machine generated, so
maybe not too readable). The type signature you can ignore, it is there for
paranoia in case the class definition has changed since pickling - at some point
I convinced myself it could lead to memory corruption.
pex_create_uninitialized() is the most salient bit - it allocates the right type
of object (base classes included), without actually calling __init__:
------------
cdef pex_create_uninitialized(type_obj):
if not isinstance(type_obj,type):
raise TypeError("Expecting a type object (eg 'item' from 'cdef class item'),
not '%s' of %s"%(type_obj,type(type_obj)))
cdef PyTypeObject *typeptr = <PyTypeObject*>type_obj
h=<object>typeptr[0].tp_new(typeptr,NULL,NULL)
Py_DECREF(h) # need for some reason
return h
def __px__pex_create_uninitialized_def_wrap(type):
return pex_create_uninitialized(type)
cdef class base: ## 181_pickle_play.px,1
def _typesig_(me):
return (('double', 'd'), ('int', 'i'))
def _todict_(me):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_dictcoercion=False"
d = {
'd': me.d,
'i': me.i,
}
return d
def _fromdict_(me,dict):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_dictcoercion=False"
me.d = dict['d']
me.i = dict['i']
def __setstate__(me,state):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_pickle=False"
type_signature,fields = state
unpickled=type_signature
expected=(('double', 'd'), ('int', 'i'))
if unpickled <> expected:
<die horrible death>
me._fromdict_(fields)
def __reduce__(me):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_pickle=False"
type_signature = \
__px__type_signature_memoization_for_pickling.setdefault('base',
(('double','d'), ('int', 'i')))
return (__px__pex_create_uninitialized_def_wrap, (type(me),),
(type_signature,me._todict_()) )
cdef class derived(base): ## 181_pickle_play.px,5
def _typesig_(me):
return base._typesig_(me) + (('char', 'c'), ('object', 'ob'))
def _todict_(me):"
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_dictcoercion=False"
d = {
'_baseclass_':base._todict_(me),
'c': me.c,
'ob': me.ob,
}
return d
def _fromdict_(me,dict):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_dictcoercion=False"
base._fromdict_(me,dict['_baseclass_'])
me.c = dict['c']
me.ob = dict['ob']
def __setstate__(me,state):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_pickle=False"
type_signature,fields = state
unpickled=type_signature
expected=(('char', 'c'), ('object', 'ob'))
if unpickled <> expected:
<die horrible death>
me._fromdict_(fields)
def __reduce__(me):
## made by pex, turn off generation with
## "%whencompiling: scope.pragma_gen_pickle=False"
type_signature = \
__px__type_signature_memoization_for_pickling.setdefault('derived',
(('char','c'), ('object', 'ob')))
return (__px__pex_create_uninitialized_def_wrap, (type(me),),
(type_signature,me._todict_()) )
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev