python - cython 包装 cpp 结构和函数,参数为结构数组

标签 python c++ cython

我正在使用 Cython 在 Python 中包装一个 C++ 库。不幸的是,我无法访问 c++ 库。因此,我必须找到一种方法来包装由 lib API 公开的结构和函数。

我的问题是关于包装 C++ 结构的最佳方式;随后,如何在 python 中创建内存 View 并将其指针(第一个元素地址)传递给参数为 cpp 结构数组的 c++ 函数。

例如,假设我有以下 h 文件:

//test.h

struct cxxTestData
{
   int m_id;
   double m_value;
};

void processData(cxxTestData* array_of_test_data, int isizeArr)

我的 pyx 文件将如下所示

cdef extern from "Test.h":
    cdef struct cxxTestData:
        int m_id
        double m_value

cdef class pyTestData:
    cdef cxxTestData cstr

    def __init__(self, id, value):
        self.cstr.m_id = id
        self.cstr.m_value = value

    @property
    def ID(self):
        return self.cstr.m_id

    @property
    def Value(self):
        return self.cstr.m_value

现在,我想创建一些 pyTestData 并将它们存储在 dtype 对象数组中。然后我想在 cython/python 函数中将这个数组作为内存 View 传递。

包装函数将具有以下签名

cpdef void pyProcessData(pyTestData[::1] test_data_arr)

我已经测试了上面的内容并且编译成功。我还设法修改了每个结构的成员。但是,这不是我想要实现的目标。我的问题是如何从这一点开始我可以传递一个数组,其中 c++ 结构封装在每个 pyTestData 对象中(通过 self.cstr)。

例如,请查看以下 list :

cpdef void pyProcessData(pyTestData[::1] test_data_arr):
    cdef int isize test_data_arr.shape[0]

    # here I want to create/insert an array of type cxxTestData to pass it 
    # to the cpp function
    # In other words, I want to create an array of [test_data_arr.cstr]
    # I guess I can use cxxTestData[::1] or cxxTestData* via malloc and
    # copy each test_data_arr[i].cstr to this new array
    cdef cxxTestData* testarray = <cxxTestData*>malloc(isize*sizeof(cxxTestData))

    cdef int i
    for i in range(isize):
        testarray[i] = test_data_arr[i].cstr
    processData(&testarray[0], isize)

    for i in range(isize):
        arrcntrs[i].pystr = testarray[i]

    free(testarray)

有人遇到过这种情况吗?有没有更好的方法可以在上面的函数中传递我的 python 对象,而不必在内部复制 cxx 结构?

非常感谢,如果我做错了根本性的事情,我深表歉意。

最佳答案

由于您希望将一个 cxxTestData 数组传递给您的 C++ 函数,最好的办法是将其分配为一个数组。一些未经测试的代码说明了该方法:

cdef class TestDataArray:
    cdef cxxTestData* array:
    def __init__(self, int length):
        self.array = <cxxTestData*>calloc(length,sizeof(cxxTestData))
    def __dealloc__(self):
        free(self.array)
    def __getitem__(self, int idx):
        return PyTestData.from_pointer(&self.array[idx],self) # see later
    def __setitem__(self, int idx, PyTestData pyobj): # this is optional
        self.array[idx] = deref(pyobj.cstr)

然后您想要稍微修改您的 PyTestData 类,以便它包含一个指针而不是直接包含该类。它还应该有一个字段代表数据的最终所有者(例如数组)。这确保数组保持事件状态,并且还允许 PyTestData 拥有自己的数据的情况:

cdef class PyTestData:
    cdef cxxTestData* cstr
    cdef object owner

    def __init__(self, id, value):
        self.owner = None
        self.cstr = <cxxTestData*>malloc(sizeof(cxxTestData))
        self.cstr.m_id = id
        self.cstr.m_value = value

    def __dealloc__(self):
        if self.owner is None: # i.e. this class owns it
             free(self.cstr)

    @staticmethod
    cdef PyTestData from_pointer(cxxTestData* ptr, owner):
        # calling __new__ avoids calling the constructor
        cdef PyTestData x = PyTestData.__new__(PyTestData)
        x.owner = owner
        x.cstr = ptr
        return x

创建 TestDataArray 类需要一些额外的努力,但它以 C++ 可直接使用的格式存储数据,因此我认为这是最好的解决方案。

关于python - cython 包装 cpp 结构和函数,参数为结构数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54653339/

相关文章:

python - 运行扭曲的应用程序时出错

c++ - 使用元编程进行消息队列管理

c++ - 当进程退出时收到通知

python - 使用 Cython 处理可变大小的列表

python - 无法从 conda 环境构建 cython 代码

python - 添加优化会降低分类器算法的准确性、精确度和 f1

python - 如何防止python函数读取外部范围变量?

python - NetworkX——创建属于 4 节点 clique 的所有节点的新图

c++ - Qt:如何让 QWidget 出现在主窗口的多个位置?

python - 你能导入一个 .so 文件吗?