【问题标题】:How to write a complete Python wrapper around a C Struct using Cython?如何使用 Cython 围绕 C 结构编写完整的 Python 包装器?
【发布时间】:2016-10-25 08:47:41
【问题描述】:

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

#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 object has no attribute get.

似乎我不知道什么时候在 Cython 中调用 cdef 函数。

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

【问题讨论】:

标签: python c wrapper cython


【解决方案1】:

问题在于 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,因此它可以愉快地调用与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(即 cdefed 为 A)时,它会检查类型是否匹配(如果不匹配,则会引发运行时异常)。由于another_reference_to_var 在编译时已知为A,因此您可以调用As cdef 函数。

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

【讨论】:

  • +1 这是一个更好的答案,所以我立即删除了我的答案,因为它有点误导。 Here 是一个 url,其中包含为 OP 包装结构以查看他是否需要的完整示例。
  • 像魅力一样工作。 Bs __cinit__ 中缺少的类型信息是问题所在。添加py_context 可以解决问题。您的信息应该添加到 Cython 文档中,因为它们有时有点模糊。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-11
  • 1970-01-01
  • 2013-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多