C / C ++ von Python aus aufrufen?

521

Was wäre der schnellste Weg, um eine Python-Bindung an eine C- oder C ++ - Bibliothek zu erstellen?

(Ich benutze Windows, wenn dies wichtig ist.)

shoosh
quelle

Antworten:

170

Sie sollten sich Boost.Python ansehen . Hier ist die kurze Einführung von ihrer Website:

Die Boost Python Library ist ein Framework für die Schnittstelle von Python und C ++. Sie können damit schnell und nahtlos Funktionen und Objekte von C ++ - Klassen für Python verfügbar machen und umgekehrt, ohne spezielle Tools - nur Ihren C ++ - Compiler. Es wurde entwickelt, um C ++ - Schnittstellen nicht aufdringlich zu verpacken, sodass Sie den C ++ - Code überhaupt nicht ändern müssen, um ihn zu verpacken. Boost.Python ist daher ideal, um Bibliotheken von Drittanbietern Python zugänglich zu machen. Die Verwendung fortschrittlicher Metaprogrammiertechniken in der Bibliothek vereinfacht die Syntax für Benutzer, sodass der Wrapping-Code wie eine Art deklarative Interface Definition Language (IDL) aussieht.

Ralph
quelle
Boost.Python ist eine der benutzerfreundlicheren Bibliotheken in Boost. Für eine einfache Funktionsaufruf-API ist sie recht einfach und bietet eine Boilerplate, die Sie selbst schreiben müssten. Es ist etwas komplizierter, wenn Sie eine objektorientierte API verfügbar machen möchten.
Jwfearn
15
Boost.Python ist das Schlimmste, was man sich vorstellen kann. Für jede neue Maschine und mit jedem Upgrade gehen Verbindungsprobleme einher.
Müller
14
Fast 11 Jahre später Zeit für einige Überlegungen zur Qualität dieser Antwort?
J Evans
4
Ist dies immer noch der beste Ansatz für die Schnittstelle zwischen Python und C ++?
TushaR
8
Vielleicht können Sie pybind11 ausprobieren, das im Vergleich zu Boost leicht ist.
Jdhao
659

Das ctypes- Modul ist Teil der Standardbibliothek und daher stabiler und allgemein verfügbar als swig , was mir immer Probleme bereitete .

Bei ctypes müssen Sie alle Abhängigkeiten der Kompilierungszeit von Python erfüllen, und Ihre Bindung funktioniert für alle Pythons mit ctypes, nicht nur für die, für die sie kompiliert wurden.

Angenommen, Sie haben eine einfache C ++ - Beispielklasse, mit der Sie in einer Datei namens foo.cpp sprechen möchten:

#include <iostream>

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

Da ctypes nur mit C-Funktionen kommunizieren können, müssen Sie diejenigen angeben, die sie als externes "C" deklarieren.

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

Als nächstes müssen Sie dies zu einer gemeinsam genutzten Bibliothek kompilieren

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

Und schließlich müssen Sie Ihren Python-Wrapper schreiben (z. B. in 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)

Sobald Sie das haben, können Sie es wie nennen

f = Foo()
f.bar() #and you will see "Hello" on the screen
Florian Bösch
quelle
14
Dies ist ziemlich genau das, was boost.python in einem einzigen Funktionsaufruf für Sie erledigt.
Martin Beckett
203
ctypes befindet sich in der Python-Standardbibliothek, swig und boost nicht. Swig und Boost basieren auf Erweiterungsmodulen und sind daher an Python-Minor-Versionen gebunden, die unabhängige gemeinsam genutzte Objekte nicht sind. Das Bauen eines Schluck- oder Boost-Wrappers kann schmerzhaft sein, ctypes stellt keine Build-Anforderungen.
Florian Bösch
25
Boost basiert auf der Magie von Voodoo-Vorlagen und einem vollständig benutzerdefinierten Build-System. Ctypes setzt auf Einfachheit. ctypes ist dynamisch, boost ist statisch. ctypes kann verschiedene Versionen von Bibliotheken verarbeiten. Boost kann nicht.
Florian Bösch
32
Unter Windows musste ich in meinen Funktionssignaturen __declspec (dllexport) angeben, damit Python sie sehen kann. Aus dem obigen Beispiel würde dies entsprechen: extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }
Alan Macdonald
13
Vergessen Sie nicht, den Zeiger anschließend zu löschen, indem Sie z. B. eine Foo_deleteFunktion bereitstellen und sie entweder von einem Python-Destruktor aus aufrufen oder das Objekt in eine Ressource einschließen .
Adversus
58

