【C語言】如何在C程序中調用Python腳本


有時候在寫C語言程序的時候又想利用一下python強大的模塊,於是C與python的混合編程便應運而生。
下面簡單說說在C語言編譯環境中調用python腳本文件的基礎應用。

一、環境配置
以vs2017為例。

0x00 平台
首先你要知道你電腦上安裝的python環境是64位還是32位,vs的編譯平台需要與python環境一致。
比如我的python環境是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‘

雙擊“linker”(鏈接器)下的“Input”,添加python39_d.lib這個依賴項

點擊確定則配置完成。

這樣在寫程序的時候添加Python.h頭文件就不會報錯,python39_d.lib里的API函數也就可以正常使用了。

二、案例
主要流程就是:

初始化python
導入py腳本(模塊)
獲取模塊里的函數
必要的C語言數據類型轉python的數據類型(傳參前)
調用函數
釋放python
#include<stdio.h>
#include <Python.h>
int main()
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
//待傳參數
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 {
//直接獲取模塊中的函數
pFunc = PyObject_GetAttrString(pModule, "create_graph");
//驗證函數是否獲取成功
if (!pFunc) {
printf("函數導入失敗\n");
Py_Finalize();
}

//將c/c++類型數據轉換為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);

//調用直接獲得的函數,並傳遞參數
pValue = PyObject_CallObject(pFunc, pArgs);

//釋放python
Py_Finalize();

printf("success");
return 0;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
順便給出我的graph.py的腳本,這是一個以參數的數值生成對應的excel文件的腳本,這兩個源代碼是根據我的另一篇關於排序算法的博文改的案例。

# -*- coding:utf-8 -*-
import xlsxwriter

def create_graph(a,b,c,d,e,f):
# 創建一個excel
workbook = xlsxwriter.Workbook("排序算法比較結果.xlsx")
# 創建一個sheet
worksheet = workbook.add_worksheet()
# worksheet = workbook.add_worksheet("bug_analysis")

# 自定義樣式,加粗
bold = workbook.add_format({'bold': 1})

# --------1、准備數據並寫入excel---------------
# 向excel中寫入數據,建立圖標時要用到
headings = ["排序方法", "排序時間"]
data = [["簡單選擇排序", "直接插入排序", "冒泡排序", "快速排序", "兩路合並排序", "堆排序"],[a,b,c,d,e,f]]

# 寫入表頭
worksheet.write_row('A1', headings, bold)

# 寫入數據
worksheet.write_column('A2', data[0])
worksheet.write_column('B2', data[1])

# --------2、生成圖表並插入到excel---------------
# 創建一個柱狀圖(column chart)
chart_col = workbook.add_chart({'type': 'column'})

# 配置第一個系列數據
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
三、常用API
1、運行Python指令

PyRun_SimpleString("print(os.getcwd(),a)");
pyext.eval(R"(a+='qwer')");
1
2
2、加載Python模塊

PyObject * pModule =PyImport_ImportModule("tp"); //test:Python文件名,若腳本有錯則返回空
PyRun_SimpleString("import os");
1
2
3、給Python的變量賦值

對於數值,使用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}
1
2
3
4
5
6
7
8
9
10
11
12
對於其他數據結構,使用相應的函數設置,例如:

PyObject *pArgs = PyTuple_New(1);
PyObject *pDict = PyDict_New(); //創建字典類型變量
PyDict_SetItemString(pDict, "Name", Py_BuildValue("s", "YQC")); //往字典類型變量中填充數據
PyDict_SetItemString(pDict, "Age", Py_BuildValue("i", 25)); //往字典類型變量中填充數據
PyTuple_SetItem(pArgs, 0, pDict);//0---序號 將字典類型變量添加到參數元組中
1
2
3
4
5
構造好對象以后,通過PyObject_SetAttrString來設置進入Python中:

PyObject *ps=PyUnicode_DecodeUTF8(val,strlen(val),"ignore"); //構造了一個對象
PyObject_SetAttrString(p_main_Module,key,ps); //設置
1
2
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);
1
2
3
4
5
6
對於元組的解析:

int ok;
ok = PyArg_ParseTuple(args, "s", &s); //Python call: f('whoops!')
ok = PyArg_ParseTuple(args, "lls", &k, &l, &s);//Python call: f(1, 2,'three')
ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);//Python call: f((1, 2), 'three')
ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);//Python calls:
//f('spam')
//f('spam', 'w')
//f('spam', 'wb', 100000)
1
2
3
4
5
6
7
8
5、調用Python函數

PyObject * pfun=PyObject_GetAttrString(pModule, "testdict"); //testdict:Python文件中的函數名
PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //調用函數
1
2
6、設置函數讓Python調用

首先定義c函數,然后聲明方法列表,然后聲明模塊,然后增加這個模塊,最后調用

static int numargs=1890;
static PyObject* emb_numargs(PyObject *self, PyObject *args) //C函數
{
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) //模塊初始化函數
{
return PyModule_Create(&EmbModule);
}
//增加模塊:
PyImport_AppendInittab("emb", &PyInit_emb); //增加一個模塊

雙喜鳥


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM