淺析 C++ 調用 Python 模塊
作為一種膠水語言,Python 能夠很容易地調用 C 、 C++ 等語言,也能夠通過其他語言調用 Python 的模塊。
Python 提供了 C++ 庫,使得開發者能很方便地從 C++ 程序中調用 Python 模塊。
具體的文檔參考官方指南:
Embedding Python in Another Application
調用方法
1 鏈接到 Python 調用庫
Python 安裝目錄下已經包含頭文件( include
目錄)和庫文件 ( Windows 下為 python27.lib
)。
使用之前需要鏈接到此庫。
2 直接調用 Python 語句
#include "python/Python.h" int main() { Py_Initialize(); ## 初始化 PyRun_SimpleString("print 'hello'"); Py_Finalize(); ## 釋放資源 }
3 加載 Python 模塊並調用函數
~/test
目錄下含有 test.py
:
def test_add(a, b): print 'add ', a, ' and ', b return a+b
則可以通過以下代碼調用 test_add
函數 :
#include "python/Python.h" #include <iostream> using namespace std; int main() { Py_Initialize(); // 初始化 // 將Python工作路徑切換到待調用模塊所在目錄,一定要保證路徑名的正確性 string path = "~/test"; string chdir_cmd = string("sys.path.append(\"") + path + "\")"; const char* cstr_cmd = chdir_cmd.c_str(); PyRun_SimpleString("import sys"); PyRun_SimpleString(cstr_cmd); // 加載模塊 PyObject* moduleName = PyString_FromString("test"); //模塊名,不是文件名 PyObject* pModule = PyImport_Import(moduleName); if (!pModule) // 加載模塊失敗 { cout << "[ERROR] Python get module failed." << endl; return 0; } cout << "[INFO] Python get module succeed." << endl; // 加載函數 PyObject* pv = PyObject_GetAttrString(pModule, "test_add"); if (!pv || !PyCallable_Check(pv)) // 驗證是否加載成功 { cout << "[ERROR] Can't find funftion (test_add)" << endl; return 0; } cout << "[INFO] Get function (test_add) succeed." << endl; // 設置參數 PyObject* args = PyTuple_New(2); // 2個參數 PyObject* arg1 = PyInt_FromLong(4); // 參數一設為4 PyObject* arg2 = PyInt_FromLong(3); // 參數二設為3 PyTuple_SetItem(args, 0, arg1); PyTuple_SetItem(args, 1, arg2); // 調用函數 PyObject* pRet = PyObject_CallObject(pv, args); // 獲取參數 if (pRet) // 驗證是否調用成功 { long result = PyInt_AsLong(pRet); cout << "result:" << result; } Py_Finalize(); ## 釋放資源 return 0; }
參數傳遞
1 C++ 向 Python 傳遞參數
Python 的參數實際上是元組,因此傳參實際上就是構造一個合適的元組。
常用的有兩種方法:
-
使用
PyTuple_New
創建元組,PyTuple_SetItem
設置元組值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);
-
直接使用Py_BuildValue構造元組
PyObject* args = Py_BuildValue("(ifs)", 100, 3.14, "hello"); PyObject* args = Py_BuildValue("()"); // 無參函數
-
i
,s
,f
之類的格式字符串可以參考 格式字符串
2 轉換 Python 返回值
調用 Python 得到的都是PyObject對象,因此需要使用 Python 提供的庫里面的一些函數將返回值轉換為 C++ , 例如 PyInt_AsLong
,PyFloat_AsDouble
, PyString_AsString
等。
還可以使用 PyArg_ParseTuple
函數來將返回值作為元組解析。
PyArg_Parse
也是一個使用很方便的轉換函數。
PyArg_ParseTuple
和 PyArg_Parse
都使用 格式字符串
注意事項
- 需要將 Python 的工作目錄切換到模塊所在路徑
- 按照模塊名加載而不是文件名
- 模塊加載或者函數加載需要驗證是否成功,否則可能會引起堆棧錯誤導致程序崩潰
- 需要使用
Py_DECREF(PyObject*)
來解除對象的引用(以便Python垃圾回收)
http://blog.csdn.net/tobacco5648/article/details/50890106