天天看點

關于 C++ 調用 python 詳情

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

C++可變參數