构造Python绑定到C或c++库的最快方法是什么?

(如果这很重要的话,我使用的是Windows。)


当前回答

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

The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library's use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).

其他回答

问题是如何从Python中调用C函数,如果我理解正确的话。那么最好的选择是c类型(顺便说一句,可移植到所有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

关于详细的指南,你可以参考我的博客文章。

最快的方法是使用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上构建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++编译器,几乎支持所有语言特性。这包括预处理、指针、类、继承,甚至c++模板。SWIG还可以用于用目标语言将结构和类打包为代理类——以非常自然的方式公开底层功能。

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

The Boost Python Library is a framework for interfacing Python and C++. It allows you to quickly and seamlessly expose C++ classes functions and objects to Python, and vice-versa, using no special tools -- just your C++ compiler. It is designed to wrap C++ interfaces non-intrusively, so that you should not have to change the C++ code at all in order to wrap it, making Boost.Python ideal for exposing 3rd-party libraries to Python. The library's use of advanced metaprogramming techniques simplifies its syntax for users, so that wrapping code takes on the look of a kind of declarative interface definition language (IDL).

我喜欢cppyy,它使得用c++代码扩展Python变得非常容易,在需要时极大地提高了性能。

它功能强大,坦白说使用起来非常简单,

这里是一个如何创建numpy数组并将其传递给c++中的类成员函数的示例。

cppyy_test.py

import cppyy
import numpy as np
cppyy.include('Buffer.h')


s = cppyy.gbl.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)
print(numpy_array[:20])

Buffer.h

struct Buffer {
  void get_numpy_array(double *ad, int size) {
    for( long i=0; i < size; i++)
        ad[i]=i;
  }
};

你也可以很容易地创建一个Python模块(使用CMake),这样你就可以避免一直重新编译c++代码。

对于现代c++,使用cppyy: http://cppyy.readthedocs.io/en/latest/

它基于Clang/LLVM的c++解释器kling。绑定是在运行时进行的,不需要额外的中间语言。得益于Clang,它支持c++ 17。

使用pip安装:

    $ pip install cppyy

对于小型项目,只需加载您感兴趣的相关库和标头。例如,从ctypes例子中获取的代码是这个线程,但是在头和代码部分中被分割:

    $ cat foo.h
    class Foo {
    public:
        void bar();
    };

    $ cat foo.cpp
    #include "foo.h"
    #include <iostream>

    void Foo::bar() { std::cout << "Hello" << std::endl; }

编译:

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

并使用它:

    $ python
    >>> import cppyy
    >>> cppyy.include("foo.h")
    >>> cppyy.load_library("foo")
    >>> from cppyy.gbl import Foo
    >>> f = Foo()
    >>> f.bar()
    Hello
    >>>

大型项目支持自动加载准备好的反射信息和cmake片段来创建它们,以便已安装包的用户可以简单地运行:

    $ python
    >>> import cppyy
    >>> f = cppyy.gbl.Foo()
    >>> f.bar()
    Hello
    >>>

多亏了LLVM,高级特性才得以实现,比如自动模板实例化。继续这个例子:

    >>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
    >>> v.push_back(f)
    >>> len(v)
    1
    >>> v[0].bar()
    Hello
    >>>

注:我是cppyy的作者。