Der schnellste Weg, dies zu tun, ist die Verwendung von SWIG .

Beispiel aus dem SWIG- Tutorial :

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

Schnittstellendatei:

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

extern int fact(int n);

Erstellen eines Python-Moduls unter Unix:

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

Verwendungszweck:

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

Beachten Sie, dass Sie Python-Dev haben müssen. In einigen Systemen befinden sich Python-Header-Dateien je nach Installation in /usr/include/python2.7.

Aus dem Tutorial:

SWIG ist ein ziemlich vollständiger C ++ - Compiler mit Unterstützung für fast alle Sprachfunktionen. Dies umfasst Vorverarbeitung, Zeiger, Klassen, Vererbung und sogar C ++ - Vorlagen. SWIG kann auch verwendet werden, um Strukturen und Klassen in Proxy-Klassen in der Zielsprache zu packen, wodurch die zugrunde liegende Funktionalität auf sehr natürliche Weise verfügbar gemacht wird.

Ben Hoffstein
quelle
50

Ich habe meine Reise in der Python <-> C ++ - Bindung von dieser Seite aus mit dem Ziel begonnen, Datentypen auf hoher Ebene (mehrdimensionale STL-Vektoren mit Python-Listen) zu verknüpfen :-)

Nachdem ich die Lösungen ausprobiert habe, die sowohl auf ctypes als auch auf boost.python basieren (und kein Softwareentwickler sind), habe ich sie als komplex empfunden, wenn eine Bindung von Datentypen auf hoher Ebene erforderlich ist, während ich SWIG gefunden habe solchen Fällen als viel einfacher .

In diesem Beispiel wird daher SWIG verwendet, und es wurde unter Linux getestet (aber SWIG ist verfügbar und wird auch unter Windows häufig verwendet).

Ziel ist es, Python eine C ++ - Funktion zur Verfügung zu stellen, die eine Matrix in Form eines 2D-STL-Vektors verwendet und einen Durchschnitt jeder Zeile zurückgibt (als 1D-STL-Vektor).

Der Code in C ++ ("code.cpp") lautet wie folgt:

#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;
}

Der entsprechende Header ("code.h") lautet:

#ifndef _code
#define _code

#include <vector>

std::vector<double> average (std::vector< std::vector<double> > i_matrix);

#endif

Wir kompilieren zuerst den C ++ - Code, um eine Objektdatei zu erstellen:

g++ -c -fPIC code.cpp

Anschließend definieren wir eine SWIG-Schnittstellendefinitionsdatei ("code.i") für unsere C ++ - Funktionen.

%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"

Mit SWIG generieren wir einen C ++ - Schnittstellenquellcode aus der SWIG-Schnittstellendefinitionsdatei.

swig -c++ -python code.i

Wir kompilieren schließlich die generierte Quelldatei der C ++ - Schnittstelle und verknüpfen alles miteinander, um eine gemeinsam genutzte Bibliothek zu generieren, die direkt von Python importiert werden kann (das "_" ist wichtig):

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

Wir können jetzt die Funktion in Python-Skripten verwenden:

#!/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
Antonello
quelle
Eine reale Fallimplementierung, bei der im C ++ - Code stl-Vektoren als nicht konstante Referenzen übergeben werden und daher von Python als Ausgabeparameter verfügbar sind: lobianco.org/antonello/personal:portfolio:portopt
Antonello
30

