C++调用Python脚本学习笔记

一.前言

最近碰到了一个奇怪的需求,需要用C++调用Python脚本(Python调用C++倒是常见,反过来以前真没见过),因此去网上学习了一波顺便将学习过程中的笔记分享一波,话不多说,请看下文。

二.VS中调用Python配置

首先在Visual Studio中创建项目,注意需要选择X64进行编译,即:

mode select

然后,需要将Python安装目录下的includelibs目录引入到本项目中去,具体做法如下:

  • 对于include,选择项目–>配置属性–>C/C+±->附加包目录,在附加目录那一栏填入include的绝对路径。
  • 对于libs,选择项目–>配置属性–>链接器–>附加库目录,在附加库目录那一栏填入libs的绝对路径,注意还需要将pythonxx.lib复制一份为pythonxx_d.lib仍然放在该文件中。

xx表示python的版本,比如3.8版本即为python38

完成上述步骤就可以在VS的cpp源文件中引入头文件Python.h头文件,并使用Python提供的C API库了。

三.C++中Python的使用方法

3.1 Python解释器环境

首先需要为程序提供解释器环境,在程序结束后要销毁创建的解释器,与解释器相关的接口如下:

// 设置python环境EXE文件的路径
void Py_SetPythonHome(python_path);

// 初始化Python解释器
void Py_Initialize();

// 解释器是否初始化完成,失败则返回0
int Py_IsInitialized();

// 销毁创建的解释器
void Py_Finalize();

3.2 调用Python模块和调用相关的函数

这里指的Python模块包括封装好的库以及自定义的Py文件。首先给出最简单的调用方法(无法传递参数),其对应的接口如下所示:

// 直接以字符串的形式传入python代码
int PyRun_SimpleString(const char*);
// PyRun_SimpleString("print('hello world')");

// 将python脚本传入直接执行,fp为脚本对应的文件指针,filename为脚本名
int PyRun_SimpleFile(FILE *fp, const char *filename);

倘若要调用自定义的python脚本,则可以使用下面的常用接口:

// 加载模块,传入python脚本名或封装好的库名
PyObject* PyImport_ImportModule(char *name);

// 获取模块中的函数列表,该函数返回一个key为函数名,value为函数调用地址的字典
PyObject* PyModule_GetDict( PyObject *module);
// 从函数字典中获取相应的函数,dp为函数字典,key为要获取函数的名称
PyDict_GetItemString(PyObject *dp, const char *key);

// 直接传递属性名来获取模块中的相应对象
PyObject* PyObject_GetAttrString(PyObject *o, char *attr_name);

// 函数调用, callable_object为函数对象,args为需要传入的参数
PyObject* PyObject_CallObject( PyObject *callable_object, PyObject *args);

// 参数传递
// 将C++的数据类型转换为python对应的类型
PyObject* Py_BuildValue( const char *format, ...);
// 定义size为len的元组
PyObject* PyTuple_New( Py_ssize_t len);
// 创建完元组后,往元组内添加元素,p为要操作的元组,pos为索引,o为通过Py_BudilValue转换后的值
int PyTuple_SetItem( PyObject *p, Py_ssize_t pos, PyObject *o) ;

注意函数的参数列表必须为元组。

3.3 C++与Py的数据类型转换

上节介绍到通过Py_BuildValue函数可以进行数据类型的转换,下面给出常用数据类型对应的转换关系表:

format值C语言对应数据类型Py对应数据类型
s使用utf-8编码将以null结尾的字符串String对象
b/i/h/lchar/int/short int/long整数对象
f/dfloat/double浮点数对象

对于C++传递数组到Python限于篇幅,本文就不展开了,具体可以参考下C调用Python(传递数字、字符串、list数组(一维、二维),结构体)

3.4 返回值的处理

python脚本的返回值可以用下面的API进行处理:

int PyArg_Parse( PyObject *args, char *format, ...);
// PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
// int nResult;
// PyArg_Parse(pReturn, "i", &nResult);

需要注意若返回的是多个参数,可以用处理列表、元组或字典的方法来进行解析。

四.使用示例

首先创建一个名为temp的py文件,其中包含的源码如下:

def hello(name):
    print("hello {}".format(name))

def add(a,b):
    return a + b

然后将该文件放至VS项目可执行文件同目录下,具体做法为:

  • 若使用Debug(x64)模式,则在项目目录–>x64–>Debug目录
  • 若使用Release(X64)模式,则在项目目录–>x64–>Release目录

或者也可以利用PyRun_SimpleString函数来调用sys模块来进行指定如:

PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('C:/xxxxx')"); // c:/xxxxx表示py文件所在的位置

然后,便是c++程序的编写,对应的源码如下:

#include <iostream>
#include<Python.h>
using namespace std;

int main() {
	// 设置python的执行路径
	Py_SetPythonHome(L"C:/xxxxx");
	Py_Initialize();
	if (Py_IsInitialized()) {
		PyObject* pModule = NULL;
		PyObject* pFunc = NULL;
		 // 直接指定.py文件的位置
		 // PyRun_SimpleString("import sys");
		 // PyRun_SimpleString("sys.path.append('C:/xxxxx')");
		pModule = PyImport_ImportModule("temp");
		if (pModule) {
			pFunc = PyObject_GetAttrString(pModule, "add");
			PyObject* pArgs = PyTuple_New(2);
			PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2));
			PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 3));
			PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);
			int nResult;
			PyArg_Parse(pReturn, "i", &nResult);
			cout << nResult << endl;

			pFunc = PyObject_GetAttrString(pModule,"hello");
			PyObject* pArgs1 = PyTuple_New(1);
			PyTuple_SetItem(pArgs1,0, Py_BuildValue("s", "XiaoMing"));
			PyObject_CallObject(pFunc, pArgs1);

		
		}
	}
	Py_Finalize();
	return 0;
}

执行以上程序就可以输出如下的结果:

outcome

五.结语

博主在学习的过程中参考了如下大佬的资料:
Visual Studio中C++的包含目录、附加包含目录和库目录和附加库目录的区别

C++ 调用Python脚本

Visual Studio 2019 添加dll库

C++调用python方法及环境配置(Windows环境、VS工具)

以上便是本文的全部内容,要是觉得不错的话就点个赞或关注一下博主吧,你们的支持是博主继续创作的不解动力,当然若是有任何问题也敬请批评指正!!!

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

斯曦巍峨

码文不易,有条件的可以支持一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值