【问题标题】:Call cdef function by name in Cython在 Cython 中按名称调用 cdef 函数
【发布时间】:2017-09-23 10:40:21
【问题描述】:

我在 Cython 中有一堆 cdef 函数,它们由 pyx 文件中的 def 函数调用,例如:

cdef inline void myfunc_c(...):
    (...)
    return

def wrapper(...):
    myfunc_c(...)
    return

这很好用。但为了简化不必为每个 cdef 函数使用 python 包装器,我试图按名称索引 cdef 函数,方法是将它们分配给字典或类似的东西:

def wrapper(operation):
    if operation == 'my_func':
        func = myfunc_c
    func(...)
    return

但这不起作用。 Cython 抱怨它不知道myfunc_c 的类型。

有没有办法按名称索引或调用cpdef 函数(例如,使用字符串)?我也尝试过locals()['myfunc_c'] 之类的方法,但也没有用。

【问题讨论】:

  • 我以前没有使用过 Cython,但这似乎没有意义 - 为什么你可以调用 myfunc_c inside 一个 Python 函数,而不是 外面一个?

标签: python cython


【解决方案1】:

对于一个通用 cdef 函数,这是不可能的——它们只定义了一个 C 接口而不是一个 Python 接口,所以没有可用的自省。

对于cdef 函数declared with api(例如cdef api funcname()),它实际上是可能的。有一个未记录的字典__pyx_capi__。这定义了一个包含函数指针的 PyCapsules 字典(按名称索引)。然后你会做

capsule_name = PyCapsule_GetName(obj)
func = PyCapsule_GetPointer(obj, capsule_name)

(其中PyCapsule_* 是从 Python C API 导入的函数)。 func 是一个 void*,您可以将其转换为适当类型的函数指针。选择正确的类型很重要,这取决于您!

虽然没有记录,但__pyx_capi__ 接口相对稳定,并被 Scipy 用于其LowLevelCallable 功能,例如。

cpdef 函数定义了 Python 和 C 接口。在一个函数中,它们将在globals() 而不是locals() 中可用(因为locals() 只给出了该函数中定义的变量。)


我实际上并不认为你想这样做。我认为您只想使用 cpdef 而不是 cdef,因为这会自动为函数生成 Python 包装器。

【讨论】:

  • 也许我确实应该采用cpdef 的方式。出于性能原因,我避免使用它:我确实需要在“包装器”部分中执行一些纯 python 操作,并且担心使用 cpdef 它不会得到完全优化。
  • 如果您担心,可能值得安排时间。值得记住的是,Cython 确实编译了所有 defcpdefcdef 函数,因此速度上的差异仅来自函数调用机制(cpdefcdef 之间不会有太大差异)。
  • 我已经用另一种方法更新了它,您实际上可以按名称获取 cdef 函数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-19
  • 1970-01-01
  • 1970-01-01
  • 2011-10-13
  • 1970-01-01
  • 2015-06-23
相关资源
最近更新 更多