C++調用Python的API總結
5 人贊了文章
最近在做C++調Python的work,簡單總結下
(一) 初始化和關閉Python解釋器
#include<Python.h>
Py_Initialize();
…
Py_Finalize();
所有的Python程序都要在這之間執行
(二)load Python模塊
又分為以下兩種方式
(1) 直接Load一個Python寫好的文件(假設文件名叫pytest.py, 在當前目錄下)
PyObject *pName,*pModule;
PyRun_SimpleString("import sys");//導入系統模塊
PyRun_SimpleString("sys.path.append(./)");//指定pytest.py所在的目錄
pName = PyString_FromString("pytest");//指定要導入的文件名
pModule = PyImport_Import(pName); //將pytest.py導入模塊指針pModule
(2) Load一個已經安裝好的Python模塊 (假設模塊名叫pytest)
PyObject* pModule;
pModule = PyImport_Import(PyString_FromString(「ptest」));//將pytest導入模塊指針pModule
(三) 從pModule模塊里load需要調用的函數並執行
又分為以下兩種方式
(1) 從模塊里直接load一個函數(假設函數名叫func, 有一個int型的輸入變數,返回一個int型整數)
PyObject *pfunc, *args, *results;
Pfunc= PyObject_GetAttrString(pModule,"func"); //pModule是上一步load好的Python模塊
args = Py_BuildValue("(i)",12345);//設置調用func時的輸入變數,這裡假設為12345
results= PyObject_CallObject(Pfunc, args);//執行func(12345),並將結果返回給results
(2) 從模塊里load一個類,然後調用類內部的函數 (假設類名叫Executor, 初始化需要當前文件夾下的配置文件config.txt, 函數名叫func)
PyObject *pClass, *pDict,*pInstance, *class_args,*results;
pDict = PyModule_GetDict(pModule); //拿到pModule里的所有類和函數定義
pClass=PyDict_GetItemString(pDict,"Executor");//找到名為Executor的類
class_args =Py_BuildValue("(s)","./config.txt"); //設置類初始化需要的參數
pInstance=PyInstance_New(pClass, class_args,NULL ); //初始化Executor,建立實例pInstance
results=PyObject_CallMethod(pInstance,"func","(i)",12345);// 執行pInstance.func(12345)
(四) C++向Python傳遞參數
因為在Python中,所有的類型都經過了一層封裝,導致C++的參數需要做一個類型轉換,轉換成PyObject*才能傳入Python。例如C++的一個int就是個整數,該值佔用8bytes(64位)的存儲空間,而一個Python的int其實是一個PyObject* 指向的24bytes的結構。前8bytes是個整數,代表引用次數,中間8bytes是個指向int類型定義的指針,最後8bytes才是這個int的值。所以C++和Python之間參數的互相傳遞都需要調用Python提供的API。
假設函數的輸入變數有三個分別為一個整數(i),一個浮點數(f)和一個字元串(s)
PyObject* args = PyTuple_New(3);
PyObject* arg1 = Py_BuildValue("i",100); // 整數參數
PyObject* arg2 =Py_BuildValue("f", 3.14); // 浮點數參數
PyObject* arg3 =Py_BuildValue("s", "hello"); // 字元串參數
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
PyTuple_SetItem(args, 2, arg3);
以上函數可簡化為
PyObject* args = Py_BuildValue("(ifs)",100, 3.14, "hello");
如果輸入參數是另一個Python函數的輸出結果PyObject* results (o)
PyObject* args = Py_BuildValue("(o)",results);
具體參數格式Parsing arguments and building values
(五) 解析Python的返回值PyObject*results
同C++傳遞參數到Python類似,調用解析函數
單個返回值:PyArg_Parse()
多返回值:PyArg_ParseTuple()
具體例子:1.7 Format Strings for PyArg_ParseTuple()
(六) 編譯執行
假設寫好的文件名為example_python.cpp, 想要編譯出的可執行文件叫Test, 可用命令
g++example_python.cpp -o Test -I/usr/include/python2.7/ -lpython2.7
推薦閱讀:
※50多種適合機器學習和預測應用的API,你的選擇是?(2018年版本)
※Mapbox 現向所有新註冊用戶開放免費API!
※什麼是好用的 API 文檔
※用Nodejs,GraphQL,MongoDB,Hapi和Swagger構建強大的API(一)