Schauen Sie sich Pyrex oder Cython an . Sie sind Python-ähnliche Sprachen für die Schnittstelle zwischen C / C ++ und Python.

Jason Baker
quelle
1
+1 für Cython! Ich habe cffi nicht ausprobiert, daher kann ich nicht sagen, was besser ist, aber ich habe sehr gute Erfahrungen mit Cython gemacht - Sie schreiben immer noch Python-Code, können aber C darin verwenden. Es war etwas schwierig für mich, den Build-Prozess mit Cython einzurichten, den ich später in einem Blog-Beitrag erklärte: martinsosic.com/development/2016/02/08/…
Martinsos
Möglicherweise möchten Sie die Antwort so verbessern, dass sie keine reine Linkantwort mehr ist.
Adelin
Ich benutze Cython seit ungefähr einer Woche und es gefällt mir sehr gut: 1) Ich habe ctypes im Einsatz gesehen und es ist hässlich und sehr fehleranfällig mit zahlreichen Fallstricken. 2) Es ermöglicht Ihnen, Python-Code zu nehmen und ihn zu beschleunigen 3) Es ist einfach, Python-Wrapper für C / C ++ - Methoden und -Objekte zu schreiben. 4) Es wird immer noch gut unterstützt. Es könnte mehr Anleitung für die Installation auf venvs und das Cross-Compilieren geben, was einige Zeit in Anspruch genommen hat. Es gibt ein sehr gutes 4-stündiges Video-Tutorial hier: youtube.com/watch?v=gMvkiQ-gOW8
Den-Jason
22

Verwenden Sie für modernes C ++ cppyy: http://cppyy.readthedocs.io/en/latest/

Es basiert auf Cling, dem C ++ - Interpreter für Clang / LLVM. Die Bindungen sind zur Laufzeit und es ist keine zusätzliche Zwischensprache erforderlich. Dank Clang unterstützt es C ++ 17.

Installieren Sie es mit pip:

    $ pip install cppyy

Laden Sie für kleine Projekte einfach die entsprechende Bibliothek und die Header, an denen Sie interessiert sind. Nehmen Sie beispielsweise den Code aus dem Beispiel ctypes in diesem Thread, teilen Sie ihn jedoch in Header- und Codeabschnitte auf:

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

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

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

Kompilieren Sie es:

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

und benutze es:

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

Große Projekte werden durch das automatische Laden der vorbereiteten Reflektionsinformationen und der cmake-Fragmente zum Erstellen unterstützt, sodass Benutzer installierter Pakete einfach Folgendes ausführen können:

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

Dank LLVM sind erweiterte Funktionen wie die automatische Instanziierung von Vorlagen möglich. So setzen Sie das Beispiel fort:

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

Hinweis: Ich bin der Autor von cppyy.

