Boost.Python wird häufig beim Erstellen einer Bibliothek für Python mit C ++ verwendet, kann aber auch zum sogenannten "Einbetten" verwendet werden, bei dem Python-Code von C ++ verwendet wird.
Gibt es nicht viel Nachfrage nach Python-Code aus C ++? Selbst wenn Sie nach "Boost Python" usw. suchen, erhalten Sie nur Artikel über die entgegengesetzte Verwendung (bei Verwendung von C ++ - Code aus Python). In diesem Fall ist der Artikel beim Einbetten von Python in C ++ leicht zu finden, wenn Sie das Suchwort "einbetten" (eingebettet) eingeben.
main.cpp
#include <boost/python.hpp>
namespace py = boost::python;
int main()
{
Py_Initialize(); //Muss zuerst angerufen werden
try
{
//"Drucken" in Python('Hello World!')Ausführen
py::object global = py::import("__main__").attr("__dict__");
py::exec("print('Hello World!')", global);
}
catch (const py::error_already_set &)
{
//Zeigen Sie Fehlerdetails an, wenn beim Ausführen von Python-Code ein Fehler auftritt
PyErr_Print();
}
return 0;
}
In diesem Beispiel wird die Funktion py :: exec ()
verwendet, um einfach den Python-Code print ('Hello World!')
Auszuführen.
Ich führe meinen Code im globalen Namespace von Python aus, indem ich ein Objekt im globalen Namespace von Python in einer Variablen namens "global" abrufe.
Boost.Python ruft die C-Oberfläche von Python hinter den Kulissen auf. Sie müssen daher die Funktion "Py_Initialize ()" aufrufen, bevor Sie sie verwenden können. (* Laut offiziellem Tutorial sollte "Py_Finalize ()" im Code nicht aufgerufen werden.)
Wenn in Python ein Laufzeitfehler auftritt, wird eine Ausnahme vom Typ "py :: error_already_set" ausgelöst, sodass dieser abgefangen wird und der Inhalt mit "PyErr_Print ()" angezeigt wird.
Für Linux + GCC können Sie mit dem folgenden Befehl kompilieren.
Wie zu kompilieren
$ g++ main.cpp `pkg-config python3-embed --cflags --libs` -lboost_python38
Abhängig von der Umgebung gibt es möglicherweise eine Version ohne "python3-embedded". Ändern Sie sie daher entsprechend in "pkg-config python3" (in der Version mit "python3-embedded" ist die Bibliothek zum Einbetten vom Original ausgeschlossen Daher kann die Verwendung von "pkg-config python3" zu einem Verbindungsfehler führen.
Außerdem hängt der Teil "boost_python38" von der Version und der Umgebung ab (möglicherweise im Format "boost_python-py38").
Wenn Sie den Namen der Boost.Python-Bibliothek, zu der eine Verknüpfung hergestellt werden soll, nicht kennen, können Sie ihn mit dem folgenden Befehl nachschlagen:
Der **
Teil von lib **. Also
, der angezeigt wird, ist der Bibliotheksname.
Boost.So finden Sie heraus, ob Sie den Namen der Python-Bibliothek nicht kennen
$ ldconfig -p | grep "boost_python3"
Von hier aus werden wir uns ansehen, wie die einzelnen Funktionen verwendet werden.
Unter der Annahme, dass "Namespace py = boost :: python;" geschrieben ist, wird es im Folgenden als "py" geschrieben. Außerdem ist "global" im Code dasselbe wie im ersten Beispiel, es ist ein Objekt des globalen Namespace, der durch den folgenden Code erhalten wird.
py::object global = py::import("__main__").attr("__dict__");
py :: eval ()
: Bewerten Sie den Ausdruck in Python und geben Sie das Ergebnis zurückWenn Sie einen Python-Ausdruck als Zeichenfolge angeben, wird das Ergebnis als Typ "py :: object" zurückgegeben.
Sie können das Ergebnis als C ++ - Typ erhalten, indem Sie es wie unten gezeigt mit py :: extract <Typname>
kombinieren.
// "2**3"Holen Sie sich das Ergebnis von
py::object result = py::eval("2**3", global);
//Konvertieren Sie das Ergebnis in den Typ int und geben Sie es aus
std::cout << py::extract<int>(result) << std::endl;
Ausführungsergebnis
8
In diesem Beispiel werden die Funktionen in Python nicht speziell verwendet. Selbst wenn der Namespace "global" des zweiten Arguments weggelassen wird, funktioniert dies. Beachten Sie jedoch, dass Sie, wenn Sie das zweite Argument weglassen, keine in Python integrierten Funktionen wie "pow" oder Variablen / Funktionen verwenden können, die Sie separat definiert haben.
py :: exec ()
: Übergeben Sie Python-Code als Zeichenfolge und führen Sie ihn ausWie im ersten Beispiel wird der Python-Code so ausgeführt, wie er ist, wenn Sie der Funktion py :: exec ()
den Python-Code als Zeichenfolge geben.
Im Gegensatz zu py :: eval ()
kann es auch mehrere durch Zeilenumbrüche getrennte Befehle ausführen und Klassen definieren.
py::exec(
"print('Hello!')\n"
"print('World!')", global);
Ausführungsergebnis
Hello!
World!
Wenn eine neue Variable erstellt wird, wird sie im im zweiten Argument angegebenen Namespace generiert.
//2, um eine Variable im globalen Namespace von Python zu erhalten**Ersatz 3
py::exec("result = 2**3", global);
//Konvertieren Sie das Ergebnis in den Typ int und geben Sie es aus
std::cout << py::extract<int>(global["result"]) << std::endl;
Ausführungsergebnis
8
py :: exec_file ()
: Führen Sie Python-Code aus einer Datei ausSie können py :: exec_file ()
verwenden, um den Inhalt der Datei zu lesen und wie py :: exec ()
auszuführen.
Das erste Argument ist der Dateipfad zum Python-Skript.
py::exec_file("hello.py", global);
Dies ist nützlich, wenn Sie die Definition Ihrer eigenen Klasse als Python-Skriptdatei getrennt von C ++ vorbereiten möchten.
py :: object :: attr ()
: Objektfeld- / MethodenreferenzFelder (Mitgliedsvariablen) und Methoden (Mitgliedsfunktionen) von py :: object
können mit der Funktion attr ()
verwendet werden.
Beispiel für den Aufruf der Join-Methode vom Typ str
// ['hoge','fuga','piyo']Erstellen Sie eine Liste mit dem Namen
py::object list = py::eval("['hoge','fuga','piyo']", global);
// 「','.join(list)Und kombinieren Sie die Zeichenfolgen in der Liste durch Kommas getrennt
py::object result = py::object(",").attr("join")(list);
//Konvertieren Sie das Ergebnis in Zeichenfolgentyp und Ausgabe
std::string resultStr = py::extract<std::string>(result);
std::cout << resultStr << std::endl;
Ausführungsergebnis
hoge,fuga,piyo
py :: import ()
: Verwendung der Python-BibliothekSie können py :: import
verwenden, um eine Bibliothek auf die gleiche Weise wie Pythons import
-Anweisung zu importieren.
py::object np = py::import("numpy");
Schreiben wir als Beispiel den folgenden Python-Code in C ++, ohne py :: exec ()
zu verwenden.
Dies ist ein Beispiel zur Anzeige des Graphen von y = x ^ 2 mit matplotlib.
Python-Codebeispiel
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(-10, 10, 0.1)
y = x ** 2
plt.plot(x, y)
plt.show()
Boost oben.C mit Python++Probe geschrieben in
py::object np = py::import("numpy");
py::object plt = py::import("matplotlib.pyplot");
py::object x = np.attr("arange")(-10, 10, 0.1);
py::object y = x * x;
plt.attr("plot")(x, y);
plt.attr("show")();
(Da x ** 2
nicht wie auf der C ++ - Seite geschrieben werden kann, wird es stattdessen auf x * x
gesetzt.)
Bei der Ausführung wird das Diagramm wie unten gezeigt in matplotlib angezeigt.
py :: extract ()
, das in diesem Artikel nicht vorgestellt wird.Recommended Posts