文章目录
前言(背景介绍)
因为项目中需要使用到Python脚本,而主代码是用C++书写的,因此需要实现C++调用Python。
因为此篇文章主要起测试连接作用,因此使用比较简单,下方为Python脚本内容:
# 文件名称:usePython.py
def hello():
print("Hello python")
def add(arg1, arg2):
return arg1 + arg2
要想使用Python,主要分为两大步:环境配置、代码中调用Python文件。
一:环境配置
在查阅了相关资料之后,特将基础操作总结如下:
1. 安装Python
我是用的是Python3.8.1版本,如下图所示:
直接双击安装,默认路径为C:\Users\admin\AppData\Local\Programs\Python\Python38,安装结束后Python38路径下内容如下所示:
2. 创建C++项目
这一步就不多说了。
3. 拷贝文件夹
这一步主要配置的是Python安装路径下的include文件夹和libs文件夹,需要将这两个文件夹拷贝到工程中,因为项目比较简单,因此直接放在了工程文件夹下,如下图所示:
这一步需要注意的是,原路径下只有python38.lib,这个是针对于release项目的,在debug模式下,需要将之拷贝一份,并将名称改为python38_d.lib,如下两张图所示(第一张:Python安装路径下,第二张:工程项目下)
4. 在VS中配置Python内容
配置好include和lib路径,以及在debug和release模式下使用到的.lib名称(就是普通的静态库、动态库配置的方式),如下几张图所示。
5. 将py文件拷贝到可执行程序目录下
如下图所示:
二:代码中调用py文件
上面已经做好了相关的配置,现在就可以正式开始使用py文件了。
也主要分为两大块,一个是调用没有参数的py函数,一个是调用有参数的py函数。
话不多说,先上代码:
#include <iostream>
#include <Python.h> //包含Python头文件以使用Python的相关函数
using namespace std;
int main(int argc, char* argv[])
{
Py_Initialize(); //初始化Python的相关内容(必填项)
if (Py_IsInitialized()) //判断是否初始化成功
{
PyObject *pModule = nullptr;
PyObject *pFunc = nullptr;
pModule = PyImport_ImportModule("usePython"); //导入Python脚本模块
if (pModule)
{
///< 调用无参函数
pFunc = PyObject_GetAttrString(pModule, "hello");
PyEval_CallObject(pFunc, nullptr);
///< 调用有参函数
pFunc = PyObject_GetAttrString(pModule, "add");
PyObject *args = PyTuple_New(2);
PyObject *arg1 = PyLong_FromLong(3);
PyObject *arg2 = PyLong_FromLong(8);
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
PyObject *pResult = PyObject_CallObject(pFunc, args);
if (pResult)
{
long result = PyLong_AsLong(pResult);
cout << result << endl;
}
}
}
system("pause");
return 0;
}
1. 初始化
如上述代码所示,在调用Python函数之前,需要先调用Py_Initialized()函数进行初始化操作,这一步是必须的。
其实在正式项目中,在初始化之前还需要判断Python是否已经安装,这一步就不多说了,毕竟这里仅仅是进行一个简单的调用操作。
这里面的基本单元都是PyObject对象,无论是模块、函数、参数、返回值,在这里面全部是PyObject对象。
2. 导入python脚本模块
接下来就是导入python模块了。
导入模块听起来高端,实际上可以简单理解为将py脚本文件加载进代码中。
使用的函数是:pModule = PyImport_ImportModule(“usePython”);
其中userPython就是我自己写的python脚本文件的名称。
3. 函数调用
在判断模块成功导入之后,就可以开始正式的函数调用了。
函数调用主要分为两大类:无参函数,有参函数。
以下分别进行介绍。
3.1 无参函数调用
这里面的无参函数就是hello函数了,具体的使用如下:
pFunc = PyObject_GetAttrString(pModule, "hello");
PyEval_CallObject(pFunc, nullptr);
因为没有参数,所以使用起来非常简单,通过函数名得到这个函数,然后直接执行即可。
(具体的函数因为不甚了解,因此这里不多说,等我了解之后,将会再开一片博客详细介绍)
3.2 有参函数调用
有参函数的调用相对来说比较麻烦,详见下方代码:
pFunc = PyObject_GetAttrString(pModule, "add");
PyObject *args = PyTuple_New(2);
PyObject *arg1 = PyLong_FromLong(3);
PyObject *arg2 = PyLong_FromLong(8);
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
PyObject *pResult = PyObject_CallObject(pFunc, args);
if (pResult)
{
long result = PyLong_AsLong(pResult);
cout << result << endl;
}
这里面就说到了在这种方式下,操作的基本单元是PyObject对象,无论是参数还是返回值。
但是因为PyObject只是一个对象,那么如果想要传入多个参数该如何处理呢?
这就是使用到了tuple,也就是这里面的 PyObject *args = PyTuple_New(2); 这句话,这句话的意思是将args声明为一种元组类型的PyObject对象,这样它就可以存放多个参数了。
返回值也同样如此,返回值也是PyObject类型,根据需要将之转化为自己需要的类型。
另外值得注意的是,需要进行类型的转化,毕竟是数字转化为一个指针类型,需要进行相关的操作。
4. 结果演示
参考链接
详解C++调用Python脚本中的函数的实例代码
讲述C++中调用Python脚本
使用C++调用Python代码的方法详解
C++ 调用Python脚本