C语言调用Python脚本 C语言中程序怎样调用Python脚本
Em0s_Erit 人气:2有时候在写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; } }
顺便给出我的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)
三、常用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的变量赋值
对于数值,使用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}
对于其他数据结构,使用相应的函数设置,例如:
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---序号 将字典类型变量添加到参数元组中
构造好对象以后,通过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文件中的函数名 PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //调用函数
5、调用Python函数
PyObject * pfun=PyObject_GetAttrString(pModule, "testdict"); //testdict:Python文件中的函数名 PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //调用函数
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); //增加一个模块
加载全部内容