我正在使用Cython为Python的C库编写一个高级接口
我有一个扩展类型A
,它使用指向更复杂的C上下文结构c_context
的指针初始化库。指针保存在A
中
A
还有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结构的最佳方法是什么?
答案 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
在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
,因此可以愉快地调用与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_var
为A
,因此您可以调用A
个cdef
函数。
基本上,您需要指定__cinit__
函数的相关输入的类型。