从Python调用C / C ++?

什么是最快的方法来构build一个Python或C + +库的绑定?

(如果这个问题我正在使用Windows。)

你应该看看Boost.Python 。 以下是他们网站的简短介绍:

Boost Python库是一个用于连接Python和C ++的框架。 它使您可以快速无缝地将C ++类的函数和对象暴露给Python,反之亦然,不需要任何特殊的工具 – 只要您的C ++编译器。 它被devise为非侵入性地包装C ++接口,所以您不必为了包装而更改C ++代码,使得Boost.Python非常适合向Python公开第三方库。 该库使用高级元编程技术简化了用户的语法,使得包装代码呈现出一种声明式接口定义语言(IDL)的外观。

我喜欢ctypes很多, swig总是倾向于给我一些问题 。 另外ctypes的优点是你不需要满足任何python的编译时间依赖,你的绑定可以在任何具有ctypes的python上工作,而不仅仅是编译的。

假设您有一个简单的C ++示例类,您想要在一个名为foo.cpp的文件中进行交谈:

#include <iostream> class Foo{ public: void bar(){ std::cout << "Hello" << std::endl; } }; 

由于ctypes只能与C函数对话,所以需要提供那些声明为extern“C”

 extern "C" { Foo* Foo_new(){ return new Foo(); } void Foo_bar(Foo* foo){ foo->bar(); } } 

接下来,您必须将其编译到共享库

 g++ -c -fPIC foo.cpp -o foo.o g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o 

最后你必须编写你的Python包装(例如在fooWrapper.py中)

 from ctypes import cdll lib = cdll.LoadLibrary('./libfoo.so') class Foo(object): def __init__(self): self.obj = lib.Foo_new() def bar(self): lib.Foo_bar(self.obj) 

一旦你有了,你可以这样称呼它

 f = Foo() f.bar() #and you will see "Hello" on the screen 

最快的方法是使用SWIG 。

SWIG 教程示例 :

 /* File : example.c */ int fact(int n) { if (n <= 1) return 1; else return n*fact(n-1); } 

接口文件:

 /* example.i */ %module example %{ /* Put header files here or function declarations like below */ extern int fact(int n); %} extern int fact(int n); 

在Unix上构build一个Python模块:

 swig -python example.i gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7 gcc -shared example.o example_wrap.o -o _example.so 

用法:

 >>> import example >>> example.fact(5) 120 

请注意,你必须有python-dev。 另外在一些系统中,python头文件将会在/usr/include/python2.7的基础上安装它。

从教程:

SWIG是一个相当完整的C ++编译器,支持几乎所有的语言function。 这包括预处理,指针,类,inheritance,甚至C ++模板。 SWIG也可以用于将结构和类打包到目标语言的代理类中 – 以非常自然的方式公开底层的function。

我从这个页面的Python C ++绑定开始我的旅程,目标是链接高级数据types(多维STL向量与Python列表):-)

在尝试基于ctypes和boost.python (而不是软件工程师)的解决scheme时,我发现它们在需要高级数据types绑定时很复杂,而在这种情况下,我发现SWIG更加简单。

这个例子因此使用了SWIG,并且已经在Linux中进行了testing(但是SWIG可用并且在Windows中也被广泛使用)。

其目的是为Python提供一个C ++函数,该函数采用2D STL向量forms的matrix,并返回每一行的平均值(作为一维STL向量)。

C ++(“code.cpp”)中的代码如下所示:

 #include <vector> #include "code.h" using namespace std; vector<double> average (vector< vector<double> > i_matrix) { // Compute average of each row.. vector <double> averages; for (int r = 0; r < i_matrix.size(); r++){ double rsum = 0.0; double ncols= i_matrix[r].size(); for (int c = 0; c< i_matrix[r].size(); c++){ rsum += i_matrix[r][c]; } averages.push_back(rsum/ncols); } return averages; } 

等效头(“code.h”)是:

 #ifndef _code #define _code #include <vector> std::vector<double> average (std::vector< std::vector<double> > i_matrix); #endif 

