1. 程式人生 > >混合程式設計之——C++呼叫python2.7&python3.5

混合程式設計之——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