Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何在Cython中将函数指针传递给外部程序_Python_Cython - Fatal编程技术网

Python 如何在Cython中将函数指针传递给外部程序

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

我正试图围绕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 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