如何将结构指针传递给Cython的cdef类的__cinit__

时间:2016-01-29 16:05:35

标签: python pointers struct constructor cython

我正在尝试使用 cinit 来实现cdef类,它必须使用cdef结构指针。

C标题

typedef struct foo *FOO;

PXD文件:

extern ...:

    cdef struct foo
    ctypedef foo *FOO

PYX文件:

cdef class ClassX(object):

    def __cinit__(self, FOO arg):
        ...

Cython编译器说“无法将Python对象参数转换为'FOO'类型”。有什么问题以及如何将struct指针传递给 cinit

2 个答案:

答案 0 :(得分:1)

看起来我发现了类似的问题:how to cython class function's parameter accept c++ struct。简短回答:无法将C-struct传递给Python(def)函数。我必须将一个结构包装到Python对象中。

答案 1 :(得分:0)

这里有一些我设法为我的案例解决它的方法,这些方法非常具体。

方法 1 - 将指针转换为 uint64 数字(有点脏) 您必须确保在复制之前没有删除引用,但首先将您的结构指针转换为一个无符号的 64 位数字,然后转换并可能 deref 回您的对象。像这样

from cython.operator cimport dereference as deref
ctypedef unsigned long long uint64_t

...

cdef class SomeClass(object):
    cdef FooStruct foo

    def __cinit__(self, uint64_t arg):
        self.foo = deref(<FooStruct*> arg)  # preferably copy over keeping pointer

然后构建它

cdef FooStruct yourfoo = ...  # your struct
cdef SomeClass res
res = SomeClass(<uint64_t> &yourfoo)

这不是最漂亮的解决方案,但它适用于特定情况。

方法 2 - 相同的 PYX 文件分配功能(首选) 我发现此方法仅适用于同一个 PYX 文件中的对象引用。因此,如果您使用复制数据的 setter 函数定义 cdef class,该函数不会暴露给 python,那么您可以更新内部结构。

cdef class SomeClass(object):
    cdef FooStruct foo

    def __cinit__(self):
        ...

    cdef void _set(self, FooStruct &data):
        self.foo = data  # copy

现在构造它的两行

cdef FooStruct yourfoo = ...  # your struct
cdef SomeClass res
res = SomeClass()
res._set(yourfoo)