C語言中程序如何調(diào)用Python腳本
有時候在寫C語言程序的時候又想利用一下python強(qiáng)大的模塊,于是C與python的混合編程便應(yīng)運(yùn)而生。
下面簡單說說在C語言編譯環(huán)境中調(diào)用python腳本文件的基礎(chǔ)應(yīng)用。
一、環(huán)境配置
以vs2017為例。
0x00 平臺
首先你要知道你電腦上安裝的python環(huán)境是64位還是32位,vs的編譯平臺需要與python環(huán)境一致。
比如我的python環(huán)境是64位,vs工程就要配置成x64。
右鍵點(diǎn)擊你的解決方案,點(diǎn)擊屬性,
0x01 添加 包含目錄 和 庫目錄
在屬性窗口雙擊“VC++ Directories”(VC++目錄),把在Include Directories (包含目錄)和 Library Directories(庫目錄)下添加python安裝路徑下的include和ibs文件夾的路徑。
0x02 添加依賴項(xiàng)
在添加之前一定要先確保自己安裝了python的debug版本,詳見我的另一篇博客【VS2017】“LNK1104 cannot open file ‘python39_d.lib‘
雙擊“l(fā)inker”(鏈接器)下的“Input”,添加python39_d.lib這個依賴項(xiàng)
點(diǎn)擊確定則配置完成。
這樣在寫程序的時候添加Python.h頭文件就不會報錯,python39_d.lib里的API函數(shù)也就可以正常使用了。
二、案例
主要流程就是:
- 初始化python
- 導(dǎo)入py腳本(模塊)
- 獲取模塊里的函數(shù)
- 必要的C語言數(shù)據(jù)類型轉(zhuǎn)python的數(shù)據(jù)類型(傳參前)
- 調(diào)用函數(shù)
- 釋放python
#include<stdio.h> #include <Python.h> int main() { PyObject *pName, *pModule, *pDict, *pFunc; PyObject *pArgs, *pValue; //待傳參數(shù) int time[6]={1,2,3,4,5,6}; //初始化python Py_Initialize(); // 檢查初始化是否成功 if (!Py_IsInitialized()) { printf("初始化失敗\n"); Py_Finalize(); } //設(shè)置python模塊,搜尋位置,文件放在.c文件一起 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')"); //獲取python文件名,導(dǎo)入模塊(我這里的py文件是graph.py) pModule = PyImport_ImportModule("graph"); if (!pModule) { printf("py文件導(dǎo)入失敗\n"); Py_Finalize(); } else { //直接獲取模塊中的函數(shù) pFunc = PyObject_GetAttrString(pModule, "create_graph"); //驗(yàn)證函數(shù)是否獲取成功 if (!pFunc) { printf("函數(shù)導(dǎo)入失敗\n"); Py_Finalize(); } //將c/c++類型數(shù)據(jù)轉(zhuǎn)換為python類型,利用元組傳遞 pArgs = PyTuple_New(6); pValue = PyLong_FromLong(time[0]); PyTuple_SetItem(pArgs, 0, pValue); pValue = PyLong_FromLong(time[1]); PyTuple_SetItem(pArgs, 1, pValue); pValue = PyLong_FromLong(time[2]); PyTuple_SetItem(pArgs, 2, pValue); pValue = PyLong_FromLong(time[3]); PyTuple_SetItem(pArgs, 3, pValue); pValue = PyLong_FromLong(time[4]); PyTuple_SetItem(pArgs, 4, pValue); pValue = PyLong_FromLong(time[5]); PyTuple_SetItem(pArgs, 5, pValue); //調(diào)用直接獲得的函數(shù),并傳遞參數(shù) pValue = PyObject_CallObject(pFunc, pArgs); //釋放python Py_Finalize(); printf("success"); return 0; } }
順便給出我的graph.py的腳本,這是一個以參數(shù)的數(shù)值生成對應(yīng)的excel文件的腳本,這兩個源代碼是根據(jù)我的另一篇關(guān)于排序算法的博文改的案例。
# -*- coding:utf-8 -*- import xlsxwriter def create_graph(a,b,c,d,e,f): # 創(chuàng)建一個excel workbook = xlsxwriter.Workbook("排序算法比較結(jié)果.xlsx") # 創(chuàng)建一個sheet worksheet = workbook.add_worksheet() # worksheet = workbook.add_worksheet("bug_analysis") # 自定義樣式,加粗 bold = workbook.add_format({'bold': 1}) # --------1、準(zhǔn)備數(shù)據(jù)并寫入excel--------------- # 向excel中寫入數(shù)據(jù),建立圖標(biāo)時要用到 headings = ["排序方法", "排序時間"] data = [["簡單選擇排序", "直接插入排序", "冒泡排序", "快速排序", "兩路合并排序", "堆排序"],[a,b,c,d,e,f]] # 寫入表頭 worksheet.write_row('A1', headings, bold) # 寫入數(shù)據(jù) worksheet.write_column('A2', data[0]) worksheet.write_column('B2', data[1]) # --------2、生成圖表并插入到excel--------------- # 創(chuàng)建一個柱狀圖(column chart) chart_col = workbook.add_chart({'type': 'column'}) # 配置第一個系列數(shù)據(jù) chart_col.add_series({'name': '=Sheet1!$B$1','categories': '=Sheet1!$A$2:$A$7','values': '=Sheet1!$B$2:$B$7','line': {'color': 'red'},}) # 這里的sheet1是默認(rèn)的值,因?yàn)槲覀冊谛陆╯heet時沒有指定sheet名 # 如果我們新建sheet時設(shè)置了sheet名,這里就要設(shè)置成相應(yīng)的值 # 設(shè)置圖表的title 和 x,y軸信息 chart_col.set_title({'name': "排序算法結(jié)果"}) chart_col.set_x_axis({'name': "排序方法"}) chart_col.set_y_axis({'name': "花費(fèi)時間(ms)"}) # 設(shè)置圖表的風(fēng)格 chart_col.set_style(1) # 把圖表插入到worksheet以及偏移 worksheet.insert_chart('A10', chart_col, {'x_offset': 25, 'y_offset': 10}) workbook.close() return 0 if __name__=="__main__": create_graph(10, 40, 50, 20, 10, 50)
三、常用API
1、運(yùn)行Python指令
PyRun_SimpleString("print(os.getcwd(),a)"); pyext.eval(R"(a+='qwer')");
2、加載Python模塊
PyObject * pModule =PyImport_ImportModule("tp"); //test:Python文件名,若腳本有錯則返回空 PyRun_SimpleString("import os");
3、給Python的變量賦值
對于數(shù)值,使用Py_BuildValue:
Py_BuildValue("") None Py_BuildValue("i", 123) 123 Py_BuildValue("iii", 123, 456, 789) (123, 456, 789) Py_BuildValue("s", "hello") 'hello' Py_BuildValue("ss", "hello", "world") ('hello', 'world') Py_BuildValue("s#", "hello", 4) 'hell' Py_BuildValue("()") () Py_BuildValue("(i)", 123) (123,) Py_BuildValue("(ii)", 123, 456) (123, 456) Py_BuildValue("(i,i)", 123, 456) (123, 456) Py_BuildValue("[i,i]", 123, 456) [123, 456] Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}
對于其他數(shù)據(jù)結(jié)構(gòu),使用相應(yīng)的函數(shù)設(shè)置,例如:
PyObject *pArgs = PyTuple_New(1); PyObject *pDict = PyDict_New(); //創(chuàng)建字典類型變量 PyDict_SetItemString(pDict, "Name", Py_BuildValue("s", "YQC")); //往字典類型變量中填充數(shù)據(jù) PyDict_SetItemString(pDict, "Age", Py_BuildValue("i", 25)); //往字典類型變量中填充數(shù)據(jù) PyTuple_SetItem(pArgs, 0, pDict);//0---序號 將字典類型變量添加到參數(shù)元組中
構(gòu)造好對象以后,通過PyObject_SetAttrString來設(shè)置進(jìn)入Python中:
PyObject *ps=PyUnicode_DecodeUTF8(val,strlen(val),"ignore"); //構(gòu)造了一個對象 PyObject_SetAttrString(p_main_Module,key,ps); //設(shè)置
4、獲取Python變量的值
首先取得變量的指針,然后通過PyArg_Parse解析
pModule =PyImport_ImportModule("__main__"); pReturn = PyObject_GetAttrString(pModule, "a"); //可以獲得全局變量 int size = PyDict_Size(pReturn); PyObject *pNewAge = PyDict_GetItemString(pReturn, "Age"); int newAge; PyArg_Parse(pNewAge, "i", &newAge);
對于元組的解析:
PyObject * pfun=PyObject_GetAttrString(pModule, "testdict"); //testdict:Python文件中的函數(shù)名 PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //調(diào)用函數(shù)
5、調(diào)用Python函數(shù)
PyObject * pfun=PyObject_GetAttrString(pModule, "testdict"); //testdict:Python文件中的函數(shù)名 PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //調(diào)用函數(shù)
6、設(shè)置函數(shù)讓Python調(diào)用
首先定義c函數(shù),然后聲明方法列表,然后聲明模塊,然后增加這個模塊,最后調(diào)用
static int numargs=1890; static PyObject* emb_numargs(PyObject *self, PyObject *args) //C函數(shù) { if(!PyArg_ParseTuple(args, ":numargs")) return NULL; return PyLong_FromLong(numargs); } static PyMethodDef EmbMethods[] = { //方法列表 {"numargs", emb_numargs, METH_VARARGS, "Return the number of arguments received by the process."}, {NULL, NULL, 0, NULL} }; static PyModuleDef EmbModule = { //模塊聲明 PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods, NULL, NULL, NULL, NULL }; static PyObject* PyInit_emb(void) //模塊初始化函數(shù) { return PyModule_Create(&EmbModule); } //增加模塊: PyImport_AppendInittab("emb", &PyInit_emb); //增加一個模塊
到此這篇關(guān)于C語言中程序如何調(diào)用Python腳本的文章就介紹到這了,更多相關(guān)C語言調(diào)用Python腳本內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境
這篇文章主要介紹了windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03深入剖析設(shè)計模式中的組合模式應(yīng)用及在C++中的實(shí)現(xiàn)
這篇文章主要介紹了設(shè)計模式中的組合模式應(yīng)用及在C++中的實(shí)現(xiàn),組合模式可以清晰地反映出遞歸構(gòu)建樹狀的組合結(jié)構(gòu),需要的朋友可以參考下2016-03-03詳解C++編程中的條件判斷語句if-else與switch的用法
這篇文章主要介紹了C++編程中的條件判斷語句if-else與switch的用法,是C++入門學(xué)習(xí)中的基礎(chǔ)知識,需要的朋友可以參考下2016-01-01使用VS2019編譯CEF2623項(xiàng)目的libcef_dll_wrapper.lib的方法
這篇文章主要介紹了使用VS2019編譯CEF2623項(xiàng)目的libcef_dll_wrapper.lib的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04VS2022實(shí)現(xiàn)VC++打包生成安裝文件圖文詳細(xì)歷程
本文主要介紹了VS2022實(shí)現(xiàn)VC++打包生成安裝文件圖文詳細(xì)歷程,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02