python call c++




從Python調用C/C++? (10)

本文聲稱Python是所有科學家的需要 ,基本上說:首先在Python中對所有東西進行原型設計。 然後,當你需要加快速度時,使用SWIG並將此部分轉換為C.

什麼是構建C或C ++庫的Python綁定的最快捷方式?

(如果這很重要,我正在使用Windows。)


你應該看看Boost.Python 。 以下是他們網站的簡短介紹:

Boost Python庫是一個用於連接Python和C ++的框架。 它允許您快速無縫地將C ++類的函數和對象暴露給Python,反之亦然,不需要特殊的工具 - 只需要您的C ++編譯器。 它旨在非侵入性地封裝C ++接口,因此您不必為了封裝而更改C ++代碼,使得Boost.Python非常適合向Python公開第三方庫。 該庫使用高級元編程技術簡化了用戶的語法,使得包裝代碼呈現出一種聲明式接口定義語言(IDL)的外觀。


問題是如果我理解正確,如何從Python調用C函數。 然後最好的選擇是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

有關詳細指南,您可能想參閱我的博客文章


對於現代C ++,請使用cppyy: http://cppyy.readthedocs.io/en/latest/ ://cppyy.readthedocs.io/en/latest/

它基於Cling,Clang / LLVM的C ++解釋器。 綁定在運行時不需要額外的中間語言。 感謝Clang,它支持C ++ 17。

使用pip安裝它:

    $ pip install cppyy

對於小型項目,只需加載相關的庫和感興趣的頭文件即可。例如,從ctypes example中獲取代碼就是這個線程,但是在頭文件和代碼段中分割:

    $ 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的作者。


我從來沒有用過它,但我聽說過ctypes好東西。 如果你試圖在C ++中使用它,一定要通過extern "C"避開名稱混亂。 感謝評論,FlorianBösch。


我從這個頁面的Python < - > C ++綁定開始了我的旅程,目的是鏈接高級數據類型(多維STL向量與Python列表):-)

在嘗試基於ctypesboost.python (而不是軟件工程師)的解決方案後,我發現它們在需要高級數據類型綁定時很複雜,而我發現SWIG在這種情況下更加簡單。

這個例子因此使用了SWIG,並且已經在Linux中進行了測試(但SWIG可用並且在Windows中也被廣泛使用)。

目標是為Python提供一個C ++函數,該函數採用2D STL向量形式的矩陣並返回每行的平均值(作為一維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 ++代碼來創建一個目標文件:

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

最快捷的方法是使用swig

SWIG tutorial

/* 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也可用於將結構和類打包成目標語言的代理類 - 以非常自然的方式公開底層功能。


檢查pyrexCython 。 它們是用於C / C ++和Python之間接口的類Python語言。


除非您預計編寫Java包裝器,否則Cython絕對是您的選擇,在這種情況下,SWIG可能更可取。

我建議使用runcython命令行實用程序,它使得使用Cython的過程非常簡單。 如果您需要將結構化數據傳遞給C ++,請查看Google的protobuf庫,這非常方便。

以下是我使用這兩種工具創建的最小示例:

https://github.com/nicodjimenez/python2cpp

希望它可以成為一個有用的起點。


首先,你應該決定你的特定目的是什麼。 上面提到關於擴展和嵌入Python解釋器的官方Python文檔,我可以添加關於二進制擴展的良好概述 。 用例可以分為3類:

  • 加速器模塊 :運行速度比在CPython中運行的等效純Python代碼快。
  • 包裝模塊 :將現有的C接口公開到Python代碼。
  • 低級別系統訪問 :訪問CPython運行時的低級功能,操作系統或底層硬件。

為了給其他感興趣的人提供一些更廣泛的視角,並且由於你最初的問題有點含糊(“對C或C ++庫”),我認為這些信息可能對你很有意思。 在上面的鏈接中,您可以閱讀使用二進制擴展及其替代方法的缺點。

除了建議的其他答案之外,如果你需要一個加速器模塊,你可以試試Numba 。 它的工作原理是“通過在導入時,運行時或靜態地使用LLVM編譯器基礎結構生成優化的機器代碼(使用包含的pycc工具)”。





c