通过pickle保存cython扩展

Posted

技术标签:

【中文标题】通过pickle保存cython扩展【英文标题】:save cython extension by pickle 【发布时间】:2017-10-01 08:04:55 【问题描述】:

我有一个用cython 编写的类或扩展类型,如下所示:

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

我使用distutils从这个cython文件(它的名字是som.pyx)创建了一个python模块,然后我将它导入python并用它来创建和训练一个模型,但是当我想要的时候使用pickle 保存我的模型,它给了我这个错误:

TypeError: can't pickle som.Self_Organized_Map objects

pickle 或我的代码有什么问题?泡菜不能保存扩展对象吗?

【问题讨论】:

有相当多的文档和以前的问题看起来不像你读过:例如docs.python.org/3/library/…([扩展类型默认不定义__dict__( cython.readthedocs.io/en/latest/src/reference/…))。之前的几个相关问题:***.com/questions/12646436/pickle-cython-class***.com/questions/36301322/… 另外,你的标题提到了指针,但你的代码没有显示任何指针。也许澄清一下? @DavidW 谢谢我更正了! 【参考方案1】:

默认情况下,Cython 类不可腌制,因此您需要自己实现 Pickle interface。您可以在许多不同的级别上执行此操作,但 __getstate____setstate__ 是用户最友好的级别,因此除非您有充分的理由,否则这是一个很好的起点。

如果类的内容是可腌制的,那么就像在 __getstate__ 中返回它们的元组并在 __setstate__ 中返回它们一样简单。 Memoryviews 本身不是可腌制的,但可能有一个 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++ 对象,那么它会复杂得多。对于简单类型的好地方,只需将内存复制到字节数组中或利用 Cython 的默认 struct<->dict 相互转换。但是,如果该类包含指针,那么这将不起作用,您需要在 C/C++ 中为其实现可靠的加载/保存机制。

【讨论】:

【参考方案2】:

从 Cython 0.26(2017 年 7 月发布)开始,只要 cdef 类不包含指针或联合,就可以自动腌制它们。对于包含结构的类,可以使用 @cython.auto_pickle(True) 装饰器启用自动酸洗。由于高代码开销和其他原因,默认情况下禁用它。

更多信息可以在changelog和the website of Stefan Behnel上找到。

【讨论】:

优于人工酸洗

以上是关于通过pickle保存cython扩展的主要内容,如果未能解决你的问题,请参考以下文章

《Cython系列》4. Cython中的扩展类

Cython:扩展类型的链接列表

如何将内置的 Cython 扩展从 PC 转移到另一台?

python怎么使用cython

Cython 扩展模块类方法不可见/命名 提及时出错

Cython初窥