在编写项目的过程中,需要在c++下调用一个python模块,现在将方法整理一下,留存备用。
首先需要导入对应的头文件 :
#include <python2.7/Python.h>
接下来是代码实现部分:
//初始化python运行环境
Py_Initialize();
//将python的执行目录切换到当前目录下
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
//定义一些需要使用到的变量
PyObject* pModule = NULL;
PyObject* pFunc = NULL;
PyObject* pParam = NULL;
//这里由于我的python方法返回值是一个比较复杂的结果,所以我定义了很多result变量用于处理返回值
PyObject* pResult = NULL;//接收最外层的结果
PyObject* pSingleResult = NULL;//拆分最外层结果为单条结果
PyObject* pSingleResult_Content = NULL;//取单条结果的LIST的某个字段
PyObject* pResultCodeStr = NULL;//取单条结果的检测代码List的某个字段
const char* pBuffer = NULL;
int iResult = 0;
//导入py文件
pModule = PyImport_ImportModule("文件名(不需要带后缀.py)");
if (!pModule) {
exit (0);
}
//根据函数名,取出python文件中函数,后面将会有调用这个函数的时候
pFunc = PyObject_GetAttrString(pModule, "函数名(不需要带参数列表,也不要加括号)");
if (!pFunc){ // || !PyCallable_Check(pFunc)
exit (0);
}
//生成一个参数变量
//第一个参数为变量类型
// s 表示字符串,
// i 表示整型变量,
// f 表示浮点数,
// O 表示一个Python对象。
//支持一个生成多个对象
//例如: pArgs = Py_BuildValue("ii", 12, 14);
pParam = Py_BuildValue("(ss)", htmlCode.c_str(),rules.c_str());
//使用刚才取出来的函数对象,调用函数,传递刚建立的参数对象,并接收返回值
pResult = PyEval_CallObject(pFunc,pParam);
// PyArg_Parse 把python对象,按照第二个参数的类型取出来,保存至第三个变量中。第二个参数是拆分出来的类型,后面跟着的是赋值的对象
// PyList_Size 获取python中list的长度(对象个数)
//PyList_GetItem(python List对象,对象的index值,从0开始) 即取出list中的某个元素
if(pResult)
{
iResult = PyList_Size(pResult);
for(int i=0;i<iResult;i++){
//yaraResult 是我自己定义的一个类,用于将python的返回值保存为方便使用的格式
yaraResult yaraRet;
pSingleResult = PyList_GetItem(pResult,i);
//接下来的操作都是用于取出Python的结果值,因为返回值是不断嵌套的list 和 set ,会比较麻烦
pSingleResult_Content = PyList_GetItem(pSingleResult,4);
if(PyArg_Parse(pSingleResult_Content, "s", &pBuffer)){
yaraRet.name = pBuffer;
}
//
pSingleResult_Content = PyList_GetItem(pSingleResult,1);
if(PyArg_Parse(pSingleResult_Content, "(s)", &pBuffer))
yaraRet.flawname = pBuffer;
//
pSingleResult_Content = PyList_GetItem(pSingleResult,2);
int iStrCount = PyList_Size(pSingleResult_Content);
for(int j=0;j<iStrCount;j++){
pResultCodeStr = PyList_GetItem(pSingleResult_Content,j);
if(PyArg_Parse(pResultCodeStr, "s", &pBuffer))
yaraRet.flawCode = yaraRet.flawCode + ' ' + pBuffer;
}//end_for_PyList_Size(pCheckResultStr);
result.push_back(yaraRet);
}//end_for_PyList_Size(pResult)
}//end_if_if(pResult)
//使用结束后,释放掉这些Python对象
if(pModule)
Py_DECREF(pModule);
if(pFunc)
Py_DECREF(pFunc);
if(pParam)
Py_DECREF(pParam);
if(pResult)
Py_DECREF(pResult);
if(pSingleResult)
Py_DECREF(pSingleResult);
if(pSingleResult_Content)
Py_DECREF(pSingleResult_Content);
if(pResultCodeStr)
Py_DECREF(pResultCodeStr);
//结束掉python的运行环境
Py_Finalize();
return result;
}
在使用过程中,发现了 PyArg_Parse 的一个特殊的地方。
PyArg_Parse(pResult ,"s", &pBuffer))
PyArg_Parse(pResult, "(s)", &pBuffer))
这两种取值方式是不同的。
第一种方式是将python对象直接强制转换成字符串类型,然后输出
第二种方式是将python对象看作是一个set,然后取出这个set的值,作为字符串输出。
因此有时候,在使用PyArg_Parse的时候可能没法正确的取出值,这个时候可以考虑一下是不是参数的设置问题。