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;
}