1. 程式人生 > >C++呼叫python程式碼

C++呼叫python程式碼

【需求】:使用c++呼叫python中sklearn包的SVM,訓練+識別。
【需要解決的問題】:相關的環境配置,c++與python資料型別的互轉,不安裝python的環境下執行。

【測試用的python包】:python2.7.14-32位
【測試用的vs工程】:debug 32位

【步驟】:(具體的示例,在這裡
1. 先配置VS的專案屬性,一個是包含目錄,一個是庫目錄。
包含目錄新增python根目錄下的include資料夾;庫目錄新增python根目錄下的Lib資料夾。
lib資料夾裡放【python27.lib檔案】和【python27_d.lib檔案】,我現在debug32位下用的就是【python27_d.lib檔案】。

2. 把【python27.dll檔案】和C++要呼叫的【.py檔案】都放到工程下debug資料夾下,也就是跟【.exe檔案】相同目錄下。
當前還有python環境時,【python27.dll檔案】在你安裝python後的C盤windows\SysWOW64資料夾下。

3. 在vs環境下除錯時,需要將Python27資料夾放到呼叫python程式碼的【.cpp檔案】同目錄中;在軟體釋出後執行時,Python27資料夾放到【.exe檔案】相同目錄下。

4. C++的程式碼中新增Python.h標頭檔案。

【使用的幾個API函式】:
1. Py_SetPythonHome( "路徑")
    設定執行py檔案時,搜尋依賴檔案的路徑。
2. Py_Initialize( )和Py_Finalize( )
    成對兒出現,用在呼叫python的頭尾。
3. PyImport_ImportModule("py的檔名")
    純檔名,不包含".py"這幾個字元,返回一個PyObject型別的指標,例如拿PyObject* pModule接收返回值。
4. PyObject_GetAttrString(pModule, "wcyaaa")
    拿到python中函式的索引,上面的pModule放到第一個引數,表示從這個py檔案裡取資料;後面第二個引數是要呼叫的python函式的函式名。
    返回一個PyObject型別的指標,例如拿PyObject* pFunc接收返回值。
5. PyEval_CallObject(pFunc, NULL)

    呼叫pFunc對應的那個python中的函式,上面的pFunc放到第一個引數,表示呼叫這個函式;後面第二個引數是要傳入python函式的引數。這裡呼叫的是無參的函式,就填NULL。
    返回的內容為python函式的返回值,型別仍是PyObject*。
6. PyTuple_New(引數個數)
    如果需要傳引數到python函式中,那這裡就將“傳參個數”設定成對應的數量。傳元組就類似C++中的const,不能改。
    返回值同樣是PyObject型別的指標,例如拿PyObject *pArgs接收返回值。

7. PyTuple_SetItem(pArgs, 0, variable)
    第一個引數就是負責傳遞引數的管道,也就是那個元組;第二個引數是這個元組中的第幾個元素;第三個引數是要放入元組對應位置的資料(這個需要是
PyObject *)。
    呼叫函式傳參時,就這麼寫:PyEval_CallObject(pFunc, pArgs)
8. Py_BuildValue("i",variable)
    將C++的資料結構轉成python的資料結構。第一個引數是格式設定,第二個引數是待轉換的C++變數。
9. PyArg_Parse(pVal, "i", &result)
    將python的資料結構轉換成C++的資料結構。第一個引數是接收的python函式的返回值;第二個引數是引數設定;第三個引數是用來接收轉換後C++型別的資料。

【不安裝python環境執行】:
在執行python程式之前,也就是Py_Initialize( )之前呼叫一下Py_SetPythonHome( "路徑"),把搜尋依賴檔案的路徑設定成Python27資料夾的路徑,就ok了。

示例程式碼裡面有很多不足:
比如構造二維巢狀的list時,直接粗暴的13個值塞進去了,其實可以分層來造;