我们首先编译C ++代码来创build一个目标文件:

 g++ -c -fPIC code.cpp 

然后我们为C ++函数定义一个SWIG接口定义文件 (“code.i”)。

 %module code %{ #include "code.h" %} %include "std_vector.i" namespace std { /* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */ %template(VecDouble) vector<double>; %template(VecVecdouble) vector< vector<double> >; } %include "code.h" 

使用SWIG,我们从SWIG接口定义文件生成一个C ++接口源代码。

 swig -c++ -python code.i 

我们最终编译生成的C ++接口源文件,并将所有东西链接在一起生成一个可直接由Python导入的共享库(“_”很重要):

 g++ -c -fPIC code_wrap.cxx -I/usr/include/python2.7 -I/usr/lib/python2.7 g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o 

我们现在可以在Python脚本中使用这个函数:

 #!/usr/bin/env python import code a= [[3,5,7],[8,10,12]] print a b = code.average(a) print "Assignment done" print a print b 

检查pyrex或Cython 。 它们是用于连接C / C ++和Python的类Python语言。

我从来没有用过,但我听说过ctypes的好东西。 如果你想用C ++来使用它,一定要通过extern "C"来避开名字混搭。 感谢评论,FlorianBösch。

声称Python是所有科学家需要的文章 ,基本上都是这样说的:首先在Python中创build所有的东西。 那么当你需要加快速度的时候,使用SWIG并把这部分翻译成C.

我认为Python的cffi可以是一个选项。

目标是从Python调用C代码。 你应该可以在不学习第三语言的情况下做到这一点:每种select都需要你学习他们自己的语言(Cython,SWIG)或者API(ctypes)。 所以我们试着假设你知道Python和C,并尽量减less你需要学习的额外的API。

http://cffi.readthedocs.org/en/release-0.7/

还有pybind11 ,它就像Boost的一个轻量级版本,并与所有现代C ++编译器兼容:

https://pybind11.readthedocs.io/en/latest/

除非你预计编写Java包装器,否则Cython绝对是要走的路,在这种情况下,SWIG可能更可取。

我推荐使用runcython命令行工具,这使得使用Cython的过程非常容易。 如果您需要将结构化数据传递给C ++,请查看Google的protobuf库,这非常方便。

这里是我使用这两个工具的一个简单例子:

https://github.com/nicodjimenez/python2cpp

希望这可以成为一个有用的起点。

问题是如果我正确理解,如何从Python调用C函数。 那么最好的select是Ctypes(顺便说一句,所有Python的变体都可以)。

 >>> from ctypes import * >>> libc = cdll.msvcrt >>> print libc.time(None) 1438069008 >>> printf = libc.printf >>> printf("Hello, %s\n", "World!") Hello, World! 14 >>> printf("%d bottles of beer\n", 42) 42 bottles of beer 19 

有关详细指南,您可能需要参阅我的博客文章 。

其中一个正式的Python文档包含了使用C / C ++扩展Python的细节。 即使没有使用SWIG ,它也非常简单,在Windows上运行得非常好。

首先,你应该决定什么是你的特定目的。 上面提到了关于扩展和embeddedPython解释器的官方Python文档,我可以添加关于二进制扩展的一个很好的概述 。 用例可以分为3类:

  • 加速器模块 :运行速度比在CPython中运行的等效的纯Python代码快。
  • 包装模块 :将现有的C接口公开到Python代码。
  • 低级系统访问 :访问CPython运行时的低级function,操作系统或底层硬件。

为了给其他感兴趣的人提供一些更广泛的视angular,既然你最初的问题有点含糊(“到C或C ++库”),我认为这些信息可能对你很有意思。 在上面的链接中,您可以阅读使用二进制扩展及其替代方法的缺点。

除了build议的其他答案,如果你想要一个加速器模块,你可以试试Numba 。 它的工作原理是“通过在导入时,运行时或静态地使用LLVM编译器基础结构生成优化的机器代码(使用包含的pycc工具)”。