<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 4677字,需瀏覽 10分鐘

           ·

          2022-07-31 15:37

          編者薦語

           

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


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


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


          基本使用方法

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



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

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

          如果需要使用這個套API,我們需要引入一個頭文件和一個庫文件,以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)該是需要保證如下兩個環(huán)境變量的存在(暫未測試)。



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


          #include <Python.h>


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


          Py_Initialize();


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


          Py_Finalize();


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


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


          舉個簡單的栗子

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

          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 并繪制圖像并顯示了出來。


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

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

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


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


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


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

          在 Python/C API 中提供了 Py_BuildValue() 函數(shù)對數(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)建一個新的 Python 列表。PyList_New() 函數(shù)的返回值為所創(chuàng)建的列表。


          3.元組操作

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


          4.字典操作

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


          5. cv::Mat 操作

          cv::Mat應(yīng)該是我們會經(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;}


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


          舉個稍復(fù)雜一點的栗子

          此方法可以進(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ù)制到編譯后文件的路徑下,同時不用加后綴名“.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ù)對象
          // 參數(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 文件搜索路徑為編譯后的文件路徑):



            這樣比較簡單的兩個實現(xiàn)就完成了,更多操作請參考: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
            點贊
            評論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報
            評論
            圖片
            表情
            推薦
            點贊
            評論
            收藏
            分享

            手機(jī)掃一掃分享

            分享
            舉報
            <kbd id="afajh"><form id="afajh"></form></kbd>
            <strong id="afajh"><dl id="afajh"></dl></strong>
              <del id="afajh"><form id="afajh"></form></del>
                  1. <th id="afajh"><progress id="afajh"></progress></th>
                    <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    欧美伊人大香焦 | 丰满熟妇乱又伦 | 欧美天天澡天天爽日日a | 欧美日成人久久久久手机版 | 国产日皮视频免费观看 |