[英]How to write a complete Python wrapper around a C Struct using Cython?
我正在使用Cython为Python的C库编写一个高级接口。
我有一个扩展Type 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()
__cinit__
导致: AttributeError: py_context object has no attribute get.
似乎在Cython中调用cdef
函数时,我并没有犹豫。
所以我的问题是:再次从包装类中提取C结构的最佳方法是什么?
问题在于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
可以采用任何类型的变量。 然而,当你把它分配给another_reference_to_var
这是cdef
版是一个A
它会检查类型匹配(并引发一个运行时异常,如果事实并非如此)。 由于在编译时another_reference_to_var
被称为A
,因此可以调用A
的cdef
函数。
本质上,您需要为__cinit__
函数指定相关输入的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.