Python 如何在Cython中将函数指针传递给外部程序
我正试图围绕C程序编写一个包装器,以便可以从Python调用它。我用Cython来做这个。C函数将回调函数作为参数,但是这个回调函数只有在python程序运行时才知道。我一直在寻找如何做到这一点,似乎没有简单的解决方案,但以下似乎可行:Python 如何在Cython中将函数指针传递给外部程序,python,cython,Python,Cython,我正试图围绕C程序编写一个包装器,以便可以从Python调用它。我用Cython来做这个。C函数将回调函数作为参数,但是这个回调函数只有在python程序运行时才知道。我一直在寻找如何做到这一点,似乎没有简单的解决方案,但以下似乎可行: #python.py libc = cdll.LoadLibrary("myfunc.so") #Callback function is defined in myfunc.so .... c_wrapper(libc.fun, ...) #c#u w
#python.py
libc = cdll.LoadLibrary("myfunc.so") #Callback function is defined in myfunc.so
....
c_wrapper(libc.fun, ...)
#c#u wrapper.pyx
cdef extern void main function(void*F,…)#我们正在包装的初始C函数
ctypedef void(*myfuncptr)()
def c_wrapper(f,…)#我们的函数指针作为Python对象传递给包装器
cdef myfuncptr thisfunc
thisfunc=(地址(f))[0]
main函数(thisfunc,…)
这种方法适用于C和FORTRAN函数(我假设它适用于大多数编译语言)和Python函数(使用C类型),但似乎有点笨拙。在Cython有没有更简单的方法
谢谢
编辑:我无法更改我试图包装的C库,我想你知道了吧
可以从C调用我的Python代码吗
回答:是的,很容易。按照中的Demos/callback/中的示例进行操作
Cython源分布
因此,知道您可以加载主函数,让我们采用另一种方法。我编写了几个愚蠢的函数来测试这一点:
/* lib.c -> lib.so */
#include <stdio.h>
void fn1(void) {
puts("Called function 1");
}
void fn2(void) {
puts("Called function 2");
}
可以直接从Python传递:
>>> from ctypes import cdll
>>> lib = cdll.LoadLibrary('./lib.so')
>>> main = cdll.LoadLibrary('./main.so')
>>> main.mainfunction(lib.fn1)
Called function 1
>>> main.mainfunction(lib.fn2)
Called function 2
现在,让我们包装一个Python函数:
>>> from ctypes import CFUNCTYPE
>>> def pyfn():
... print "Called the Python function"
...
>>> CWRAPPER = CFUNCTYPE(None)
>>> wrapped_py_func = CWRAPPER(pyfn)
>>> main.mainfunction(wrapped_py_func)
Called the Python function
如果有一个就好了。但如果你没有得到任何答案,你提出的解决方案可能对其他人有用。在这种情况下,也许您可以将其重新表述为成对问题/解决方案?好的,有一件事我第一次没有得到,因此我的答案是:回调函数可能来自C/FORTRAN库,也可能是Python本机函数。是这样吗?@Ricardo,没错。对不起,我可能没有明确说明这一点。基本上,如果函数来自C/FORTRAN库,它将存储为_FuncPtr对象,如果函数是用本机Python编写的,它可以存储为CFunctionType(通过使用C类型)。我想我真正想问的是,是否有任何精巧的方法可以将其中的任何一个/全部转换为包装器中的C函数指针?@Dan:Mmh。。。只有一件事。您的
main函数
是否也从库中加载(即,是否可以使用cdll.LoadLibrary
加载它?)@Ricardo是的,它可以这样加载。。。你是说我可以彻底清除Cython,然后从Python中调用main函数
?谢谢@Ricardo Cárdenes,我已经看到了这个示例,它展示了如何包装一个具有回调接口的C API,以便您可以将Python函数作为回调传递给它。这是一个很好的例子,说明了如果我能够访问我试图包装的C库,那么这个问题是如何解决的,不幸的是,我无法触摸它。感谢you@Dan:新答案,基于其他假设。谢谢,只是一个小问题。为什么重要的是使用dll加载main函数
,而不是在Cython中声明它?另外,您是否尝试过运行这个示例,并且它运行时没有出现错误?似乎我已经在Cython内部尝试了一种非常类似的技术,我把它归结为这样一个事实:使用cdll加载的函数是错误的类型,不能直接交给我们的C函数?例如:>>print lib.fn1
>print pyfn
>print wrapped\u func
那么,ctypes
知道如何在不同的本机C函数之间进行转换,并帮助您包装Python函数,将它们作为回调发送,这就是为什么。是的,我已经测试过了。你们看到的大部分是我的控制台上的剪切+粘贴(减去返回值)好的,干杯。我要好好看看。我想我一定是有点困惑了。再次干杯!
>>> from ctypes import cdll
>>> lib = cdll.LoadLibrary('./lib.so')
>>> main = cdll.LoadLibrary('./main.so')
>>> main.mainfunction(lib.fn1)
Called function 1
>>> main.mainfunction(lib.fn2)
Called function 2
>>> from ctypes import CFUNCTYPE
>>> def pyfn():
... print "Called the Python function"
...
>>> CWRAPPER = CFUNCTYPE(None)
>>> wrapped_py_func = CWRAPPER(pyfn)
>>> main.mainfunction(wrapped_py_func)
Called the Python function