Wim Lavrijsen
quelle
3
Eigentlich nicht: Cython ist eine Python-ähnliche Programmiersprache zum Schreiben von C-Erweiterungsmodulen für Python (der Cython-Code wird zusammen mit dem erforderlichen C-API-Boilerplate in C übersetzt). Es bietet einige grundlegende C ++ - Unterstützung. Das Programmieren mit cppyy beinhaltet nur Python und C ++, keine Spracherweiterungen. Es ist voll zur Laufzeit und generiert keinen Offline-Code (Lazy Generation skaliert viel besser). Es zielt auf modernes C ++ ab (einschließlich automatischer Vorlageninstanziierungen, Verschiebungen, Initialisierungslisten, Lambdas usw. usw.), und PyPy wird nativ unterstützt (dh nicht über die langsame C-API-Emulationsschicht).
Wim Lavrijsen
2
Dieses PyHPC'16-Papier enthält eine Reihe von Benchmark-Nummern. Seitdem gab es jedoch deutliche Verbesserungen auf der CPython-Seite.
Wim Lavrijsen
Ich mag diesen Ansatz , weil Sie mit zusätzlichen Integrationsarbeit nicht zu tun haben swig, ctypesoder boost.python. Anstatt dass Sie Code schreiben müssen, damit Python mit Ihrem C ++ - Code funktioniert ... Python macht die harte Arbeit, um C ++ herauszufinden. Vorausgesetzt, es funktioniert tatsächlich.
Trevor Boyd Smith
cppyy ist sehr interessant! Ich sehe in den Dokumenten, dass Umverteilung und Vorverpackung behandelt werden. Funktioniert dies bekanntermaßen gut mit Tools, die auch Python-Code verpacken (z. B. PyInstaller)? Und hängt dies mit dem ROOT-Projekt zusammen oder nutzt es seine Arbeit?
JimB
Vielen Dank! Ich bin mit PyInstaller nicht vertraut, aber die "Wörterbücher", die Forward-Deklarationen, Pfade und Header zusammenfassen, sind C ++ - Codes, die in gemeinsam genutzten Bibliotheken kompiliert wurden. Da cppyy zum Binden von C ++ - Code verwendet wird, sollte der Umgang mit etwas mehr C ++ - Code in Ordnung sein. Und dieser Code ist nicht abhängig von der Python C-API (nur das libcppyy-Modul), was die Dinge vereinfacht. cppyy selbst kann von conda-forge oder pypi (pip) installiert werden, sodass jede dieser Umgebungen sicher funktioniert. Ja, Cppyy hat als Gabel von PyROOT angefangen, aber es hat sich seitdem so stark verbessert, dass das ROOT-Team PyROOT auf Cppyy neu basiert.
Wim Lavrijsen
15

Ich habe es nie benutzt, aber ich habe gute Dinge über ctypes gehört . Wenn Sie versuchen, es mit C ++ zu verwenden, sollten Sie die Namensverknüpfung über vermeiden extern "C". Danke für den Kommentar, Florian Bösch.

John
quelle
13

Ich denke, CFFI für Python kann eine Option sein.

Ziel ist es, C-Code aus Python aufzurufen. Sie sollten dazu in der Lage sein, ohne eine dritte Sprache zu lernen: Für jede Alternative müssen Sie ihre eigene Sprache (Cython, SWIG) oder API (ctypes) lernen. Daher haben wir versucht anzunehmen, dass Sie Python und C kennen und die zusätzlichen API-Teile, die Sie lernen müssen, minimieren.

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

mrgloom
quelle
2
Ich denke, das kann nur c (nicht c ++) aufrufen, immer noch +1 (ich mag cffi wirklich).
Andy Hayden
8

Die Frage ist, wie man eine C-Funktion von Python aus aufruft, wenn ich das richtig verstanden habe. Dann sind Ctypes die beste Wahl (BTW portabel für alle Python-Varianten).

>>> 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

Eine ausführliche Anleitung finden Sie in meinem Blog-Artikel .

Jadav Bheda
quelle
Es kann erwähnenswert sein, dass ctypes zwar portabel sind, Ihr Code jedoch eine Windows-spezifische C-Bibliothek erfordert.
Palec
7

Eines der offiziellen Python-Dokumente enthält Details zum Erweitern von Python mit C / C ++ . Auch ohne die Verwendung von SWIG ist es recht einfach und funktioniert unter Windows einwandfrei.

Andrew Edgecombe
quelle
6

Cython ist definitiv der richtige Weg, es sei denn, Sie erwarten das Schreiben von Java-Wrappern. In diesem Fall ist SWIG möglicherweise vorzuziehen.

Ich empfehle die Verwendung des runcythonBefehlszeilenprogramms, da dies die Verwendung von Cython extrem einfach macht. Wenn Sie strukturierte Daten an C ++ übergeben müssen, schauen Sie sich die Protobuf-Bibliothek von Google an. Dies ist sehr praktisch.

