深入淺析 C++ 調(diào)用 Python 模塊
一般開發(fā)過游戲的都知道Lua和C++可以很好的結(jié)合在一起,取長(zhǎng)補(bǔ)短,把Lua腳本當(dāng)成類似動(dòng)態(tài)鏈接庫(kù)來使用,很好的利用了腳本開發(fā)的靈活性。而作為一門流行的通用型腳本語(yǔ)言Python,也是可以做到的。在一個(gè)C++應(yīng)用程序中,我們可以用一組插件來實(shí)現(xiàn)一些具有統(tǒng)一接口的功能,一般插件都是使用動(dòng)態(tài)鏈接庫(kù)實(shí)現(xiàn),如果插件的變化比較頻繁,我們可以使用Python來代替動(dòng)態(tài)鏈接庫(kù)形式的插件(堪稱文本形式的動(dòng)態(tài)鏈接庫(kù)),這樣可以方便地根據(jù)需求的變化改寫腳本代碼,而不是必須重新編譯鏈接二進(jìn)制的動(dòng)態(tài)鏈接庫(kù)。靈活性大大的提高了。
作為一種膠水語(yǔ)言,Python 能夠很容易地調(diào)用 C 、 C++ 等語(yǔ)言,也能夠通過其他語(yǔ)言調(diào)用 Python 的模塊。
Python 提供了 C++ 庫(kù),使得開發(fā)者能很方便地從 C++ 程序中調(diào)用 Python 模塊。
具體的文檔參考官方指南:
Embedding Python in Another Application
調(diào)用方法
1 鏈接到 Python 調(diào)用庫(kù)
Python 安裝目錄下已經(jīng)包含頭文件( include 目錄)和庫(kù)文件 ( Windows 下為 python27.lib)。
使用之前需要鏈接到此庫(kù)。
2 直接調(diào)用 Python 語(yǔ)句
<code class="language-cpp hljs ">#include "python/Python.h" int main() { Py_Initialize(); ## 初始化 PyRun_SimpleString("print 'hello'"); Py_Finalize(); ## 釋放資源 } </code>
3 加載 Python 模塊并調(diào)用函數(shù)
~/test 目錄下含有 test.py :
<code class="language-python hljs ">def test_add(a, b): print 'add ', a, ' and ', b return a+b</code>
則可以通過以下代碼調(diào)用 test_add 函數(shù) :
<code class="language-cpp hljs ">#include "python/Python.h" #include <iostream> using namespace std; int main() { Py_Initialize(); // 初始化 // 將Python工作路徑切換到待調(diào)用模塊所在目錄,一定要保證路徑名的正確性 string path = "~/test"; string chdir_cmd = string("sys.path.append(\"") + path + "\")"; const char* cstr_cmd = chdir_cmd.c_str(); PyRun_SimpleString("import sys"); PyRun_SimpleString(cstr_cmd); // 加載模塊 PyObject* moduleName = PyString_FromString("test"); //模塊名,不是文件名 PyObject* pModule = PyImport_Import(moduleName); if (!pModule) // 加載模塊失敗 { cout << "[ERROR] Python get module failed." << endl; return 0; } cout << "[INFO] Python get module succeed." << endl; // 加載函數(shù) PyObject* pv = PyObject_GetAttrString(pModule, "test_add"); if (!pv || !PyCallable_Check(pv)) // 驗(yàn)證是否加載成功 { cout << "[ERROR] Can't find funftion (test_add)" << endl; return 0; } cout << "[INFO] Get function (test_add) succeed." << endl; // 設(shè)置參數(shù) PyObject* args = PyTuple_New(2); // 2個(gè)參數(shù) PyObject* arg1 = PyInt_FromLong(4); // 參數(shù)一設(shè)為4 PyObject* arg2 = PyInt_FromLong(3); // 參數(shù)二設(shè)為3 PyTuple_SetItem(args, 0, arg1); PyTuple_SetItem(args, 1, arg2); // 調(diào)用函數(shù) PyObject* pRet = PyObject_CallObject(pv, args); // 獲取參數(shù) if (pRet) // 驗(yàn)證是否調(diào)用成功 { long result = PyInt_AsLong(pRet); cout << "result:" << result; } Py_Finalize(); ## 釋放資源 return 0; } </iostream></code>
參數(shù)傳遞
1 C++ 向 Python 傳遞參數(shù)
Python 的參數(shù)實(shí)際上是元組,因此傳參實(shí)際上就是構(gòu)造一個(gè)合適的元組。
常用的有兩種方法:
使用 PyTuple_New 創(chuàng)建元組, PyTuple_SetItem 設(shè)置元組值
<code class="language-cpp hljs ">PyObject* args = PyTuple_New(3); PyObject* arg1 = Py_BuildValue("i", 100); // 整數(shù)參數(shù) PyObject* arg2 = Py_BuildValue("f", 3.14); // 浮點(diǎn)數(shù)參數(shù) PyObject* arg3 = Py_BuildValue("s", "hello"); // 字符串參數(shù) PyTuple_SetItem(args, 0, arg1); PyTuple_SetItem(args, 1, arg2); PyTuple_SetItem(args, 2, arg3);</code>
直接使用Py_BuildValue構(gòu)造元組
<code class="language-cpp hljs ">PyObject* args = Py_BuildValue("ifs", 100, 3.14, "hello"); PyObject* args = Py_BuildValue("()"); // 無參函數(shù)</code>
i, s, f之類的格式字符串可以參考 格式字符串
2 轉(zhuǎn)換 Python 返回值
調(diào)用 Python 得到的都是PyObject對(duì)象,因此需要使用 Python 提供的庫(kù)里面的一些函數(shù)將返回值轉(zhuǎn)換為 C++ , 例如 PyInt_AsLong,PyFloat_AsDouble, PyString_AsString 等。
還可以使用 PyArg_ParseTuple 函數(shù)來將返回值作為元組解析。
PyArg_Parse 也是一個(gè)使用很方便的轉(zhuǎn)換函數(shù)。
PyArg_ParseTuple 和 PyArg_Parse 都使用 格式字符串
注意事項(xiàng)
需要將 Python 的工作目錄切換到模塊所在路徑 按照模塊名加載而不是文件名 模塊加載或者函數(shù)加載需要驗(yàn)證是否成功,否則可能會(huì)引起堆棧錯(cuò)誤導(dǎo)致程序崩潰 需要使用 Py_DECREF(PyObject*) 來解除對(duì)象的引用(以便Python垃圾回收)
以上所述是小編給大家介紹的C++ 調(diào)用 Python 模塊的相關(guān)知識(shí),希望對(duì)大家有所幫助!
相關(guān)文章
OpenCV圖像特征提取之Shi-Tomasi角點(diǎn)檢測(cè)算法詳解
Harris角點(diǎn)檢測(cè)算法就是對(duì)角點(diǎn)響應(yīng)函數(shù)R進(jìn)行閾值處理,Shi-Tomasi原理幾乎和Harris一樣的,只不過最后計(jì)算角點(diǎn)響應(yīng)的公式發(fā)生了變化。本文將和大家詳細(xì)說說Shi-Tomasi角點(diǎn)檢測(cè)算法的原理與實(shí)現(xiàn),需要的可以參考一下2022-09-09C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹
大家好,本篇文章主要講的是C語(yǔ)言動(dòng)態(tài)內(nèi)存管理介紹,感興趣的同學(xué)趕快來看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽2021-12-12C++的STL中accumulate函數(shù)的使用方法
這篇文章主要介紹了C++的STL中accumulate的使用方法,accumulate作用是累加求和即自定義類型數(shù)據(jù)處理,下文具體的操作方法需要的小伙伴可以參考一下2022-03-03C語(yǔ)言與C++動(dòng)態(tài)通訊錄超詳細(xì)實(shí)現(xiàn)流程
這篇文章主要為大家介紹了C語(yǔ)言與C++動(dòng)態(tài)實(shí)現(xiàn)通訊錄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助2022-05-05用32位int型變量表示單引號(hào)括起來的四個(gè)字符的深入探討
本篇文章是對(duì)用32位int型變量表示單引號(hào)括起來的四個(gè)字符進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05使用MinGW使Windows通過gcc實(shí)現(xiàn)C或C++程序本地編譯執(zhí)行的方法
這篇文章主要介紹了使用MinGW使Windows通過gcc實(shí)現(xiàn)C或C++程序本地編譯執(zhí)行的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11C語(yǔ)言實(shí)現(xiàn)快速排序的方法及優(yōu)化
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)快速排序的方法及優(yōu)化,快速排序是Hoare于1962年提出的一種二叉樹結(jié)構(gòu)的交換排序方法,下面我們來看一看傳說中的快速排序的特點(diǎn)與效率怎么樣,需要的朋友可以參考下2023-07-07使用C++和代理IP實(shí)現(xiàn)天氣預(yù)報(bào)的采集
在當(dāng)今的互聯(lián)網(wǎng)時(shí)代,網(wǎng)絡(luò)信息的獲取變得日益重要,天氣預(yù)報(bào)信息作為日常生活的重要參考,其獲取方式也隨著技術(shù)的發(fā)展而不斷變化,在本文中,我們將探討如何使用C++和代理IP來采集天氣預(yù)報(bào)信息,文中通過代碼講解的非常詳細(xì),需要的朋友可以參考下2023-12-12QT中QTableWidget加載大量數(shù)據(jù)不卡頓的解決
本文主要介紹了QT中QTableWidget加載大量數(shù)據(jù)不卡頓的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07