Boost.Python est souvent utilisé lors de la création d'une bibliothèque pour Python en utilisant C ++, mais il peut également être utilisé pour ce que l'on appelle "l'incorporation" qui utilise du code Python du côté C ++.
N'y a-t-il pas beaucoup de demande pour l'utilisation du code Python à partir de C ++? Même si vous recherchez "boost python" etc., vous n'obtiendrez que des articles sur l'utilisation inverse (lorsque vous utilisez le code C ++ de Python). Dans ce cas, si vous incluez le mot-clé de recherche "embed" (intégré), l'article lors de l'incorporation de Python dans C ++ sera facile à consulter.
main.cpp
#include <boost/python.hpp>
namespace py = boost::python;
int main()
{
Py_Initialize(); //Doit être appelé en premier
try
{
//"Imprimer" en Python('Hello World!')Exécuter
py::object global = py::import("__main__").attr("__dict__");
py::exec("print('Hello World!')", global);
}
catch (const py::error_already_set &)
{
//Afficher les détails de l'erreur si une erreur se produit lors de l'exécution du code Python
PyErr_Print();
}
return 0;
}
Dans cet exemple, la fonction py :: exec ()
est utilisée pour exécuter simplement le code Python print ('Hello World!')
.
J'exécute mon code dans l'espace de noms global sur Python en obtenant un objet dans l'espace de noms global sur Python dans une variable appelée «global».
Boost.Python appelle l'interface C de Python dans les coulisses, vous devez donc appeler la fonction Py_Initialize ()
avant de l'utiliser.
(* Selon le tutoriel officiel, Py_Finalize ()
ne doit pas être appelé dans le code)
De plus, si une erreur d'exécution se produit dans Python, une exception de type py :: error_already_set
sera lancée, donc cela est intercepté et le contenu est affiché avec PyErr_Print ()
.
Pour Linux + GCC, vous pouvez compiler avec la commande suivante.
Comment compiler
$ g++ main.cpp `pkg-config python3-embed --cflags --libs` -lboost_python38
Selon l'environnement, il peut y avoir une version sans python3-embed
, alors changez-la en pkg-config python3
selon le cas (dans la version avec python3-embed
, la bibliothèque pour l'incorporation est exclue de l'original Par conséquent, l'utilisation de pkg-config python3
peut entraîner une erreur de lien).
De plus, la partie boost_python38
de ce qui précède dépend de la version et de l'environnement (elle peut être au format boost_python-py38
).
Si vous ne connaissez pas le nom de la bibliothèque Boost.Python vers laquelle créer un lien, vous pouvez le rechercher avec la commande suivante:
La partie **
de lib **. So
qui apparaît est le nom de la bibliothèque.
Boost.Comment savoir si vous ne connaissez pas le nom de la bibliothèque Python
$ ldconfig -p | grep "boost_python3"
À partir de là, nous verrons comment utiliser chaque fonction spécifique.
Par la suite, en supposant que namespace py = boost :: python;
est écrit, il s'écrit py
.
De plus, «global» dans le code est le même que le premier exemple, c'est un objet de l'espace de noms global obtenu par le code suivant.
py::object global = py::import("__main__").attr("__dict__");
py :: eval ()
: évalue l'expression en Python et renvoie le résultatSi vous donnez une expression Python sous forme de chaîne, le résultat sera renvoyé sous forme de type py :: object
.
Vous pouvez obtenir le résultat sous forme de type C ++ en le combinant avec py :: extract <type name>
comme indiqué ci-dessous.
// "2**3"Obtenez le résultat de
py::object result = py::eval("2**3", global);
//Convertir le résultat en type int et en sortie
std::cout << py::extract<int>(result) << std::endl;
Résultat d'exécution
8
Dans le cas de cet exemple, les fonctions en Python ne sont pas utilisées en particulier, donc même si l'espace de noms global
du deuxième argument est omis, cela fonctionnera.
Cependant, veuillez noter que si vous omettez le deuxième argument, vous ne pourrez pas utiliser les fonctions intégrées de Python telles que pow
, ou les variables / fonctions que vous avez définies séparément.
py :: exec ()
: passe le code Python sous forme de chaîne et exécuteComme ce fut le cas avec le premier exemple, si vous donnez à la fonction py :: exec ()
le code Python sous forme de chaîne, il sera exécuté tel quel.
Contrairement à py :: eval ()
, il peut également exécuter plusieurs commandes séparées par des sauts de ligne et définir des classes.
py::exec(
"print('Hello!')\n"
"print('World!')", global);
Résultat d'exécution
Hello!
World!
Lorsqu'une nouvelle variable est créée, elle sera générée sur l'espace de noms donné dans le deuxième argument.
//2 à la variable de résultat dans l'espace de noms global de Python**Remplaçant 3
py::exec("result = 2**3", global);
//Convertir le résultat en type int et en sortie
std::cout << py::extract<int>(global["result"]) << std::endl;
Résultat d'exécution
8
py :: exec_file ()
: Exécute le code Python à partir du fichierVous pouvez utiliser py :: exec_file ()
pour lire le contenu du fichier et l'exécuter de la même manière que py :: exec ()
.
Le premier argument est le chemin du fichier vers le script Python.
py::exec_file("hello.py", global);
Ceci est utile lorsque vous souhaitez préparer la définition de votre propre classe en tant que fichier de script Python séparément de C ++.
py :: object :: attr ()
: référence de champ / méthode d'objetLes champs (variables membres) et les méthodes (fonctions membres) de py :: object
peuvent être utilisés en utilisant la fonction ʻattr ()`.
Exemple d'appel de la méthode de jointure de type str
// ['hoge','fuga','piyo']Créez une liste appelée
py::object list = py::eval("['hoge','fuga','piyo']", global);
// 「','.join(list)Et combinez les chaînes de la liste séparées par des virgules
py::object result = py::object(",").attr("join")(list);
//Convertir le résultat en type de chaîne et en sortie
std::string resultStr = py::extract<std::string>(result);
std::cout << resultStr << std::endl;
Résultat d'exécution
hoge,fuga,piyo
py :: import ()
: Utilisation de la bibliothèque PythonVous pouvez utiliser py :: import
pour importer une bibliothèque de la même manière que l'instruction ʻimport` de Python.
py::object np = py::import("numpy");
À titre d'exemple, écrivons le code Python suivant en C ++ sans utiliser py :: exec ()
.
Voici un exemple pour afficher le graphique de y = x ^ 2 avec matplotlib.
Exemple de code Python
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 ci-dessus.C en utilisant Python++Échantillon rédigé en
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")();
(Puisque x ** 2
ne peut pas être écrit tel quel côté C ++, il est défini sur x * x
à la place.)
Une fois exécuté, le graphique sera affiché dans matplotlib comme indiqué ci-dessous.
py :: extract ()
, qui n'est pas présenté dans cet article.Recommended Posts