C++如何调用python并取返回值
C++调用python并取返回值
前面介绍了用python调用C++时用swig工具,现在简单介绍一下C++调用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); // 创建tester类 PyObject* pyRet = PyObject_CallMethod(pyIns, "add", "ii", 5, 6); // 调用tester.add方法,传入2个int型参数 int ok = -1; int retok = PyArg_Parse(pyRet, "i", &ok); // 从返回值从取出int型返回值 Py_Finalize(); system("pause"); }
整个过程最重要的是 PyBoject_CallMethod,传入的参数类型一定不能搞错。
还有取返回值的时候PyArg_Parse取单个返回值,要是取多个的可以用PyArg_ParseTuple,要取的类型也必须完全匹配。
c++调用python时参数传递和返回值解析
通过python接口在cpp中调用python函数时,构建传参和解析返回值都会用到python内的变量类型和c++的变量类型之间的转换。
返回值是numpy等复杂结构的数据时,可以通过先转换为list等类型再返回,或者单独构建一个函数,获取numpy内某个位置的变量的函数。
下面几个基础类型的返回值解析
#python #返回一个参数 def returnInt(a,b): return a+b #返回两个相同类型的参数 def returnTwoInt(): return 1,2 #返回字符串 def returnString(): srt = 'hello world' return srt #返回list def returnList(): para = [1, 2, 3, 4] return 1,para.tolist() #返回两个不同类型的参数 def returnTwo(): para = [1, 2, 3, 4] return 1,para.tolist() #返回矩阵 def returnMat(): img = cv2.imread('test1.bmp',cv2.IMREAD_GRAYSCALE) return img
//调用python函数,返回的数据统一为PyObject类型,需要根据实际类型进行解析 PyObject* pReturn = PyObject_CallObject(pFunc, pArgs); //当不需要传参时,可以将参数位置为空 PyObject* pReturn = PyObject_CallObject(pFunc,NULL);
PyObject为结构体,参数ob_type->tp_name 为数据的类型
//不同类型参数传递 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 两个不同类型的参数 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; } //返回单独一个变量 //构建输入 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; //返回多个变量 //循环解析 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; //解析二维矩阵 //获得序列长度,即行数 Py_ssize_t rsize = PyObject_Size(pReturn); std::cout << rsize << std::endl; //转换到迭代器,用于提取数据 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 } //获得当前行的数据数量 Py_ssize_t foosize = PyObject_Size(next); std::cout << foosize << std::endl; //转换到迭代器,用于获取数据 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
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
最新评论