clase de cython pickle

Tengo que guardar y cargar una instancia de clase cython. Mi clase de cython es esto más varios métodos:

import numpy as np cimport numpy as np cimport cython cdef class Perceptron_avg_my: cdef int wlen,freePos cdef np.ndarray w,wtot,wac,wtotc #np.ndarray[np.int32_t] cdef np.ndarray wmean #np.ndarray[np.float32_t] cdef public dict fpos def __cinit__(self,np.int64_t wlen=4*10**7): self.fpos= dict() self.freePos=1 self.wlen=wlen self.w=np.zeros(wlen,np.int32) self.wtot=np.zeros(wlen,np.int32) self.wac=np.zeros(wlen,np.int32) self.wtotc=np.zeros(wlen,np.int32) self.wmean=np.zeros(wlen,np.float32) cpdef evaluate_noavg(self,list f): cdef np.ndarray[np.int32_t] w = self.w cdef dict fpos = self.fpos cdef bytes ff cdef int i cdef long int score=0 for ff in f: i=fpos.get(ff,0) if i != 0: score += w[i] return score 

Estaba pensando en usar el módulo cPickle. Entiendo que tengo que implementar un método __reduce __ (auto) pero tengo algún problema para encontrar un ejemplo y entender bien la documentación.

Intenté agregar algo como esto a Perceptron_avg_my pero no funciona:

  def rebuild(self,l): self.fpos=l[0] self.freePos=l[1] def __reduce__(self): #print 'reduce call' return (Perceptron_avg_my.rebuild,(self.fpos,self.freePos)) 

¿alguna sugerencia? ¡¡¡Muchas gracias!!!

No sé si lo encontró, pero la documentación oficial de Python tiene una sección sobre tipos de extensiones de decapado (desafortunadamente no parece haber una versión de Python 3 de este documento, pero funciona igual en Python 3).

Creo que tienes tres problemas aquí. En primer lugar, se supone que la función devuelta por __reduce__ crea un nuevo objeto desde cero y lo devuelve, mientras que la función de rebuild solo establece algunos atributos. En segundo lugar, la tupla devuelta por __reduce__ debe ser seleccionable, y como método, Perceptron_avg_my.rebuild no es seleccionable (creo que se espera que se corrija en Python 3.3 o 3.4). En su lugar, podría convertirlo en una función de nivel de módulo. Finalmente, los argumentos (self.fpos,self.freePos) se pasan para rebuild individualmente, usted no tiene que desempaquetar la tupla.

Lo siguiente parece funcionar para mí (aunque es probable que también desee almacenar los valores de los otros atributos, de lo contrario, solo tendrán los valores iniciales establecidos por __init__ ):

 #inside the class definition def __reduce__(self): return (rebuild, (self.wlen, self.fpos, self.freePos)) #standalone function def rebuild(wlen, fpos, freePos): p = Perceptron_avg_my(wlen) p.fpos = fpos p.freePos = freePos return p 

A partir de Cython 0.26 (lanzado en julio de 2017), ya no es necesario implementar el protocolo pickle. Todas las clases cdef que no contienen punteros o uniones se pueden decapar automáticamente. Para las clases que contienen estructuras, el decapado automático está deshabilitado de forma predeterminada, debido a (entre otras razones) una sobrecarga de código alta. El decapado automático se puede habilitar para clases con estructuras utilizando el @cython.auto_pickle(True) .

Se puede encontrar más información en el registro de cambios y en el sitio web de Stefan Behnel .

Utilicé esta solución que funciona pero no estoy seguro de que sea la mejor solución.

Creé un nuevo archivo de soporte para declarar la función llamada por reducir (si lo pongo en el módulo cython no funciona):

 #perceptron_supp.py from perceptron import Perceptron def rebuild_perceptron(wlen,freePos,fpos,w,nw_avg,wtot_avg,wsup_avg,wmean_avg,wtot_my,wac_my,wtotc_my,wmean_my): return Perceptron(wlen,True,freePos,fpos,w,nw_avg,wtot_avg,wsup_avg,wmean_avg,wtot_my,wac_my,wtotc_my,wmean_my) 

Y luego importo esta función en el módulo cython:

 #perceptron.pyx import numpy as np cimport numpy as np cimport cython #added from perceptron_supp import rebuild_perceptron cdef class Perceptron: cdef int wlen,freePos cdef dict fpos cdef np.ndarray w #np.ndarray[np.int32_t] cdef int nw_avg cdef np.ndarray wtot_avg,wsup_avg #np.ndarray[np.int32_t] cdef np.ndarray wmean_avg #np.ndarray[np.float64_t] cdef np.ndarray wtot_my,wac_my,wtotc_my #np.ndarray[np.int32_t] cdef np.ndarray wmean_my #np.ndarray[np.float64_t] def __cinit__(self,int wlen=4*10**7,setValues=False,freePos=0,fpos=0,w=0,nw_avg=0,wtot_avg=0,wsup_avg=0,wmean_avg=0,wtot_my=0,wac_my=0,wtotc_my=0,wmean_my=0): if not setValues: self.wlen=wlen self.freePos=1 self.fpos= dict() self.w=np.zeros(wlen,np.int32) self.nw_avg=1 self.wtot_avg=np.zeros(wlen,np.int32) self.wsup_avg=np.zeros(wlen,np.int32) self.wmean_avg=np.zeros(wlen,np.float64) self.wtot_my=np.zeros(wlen,np.int32) self.wac_my=np.zeros(wlen,np.int32) self.wtotc_my=np.zeros(wlen,np.int32) self.wmean_my=np.zeros(wlen,np.float64) else: self.wlen=wlen self.freePos=freePos self.fpos=fpos self.w=w self.nw_avg=nw_avg self.wtot_avg=wtot_avg self.wsup_avg=wsup_avg self.wmean_avg=wmean_avg self.wtot_my=wtot_my self.wac_my=wac_my self.wtotc_my=wtotc_my self.wmean_my=wmean_my def __reduce__(self): return (rebuild_perceptron,(self.wlen,self.freePos,self.fpos,self.w,self.nw_avg,self.wtot_avg,self.wsup_avg,self.wmean_avg,self.wtot_my,self.wac_my,self.wtotc_my,self.wmean_my)) 

Cuando uso mi módulo de perceptrón, solo tengo que hacerlo: desde el perceptrón importa Perceptron y ahora puedo hacer cPyckle.dump o cPickle.load cuando lo necesito.

Si alguien tiene una mejor solución muchas gracias !!!