如何使用Cython在C Struct周围编写完整的Python包装器?

时间:2016-06-23 07:06:05

标签: python c wrapper cython

我正在使用Cython为Python的C库编写一个高级接口 我有一个扩展类型A,它使用指向更复杂的C上下文结构c_context的指针初始化库。指针保存在AA还有def函数,该函数又创建另一个扩展类型B,使用库函数调用初始化另一个C结构。在B中进行的后续库调用需要此结构 B需要来自c_context的{​​{1}}指针,该指针由我在扩展程序类型A中包含,以便将其从py_context传递给__cinit__

B

使用正确的C上下文传递包装器可以完美地工作。

现在我需要再次从#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中。我将B添加到cdef c_context get(self)。 从B py_context.pxd/pyx拨打py_context.get()会导致:__cinit__

在Cython中调用AttributeError: py_context object has no attribute get.函数时似乎无法理解。

所以我的问题是:从我的包装器类中再次提取C结构的最佳方法是什么?

1 个答案:

答案 0 :(得分:6)

麻烦的是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

f1var的类型未知,因此您无法调用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,因此可以愉快地调用与cdef相关联的A个函数。如果您传递的内容不是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可以采用任何类型的变量。但是,当您将another_reference_to_var cdef分配为A时,它会检查该类型是否匹配(如果不匹配,则会引发运行时异常)。由于在编译时已知another_reference_to_varA,因此您可以调用Acdef函数。

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