Python/C 相互调用
使用C语言扩展Python
声明接口
#pragma once
#define DLL_API __declspec(dllexport)
// #define CALL __stdcall
#define CALL
DLL_API double CALL py_get_squre(double);
使用C语言实现可被Python的直接调用的接口
#include <Python.h>
#pragma comment(lib,"python38.lib")
#include "calc.h"
/*
实现相关功能的C函数
*/
DLL_API double CALL py_get_squre(double a)
{
return a * a;
}
/*
【包裹函数】
将python接口参数转换为C接口参数,调用C函数,并将返回的C参数转换为python参数返回
过程:传入Python参数 -> 转换为C参数 -> 调用C接口 -> 返回C参数 -> 转换为python参数返回
*/
static PyObject * _py_get_squre(PyObject * self, PyObject * args)
{
double _a;
double ret;
if (!PyArg_ParseTuple(args, "d", &_a))
{
printf("PyArg_ParseTuple 参数解析失败\n");
return NULL;
}
ret = py_get_squre(_a);
return PyFloat_FromDouble(ret);
}
/*
Method导出表 calc_module_methods(名字自己随便起)
告诉python模块里有哪些参数可以被调用
*/
static PyMethodDef calc_module_methods[] =
{
{
"py_get_squre", //给出python环境的函数名称
_py_get_squre, //包裹函数
METH_VARARGS, //该宏表示:参数变长
"" //一个说明性的字符串
},
// 导出表以 ... 结尾
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef calc_module =
{
PyModuleDef_HEAD_INIT,
"calc_module",
NULL,
-1,
calc_module_methods
};
/*
导出函数 PyInit_calc_module(名字不能随便起,"PyInit_ + 模块名")
导出函数中将模块名称与导出表进行连接
*/
PyMODINIT_FUNC PyInit_calc(void)
{
PyObject *m;
m = PyModule_Create(&calc_module);
if (m == NULL)
{
printf("模块加载失败\n");
return NULL;
}
// Debug
//printf("PyInit calc_module\n");
return m;
}
在C中调用Python脚本
def factorial(n):
if n < 0:
print("参数输入错误\n")
return False
if n == 0:
print(1)
return True
ret = 1
for i in range(1, n+1):
ret *= i
print(ret)
return True
/*
* @breaf VS2017 C调用Python脚本
*
* 问题记录:
* 1.报错:python37_d.lib 在Debug模式下,需要在安装python的时候安装相应的"python debug bin/library"
* 有对应的选项,具体名称我记不住了。安装的时候如果忘记安装了,后续Modify也可以
*/
#include <Python.h>
/*
C调用Python模块实现的接口
*/
int factorial(int n)
{
PyObject * pModule, *pFun;
PyObject *pArgs, *pValue;
PyObject * pModuleName;
/*
默认情况,需要将该python脚本放在输出的exe文件目录下,才能正常被导入。
若添加上这句,表示导入当前目录下的python脚本,即可以把脚本放在工程目录下
方便Debug和Release调用。也方便修改python脚本
(当然了也可以写为绝对地址)
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('F:/Code/VS2017/pyc/pyc')");
*/
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
// 导入模块,即自己写的python脚本
pModuleName = PyUnicode_FromString("arith");
pModule = PyImport_Import(pModuleName);
// pModule = PyImport_ImportModule("Apaki");
if (pModule == NULL)
{
printf("导入python模块失败\n");
return 0;
}
// 确定调用的函数名称
pFun = PyObject_GetAttrString(pModule, "factorial");
// 配置传递的参数
pArgs = PyTuple_New(1);
PyTuple_SetItem(pArgs, 0, PyLong_FromLong(n));
// 调用函数,并且取得返回值
pValue = PyObject_CallObject(pFun, pArgs);
if (pValue != Py_True)
{
printf("返回结果无效\n");
return 0;
}
// 若返回0,则失败,返回1数据正常
return 1;
}