使用 pyx/pxd 文件中的函数工厂为 C 库生成 cython 函数包装器

Ste*_*fan 5 python numpy cython python-c-extension

我正在重新评估将外部 C 库包装到 Python 中的不同方法。我很久以前就选择使用简单的 Python C API,它快速、简单、独立,而且正如我认为的那样,它是面向未来的。然后我偶然发现了PyPy,它显然不打算支持 CPython API,但将来可能会成为一个有趣的替代方案......因此我正在寻找一个更高级别的入口点。ctypes速度很慢,所以现在我回到了cython,它似乎正在努力支持 PyPy。

我的库有许多具有相同签名的函数,因此我广泛使用 C 预处理器宏来生成 Python 模块。我认为这在 cython 中会变得更加舒适,因为我可以访问整个 Python 语言。但是,我在为函数包装器编写工厂时遇到问题:

import cython
from numpy cimport ndarray, double_t

cimport my_c_library

cdef my_c_library.data D

ctypedef double_t DTYPE_t

cdef parse_args(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
    D.n = P.size
    D.m = x.size
    D.P = <double*> P.data
    D.x = <double*> x.data
    D.y = <double*> y.data

def _fun_factory(name):
    cpdef fun(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
        parse_args(P, x, y)
        getattr(my_c_library, name)(&D)
        return y
    return fun

fun1 = _fun_factory('fun1')
fun2 = _fun_factory('fun2')
# ... many more function definitions ...
Run Code Online (Sandbox Code Playgroud)

cython 编译器抱怨:“此处不允许 C 函数定义”,指的是cpdef内部_fun_factory. 这里有什么问题?我认为pyx文件就像普通的 python 文件一样。pyx除了从单独的 python 脚本动态生成文件(例如 )之外,有没有办法让它工作setup.py

我也很惊讶 cython 不让我这样做:

ctypedef ndarray[double_t, ndim=1] p_t
Run Code Online (Sandbox Code Playgroud)

清理代码。为什么这不起作用?

我知道有自动C -> cython翻译器,但我不愿意让自己依赖这样的第三方工具。但如果您认为它已准备好用于生产使用,请随时推荐一个。

Fre*_*Foo 3

pyx文件与 Python 文件不同,您可以匹配 C 和 Python 函数,并且对使用 C(cdefcpdef)函数执行的操作存在一些限制。其一,您无法在运行时动态生成 C 代码,而这正是您的代码试图做的事情。由于fun实际上只是在对其参数进行类型检查后执行一些 Python 代码,因此您不妨将其设为常规 Python 函数:

def fun(P, x, y):
    parse_args(P, x, y)
    getattr(my_c_library, name)(&D)
    return y
Run Code Online (Sandbox Code Playgroud)

parse_args将进行相同的参数检查,因此您不会丢失任何内容。(不过,我不确定是否getattr适用于已编译的 C 库。您可能也cimport需要它。)import

至于ctypedef,这可能是 Cython 中的一些限制/错误,目前还没有人有时间修复。