2017-05-03 60 views
2

用Cython擴展我已經寫在cython這樣一類或擴展類型:保存通過泡菜

cdef class Self_Organized_Map: 
    cdef 
    def __cinit__(self,np.ndarray data,.....): 
    .... 

我創建一個python模塊從該cython文件(其名稱是som.pyx)使用distutils,然後我導入這python,並用它來創建和訓練一個模型,但是當我想用pickle它給了我這個犯錯救我的模型:

TypeError: can't pickle som.Self_Organized_Map objects

什麼是錯的鹹菜或M y代碼?醃菜不能保存擴展對象?

+1

有相當多的文檔和以前的問題,它看起來不像你讀過的:如https://docs.python.org/3/library/pickle.html#what-c​​an-be- pickled-unpickled([擴展類型沒有定義'__dict__'默認情況下}(http://cython.readthedocs.io/en/latest/src/reference/extension_types.html#attributes))。一些相關的以前的問題:http://stackoverflow.com/questions/12646436/pickle-cython-class http://stackoverflow.com/questions/36301322/pickle-cython-class-with-c-pointers – DavidW

+1

此外,您的標題提到指針,但你的代碼不顯示任何。也許澄清? – DavidW

+0

@DavidW謝謝我糾正它! –

回答

2

自從Cython 0.26(2017年7月發佈)以來,只要cdef類不包含指針或聯合,cdef類就可以自動進行醃製。對於包含結構的類,可以使用@cython.auto_pickle(True)裝飾器啓用自動酸洗。由於其他原因導致高代碼開銷,因此它被默認禁用。

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

4

默認情況下,Cython類不是pickleable,因此您需要自己實現Pickle interface。有很多不同的級別可以做到這一點,但__getstate____setstate__是用戶友好性最高的級別,所以它是一個很好的開始,除非您有其他充足的理由。

如果該類的內容是pickleable,則只需返回__getstate__中的元組和__setstate__中的相反操作即可。記憶體視圖本身不可pickleable,但有base屬性可能。

cdef class C: 
    cdef double[:] array 
    cdef python_obj 
    cdef int integer 

    def __init__(self,array,python_obj,integer): 
     self.array = array 
     self.python_obj = python_obj 
     self.integer = integer 

    def __getstate__(self): 
     return (self.array.base, # memoryviews aren't pickleable, need to get underlying object 
          # and hope it's pickleable 
       self.python_obj, self.integer) 

    def __setstate__(self,x): 
     self.array, self.python_obj, self.integer = x 

如果你的類擁有C或C++對象,那麼它就複雜得多。對於簡單的類型,只需將內存複製到bytearray中即可,或者利用Cython的默認struct<->dict相互轉換。但是,如果類包含指針,那麼這將不起作用,您需要在C/C++中爲它實現可靠的加載/保存機制。