Sprachgewirr
Um eine Kontroverse zwischen Programmierern hervorzurufen, genügt eine einzige Frage:
“Welche optimale Programmiersprache?”
Weniger strittig ist die Frage:
“Welches ist die beliebteste Sprache?”
Eine einfache Möglichkeit, die Beliebtheit einer Sprache abzuschätzen, ist die Häufigkeit zu ermitteln, mit der sie verwendet wird. Quelloffene Projekte bieten sich als Datengrundlage an.
Ein Blick auf githubs beliebteste Sprachen zeigt uns einige Kandidaten:
-
python
-
JavaScript
-
java
-
go
-
C++
Zwei Kandidaten verdienen besondere Aufmerksamkeit.
C++ allgegenwärtige, mysteriös, überraschend und uferlos. Ein Werkzeug zur Entwicklung flexibler und schneller Programme, mit dem Komfort eines Teleprinters.
Python, einfach, simple, klar, von zahllosen Bibliotheken unterstützt und marginal schneller als Limax maximus.
All dies macht Python zu einer der beliebtesten interpretierte Sprachen.
Das Dilemma
Dies stellt uns vor eine Herausforderung:
Wir könnten in C++ schreiben, um Laufzeit zu optimieren oder auf einer bereits in C++ geschriebenen Code-Basis aufbauen.
oder wir könnten in Python schreiben, da es leichter verstanden wird und eine breitere Nutzerbasis aufweist.
Zum Glück gibt es einen Mittelweg, in welchem wir in C++ schreiben und anschließen Python verwenden.
Um dies zu erreichen, muss eine Softwareschicht, eine Schnittstelle, eingeführt werden, welche die Kommunikation zwischen der C++-Bibliothek und einem Python-Skript ermöglicht.
pybind11
Wir haben uns für die Verwendung von pybind11 entschieden.
Laut seiner github-Seite “ist pybind11 eine schmale, header-only Bibliothek, die C++-Typen in Python darstellt […]”.
Sie stellt Funktionen zur Verfügung, die es uns ermöglichen, unsere gesamte Bibliothek in Python verfügbar zu machen.
Alles, was wir tun müssen, ist, eine kleine .cpp-Datei zu unserer Bibliothek hinzuzufügen und mit einer speziellen cmake-Funktion zu kompilieren. Dadurch wird Datei(.pyd) erzeugt, die direkt von Python verwendet werden kann.
Pybind11 ermöglicht es uns also, mit minimalen Änderungen eine C++ Bibliothek in Python zur Verfügung zu stellen.
Pybind11 kann als Git-Submodul, github repository oder über conan in das Projekt eingebunden werden, daher sollte es einfach in bereits bestehende Projekte integriert werden können.
How-To
Pybind11 verfügt natürlich über eine eigene Dokumentation, diese stellte mich jedoch durchaus vor einige Herausforderungen bei der Integration in unserer Projekte.
Deshalb möchte ich an dieser Stelle eine Kurzanleitung geben.
Ich empfehle Ihnen dringend, zumindest das Basisbeispiel zu lesen, da ich darauf aufbaue.
Um die von Python nutzbare Datei zu erstellen, binden wir zuerst pybind 11 in cmake ein und anschließen die .cpp-Datein mittels
pybind11_add_module()
(einen add_library-wrapper) zu unserer CMakeLists.txt hinzu.
In der .cpp-Datei müssen wir unser Modul deklarieren. Das Hinzufügen eines Docstrings wird empfohlen, um so Pythons interne Dokumentation/Hilfsschnittstelle zu unterstützen:
PYBIND11_MODULE(MyModuleName, module) { module.doc() = "Perfect docstring."; }
Funktionen können nun in Form von Funktionsreferenzen hinzugefügt werden, aus den Beispielen:
#include <pybind11/pybind11.h> int add(int i, int j) { return i + j; } PYBIND11_MODULE(example, m) { m.doc() = "pybind11 example plugin"; // optional module docstring m.def("add", &add, "A function that adds two numbers"); }
Das Hinzufügen von Klassen erfolgt auf ähnliche Weise wie in den docs beschrieben. Es sei hinzugefügt, dass das Hinzufügen einer Methode das aufgerufene Objekt zurückgibt, sodass mehrere Methoden verkettet mit der Klasse verbunden werden können.
PYBIND11_MODULE(example, module) { py::class_<Wheel>(module, "Wheel") .def(py::init<Radius()&>()) // A constructor with an argument .def("turn", &Wheel::Turn) .def("stop", &Wheel::Stop); }
Wenn Sie Ihre neue Bibliothek nun testen möchten, vergewissern Sie sich, dass sich die erzeugte Binärdatei im Arbeitsverzeichnis Ihres Python-Interpreters befindet.
Importieren Sie nun Ihr Modul, mit dem zuvor zugewiesenen Namen.
In unseren beiden letzten Fällen wäre dies “example”.
In Python können schreiben wir also:
import example wheelInstance = example.Wheel(5.0) print(Wheel.turn())
Einfache Datenkonvertierung und Interpreter
Vielleicht haben sie bereits herausgefunden, dass pybind11 die direkte Konvertierung von STL zu Python-Datentypen und Eigen zu numpy -Datentypen ermöglicht, wenn die korrekter Header eingebunden werden.
Es ermöglicht auch die Einbettung eines Python-Interpreters in den C++ Code.
Dies kann sich als praktisch erweisen, wenn Sie Python-Datentypen als Eingabe verarbeiten wollen. Bedenken Sie aber, dass der Interpreter nur einmal geöffnet werden sollte. Wird Ihr Code als vom Python-Interpreter aufgerufen, sollten Sie den Interpreter in Ihrem Code nicht erneut starten.
Ich rate auch davon ab, Python und C++ Code zu großzügig zu mischen, da solche Konstruktionen rasch ziemlich komplex und damit nicht mehr zu warten werden können.
Stellen Sie sich vor, sie würden in einem Funktionsaufruf fünfmal zwischen Python und C++ wechseln. Dies dürfte sowohl Ihnen, Ihren Kollegen als auch Ihrer IDE das Leben eher schwermachen.
Fazit
Ich hoffe, dieser Artikel motiviert Sie, einen Blick auf pybind11 zu werfen und es auszuprobieren, sollten sie C++ Code für eine Python affine Nutzer zur Verfügung stellen wollen.