1. 程式人生 > >“探坑”——在C++中執行python指令碼的艱辛嘗試

“探坑”——在C++中執行python指令碼的艱辛嘗試

之前的一篇部落格提到,喵哥打算用C++呼叫python,然後在python中執行powershell,但是在初次嘗試後,喵哥發現這不是一個簡單的工作,有很多坑需要注意!此篇文章主要圍繞如何在C++中呼叫python(windows10)來陳述喵哥遇到的一些初學者需要留心的地方。

在VS2013中配置python環境

跟大部分環境配置差不多,主要是在專案里加入標頭檔案和庫檔案。需要注意的是VS的專案的位數要跟python一致,不然會出現“無法解析的外部符號”。

1.新增標頭檔案(.h)和庫檔案(.lib)的路徑

 在“VC++目錄”下的包含目錄和庫目錄分別輸入對應python的標頭檔案和庫檔案路徑,喵哥用的是Anaconda管理python,所以不能按照這個找路徑。通常,只要在python直譯器(python.exe)根目錄下找到“include”和“libs”資料夾即可。

2.新增所需要的庫檔案——.lib和.dll

在上述庫檔案路徑下找到python27.lib,複製全稱到上圖的附加依賴項中,然後在python直譯器的路徑下找到python27.dll,複製這個檔案到VS解決方案生成的可執行檔案路徑下(需要生成解決方案才有這個路徑)。

3.檢查系統環境變數中有無PYTHONHOME變數

檢查系統環境變數有無PYTHONHOME變數,並且這個變數對應的值應該是對應python直譯器的路徑。不然會執行程式碼出錯,雖然可能沒有錯誤顯示。不過一般來說,只要是直接安裝python的話,都有這個變數的。喵哥用的是Anaconda,所以得自己新增。

4.修改python裡的一個頭檔案

通常需要修改的標頭檔案是pyconfig.h,因為在這個標頭檔案裡有這麼一行程式碼:

#	ifdef _DEBUG

#				pragma comment(lib,"python27_d.lib")
#			else
#				pragma comment(lib,"python27.lib")
#			endif /* _DEBUG */

應該是在Debug時,讀取python27_d.lib,而在release時,讀取python27.lib,python給的只有python27.lib,按理說,只要用release就可以正常執行,但是喵哥遇到的情況是:在release下,還是第一句程式碼有效。。。所以有誰遇到這樣的情況(提示找不到python27_d.lib)不要著急,自己手動修改標頭檔案就好,都改成python27.lib。

另外,喵哥在實際運用中還遇到一些標頭檔案對某些變數重定義的情況,這些基本都是修改標頭檔案,記得標註就好了。

5.例項

python,1.py:

def add(a,b):
    print ("in python function add")
    print ("a = " + str(a))
    print ("b = " + str(b))
    print ("ret = " + str(a+b))
    return

C++:

#include "stdafx.h"
#include "Python.h"

int _tmain(int argc, _TCHAR* argv[])
{
	
	// 初始化Python
	//在使用Python系統前,必須使用Py_Initialize對其
	//進行初始化。它會載入Python的內建模組並新增系統路
	//徑到模組搜尋路徑中。這個函式沒有返回值,檢查系統
	//是否初始化成功需要使用Py_IsInitialized。
	Py_Initialize();
	// 檢查初始化是否成功
	if (!Py_IsInitialized())
	{
		return -1;
	}
	// 添加當前路徑
	//把輸入的字串作為Python程式碼直接執行,返回0
	//表示成功,-1表示有錯。大多時候錯誤都是因為字串
	//中有語法錯誤。
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");
	PyRun_SimpleString("import subprocess");
	PyObject *pName, *pModule, *pDict, *pFunc, *pArgs;
	// 載入名為1的指令碼
	pName = PyString_FromString("1");
	pModule = PyImport_Import(pName);
	if (!pModule)
	{
		printf("can't find 1.py");
		getchar();
		return -1;
	}
	pDict = PyModule_GetDict(pModule);
	if (!pDict)
	{
		return -1;
	}
	// 找出函式名為add的函式
	pFunc = PyDict_GetItemString(pDict, "add");
	if (!pFunc || !PyCallable_Check(pFunc))
	{
		printf("can't find function [add]");
		getchar();
		return -1;
	}
	// 引數進棧
	pArgs = PyTuple_New(2);
	//  PyObject* Py_BuildValue(char *format, ...)
	//  把C++的變數轉換成一個Python物件。當需要從
	//  C++傳遞變數到Python時,就會使用這個函式。此函式
	//  有點類似C的printf,但格式不同。常用的格式有
	//  s 表示字串,
	//  i 表示整型變數,
	//  f 表示浮點數,
	//  O 表示一個Python物件。
	PyTuple_SetItem(pArgs, 0, Py_BuildValue("l", 3));  //"l" (integer) [long int] :將C型別的long轉換成Pyhon中的int物件。
	PyTuple_SetItem(pArgs, 1, Py_BuildValue("l", 4));
	// 呼叫Python函式
	PyObject_CallObject(pFunc, pArgs);
	
	//pFunc = PyDict_GetItemString(pDict, "redis");
	//pArgs = PyTuple_New(1);
	//PyTuple_SetItem(pArgs, 0, Py_BuildValue("")); //
	//PyObject_CallObject(pFunc, pArgs);
	Py_DECREF(pName);
	Py_DECREF(pArgs);
	Py_DECREF(pModule);
	// 關閉Python
	Py_Finalize();

	return 0;
}