Pickle Cython类与C指针

2024-03-28 18:28:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我正试图为一个cython类编写一个__reduce__()方法,该类包含C指针,但到目前为止,关于如何实现这一目标的最佳方法的信息非常少。当使用numpy数组作为成员数据时,如何正确地编写__reduce__()方法,这里有大量的例子。我希望远离Numpy数组,因为它们似乎总是作为python对象存储,并且需要调用pythonapi。我来自C语言背景,因此我非常习惯于使用调用malloc()和{}来手工处理内存,并试图将python交互保持在绝对最低限度。在

但是我遇到了一个问题。我需要在我正在创建的类上使用与copy.deepcopy()等效的东西,从Python脚本中最终使用它。我发现实现这一点的唯一好方法是通过实现__reduce__()方法实现类的pickle协议。对于大多数原语或python对象来说,这一点很简单。然而,对于如何为动态分配的C数组执行此操作,我完全不知所措。显然,我不能返回指针本身,因为在对象重建时,底层内存已经消失,所以最好的方法是什么?我确信这将需要修改__reduce__()方法以及一个或两个__init__()方法。在

我已经阅读了关于pickling扩展类型found here的python文档,以及关于选择诸如this question之类的cython类的堆栈溢出问题。在

我的课程的精简版本如下所示:

cdef class Bin:
    cdef int* job_ids
    cdef int* jobs
    cdef int primitive_data

    def __cinit__(self):
        self.job_ids = <int*>malloc(40 * sizeof(int))
        self.jobs = <int*>malloc(40 * sizeof(int))

    def __init__(self, int val):
        self.primitive_data = val

    def __dealloc__(self):
        free(job_ids)
        free(jobs)

    def __reduce__(self):
        return (self.__class__, (self.primitive_data))

Tags: 对象方法selfidsreducedatadefjobs
1条回答
网友
1楼 · 发布于 2024-03-28 18:28:01

一种方法是将数组中的数据序列化为Pythonbytes数组。__reduce__方法首先调用get_data方法,该方法将数据指针强制转换为<char*>,然后再转换为<bytes>(如果您试图直接转到那里,Cython不知道如何做)。__reduce__返回这个对象,以及对rebuild函数的引用(一个模块级函数,不是一个方法!)它可用于使用set_data方法重新创建实例。如果您需要传递多个数组,如您的示例中所示,您只需要接受rebuild的更多参数,并扩展{}返回的元组。在

我没有做过太多的测试,但它似乎起作用了。如果你传递错误的数据,它可能会爆炸。在

from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free
from libc.string cimport memcpy

cdef int length = 40

cdef class MyClass:
    cdef long *data

    def __cinit__(self):
        self.data = <long*>PyMem_Malloc(sizeof(long)*length)
        if not self.data:
            raise MemoryError()

    cdef bytes get_data(self):
        return <bytes>(<char *>self.data)[:sizeof(long)*length]

    cdef void set_data(self, bytes data):
        memcpy(self.data, <char*>data, sizeof(long)*length)

    def set_values(self):
        # assign some dummy data to the array 0..length
        for n in range(0, length):
            self.data[n] = n

    def get(self, i):
        # get the ith value of the data
        return self.data[i]

    def __reduce__(self):
        data = self.get_data()
        return (rebuild, (data,))

    def __dealloc__(self):
        PyMem_Free(self.data)

cpdef object rebuild(bytes data):
    c = MyClass()
    c.set_data(data)
    return c

示例用法(假设MyClass在你好.pyx)公司名称:

^{pr2}$

相关问题 更多 >