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++可變參數