混合程式設計之——C++呼叫python2.7&python3.5
C++呼叫python (2.7版本)
(Win7_64 + VS2013 + python2.7)由於個人偏好喜歡用python寫程式碼,尤其是資料處理等,最近想試試在VS2013裡,直接呼叫python中的曲線擬合函式。作為小白,由於之前完全沒接觸過,就一直找網上找教程,折騰了2小時總算是搞定了。接下來,為了方便和我一樣的初學者學習,我將具體的配置過程詳細寫下來,寫得不好,還望指教。(一個月後:現在看來,不建議這樣呼叫,個人覺得意義不大,若想學一下,可以繼續瀏覽;否則還是放棄直接多看會兒C++,還是能將python程式碼直接改成C++程式碼的,不用呼叫)
一、 最終結果展示:
以下程式碼是main.cpp
#include <iostream> #include <Python.h> using namespace std; extern "C" { #include "Python.h" } //呼叫輸出"Hello Python"函式 void Hello() { Py_Initialize();//呼叫Py_Initialize()進行初始化 PyObject * pModule = NULL; PyObject * pFunc = NULL; pModule = PyImport_ImportModule("Test001");//呼叫的Python檔名 pFunc = PyObject_GetAttrString(pModule, "Hello");//呼叫的函式名 PyEval_CallObject(pFunc, NULL);//呼叫函式,NULL表示引數為空 Py_Finalize();//呼叫Py_Finalize,和Py_Initialize相對應的. } //呼叫Add函式,傳兩個int型引數 void Add() { Py_Initialize(); PyObject * pModule = NULL; PyObject * pFunc = NULL; pModule = PyImport_ImportModule("Test001");//Test001:Python檔名 pFunc = PyObject_GetAttrString(pModule, "Add");//Add:Python檔案中的函式名 //建立引數: PyObject *pArgs = PyTuple_New(2);//函式呼叫的引數傳遞均是以元組的形式打包的,2表示引數個數 PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 6));//0--序號,i表示建立int型變數 PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 8));//1--序號 //返回值 PyObject *pReturn = NULL; pReturn = PyEval_CallObject(pFunc, pArgs);//呼叫函式 //將返回值轉換為int型別 int result; PyArg_Parse(pReturn, "i", &result);//i表示轉換成int型變數 cout << "6 + 8 = " << result << endl; Py_Finalize(); } int main(int argc, char** argv) { cout << "呼叫Test001.py中的Hello函式..." << endl; Hello(); cout << "\n呼叫Test001.py中的Add函式..." << endl; Add(); system("pause"); return 0; }
接著是呼叫的函式,也就是Test001.py檔案中內容:
def Hello():
print("Hello Python")
def Add(a, b):
return a+b
最後,執行結果如下:
二、環境配置
那麼究竟如何呼叫呢?我的電腦環境:Win7(64位)+anaconda2.4(python2.7.13)+VS2013,其實我習慣用anaconda3.4.2(python3.5),起初用C++去呼叫python3.5,遇到太多的坑,實在不行,按照同樣的方法試了一下python2.7,真的沒問題,欲哭無淚。。。下面我再呼叫一次,具體步驟如下:
1、python2.7的安裝(anaconda2-4.4.0-Windows-x86_64),並配置環境變數(否則報錯no module named sites);
2、將Python加到VS2013的詳細過程:
(1)桌面上新建一個資料夾,如test,再建立一個空的Win32控制檯專案,建立main.cpp儲存test資料夾中,此時的程式碼會報錯,因為還沒匯入python2.7的標頭檔案路徑與庫檔案的路徑;
(2)找到python2.7的安裝路徑:(我的是:D:\python2.7\anaconda2.4),找到路徑下的include與libs兩個資料夾,將libs中的python27.lib複製並更名為python27_d.lib;
(3)x64平臺&python2.7標頭檔案與庫檔案的路徑配置:
X64平臺:生成->配置管理器->新建;
右擊進入屬性設定頁C/C++->常規->附加包含目錄,輸入 D:\python2.7\anaconda2.4\include
再找到連結器->常規->附加目錄項,輸入 D:\python2.7\anaconda2.4\libs
結果如下圖所示:
(4)生成解決方案,顯示:
========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ==========
(5)別激動,先執行,你會發現,報錯啦!!!無法啟動此程式,因為計算機中丟失python27.dll。嘗試重新安裝該程式以解決此問題。怎麼辦呢?
將python安裝路徑下的python27.dll拷貝到桌面test資料夾中的x64資料夾中的Debug目錄下
(如:C:\Users\Zhangwei\Desktop\test\ConsoleApplication1\x64\Debug):
(6)重新生成解決方案,並執行,還是報錯了,氣不氣?如下圖:
(7)之所以報錯,是因為還未新增Test001.py,將該檔案新增到Debug路徑下
(如:C:\Users\Zhangwei\Desktop\test\ConsoleApplication1\x64\Debug):
(8)重新生成解決方案,再次執行,很激動吧,終於成功咯!!!
注意:建議別按照上面的方式更改壞境變數,否則在pycharm中選擇相應的python2.7版本時候,會報錯。
相信走到這裡,C++呼叫python應該是問題不大,至少語法上是沒有問題的,接下來我再說說我遇到的bug:
由於我習慣用python3.5,之前用VS2013呼叫python3.5,若按照上面這一套流程走下來,還是無法執行,真的是心累!我懷疑是anaconda3.4.2(python3.5.2)裡面的libs中的檔案只有三個,是不是有缺失?
後來 經過查詢相關資料,總算是找到了呼叫解決方案,現在總結如下:
C++呼叫python (3.5版本)
VS2013+python3.5
一、最終結果展示
#include <iostream>
#include <Python.h>
using namespace std;
//extern "C"
//{
//#include "Python.h"
//}
// 練習一:如何使用C++呼叫函式python中的引數返回函式?
int great_function_from_python(int a)
{
Py_SetPythonHome(L"C:/Users/Zhangwei/Anaconda3");//配置python3的環境變數
Py_Initialize();
int res;
PyObject *pModule, *pFunc;
PyObject *pArgs, *pValue;
/* import */
//pModule = PyImport_Import(PyString_FromString("great_module"));
pModule = PyImport_ImportModule("great_module");
/* great_module.great_function */
pFunc = PyObject_GetAttrString(pModule, "great_function");
/* build args */
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", a));
/* call */
PyObject *pReturn = NULL;
pReturn = PyEval_CallObject(pFunc, pArgs);
PyArg_Parse(pReturn, "i", &res);//i表示轉換成int型變數
return res;
Py_Finalize();
}
// 練習二:如何使用C++直接執行hello!
void print()
{
Py_SetPythonHome(L"C:/Users/Zhangwei/Anaconda3");//配置python3的環境變數
//Py_SetProgramName(argv[0]);
Py_Initialize();
PyRun_SimpleString("print('Hello Python!')\n");
Py_Finalize();
}
// 練習三:如何使用C++呼叫curveFitting.py中的函式Hello
void Hello() //呼叫輸出"Hello Python"函式
{
Py_SetPythonHome(L"C:/Users/Zhangwei/Anaconda3");//配置python3的環境變數
Py_Initialize();//呼叫Py_Initialize()進行初始化
if (!Py_IsInitialized())
{
printf("初始化失敗!");
}
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
pModule = PyImport_ImportModule("curveFitting");//呼叫的Python檔名
pFunc = PyObject_GetAttrString(pModule, "Hello");//呼叫的函式名
PyEval_CallObject(pFunc, NULL);//呼叫函式,NULL表示引數為空
Py_Finalize();//呼叫Py_Finalize,和Py_Initialize相對應的.
}
//練習四:如何使用C++呼叫curveFitting.py中的函式Add
void Add() //呼叫Add函式,傳兩個int型引數
{
Py_SetPythonHome(L"C:/Users/Zhangwei/Anaconda3");//配置python3的環境變數
//第一步:呼叫Py_Initialize()進行初始化
Py_Initialize();
//檢查初始化是否完成
if (!Py_IsInitialized())
{
printf("初始化失敗!");
}
//py檔案及函式宣告變數
PyObject * pModule = NULL;
PyObject * pFunc = NULL;
//載入
try
{
pModule = PyImport_ImportModule("curveFitting");//curveFitting:Python檔名
}
catch (...)
{
printf("pModule載入異常!");
}
if (pModule == NULL)
{
printf("pModule載入失敗!");
}
pFunc = PyObject_GetAttrString(pModule, "Add");//Add:Python檔案中的函式名
//建立引數:
PyObject *pArgs = PyTuple_New(2);//函式呼叫的引數傳遞均是以元組的形式打包的,2表示引數個數
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 6));//0--序號,i表示建立int型變數
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 8));//1--序號
//返回值
PyObject *pReturn = NULL;
pReturn = PyEval_CallObject(pFunc, pArgs);//呼叫函式
//將返回值轉換為int型別
int result;
PyArg_Parse(pReturn, "i", &result);//i表示轉換成int型變數
cout << "6 + 8 = " << result << endl;
Py_Finalize();
}
int main(int argc, char *argv[]) {
//練習一:
printf("執行結果為:%d\n", great_function_from_python(2));
//練習二
printf("\n");print();
//練習三
printf("\n");
cout << "呼叫curveFitting.py中的Hello函式..." << endl;
Hello();
//練習四
printf("\n");
cout << "\n呼叫curveFitting.py中的Add函式..." << endl;
Add();
system("pause");
return 0;
最後的執行結果如下:二、環境配置
如果試過第一種方法的朋友會發現,直接更改系統環境變數,會導致原本的python2.7執行始終報錯。以python3.5為例:需要單獨將anaconda3下面的,include資料夾裡面的標頭檔案、libs資料夾裡面的庫函式,以及python35.dll(動態連結庫檔案)都單獨拷貝出來,至於怎麼設定,怎麼放,咱們慢慢來。
1、桌面新建一個資料夾,取名為test_python35;
2、將anaconda3下面的,include資料夾、libs資料夾都拷貝到test_python35資料夾中;
3、開啟VS2013,新建一個專案,選好路徑,桌面的資料夾test_python35裡面的內容如下:
4、新建一個main函式如上展示圖所示,接下來需要配置環境變數
(1)新增標頭檔案
(2)新增庫檔案
(3)程式碼中配置python3的環境變數
Py_SetPythonHome(L"C:/Users/Zhangwei/Anaconda3");//配置python3的環境變數
5、生成解決方案,不會報錯,但肯定沒有結果,因為還沒有新增動態連結庫檔案呼叫的python原函式。具體做法:在生成的Debug路徑下新增python35.dll(anaconda3的安裝路徑裡面有)、呼叫的python原函式(curveFitting.py與great_module.py),如下圖所示
6、重新生成解決方案,再次執行即可,於是便得到了最開始的結果圖。
三、C++呼叫python的程式碼解讀
這部分多查閱相關檔案,很快就能上手的 ,具體就不說了,網上一大把,最後祝大家學業有成。
PS:以上程式碼已打包,下載連結為C++呼叫python3.5或者http://download.csdn.net/download/zichen_ziqi/10236034。
參考文獻
1. C++呼叫python例項:http://blog.csdn.net/u012983289/article/details/55194714
2. VS平臺簡單實用C++呼叫python3.5的方法:http://blog.csdn.net/polley88/article/details/54971560
3. python例項淺談三之C++與python相互呼叫: http://blog.csdn.net/taiyang1987912/article/details/44779719
4. C++呼叫python3:http://blog.csdn.net/lisy14/article/details/64498796
5. C++呼叫python3:http://blog.csdn.net/u014794992/article/details/52901219