1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【Python】(附代碼)入門 | 如何使用C/C++調(diào)用Python腳本

        共 4677字,需瀏覽 10分鐘

         ·

        2022-07-31 15:37

        編者薦語(yǔ)

         

        在進(jìn)行 C/C++ 進(jìn)行開(kāi)發(fā)的時(shí)候,很多非核心的功能,可以使用 Python 進(jìn)行實(shí)現(xiàn),因此學(xué)習(xí)在 C/C++ 程序中如何調(diào)用 Python 程序也是非常有必要的。實(shí)現(xiàn)的方法有許多種,今天給大家介紹一種小編認(rèn)為的最方便的方法。


        文章將會(huì)介紹一種通過(guò)嵌入 Python 來(lái)豐富你的 C/C++ 應(yīng)用程序的方法(Python/C API),這種方式會(huì)使您的應(yīng)用程序能夠在不改變程序原有功能的基礎(chǔ)上,使用 Python 編程語(yǔ)言而不是 C/C++ 語(yǔ)言來(lái)實(shí)現(xiàn)應(yīng)用程序的某些功能。


        這種方式可以用于多種目的,主要目的是允許我們通過(guò)用 Python 編寫一些腳本來(lái)根據(jù)需要定制應(yīng)用程序(某些功能可以更容易地用 Python 編寫)。當(dāng)你嵌入 Python 時(shí),主程序一般情況下與 Python 實(shí)現(xiàn)無(wú)關(guān),應(yīng)用程序的某些部分會(huì)在需要的時(shí)候調(diào)用 Python 解釋器,運(yùn)行一些我們編寫的 Python 代碼。所以,如果你需要嵌入 Python,那么你首先需要一個(gè) C/C++ 主程序。


        基本使用方法

        Python 提供了一套 C API庫(kù),使得開(kāi)發(fā)者能很方便地從C/ C++ 程序中調(diào)用 Python 模塊,C++ 用戶應(yīng)該注意,盡管 API 是完全使用 C 來(lái)定義的,但頭文件已將入口點(diǎn)聲明為 extern "C",因此 API 在 C++ 中使用此 API 不必再做任何特殊處理。



        具體的文檔參考官方指南:

        https://docs.python.org/3.9/extending/embedding.html

        如果需要使用這個(gè)套API,我們需要引入一個(gè)頭文件和一個(gè)庫(kù)文件,以Cmake構(gòu)建為例,我們需要在 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})


        Windows環(huán)境下應(yīng)該是需要保證如下兩個(gè)環(huán)境變量的存在(暫未測(cè)試)。



        然后我們就可以在 main.cpp 中引入相應(yīng)的頭文件了:


        #include <Python.h>


        之后,主程序要做的一件事就是是初始化 Python 解釋器:


        Py_Initialize();


        當(dāng)然,既然需要初始化解釋器,作為可以在 C 語(yǔ)言中編寫的代碼,我們一般還需要對(duì)它進(jìn)行釋放(在不需要的時(shí)候):


        Py_Finalize();


        現(xiàn)在我們變可以將需要運(yùn)行的 Python 語(yǔ)句以字符串的形式傳遞給 Python 解釋器:


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


        舉個(gè)簡(jiǎn)單的栗子

        此方法沒(méi)辦法進(jìn)行數(shù)值的傳遞(暫不考慮轉(zhuǎn)換為字符串傳遞,畢竟麻煩的同時(shí)接收數(shù)據(jù)也是一個(gè)大問(wèn)題):

        1. 初始化Python解釋器;

        2. 以字符串的形式傳遞代碼;

        3. 釋放python解釋器。


        代碼如下:


        #define PY_SSIZE_T_CLEAN#include <Python.h>
        int main(int, char **){ Py_Initialize(); // 初始化python解釋器 PyRun_SimpleString("import matplotlib.pyplot as plt"); // 運(yùn)行python代碼 PyRun_SimpleString("plt.plot([1,2,3,4], [12,3,23,231])"); PyRun_SimpleString("plt.show()"); Py_Finalize(); // 釋放python解釋器};


        結(jié)果如下:




        顯然,我們成功的在 C++ 程序中調(diào)用 Python 并繪制圖像并顯示了出來(lái)。


        常用數(shù)據(jù)類型

        在python中有一句話叫做“一切皆對(duì)象”,這句話可以結(jié)合源碼更好的進(jìn)行理解。

        在python里,一切變量、函數(shù)、類等,在解釋器中執(zhí)行時(shí),都會(huì)在在堆中新建一個(gè)對(duì)象,并將名字綁定在對(duì)象上。


        在 C/C++ 中,所有的 Python 類型都被聲明為 PyObject ,為了能夠操作 Python 的數(shù)據(jù),Python提供了各種數(shù)據(jù)類型和 C 語(yǔ)言數(shù)據(jù)類型的轉(zhuǎn)換操作:


        PyObject *object;  // 創(chuàng)建python的object的指針Py_DECREF(object); // 銷毀object


        1.數(shù)字與字符串處理

        在 Python/C API 中提供了 Py_BuildValue() 函數(shù)對(duì)數(shù)字和字符串進(jìn)行轉(zhuǎn)換處理,使之變成Python中相應(yīng)的數(shù)據(jù)類型。


        PyObject* Arg = Py_BuildValue("(i, i)", 1, 2);  //i表示創(chuàng)建int型變量


        2.列表操作

        在 Python/C API 中提供了 PyList_New() 函數(shù)用以創(chuàng)建一個(gè)新的 Python 列表。PyList_New() 函數(shù)的返回值為所創(chuàng)建的列表。


        3.元組操作

        在 Python/C API 中提供了 PyTuple_New() 函數(shù),用以創(chuàng)建一個(gè)新的 Python 元組。PyTuple_New() 函數(shù)返回所創(chuàng)建的元組。


        4.字典操作

        在 Python/C API 中提供了 PyDict_New() 函數(shù)用以創(chuàng)建一個(gè)新的字典。PyDict_New() 函數(shù)返回所創(chuàng)建的字典。


        5. cv::Mat 操作

        cv::Mat應(yīng)該是我們會(huì)經(jīng)常使用的格式了,參考代碼如下:


        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;}


        更多操作請(qǐng)參考:https://docs.python.org/zh-cn/3/c-api/arg.html#building-values


        舉個(gè)稍復(fù)雜一點(diǎn)的栗子

        此方法可以進(jìn)行進(jìn)行數(shù)值的傳遞

        1. 初始化Python解釋器;           

        2. 從C++到Python轉(zhuǎn)換數(shù)據(jù);

        3. 用轉(zhuǎn)換后的數(shù)據(jù)做參數(shù)調(diào)用Python函數(shù);

        4. 把函數(shù)返回值轉(zhuǎn)換為C++數(shù)據(jù)結(jié)構(gòu);

        5. 釋放python解釋器。


        C++代碼如下:


        #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('./')");
        // 要調(diào)用的python文件名 auto pModule = PyImport_ImportModule("common"); // 記得復(fù)制到編譯后文件的路徑下,同時(shí)不用加后綴名“.py“ if (!pModule) { std::cout << "Can't find your xx.py file."; getchar(); return -1; }
        //獲取模塊中的函數(shù) auto pFunc = PyObject_GetAttrString(pModule, "add"); //從字符串創(chuàng)建python函數(shù)對(duì)象
        // 參數(shù)類型轉(zhuǎn)換 PyObject *pArg = Py_BuildValue("ii", 1, 2);
        //調(diào)用直接獲得的函數(shù),并傳遞參數(shù) auto *py_result = PyEval_CallObject(pFunc, pArg);
        int c_result; // 將python類型的返回值轉(zhuǎn)換為C類型 PyArg_Parse(py_result, "i", &c_result); std::cout << "return: " << c_result << std::endl;};


        Python代碼如下(命名為 common.py):


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


        結(jié)果如下(代碼中設(shè)置的 python 文件搜索路徑為編譯后的文件路徑):



          這樣比較簡(jiǎn)單的兩個(gè)實(shí)現(xiàn)就完成了,更多操作請(qǐng)參考:https://docs.python.org/3.9/c-api/index.html#c-api-index


          參考資料         

          • https://blog.csdn.net/pipisorry/article/details/49532341

          • https://blog.csdn.net/qq_45401419/article/details/123562089

          • https://zhuanlan.zhihu.com/p/146874652


          —THE END—
          往期精彩回顧




          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          1. <strong id="7actg"></strong>
          2. <table id="7actg"></table>

          3. <address id="7actg"></address>
            <address id="7actg"></address>
            1. <object id="7actg"><tt id="7actg"></tt></object>
              国产精品爱啪在线线免费观看 | 国产在线欧美在线 | 青娱乐成人在线视频 | 国产精品久久99精品国产 | 91蝌蚪国产高清视频 | 中文字幕无码av波多野结衣 | 91探花在线视频 | 一级操逼片| 一区二区三区性爱视频 | 国产区清纯女高中被c |