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 添加依賴項
在添加之前一定要先確保自己安裝了python的debug版本,詳見我的另一篇博客【VS2017】“LNK1104 cannot open file ‘python39_d.lib‘
雙擊“l(fā)inker”(鏈接器)下的“Input”,添加python39_d.lib這個依賴項

點(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項目的libcef_dll_wrapper.lib的方法
這篇文章主要介紹了使用VS2019編譯CEF2623項目的libcef_dll_wrapper.lib的方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04
VS2022實(shí)現(xiàn)VC++打包生成安裝文件圖文詳細(xì)歷程
本文主要介紹了VS2022實(shí)現(xiàn)VC++打包生成安裝文件圖文詳細(xì)歷程,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02

