Python/CAPI简介
通过C++调用Python脚本主要要用到如下的一些Python提供的API,因为实际上C++要调用的是Python的解释器,而Python解释器本质就是实现在动态链接库里面的,因此在调用前和调用后要进行一些初始化和资源释放的工作,另外,要调用Python脚本里面的函数等等东西,需要Python提供的一些特殊API来包装C++调用。
void Py_Initialize(void)
初始化Python解释器,如果初始化失败,继续下面的调用会出现各种错误,可惜的是此函数没有返回值来判断是否初始化成功,如果失败会导致致命错误。
int Py_IsInitialized(void)
检查是否已经进行了初始化,如果返回0,表示没有进行过初始化。
void Py_Finalize()
反初始化Python解释器,包括子解释器,调用此函数同时会释放Python解释器所占用的资源。
*int PyRun_SimpleString(const char command)
实际上是一个宏,执行一段Python代码。
PyObject PyImport_ImportModule(char name)
导入一个Python模块,参数name可以是*.py文件的文件名。类似Python内建函数import。
PyObject PyModule_GetDict( PyObject module)
相当于Python模块对象的__dict__*属性,得到模块名称空间下的字典对象。
PyObject PyRun_String(const char str, int start,PyObject* globals, PyObject* locals)**
执行一段Python代码。
int PyArg_Parse(PyObject args, char format, …)**
把Python数据类型解析为C的类型,这样C程序中才可以使用Python里面的数据。
PyObject PyObject_GetAttrString(PyObject o, charattr_name)*
返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name。
PyObject Py_BuildValue(char format, …)**
和PyArg_Parse刚好相反,构建一个参数列表,把C类型转换为Python对象,使得Python里面可以使用C类型数据。
PyObject PyEval_CallObject(PyObject pfunc, PyObject*pargs)**
此函数有两个参数,而且都是Python对象指针,其中pfunc是要调用的Python 函数,一般说来可以使用PyObject_GetAttrString()获得,pargs是函数的参数列表,通常是使用Py_BuildValue()来构建。
由于注释很详细我就直接贴代码了
/*
* 该函数传递参数都是字符串
*parmcount:python函数参数个数,也就是最后多参个数
* pythonPath:python 模块路径
* modulName:模块名
* functionName: python 函数名
* ... : 多参数,python 函数参数
*/
int MainWindow::runPythonFunction(int parmsCount,const char *pythonPath,const char *modulName,const char *functionName,...){
//初始化,载入python的扩展模块
Py_Initialize();
//判断初始化是否成功
if(!Py_IsInitialized())
{
cout<<("Python init failed!\n")<<endl;
return -1;
}
cout<<"before PATH:";
PyRun_SimpleString("import os");
PyRun_SimpleString("print os.getcwd()");
cout<<endl;
// PyRun_SimpleString("print 'hello python'");//直接运行python代码
//PyRun_SimpleString 为宏,执行一段python代码
//导入当前路径
// PyRun_SimpleString("import sys");
// PyRun_SimpleString("sys.path.append('./')");
//一定要设置python 脚本所在路径不然根本找不到模块
string pat = pythonPath;
string runPath = "os.chdir('" +pat +"')";
cout<<runPath<<endl;
char path[1024] ;
strcpy(path,runPath.c_str());
PyRun_SimpleString(path);
// PyRun_SimpleString("os.chdir('/Users/systudiosy/Documents/BOB_work/IOS_archive')");
cout<<"after PATH:";
PyRun_SimpleString("import os");
PyRun_SimpleString("print os.getcwd()");
cout<<endl;
cout<<"导入路径"<<endl;
PyObject *pName = NULL;
PyObject *pModule = NULL;
PyObject *pDict = NULL;
PyObject *pFunc = NULL;
PyObject *pArgs = NULL;
//加载名为test的python脚本,引入模块
pName = PyString_FromString(modulName);
pModule = PyImport_Import(pName);
// pModule = PyImport_ImportModule("TestDef");//引入模块
if(!pModule)
{
cout<<("Load TestDef.py failed!\n")<<endl;
getchar();
return -1;
}
cout<<"load python file"<<endl;
pDict = PyModule_GetDict(pModule);
if(!pDict)
{
cout<<("Can't find dict in TestDef!\n")<<endl;
return -1;
}else {
cout<<("find dict in TestDef!\n")<<endl;
}
//获取函数为调用函数做准备
pFunc = PyDict_GetItemString(pDict,functionName);
// pFunc = PyObject_GetAttrString(pModule,"add");
if(!pFunc || !PyCallable_Check(pFunc))
{
cout<<("Can't find function!\n")<<endl;;
getchar();
return -1;
}
cout<<"get python function"<<endl;
int parmscount = parmsCount;
/*
向Python传参数是以元组(tuple)的方式传过去的,
因此我们实际上就是构造一个合适的Python元组就
可以了,要用到PyTuple_New,Py_BuildValue,PyTuple_SetItem等几个函数
*/
pArgs = PyTuple_New(parmscount);
// PyObject* Py_BuildValue(char *format, ...)
// 把C++的变量转换成一个Python对象。当需要从
// C++传递变量到Python时,就会使用这个函数。此函数
// 有点类似C的printf,但格式不同。常用的格式有
// s 表示字符串,
// i 表示整型变量, 如Py_BuildValue("ii",123,456)
// f 表示浮点数,
// O 表示一个Python对象
// PyTuple_SetItem(pArgs,0,Py_BuildValue("i",123));
// PyTuple_SetItem(pArgs,1,Py_BuildValue("i",321));
// //调用python的add函数
// PyObject *obj = PyObject_CallObject(pFunc,pArgs);
va_list ap;
va_start(ap, functionName);
// vprintf(functionName, ap);
// cout<<ap<<"---------"<<functionName<<endl;
char * tempValue=0 ;
char* parms[5];
int count =0;
//参数存储
for(int i=0;i<parmscount;i++){
tempValue=va_arg(ap,char*);
count = count+1;
parms[i] = tempValue;
cout<<"ARG-->"<<tempValue<<endl;
// tempValue=va_arg(ap,char*);
// count = count+1;
// cout<<"ARG-->"<<tempValue<<endl;
// }while (tempValue!=0);
}
for(int j = 0;j<parmscount;j++){
cout<<(parms[j])<<endl;
}
//参数配置
cout<<count<<endl;
va_end(ap);
PyObject *pArg = 0;
if(parmsCount==5){
pArg = Py_BuildValue("(s, s,s,s,s)", parms[0], parms[1], parms[2], parms[3], parms[4]);
}else if(parmsCount==4){
pArg = Py_BuildValue("(s, s,s,s)", parms[0], parms[1], parms[2], parms[3]);
}else if(parmsCount==3){
pArg = Py_BuildValue("(s, s,s)", parms[0], parms[1], parms[2]);
}else if(parmsCount==2){
pArg = Py_BuildValue("(s, s)", parms[0], parms[1]);
}else if(parmsCount==1){
pArg = Py_BuildValue("(s)", parms[0]);
}else if(parmsCount==0){
pArg = NULL;
}
//调用两个参数
// PyObject *pArg = Py_BuildValue("(i, i)", 1, 2); //参数类型转换,传递两个整型参数
PyObject*result = PyEval_CallObject(pFunc, pArg); //调用函数,并得到python类型的返回值
if(!result){
cout<<"use function failed"<<endl;
return -1;
}else{
cout<<"use function success"<<endl;
}
int sum;
PyArg_Parse(result, "i", &sum); //将python类型的返回值转换为c/c++类型
cout<<("sum=")<<sum<<endl;
//清理python对象
if(pName)
{
Py_DECREF(pName);
}
if(pArgs)
{
Py_DECREF(pArgs);
}
if(pModule)
{
Py_DECREF(pModule);
}
//关闭python调用
Py_Finalize();
return 1;
}