(avec code) mise en route | Comment utiliser C/C++ pour appeler des scripts Python

Recommandation de l'éditeur

Lors du développement de C/C++, de nombreuses fonctions non essentielles peuvent être implémentées à l'aide de Python, il est donc également nécessaire d'apprendre à appeler des programmes Python dans des programmes C/C++. Il existe de nombreuses façons d'y parvenir, et aujourd'hui je vais vous présenter une méthode qui me semble la plus pratique.

L'article présentera une méthode (API Python/C) pour enrichir votre programme d'application C/C++ en embarquant Python, ce qui permettra à votre programme d'application d'utiliser Python sans changer la fonction d'origine du programme. pour implémenter certaines fonctions de l'application.

Cette approche peut être utilisée à plusieurs fins, l'objectif principal est de nous permettre de personnaliser l'application en fonction de nos besoins en écrivant certains scripts en Python (certaines fonctions peuvent être plus facilement écrites en Python). Lorsque vous intégrez Python, le programme principal n'a généralement rien à voir avec l'implémentation de Python, et certaines parties de l'application appellent l'interpréteur Python lorsqu'il est nécessaire d'exécuter du code Python que nous avons écrit. Donc, si vous avez besoin d'intégrer Python, vous avez d'abord besoin d'un programme principal C/C++.

Utilisation de base

Python fournit un ensemble de bibliothèques d'API C, afin que les développeurs puissent facilement appeler des modules Python à partir de programmes C/C++. Les utilisateurs C++ doivent noter que bien que l'API soit complètement définie en C, le fichier d'en-tête a déclaré le point d'entrée comme extern "C" , l'API n'a donc rien à faire de spécial pour utiliser cette API en C++.

insérez la description de l'image ici
Pour des documents spécifiques, reportez-vous au guide officiel : https://docs.python.org/3.9/extending/embedding.html

Si nous devons utiliser cet ensemble d'API, nous devons introduire un fichier d'en-tête et un fichier de bibliothèque, en prenant Cmake build comme exemple, nous devons ajouter dans CMakeLists.txt :

find_package (Python COMPONENTS Interpreter Development REQUIRED)
target_include_directories(${PROJECT_NAME} PRIVATE ${Python_INCLUDE_DIRS})
target_link_libraries(${PROJECT_NAME} PRIVATE ${Python_LIBRARIES})

Dans l'environnement Windows, il faudrait s'assurer de l'existence des deux variables d'environnement suivantes (pas encore testées).

insérez la description de l'image ici
Ensuite, nous pouvons introduire le fichier d'en-tête correspondant dans main.cpp :

#include <Python.h>

Après cela, l'une des choses que fait le programme principal est d'initialiser l'interpréteur Python :

Py_Initialize();

Bien sûr, puisque l'interpréteur doit être initialisé, en tant que code pouvant être écrit en langage C, nous devons généralement le publier (lorsqu'il n'est pas nécessaire) :

Py_Finalize();

Nous pouvons maintenant transmettre l'instruction Python que nous voulons exécuter à l'interpréteur Python sous forme de chaîne :

PyRun_SimpleString("print("Hello world!")");

donner une châtaigne simple

Cette méthode n'a aucun moyen de transférer des valeurs (nous n'envisageons pas de convertir en chaînes pour le moment, après tout, il est gênant de recevoir des données en même temps, ce qui est également un gros problème) :

1. Initialiser l'interpréteur Python ;
2. Transmettre le code sous forme de chaîne ;
3. Libérer l'interpréteur Python.

code afficher comme ci-dessous:

#define PY_SSIZE_T_CLEAN
#include <Python.h>

int main(int, char **)
{
    
    
    Py_Initialize();                                       // 初始化python解释器
    PyRun_SimpleString("import matplotlib.pyplot as plt"); // 运行python代码
    PyRun_SimpleString("plt.plot([1,2,3,4], [12,3,23,231])");
    PyRun_SimpleString("plt.show()");
    Py_Finalize(); // 释放python解释器
};

Le résultat est le suivant :

insérez la description de l'image ici
Évidemment, nous appelons avec succès Python dans le programme C++ et dessinons l'image et l'affichons.

Types de données courants

Il y a un dicton en python appelé "tout est un objet", qui peut être mieux compris en combinaison avec le code source.
En python, lorsque toutes les variables, fonctions, classes, etc. sont exécutées dans l'interpréteur, un nouvel objet sera créé dans le tas et le nom sera lié à l'objet.