Hier sind einige Beispiele, die ich gemacht habe und die beide Tools verwenden:

https://github.com/nicodjimenez/python2cpp

Hoffe, es kann ein nützlicher Ausgangspunkt sein.

nicodjimenez
quelle
5

Zuerst sollten Sie entscheiden, was Ihr besonderer Zweck ist. Die offizielle Python-Dokumentation zum Erweitern und Einbetten des Python-Interpreters wurde oben erwähnt. Ich kann einen guten Überblick über binäre Erweiterungen hinzufügen . Die Anwendungsfälle können in 3 Kategorien unterteilt werden:

  • Beschleunigermodule : Um schneller als der entsprechende reine Python-Code in CPython ausgeführt zu werden.
  • Wrapper-Module : Um vorhandene C-Schnittstellen für Python-Code verfügbar zu machen.
  • Systemzugriff auf niedriger Ebene : Zugriff auf Funktionen auf niedrigerer Ebene der CPython-Laufzeit, des Betriebssystems oder der zugrunde liegenden Hardware.

Um anderen Interessierten eine breitere Perspektive zu geben und da Ihre anfängliche Frage etwas vage ist ("zu einer C- oder C ++ - Bibliothek"), denke ich, dass diese Informationen für Sie interessant sein könnten. Unter dem obigen Link können Sie die Nachteile der Verwendung von binären Erweiterungen und deren Alternativen nachlesen.

Abgesehen von den anderen vorgeschlagenen Antworten können Sie Numba ausprobieren, wenn Sie ein Beschleunigermodul wünschen . Es funktioniert "durch Generieren von optimiertem Maschinencode mithilfe der LLVM-Compiler-Infrastruktur zur Importzeit, Laufzeit oder statisch (mithilfe des mitgelieferten pycc-Tools)".

Jaroslaw Nikitenko
quelle
3

Ich liebe Cppyy, es macht es sehr einfach, Python mit C ++ - Code zu erweitern und die Leistung bei Bedarf dramatisch zu steigern.

Es ist leistungsstark und ehrlich gesagt sehr einfach zu bedienen,

Hier ist ein Beispiel dafür, wie Sie ein Numpy-Array erstellen und an eine Klassenmitgliedsfunktion in C ++ übergeben können.

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;
  }
};

Sie können auch sehr einfach ein Python-Modul erstellen (mit CMake). Auf diese Weise vermeiden Sie, dass der C ++ - Code ständig neu kompiliert wird.

Garfield
quelle
2

pybind11 minimal lauffähiges Beispiel

pybind11 wurde bereits unter https://stackoverflow.com/a/38542539/895245 erwähnt, aber ich möchte hier ein konkretes Anwendungsbeispiel und einige weitere Diskussionen zur Implementierung geben.

Alles in allem empfehle ich pybind11 sehr, da es sehr einfach zu verwenden ist: Sie fügen nur einen Header hinzu und dann verwendet pybind11 Template Magic, um die C ++ - Klasse zu untersuchen, die Sie für Python verfügbar machen möchten, und dies transparent.

Der Nachteil dieser Vorlagenmagie ist, dass sie die Kompilierung verlangsamt und jeder Datei, die pybind11 verwendet, sofort einige Sekunden hinzufügt. Siehe zum Beispiel die Untersuchung zu diesem Problem . PyTorch stimmt zu .

Hier ist ein minimales lauffähiges Beispiel, um Ihnen ein Gefühl dafür zu geben, wie großartig pybind11 ist:

class_test.cpp

#include <string>

#include <pybind11/pybind11.h>

struct ClassTest {
    ClassTest(const std::string &name) : name(name) { }
    void setName(const std::string &name_) { name = name_; }
    const std::string &getName() const { return name; }
    std::string name;
};

namespace py = pybind11;

