1. 程式人生 > >淺析 C++ 呼叫 Python 模組

淺析 C++ 呼叫 Python 模組

淺析 C++ 呼叫 Python 模組

作為一種膠水語言,Python 能夠很容易地呼叫 CC++ 等語言,也能夠通過其他語言呼叫 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_AsLongPyFloat_AsDoublePyString_AsString 等。

還可以使用 PyArg_ParseTuple 函式來將返回值作為元組解析。

PyArg_Parse 也是一個使用很方便的轉換函式。

PyArg_ParseTuplePyArg_Parse 都使用 格式字串

注意事項

  1. 需要將 Python 的工作目錄切換到模組所在路徑
  2. 按照模組名載入而不是檔名
  3. 模組載入或者函式載入需要驗證是否成功,否則可能會引起堆疊錯誤導致程式崩潰
  4. 需要使用 Py_DECREF(PyObject*) 來解除物件的引用(以便Python垃圾回收)