C語言中程序如何調(diào)用Python腳本
有時候在寫C語言程序的時候又想利用一下python強大的模塊,于是C與python的混合編程便應運而生。
下面簡單說說在C語言編譯環(huán)境中調(diào)用python腳本文件的基礎應用。
一、環(huán)境配置
以vs2017為例。
0x00 平臺
首先你要知道你電腦上安裝的python環(huán)境是64位還是32位,vs的編譯平臺需要與python環(huán)境一致。
比如我的python環(huán)境是64位,vs工程就要配置成x64。
右鍵點擊你的解決方案,點擊屬性,
0x01 添加 包含目錄 和 庫目錄
在屬性窗口雙擊“VC++ Directories”(VC++目錄),把在Include Directories (包含目錄)和 Library Directories(庫目錄)下添加python安裝路徑下的include和ibs文件夾的路徑。
0x02 添加依賴項
在添加之前一定要先確保自己安裝了python的debug版本,詳見我的另一篇博客【VS2017】“LNK1104 cannot open file ‘python39_d.lib‘
雙擊“l(fā)inker”(鏈接器)下的“Input”,添加python39_d.lib這個依賴項
點擊確定則配置完成。
這樣在寫程序的時候添加Python.h頭文件就不會報錯,python39_d.lib里的API函數(shù)也就可以正常使用了。
二、案例
主要流程就是:
- 初始化python
- 導入py腳本(模塊)
- 獲取模塊里的函數(shù)
- 必要的C語言數(shù)據(jù)類型轉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(); } //設置python模塊,搜尋位置,文件放在.c文件一起 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')"); //獲取python文件名,導入模塊(我這里的py文件是graph.py) pModule = PyImport_ImportModule("graph"); if (!pModule) { printf("py文件導入失敗\n"); Py_Finalize(); } else { //直接獲取模塊中的函數(shù) pFunc = PyObject_GetAttrString(pModule, "create_graph"); //驗證函數(shù)是否獲取成功 if (!pFunc) { printf("函數(shù)導入失敗\n"); Py_Finalize(); } //將c/c++類型數(shù)據(jù)轉換為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ù)值生成對應的excel文件的腳本,這兩個源代碼是根據(jù)我的另一篇關于排序算法的博文改的案例。
# -*- coding:utf-8 -*- import xlsxwriter def create_graph(a,b,c,d,e,f): # 創(chuàng)建一個excel workbook = xlsxwriter.Workbook("排序算法比較結果.xlsx") # 創(chuàng)建一個sheet worksheet = workbook.add_worksheet() # worksheet = workbook.add_worksheet("bug_analysis") # 自定義樣式,加粗 bold = workbook.add_format({'bold': 1}) # --------1、準備數(shù)據(jù)并寫入excel--------------- # 向excel中寫入數(shù)據(jù),建立圖標時要用到 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是默認的值,因為我們在新建sheet時沒有指定sheet名 # 如果我們新建sheet時設置了sheet名,這里就要設置成相應的值 # 設置圖表的title 和 x,y軸信息 chart_col.set_title({'name': "排序算法結果"}) chart_col.set_x_axis({'name': "排序方法"}) chart_col.set_y_axis({'name': "花費時間(ms)"}) # 設置圖表的風格 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、運行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ù)結構,使用相應的函數(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ù)元組中
構造好對象以后,通過PyObject_SetAttrString來設置進入Python中:
PyObject *ps=PyUnicode_DecodeUTF8(val,strlen(val),"ignore"); //構造了一個對象 PyObject_SetAttrString(p_main_Module,key,ps); //設置
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ù)讓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); //增加一個模塊
到此這篇關于C語言中程序如何調(diào)用Python腳本的文章就介紹到這了,更多相關C語言調(diào)用Python腳本內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境
這篇文章主要介紹了windows下安裝QT及visual studio 2017搭建開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03深入剖析設計模式中的組合模式應用及在C++中的實現(xiàn)
這篇文章主要介紹了設計模式中的組合模式應用及在C++中的實現(xiàn),組合模式可以清晰地反映出遞歸構建樹狀的組合結構,需要的朋友可以參考下2016-03-03詳解C++編程中的條件判斷語句if-else與switch的用法
這篇文章主要介紹了C++編程中的條件判斷語句if-else與switch的用法,是C++入門學習中的基礎知識,需要的朋友可以參考下2016-01-01使用VS2019編譯CEF2623項目的libcef_dll_wrapper.lib的方法
這篇文章主要介紹了使用VS2019編譯CEF2623項目的libcef_dll_wrapper.lib的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04VS2022實現(xiàn)VC++打包生成安裝文件圖文詳細歷程
本文主要介紹了VS2022實現(xiàn)VC++打包生成安裝文件圖文詳細歷程,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02