2012-09-28 52 views
6

我必須保存並加載一個cython類實例。 我用Cython類是該加的幾種方法:pickle cython class

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 

我想使用的cPickle模塊。 我明白,我必須實現一個__reduce __(個體經營)方法,但我有一些問題找到一個例子,清楚的瞭解文件

我想這樣的事情添加到Perceptron_avg_my而不是作品:

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)) 

有什麼建議嗎? 非常感謝!

+0

這裏也有幫助:https://ask.sagemath.org/question/8376/pickling-extension-classes/ –

回答

9

我不知道你是否找到它,但官方的Python文檔有a section on pickling extension types(不幸的是,似乎沒有這個文檔的Python 3版本,但它在Python 3中的工作原理是一樣的)。

我想你在這裏有三個問題。首先,__reduce__返回的函數應該從頭開始創建一個新對象並返回它,而您的rebuild函數只是設置一些屬性。其次,由__reduce__返回的元組本身必須是可挑選的,作爲一種方法,Perceptron_avg_my.rebuild是不可挑選的(我認爲這可以在python 3.3或3.4中修復)。相反,你可以把它變成一個模塊級的功能。最後,將參數(self.fpos,self.freePos)單獨傳遞給rebuild - 您不必自行解壓元組。

以下似乎爲我工作(儘管你可能要存儲其他屬性的值也一樣,否則他們就只能通過__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 
+1

謝謝詹姆斯,抱歉,如果我現在回覆!!! 我認爲還有另一個問題:\ __ reduce__返回的函數不能在cython模塊中(我真的不明白爲什麼)。我將添加一個解決方案,適用於我......但我不知道是否有更好的解決方案。 – Francesco

+0

這很奇怪:它在模塊內定義時適用於我。你沒有意外地使用'cdef'而不是'def'來定義函數,是嗎?或者,也許我們只是使用不同版本的cython或python(我用python 3.2.3/cython 0.17和python 2.7.2/cython 0.15.1嘗試過)。 – James

+0

我使用python 2.7.3/cython 0.17。 – Francesco

3

我用這個解決方法這有效,但我不確定它是最好的解決方案。

我創建了一個新的支持文件中聲明的減少(如果我把它用Cython模塊豈不作品)調用的函數:

#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) 

,然後我在用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)) 

當我使用我的感知器模塊時,我只需要做:從感知器導入Perceptron,現在我可以在需要時執行cPyckle.dump或cPickle.load。

如果有人有更好的解決方案,非常感謝!

3

從Cython 0.26(2017年7月發佈)開始,不再需要實施pickle協議。所有不包含指針或聯合的cdef類都可以自動進行酸洗。對於包含結構的類,由於(除其他原因)高代碼開銷,默認情況下禁用自動酸洗。可以使用@cython.auto_pickle(True)裝飾器爲具有結構的類啓用自動酸洗。

更多信息可在changelogthe website of Stefan Behnel中找到。

+1

很高興看到新版本!然而,我仍然必須實現我自己的酸洗機制b/c'TypeError:由於不重要的__cinit__',沒有默認的__reduce__ –