0、背景
用熟了python后,再使用C++的就觉得很不方便,因为每一次编程完毕都要编译一遍。殊不知,有些情况下,在C++程序中配合使用python程序反而很方便。
比如。
在一个C/C++应用程序中,我们一般用一组插件来实现一些具有统一接口的功能。这个插件一般都是使用动态链接库来实现的。如果插件的变化比较频繁,我们可以使用 Python 来代替动态链接库形式的插件。这样可以很方便地根据需求的变化改写脚本代码(进行不同的数据处理),而不是必须重新编译链接二进制的动态链接库。
// main.cpp
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脚本。文件及文件内容汇总如下:
运行后输出如下:
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;
}
def say():
print("hello, limanman.")
上述只是演示了下,C++中如何调用python的库和库里的函数,如下将演示如何进行参数传递。
首先修改main.cpp的代码如下所示:
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();
}
# myadd.py
def AdditionFc(a, b):
print("Now is in python module")
print("{} + {} = {}".format(a, b, a+b))
return a + b
# myadd.py
def AdditionFc(a, b):
print("Now is in python module")
print("{} + {} = {}".format(a, b, a+b))
print("{} * {} = {}".format(a, b, a*b))
return a + b