在 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,像这样:&lt;PyObject *&gt;my_python_object),你终于可以在它上面调用initSimulation 方法并对结果做一些事情。 (这里是double,但Cython 可以轻松处理vectors, sets, ...)

好吧,我知道如果您从未使用 Cython 写过任何东西,我刚刚写的内容可能会令人困惑,但它旨在简短地展示它可以在 合并方面为您做的许多事情

另一方面,与将 Python 代码重新编码为 C 相比,这种方法可能需要更多时间,具体取决于算法的复杂性。 在我看来,只有当你计划经常有这种需求时,花时间学习 Cython 才是相关的......

希望这至少能提供一些信息......

【讨论】:

谢谢!看起来我可以用同样的努力在 C 中重新编码,所以在这种情况下,我真的不必使用 Cython。但我怀疑我将来会发现这些信息非常有用。 这是 C 还是 C++? cout 的一部分,不是吗?【参考方案4】:

从 python 调用 C 会更容易。您的场景听起来很奇怪 - 通常人们用 python 编写大部分代码,除了处理器密集型部分,它是用 C 编写的。二维 FFT 是代码的计算密集型部分吗?

【讨论】:

这是计算密集度最低的部分……结果证明用 Python 编写代码比用 C 编写要方便得多。我希望为函数编写包装器更快而不是用 C 重写整个东西。

以上是关于在 Python 中调用 C 函数的主要内容,如果未能解决你的问题,请参考以下文章

Python 调用C函数

在 Python 中调用 C 函数

ROS工程中C++调用python函数

linux 下的动态库制作 以及在python 中如何调用 c 函数库

从 C 程序中调用 Python 函数

Python 外部函数调用库ctypes简介