首页/文章/ 详情

C++调用Python的好处

1年前浏览390

0、背景

用熟了python后,再使用C++的就觉得很不方便,因为每一次编程完毕都要编译一遍。殊不知,有些情况下,在C++程序中配合使用python程序反而很方便。

比如。

在一个C/C++应用程序中,我们一般用一组插件来实现一些具有统一接口的功能。这个插件一般都是使用动态链接库来实现的。如果插件的变化比较频繁,我们可以使用 Python 来代替动态链接库形式的插件。这样可以很方便地根据需求的变化改写脚本代码(进行不同的数据处理),而不是必须重新编译链接二进制的动态链接库。


1、调用原理

c++ 调用 python ,本质上是在 c++ 中启动了一个 python 解释器,由解释器对 python 相关的代码进行执行,执行完毕后释放资源,达到调用目的。

下边的代码 main.cpp 包含了调用的基本流程。














// main.cpp#include <Python.h>int main(int argc, char *argv[]) {  // 初始化python解释器.C/C++中调用Python之前必须先初始化解释器  Py_Initialize();    // 执行一个简单的执行python脚本命令  PyRun_SimpleString("print('hello world')\n");   // 撤销Py_Initialize()和随后使用Python/C API函数进行的所有初始化  Py_Finalize();  return 0;}


编译方法:


g++ main.cpp  -I /usr/include/python3.5 -l python3.5m -o test

(注意这里要替换为你实际使用的 python 库和头文件路径,可以使用 whereis python 指令找到)。

本处将上述编译的代码写成了一个简单的shell脚本。文件及文件内容汇总如下


运行后输出如下:


2、无参函数调用

在上边的例子中,我们介绍了在 c++ 中执行 python 语句的方法,简单的完成了一个 print 功能。而实际使用时,我们需要调用 python 模块以及模块中的函数,并且有可能需要参数传递以及返回值获取。

我们首先先实现一个简单的无参数传递的函数调用功能。

先修改main.cpp的内容如下:



































#include <Python.h>#include <iostream> using namespace std; int main(){    // 1、初始化python接口    Py_Initialize();  if(!Py_IsInitialized()){    cout << "python init fail" << endl;    return 0;  }    // 2、初始化python系统文件路径,保证可以访问到 .py文件  PyRun_SimpleString("import sys");  PyRun_SimpleString("sys.path.append('./script')");     // 3、调用python文件名,不用写后缀  PyObject* pModule = PyImport_ImportModule("sayhello");  if( pModule == NULL ){    cout <<"module not found" << endl;    return 1;  }    // 4、调用函数  PyObject* pFunc = PyObject_GetAttrString(pModule, "say");  if( !pFunc || !PyCallable_Check(pFunc)){    cout <<"not found function add_num" << endl;    return 0;  }    //     PyObject_CallObject(pFunc, NULL);    // 5、结束python接口初始化  Py_Finalize();  return 0;}


再写一个python库, sayhello.py,脚本内容如下:



def say():    print("hello, limanman.")


文件放置如下所示。


编译并执行,效果如下:


3、有参函数调用

上述只是演示了下,C++中如何调用python的库和库里的函数,如下将演示如何进行参数传递。

首先修改main.cpp的代码如下所示:
















































#include<Python.h> #include <iostream>using namespace std;
int main(){    Py_Initialize(); //1、初始化python接口        //初始化使用的变量    PyObject* pModule = NULL;    PyObject* pFunc = NULL;    PyObject* pName = NULL;        //2、初始化python系统文件路径,保证可以访问到 .py文件    PyRun_SimpleString("import sys");    PyRun_SimpleString("sys.path.append('./')");        //3、调用python文件名。当前的测试python文件名是 myadd.py    // 在使用这个函数的时候,只需要写文件的名称就可以了。不用写后缀。    pModule = PyImport_ImportModule("myadd");        //4、调用函数    pFunc = PyObject_GetAttrString(pModule, "AdditionFc");        //5、给python传参数    // 函数调用的参数传递均是以元组的形式打包的,2表示参数个数    // 如果AdditionFc中只有一个参数时,写1就可以了    PyObject* pArgs = PyTuple_New(2);    // 0:第一个参数,传入 int 类型的值 2    PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 2));    // 1:第二个参数,传入 int 类型的值 4    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 4));        // 6、使用C++的python接口调用该函数    PyObject* pReturn = PyEval_CallObject(pFunc, pArgs);        // 7、接收python计算好的返回值    int nResult;    // i表示转换成int型变量。    // 在这里,最需要注意的是:PyArg_Parse的最后一个参数,必须加上“&”符号    PyArg_Parse(pReturn, "i", &nResult);    cout << "return result is " << nResult << endl;        //8、结束python接口初始化    Py_Finalize();}


其中 python 脚本内容如下






# myadd.pydef AdditionFc(a, b):    print("Now is in python module")    print("{} + {} = {}".format(a, b, a+b))    return a + b


编译并测试,效果如下:

效果很明显哦。

我们在C++中定义好了输入参数,并用python根据该参数进行了计算。

假如我们需要需要更改python程序,如下所示。







# myadd.pydef AdditionFc(a, b):    print("Now is in python module")    print("{} + {} = {}".format(a, b, a+b))    print("{} * {} = {}".format(a, b, a*b))    return a + b


修改完后,我们就能立即执行原始test程序,而不需要重新编译。

效果如下:


终于又可以愉快的在C++项目中,作为一个pythoner而存在了。

瑞斯拜。

来源:车路慢慢
python
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2023-06-22
最近编辑:1年前
李慢慢
硕士 自动驾驶仿真工程师一枚
获赞 11粉丝 70文章 122课程 0
点赞
收藏
未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习 福利任务 兑换礼品
下载APP
联系我们
帮助与反馈