C++如何調(diào)用python并取返回值
C++調(diào)用python并取返回值
前面介紹了用python調(diào)用C++時用swig工具,現(xiàn)在簡單介紹一下C++調(diào)用python并取返回值的過程
python文件test.py
class tester: def add(self, a, b): return a + b
新建一個VS控制臺項目
main.cpp所有的源碼如下:
#include <stdio.h> #include <python.h> #include <windows.h> void main() { Py_Initialize(); // 初始化python虛擬機 PyObject* pyMod = PyImport_ImportModule("test"); // 加載test.py文件 PyObject* pyDict = PyModule_GetDict(pyMod); // 獲取test模塊中的字典 PyObject* pyCls = PyDict_GetItemString(pyDict, "tester"); // 從字典中查找tester類 PyObject* PyIns = PyInstance_New(pyCls, NULL, NULL); // 創(chuàng)建tester類 PyObject* pyRet = PyObject_CallMethod(pyIns, "add", "ii", 5, 6); // 調(diào)用tester.add方法,傳入2個int型參數(shù) int ok = -1; int retok = PyArg_Parse(pyRet, "i", &ok); // 從返回值從取出int型返回值 Py_Finalize(); system("pause"); }
整個過程最重要的是 PyBoject_CallMethod,傳入的參數(shù)類型一定不能搞錯。
還有取返回值的時候PyArg_Parse取單個返回值,要是取多個的可以用PyArg_ParseTuple,要取的類型也必須完全匹配。
c++調(diào)用python時參數(shù)傳遞和返回值解析
通過python接口在cpp中調(diào)用python函數(shù)時,構(gòu)建傳參和解析返回值都會用到python內(nèi)的變量類型和c++的變量類型之間的轉(zhuǎn)換。
返回值是numpy等復(fù)雜結(jié)構(gòu)的數(shù)據(jù)時,可以通過先轉(zhuǎn)換為list等類型再返回,或者單獨構(gòu)建一個函數(shù),獲取numpy內(nèi)某個位置的變量的函數(shù)。
下面幾個基礎(chǔ)類型的返回值解析
#python #返回一個參數(shù) def returnInt(a,b): return a+b #返回兩個相同類型的參數(shù) def returnTwoInt(): return 1,2 #返回字符串 def returnString(): srt = 'hello world' return srt #返回list def returnList(): para = [1, 2, 3, 4] return 1,para.tolist() #返回兩個不同類型的參數(shù) def returnTwo(): para = [1, 2, 3, 4] return 1,para.tolist() #返回矩陣 def returnMat(): img = cv2.imread('test1.bmp',cv2.IMREAD_GRAYSCALE) return img
//調(diào)用python函數(shù),返回的數(shù)據(jù)統(tǒng)一為PyObject類型,需要根據(jù)實際類型進行解析 PyObject* pReturn = PyObject_CallObject(pFunc, pArgs); //當不需要傳參時,可以將參數(shù)位置為空 PyObject* pReturn = PyObject_CallObject(pFunc,NULL);
PyObject為結(jié)構(gòu)體,參數(shù)ob_type->tp_name 為數(shù)據(jù)的類型
//不同類型參數(shù)傳遞 PyObject* p = PyTuple_New(4); for (int i = 0; i < 4; i++) PyTuple_SetItem(p, i, Py_BuildValue("i", i)); PyObject* pArgs = PyTuple_New(2); PyTuple_SetItem(pArgs, 0,Py_BuildValue ("i",1)); PyTuple_SetItem(pArgs, 0,Py_BuildValue ("O",p)); //返回為list double temp; int i_size = PyList_Size(pReturn); for (int i = 0; i < i_size; ++i) { PyArg_Parse(PyList_GetItem(pReturn, i), "d", &temp); std::cout << "return result is " << (temp) << std::endl; } //返回為 int 和 list 兩個不同類型的參數(shù) PyArg_Parse(PyTuple_GetItem(pReturn, 0), "d", &temp); std::cout << "temp is " << (temp) << std::endl; PyObject* pReturnlist; PyArg_Parse(PyTuple_GetItem(pReturn, 1), "O", &pReturnlist); i_size = PyList_Size(pReturnli); for (int i = 0; i < i_size; ++i) { PyArg_Parse(PyList_GetItem(pReturnli, i), "d", &temp); std::cout << "return result is " << (temp) << std::endl; } //返回單獨一個變量 //構(gòu)建輸入 PyObject* pArgs = PyTuple_New(2); PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 1)); PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 1)); PyObject* pReturn2 = PyObject_CallObject(pFunc, pArgs); //解析 int nResult1; //解析為int PyArg_Parse(pReturn2, "i", &nResult1); std::cout << "add=" << nResult1 << std::endl; double nResultd; //解析為double PyArg_Parse(pReturn2, "d", &nResultd); std::cout << "add=" << nResultd << std::endl; //返回字符串 //解析方法1: PyObject* repr = PyObject_Repr(pReturn); PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "strict"); char* result = PyBytes_AsString(str); std::cout << result << std::endl; //解析方法2: char* pstr = NULL; PyArg_Parse(pReturn, "s", &pstr); std::cout << pstr << std::endl; //返回多個變量 //循環(huán)解析 int nResult; i_size = PyTuple_Size(pReturn); for (int i = 0; i < i_size; ++i) { PyArg_Parse(PyTuple_GetItem(pReturn, i), "i", &nResult); std::cout << "return result is " << (nResult) << std::endl; } //直接解析 int nResult1; int nResult2; PyArg_ParseTuple(pReturn,"i|i", &nResult1, &nResult2); std::cout << "return " << nResult5<< ' ' << nResult6 << std::endl; //解析二維矩陣 //獲得序列長度,即行數(shù) Py_ssize_t rsize = PyObject_Size(pReturn); std::cout << rsize << std::endl; //轉(zhuǎn)換到迭代器,用于提取數(shù)據(jù) PyObject* iter = PyObject_GetIter(pReturn5); while (true) { //獲取矩陣的第一行 PyObject* next = PyIter_Next(iter); if (!next) { // nothing left in the iterator break; } if (!PyList_Check(next)) { // error, we were expecting a list value } //獲得當前行的數(shù)據(jù)數(shù)量 Py_ssize_t foosize = PyObject_Size(next); std::cout << foosize << std::endl; //轉(zhuǎn)換到迭代器,用于獲取數(shù)據(jù) PyObject* iter2 = PyObject_GetIter(next); while (true) { PyObject* next2 = PyIter_Next(iter2); if (!next2) break; if (!PyFloat_Check(next2)) {// error, we were expecting a floating point value} double foo = PyFloat_AsDouble(next2); std::cout << foo << " "; } std::cout << std::endl; }
python手冊,接口的使用示例等
//解析常用字段: // b <=>char 0-255的那個char // c <=>char 單個字符 // h <=>short int // l <=>long int // f <=>float // d <=>double // s <=>char* // O <=> PyObject
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
C語言非遞歸算法解決快速排序與歸并排序產(chǎn)生的棧溢出
上期我們講完了排序算法下,不知道小伙伴們有沒有發(fā)現(xiàn)一個問題,快速排序和歸并排序我們都是用遞歸來實現(xiàn)的,可能有小伙伴會問,如果說數(shù)據(jù)量很多話,棧區(qū)空間會不會不夠用呢?這期我們就來解決使用遞歸實現(xiàn)的排序?qū)е聴R绯鋈绾谓鉀Q2022-04-04