如何使用Cython在C struct上编写完整的Python包装器?

我正在使用Cython为Python编写一个高级界面的Python.
我有一个扩展类型A,它使用指向更复杂的C上下文结构c_context的指针来初始化库.指针保存在A.
A还有一个def函数,它又创建另一个扩展类型B,使用库函数调用初始化另一个C结构.这种结构对于在B中进行的后续库调用是必需的
B需要来自A的c_context指针,它由我在扩展类型py_context中包装,以便从B传递给__cinit__:

#lib.pxd (C library definitions)
cdef extern from "lib.h":
    ctypedef struct c_context:
        pass

#file py_context.pxd
from lib cimport c_context

cdef class py_context:
    cdef c_context *context
    cdef create(cls, c_context *context)
    cdef c_context* get(self)

#file py_context.pyx
def class py_context:
    @staticmethod
    cdef create(cls, c_context *c):   
        cls = py_nfc_context()  
        cls.context = c  
        return cls

    cdef c_context* get(self):
        return self.context

用正确的C语言传递包装器完美.

现在我需要再次从py_context得到C结构,并保存在B中.我将cdef c_context get(self)添加到py_context.pxd / pyx.
从Bs __cinit__调用py_context.get()导致:AttributeError:py_context对象没有属性get.

好像在Cython中调用cdef函数时,我并没有把头放在头上.

所以我的问题是:从我的包装类中提取C struct的最好方法是什么?

最佳答案
麻烦的是,Cython在编译时不知道py_context变量的数据类型.对cdef函数的调用在编译时解析,并且没有机制通过属性查找在运行时找出它(与普通的Python函数一样).

[注意,Cython中编写的def函数仍然被编译,并且可以指定数据类型,所以如果它们具有正确的信息,完全可以调用cdef函数.

你不会给出相应的代码(B类的构造函数),但这是一个非常简化的例子,希望能给你几种方法来解决它:

cdef class A:
    cdef f(self):
        return

def f1(var):
    var.f()

#f1(A()) # will fail at runtime with an attribute error

在f1中,var的类型是未知的,因此您不能调用cdef函数.

def f2(A var):
    var.f()

f2(A()) # will work
f2(1) # will fail, int can't be converted to A

在f2中,var的类型被限制为A,因此它可以愉快地调用与A相关联的cdef函数.如果你传递的东西不是A,那么你将在运行时得到一个TypeError.

def f3(var):
    cdef A another_reference_to_var = var # this does test that the types match
    another_reference_to_var.f()

f3(A()) # will work
f3(1) # will fail, int can't be converted to A

函数f3可以采用任何类型的变量.但是,当您将其分配给另一个被定义为A的an_reference_to_var时,它会检查该类型是否匹配(如果没有则引发运行时异常).由于在编译时已知an_reference_to_var为A,因此可以调用As cdef函数.

本质上,您需要指定__cinit__函数的相关输入类型.

转载注明原文:如何使用Cython在C struct上编写完整的Python包装器? - 代码日志