<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    【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)

      <kbd id="5sdj3"></kbd>
      <th id="5sdj3"></th>

    1. <dd id="5sdj3"><form id="5sdj3"></form></dd>
      <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

    2. <dd id="5sdj3"></dd>
      <dfn id="5sdj3"></dfn>
    3. <th id="5sdj3"></th>
      <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

    4. <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
    5. <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
      免费亚洲婷婷 | 欧美大香蕉网 | 少妇人妻无码AV片在线蜜芽 | 成人大香蕉网 | 无码电影视频 |