python - 是否可以使用 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 中实现这一点?
解决方案
您必须提供一个来自 cython 的包装器,该包装器可以在您的共享对象中调用。Cython 本质上具有三种“模式”
- def : 普通的 python 函数
- cpdef:具有可能的 c/cpp 内部变量的 python 可调用函数
- 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 将适用于此。
推荐阅读
- vb.net - DataGridView - 根据其他单元格计算和更新单元格值
- python - Python websocket 使用基本身份验证自动关闭
- vue.js - 在页面刷新时丢失 router.params
- javascript - 补丁请求后如何更新行为主题?
- spring-batch - 如何强制 RepositoryItemReader 仅读取新插入的记录或未处理的记录
- java - 数据源:未指定“url”属性,无法配置嵌入式数据源
- c# - 在工作线程中修改字符串然后在主线程中读取结果的正确方法是什么?
- c# - 不返回实体框架映射值
- amazon-web-services - 如何防止api网关转换base64响应
- javascript - 什么相当于 Storybook 中的 Meteor.startup