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

How to pass struct pointer to __cinit__ of Cython's cdef class

我正在尝试使用必须使用 cdef 结构指针的 cinit 来实现 cdef class。

C 头

typedef struct foo *FOO;

PXD 文件:

extern ...:

    cdef struct foo
    ctypedef foo *FOO

PYX 文件:

cdef class ClassX(object):

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

Cython 编译器说 "Cannot convert Python object argument to type 'FOO'"。有什么问题以及如何将结构指针传递给 cinit?

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

以下是我为我的案例设法解决的一些方法,它们非常具体。

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

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)

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

方法二 - 同样的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)