Exécuter du code Python sur C ++ (en utilisant Boost.Python)

introduction

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.

Exemple de code le plus simple

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 ().

Comment compiler (pour Linux + GCC)

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"

Utilisation de base

À 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ésultat

Si 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écute

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

Vous 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'objet

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

Vous 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. y=x^2のグラフ

référence

Recommended Posts

Exécuter du code Python sur C ++ (en utilisant Boost.Python)
Exécuter du code Python à partir de l'interface graphique C #
Diffusion sur LINE en utilisant python
[Treasure Data] [Python] Exécutez une requête sur Treasure Data à l'aide du client TD.
Outil de révision de code C utilisant pycparser
Remarques sur l'utilisation de MeCab depuis Python
Étude sur Tokyo Rent en utilisant Python (3-2)
Remarques sur l'installation de Python à l'aide de PyEnv
Vérifiez le style de code python à l'aide de pep8
Notes sur l'utilisation de rstrip avec python.
Installer Python sur CentOS à l'aide de Pyenv
Étude sur Tokyo Rent en utilisant Python (3-3)
Installez Python sur CentOS en utilisant pyenv
Appeler C / C ++ depuis Python sur Mac
Créez un wrapper de langage C à l'aide de Boost.Python
Remarques sur l'utilisation d'OpenCV avec Windows10 Python 3.8.3.
Détectez la "luminosité" en utilisant python sur Raspberry Pi 3!
Écrivez du code FizzBuzz piloté par les tests à l'aide de Python doctest.
Obtenez des métriques de code source Python à l'aide de radon
Installez la bibliothèque python sur Lambda à l'aide de [/ tmp]
[C] [python] Lire avec AquesTalk sous Linux
Énumérer les combinaisons en double (C ++) → Ajouter du code Python
Exécutez un servomoteur en utilisant python sur Raspberry Pi 3
Étude sur Tokyo Rent en utilisant Python (3-1 sur 3)
Exécutez le code Python sur A2019 Community Edition
Détectez la température à l'aide de python sur Raspberry Pi 3!
[Note] Exécuter du code Python à partir d'Excel (xlwings)
Exécutez Python en C ++ sur Visual Studio 2017
python setup.py tester le code en utilisant le multiprocessus
Construire l'environnement Python3.5 + matplotlib sur Ubuntu 12 en utilisant Anaconda
Python sur Windows
Détectez les interrupteurs à glissière à l'aide de python sur Raspberry Pi 3!
twitter avec python3
Remarques sur l'installation de Python3 et l'utilisation de pip sous Windows7
[Python] Exécutons le module régulièrement en utilisant schedule
Essayez d'utiliser le code QR avec Raspberry Pi
Exécutez Python YOLOv3 en C ++ sur Visual Studio 2017
Installez Python 3.8.6 sur macOS BigSur à l'aide de pyenv
Python: essayez d'utiliser l'interface utilisateur sur Pythonista 3 sur iPad
Développement Python sur Ubuntu sur AWS EC2 (à l'aide de Jupyter Lab)
Déboguer avec VS Code en utilisant Boost Python Numpy
Commencez à utiliser Python
Détectez les commutateurs magnétiques à l'aide de python sur Raspberry Pi 3!
Remarques sur l'utilisation de dict avec python [Competition Pro]
code de caractère python
Exécuter périodiquement un script Python sur AWS Data Pipeline
Remarque sur l'encodage lorsque LANG = C en Python
notes de python C ++
Essayez CI le code python poussé sur GitHub.
python sur mac
python, openFrameworks (c ++)
[Node-RED] Exécuter Python sur l'environnement virtuel Anaconda à partir de Node-RED [Anaconda] [Python]
[Python] Code conscient des algorithmes
Sonnez le buzzer en utilisant python sur Raspberry Pi 3!
Python sur Windbg