在 Python 中调用 C 函数
Posted
技术标签:
【中文标题】在 Python 中调用 C 函数【英文标题】:Calling C functions in Python 【发布时间】:2013-05-14 20:57:36 【问题描述】:我有一堆用 C 编写的函数,我想要一些我用 Python 编写的代码来访问这些函数。
我在这里阅读了几个处理类似问题的问题(例如here 和here),但我对需要采用哪种方法感到困惑。
一个问题推荐 ctypes,另一个问题推荐 cython。我已经阅读了两者的一些文档,但我完全不清楚哪个更适合我。
基本上,我已经编写了一些 python 代码来执行一些二维 FFT,我希望 C 代码能够看到该结果,然后通过我编写的各种 C 函数对其进行处理。我不知道从 C 调用 Python 是否更容易,反之亦然。
【问题讨论】:
你有库吗? .so ? 共享库? g++ -shared -Wl,-soname,mylib.so -o mylib.so my.o ? 【参考方案1】:嗯,这里你指的是以下两件事。
-
如何在python中调用c函数(扩展python)
如何从 C 程序调用 python 函数/脚本(嵌入 Python)
对于#2 '嵌入 Python'
您可以使用以下代码段:
#include "python.h"
int main(int argc, char *argv[])
Py_SetProgramName(argv[0]); /* optional but recommended */
Py_Initialize();
PyRun_SimpleString("from time import time,ctime\n"
"print 'Today is',ctime(time())\n");
/*Or if you want to run python file within from the C code*/
//pyRun_SimpleFile("Filename");
Py_Finalize();
return 0;
对于#1 “扩展 Python” 那么最好的选择是使用 Ctypes(顺便说一句,可以在所有 python 变体中移植)。
从 ctypes 导入 *
libc = cdll.msvcrt
打印 libc.time(无)
1438069008
printf = libc.printf
printf("Hello, %s\n", "World!")
你好,世界! 14
printf("%d 瓶啤酒\n", 42)
42 瓶啤酒 19
详细指南可以参考my blog article:
【讨论】:
【参考方案2】:您应该通过编写 ctypes 包装器从 Python 调用 C。 Cython 用于使类似 python 的代码运行得更快,ctypes 用于使 C 函数可从 python 调用。您需要做的是:
-
编写要使用的 C 函数。 (您可能已经这样做了)
为这些函数创建一个共享对象(.so,用于 linux、os x 等)或动态加载的库(.dll,用于 Windows)。 (也许你也已经这样做了)
编写 ctypes 包装器(这比听起来容易,I wrote a how-to for that)
在 Python 中从该包装器调用一个函数。 (这就像调用任何其他 python 函数一样简单)
【讨论】:
鉴于 OP 是 C 和 Python 代码的作者,并且 OP 更喜欢编写 Python 代码,所以不清楚这里应该使用什么。 Cython 将允许从 C 中提取更多代码。 +1 获取相关评论。而 Cython 不仅仅是性能问题。它是一个复杂而强大的工具。它允许您将 C 代码与 python 代码混合使用,因此如果您碰巧用 C 编写代码,它可以成为 C 和 Python 之间的完美桥梁。也就是说,您可以将静态(强类型变量)与动态类型混合。并通过简单的cast
从 C (PyObject
) 表示形式切换到 Python (object
) 表示形式,两种方式都可以。
链接上的教程非常好,但我必须将 int sum
更改为 int sum = 0
才能正常工作。
@Akavall 谢谢,已修复。
感谢教程链接 - 非常好。我唯一要更改的是“基本”部分中 Python 函数的名称,因为您重载了“our_function”,这可能有点令人困惑。【参考方案3】:
如果我理解得很好,你不喜欢像 c => python 或像 python => c 这样的对话。
在这种情况下,我会推荐Cython
。它对多种操作非常开放,特别是在您的情况下,从 C 调用一个用 Python 编写的函数。
这是它的工作原理(public api
):
下面的例子假设你有一个 Python 类(self
是它的一个实例),并且这个类有一个你想要调用这个类并处理结果的方法(名称method
)(这里是来自 C 的 double
)。这个函数,写在 Cython extension
中,可以帮助你完成这个调用。
cdef public api double cy_call_func_double(object self, char* method, bint *error):
if (hasattr(self, method)):
error[0] = 0
return getattr(self, method)();
else:
error[0] = 1
在 C 端,您将能够像这样执行调用:
PyObject *py_obj = ....
...
if (py_obj)
int error;
double result;
result = cy_call_func_double(py_obj, (char*)"initSimulation", &error);
cout << "Do something with the result : " << result << endl;
PyObject
是 Python/C API 提供的struct
在捕捉到py_obj
之后(通过在你的cython 扩展中投射一个普通的python object
,像这样:<PyObject *>my_python_object
),你终于可以在它上面调用initSimulation
方法并对结果做一些事情。
(这里是double
,但Cython 可以轻松处理vectors
, sets
, ...)
好吧,我知道如果您从未使用 Cython
写过任何东西,我刚刚写的内容可能会令人困惑,但它旨在简短地展示它可以在 合并方面为您做的许多事情。
另一方面,与将 Python 代码重新编码为 C 相比,这种方法可能需要更多时间,具体取决于算法的复杂性。 在我看来,只有当你计划经常有这种需求时,花时间学习 Cython 才是相关的......
希望这至少能提供一些信息......
【讨论】:
谢谢!看起来我可以用同样的努力在 C 中重新编码,所以在这种情况下,我真的不必使用 Cython。但我怀疑我将来会发现这些信息非常有用。 这是 C 还是 C++?cout
是 从 python 调用 C 会更容易。您的场景听起来很奇怪 - 通常人们用 python 编写大部分代码,除了处理器密集型部分,它是用 C 编写的。二维 FFT 是代码的计算密集型部分吗?
【讨论】:
这是计算密集度最低的部分……结果证明用 Python 编写代码比用 C 编写要方便得多。我希望为函数编写包装器更快而不是用 C 重写整个东西。以上是关于在 Python 中调用 C 函数的主要内容,如果未能解决你的问题,请参考以下文章