En C/C++, tous les types Python sont déclarés comme PyObject.Afin de pouvoir exploiter les données Python, Python fournit des opérations de conversion entre différents types de données et types de données du langage C :

PyObject *object;  // 创建python的object的指针
Py_DECREF(object); // 销毁object

1. Traitement des nombres et des chaînes
La fonction Py_BuildValue() est fournie dans l'API Python/C pour convertir les nombres et les chaînes en types de données correspondants dans Python.

PyObject* Arg = Py_BuildValue("(i, i)", 1, 2);  //i表示创建int型变量

2. Opération de liste
La fonction PyList_New() est fournie dans l'API Python/C pour créer une nouvelle liste Python. La valeur de retour de la fonction PyList_New() est la liste créée.

3. Opération Tuple
La fonction PyTuple_New() est fournie dans l'API Python/C pour créer un nouveau tuple Python. La fonction PyTuple_New() renvoie le tuple créé.

4. Fonctionnement du dictionnaire
La fonction PyDict_New() est fournie dans l'API Python/C pour créer un nouveau dictionnaire. La fonction PyDict_New() renvoie le dictionnaire créé.

5. Opération cv::Mat
cv::Mat devrait être le format que nous utiliserons souvent, le code de référence est le suivant :

PyObject *cvmat2py(cv::Mat &image)
{
    
    
    import_array();
    int row, col;
    col = image.cols; //列宽
    row = image.rows; //行高
    int channel = image.channels();
    int irow = row, icol = col * channel;
    npy_intp Dims[3] = {
    
    row, col, channel}; //图像维度信息
    PyObject *pyArray = PyArray_SimpleNewFromData(channel, Dims, NPY_UBYTE, image.data);
    PyObject *ArgArray = PyTuple_New(1);
    PyTuple_SetItem(ArgArray, 0, pyArray);
    return ArgArray;
}

Pour plus d'opérations, veuillez vous référer à : https://docs.python.org/zh-cn/3/c-api/arg.html#building-values

Prenez une châtaigne un peu plus compliquée

Cette méthode peut transférer des valeurs :

1. Initialiser l'interpréteur Python ;
2. Convertir les données de C++ en Python ;
3. Utiliser les données converties comme paramètre pour appeler la fonction Python ;
4. Convertir la valeur de retour de la fonction en une structure de données C++ ;
5. Libérer l'interpréteur Python .

Le code C++ est le suivant :


#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <iostream>

int main(int, char **)
{
    
    
    // 初始化python解释器
    Py_Initialize();
    if (!Py_IsInitialized())
    {
    
    
        return -1;
    }

    // 添加编译后文件的所在路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");

    // 要调用的python文件名
    auto pModule = PyImport_ImportModule("common"); // 记得复制到编译后文件的路径下,同时不用加后缀名“.py“
    if (!pModule)
    {
    
    
        std::cout << "Can't find your xx.py file.";
        getchar();
        return -1;
    }

    //获取模块中的函数
    auto pFunc = PyObject_GetAttrString(pModule, "add"); //从字符串创建python函数对象

    // 参数类型转换
    PyObject *pArg = Py_BuildValue("ii", 1, 2);

    //调用直接获得的函数,并传递参数
    auto *py_result = PyEval_CallObject(pFunc, pArg);

    int c_result;
    // 将python类型的返回值转换为C类型
    PyArg_Parse(py_result, "i", &c_result);
    std::cout << "return: " << c_result << std::endl;
};

Le code Python est le suivant (nommé common.py) :

def add(a, b):
    print('a: ', a)
    print('b: ', b)
    return a + b

Le résultat est le suivant (le chemin de recherche du fichier python défini dans le code est le chemin du fichier compilé) :

insérez la description de l'image ici
De cette façon, les deux implémentations relativement simples sont terminées. Pour plus d'opérations, veuillez vous référer à : https://docs.python.org/3.9/c-api/index.html#c-api-index

Les références

1.https://blog.csdn.net/pipisorry/article/details/49532341
2.https://blog.csdn.net/qq_45401419/article/details/123562089
3.https://zhuanlan.zhihu.com/ p/146874652

Je suppose que tu aimes

Origine blog.csdn.net/weixin_41006390/article/details/126191970
conseillé
Classement