首页 > 解决方案 > 是否可以使用 Cython 将 C 函数指针传递给在编译时未知的函数到 C 函数?

问题描述

我正在尝试从 Python 调用一个将函数指针作为参数的 C 函数。我需要在运行时动态确定该函数。使用ctypes,这很简单。

C 代码可能如下所示:

// my_c_funcs.h
double mul(double, double);
double add(double, double);
double do_something(double (*)(double, double), double, double);
// my_c_funcs.h
int mul(int a, int b) {
    return a*b;
}
int add(int a, int b) {
    return a + b;
}
int do_something(int (*f)(int, int), int a, int b) {
    return f(a, b);
}

将该代码编译到名为“libMyCFuncs.so”的共享库后,我可以传递一个在 Python 运行时确定的函数ctypes

# foo.py
import ctypes

lib = ctypes.cdll.LoadLibrary("./libMyCfuncs.so")

def foo(func_name, a, b):
    func = getattr(lib, func_name)
    return lib.do_something(func, a, b)

我知道我应该定义返回类型,但为了简洁起见,我把它省略了,int只使用了 s 。

上面的代码给出了预期的结果,例如调用foo.foo('add', 2, 4)yield 6。但是,我更喜欢使用 Cython,因为我大量使用二维或更高维数组,恕我直言,在 Cython 中传递数组更容易。假设 Cython 代码在“foo.pyx”中:

# foo.pyx
cdef extern from "my_c_funcs.h":
    int mul(int, int)
    int add(int, int)
    int do_something(int (*)(int, int), int, int)

def foo(func_name, int a, int b):
    # ???

打电话getattr甚至eval显然不起作用。那么我如何在 Cython 中实现这一点?

标签: pythonccython

解决方案


您必须提供一个来自 cython 的包装器,该包装器可以在您的共享对象中调用。Cython 本质上具有三种“模式”

  1. def : 普通的 python 函数
  2. cpdef:具有可能的 c/cpp 内部变量的 python 可调用函数
  3. cdef:纯 c/cpp 函数

作为您的代码的示例,一个简单的绑定将是


cdef extern from "c_funcs.h":
    double mul(double, double)
    double add (double, double)
    double do_something(double(*)(double, double), double, double)

cdef extern from "c_funcs.c":
    pass

# this is callable from python
cpdef double py_do_something_mul(str name, double x,  double y):
    return do_something(mul, x, y)

如果您想要动态调度之类的东西,您还必须为此提供一些包装。它不适用于默认的 python dicts,但 ordered 或 unored_map 将适用于此。


推荐阅读