PYBIND11_PLUGIN(class_test) {
    py::module m("my_module", "pybind11 example plugin");
    py::class_<ClassTest>(m, "ClassTest")
        .def(py::init<const std::string &>())
        .def("setName", &ClassTest::setName)
        .def("getName", &ClassTest::getName)
        .def_readwrite("name", &ClassTest::name);
    return m.ptr();
}

class_test_main.py

#!/usr/bin/env python3

import class_test

my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)

Kompilieren und ausführen:

#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
  -o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py

Dieses Beispiel zeigt, wie Sie mit pybind11 die ClassTestC ++ - Klasse mühelos für Python verfügbar machen können ! Beim Kompilieren wird eine Datei mit dem Namen erstellt, class_test.cpython-36m-x86_64-linux-gnu.sodie class_test_main.pyautomatisch als Definitionspunkt für die Datei verwendet wirdclass_test nativ definierte Modul verwendet wird.

Vielleicht setzt sich die Erkenntnis, wie großartig dies ist, nur dann bemerkbar, wenn Sie versuchen, dasselbe von Hand mit der nativen Python-API zu tun. Sehen Sie sich zum Beispiel dieses Beispiel an, das etwa 10x mehr Code enthält: https://github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c In diesem Beispiel können Sie sehen, wie der C-Code die Python-Klasse Stück für Stück mit allen darin enthaltenen Informationen (Mitgliedern, Methoden usw.) schmerzhaft und explizit definieren muss Metadaten ...). Siehe auch:

pybind11 behauptet, ähnlich zu sein, Boost.Pythonwie es unter https://stackoverflow.com/a/145436/895245 erwähnt wurde, aber minimaler, weil es von der Aufblähung befreit ist, innerhalb des Boost-Projekts zu sein:

pybind11 ist eine einfache Nur-Header-Bibliothek, die C ++ - Typen in Python verfügbar macht und umgekehrt, hauptsächlich um Python-Bindungen für vorhandenen C ++ - Code zu erstellen. Seine Ziele und Syntax ähneln der hervorragenden Boost.Python-Bibliothek von David Abrahams: Minimierung des Boilerplate-Codes in herkömmlichen Erweiterungsmodulen durch Ableiten von Typinformationen mithilfe der Introspektion zur Kompilierungszeit.

Das Hauptproblem bei Boost.Python - und der Grund für die Erstellung eines ähnlichen Projekts - ist Boost. Boost ist eine enorm große und komplexe Suite von Dienstprogrammbibliotheken, die mit fast jedem existierenden C ++ - Compiler funktioniert. Diese Kompatibilität hat ihre Kosten: Arkane Template-Tricks und Workarounds sind erforderlich, um die ältesten und fehlerhaftesten Compiler-Exemplare zu unterstützen. Jetzt, da C ++ 11-kompatible Compiler weit verbreitet sind, ist diese schwere Maschinerie zu einer übermäßig großen und unnötigen Abhängigkeit geworden.

Stellen Sie sich diese Bibliothek als eine winzige, in sich geschlossene Version von Boost.Python vor, bei der alles entfernt wurde, was für die Bindungsgenerierung nicht relevant ist. Ohne Kommentare benötigen die Core-Header-Dateien nur ~ 4K Codezeilen und hängen von Python (2.7 oder 3.x oder PyPy2.7> = 5.7) und der C ++ - Standardbibliothek ab. Diese kompakte Implementierung war dank einiger der neuen C ++ 11-Sprachfunktionen möglich (insbesondere: Tupel, Lambda-Funktionen und verschiedene Vorlagen). Seit ihrer Erstellung ist diese Bibliothek in vielerlei Hinsicht über Boost.Python hinaus gewachsen, was in vielen gängigen Situationen zu einem dramatisch einfacheren Bindungscode führt.

pybind11 ist auch die einzige nicht native Alternative, die in der aktuellen Microsoft Python C-Bindungsdokumentation unter https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in- hervorgehoben wird. Visual-Studio? view = vs-2019 ( Archiv ).

Getestet unter Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle