是否可以使用 Cython 将指向编译时未知函数的 C 函数指针传递给 C 函数?
Is it possible to pass a C function pointer to a function that is unknown at compile time to a C function using Cython?
我正在尝试从 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”的共享库后,我可以使用 ctypes
:
传递在 Python 运行时确定的函数
# 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)
我知道我应该定义 return 类型,但为简洁起见,我将其省略并仅使用 int
s。
上面的代码给出了预期的结果,例如调用 foo.foo('add', 2, 4)
会产生 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: python 具有可能 c/cpp 内部变量的可调用函数
- 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 指令,但有序的或 unorered_map 可以用于此。
我正在尝试从 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”的共享库后,我可以使用 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)
我知道我应该定义 return 类型,但为简洁起见,我将其省略并仅使用 int
s。
上面的代码给出了预期的结果,例如调用 foo.foo('add', 2, 4)
会产生 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: python 具有可能 c/cpp 内部变量的可调用函数
- 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 指令,但有序的或 unorered_map 可以用于此。