[C++]C++ 调用python

FL1768317420 2024-07-23 12:35:02 阅读 56

方法一:使用python提供给C/C++的API

主流方法将python程序编程文本形式的动态链接库,在c/c++程序中调用其中定义的函数。

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

1. 链接到Python调用库

检查Python 安装目录下已经包含头文件( 就是c++里 需要include 的目录)和库文件 ( Windows 下为 python27.lib)。

这一步可以参考下知乎网友的配置方式 C++调用python文件(包含第三方库) - 知乎

2. 直接调用 Python 语句

<code>#include "python/Python.h"

int main()

{

Py_Initialize(); ## 初始化

PyRun_SimpleString("print 'hello'");

Py_Finalize(); ## 释放资源

}

3. 无参python函数调用

Python

def say():

print("hello")

C++

#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;

}

编译

4. 有参python函数调用

python

<code># myadd.py

def AdditionFc(a, b):

print("Now is in python module")

print("{} + {} = {}".format(a, b, a+b))

return a + b

C++

// test2.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脚本文件。

(这个方法可能取返回值不方便)

以下是测试用的python脚本文件,功能是输出命令行参数:sample.py

<code># !/usr/bin/env python2.6

import sys

def test():

for arg in sys.argv:

print arg

if __name__=='__main__':

test()

以下是测试用的c程序文件:test.c

#include "python2.6/Python.h"

int main()

{

//第一步:初始化Python

//在调用Python的提供的给C的API之前,通过执行初始化

//来添加Python的内建模块、__main__、sys等

Py_Initialize();

//检查初始化是否完成

if (!Py_IsInitialized())

{

return -1;

}

//第二步:导入sys模块

PyRun_SimpleString("import sys");

//第三步:导入执行脚本时的命令行参数,如:./sample.py int argc = 2;

char *argv[2];

argv[0] = "arg1";

argv[1] = "arg2";

PySys_SetArgv(argc, argv);

//第四步:执行调用脚本文件命令,注意文件的路径

if (PyRun_SimpleString("execfile('./sample.py')") == NULL)

{

return -1;

}

//第五步:关闭Python解释器

Py_Finalize();

return 0;

}

编译指令:

g++ -g -W -o test test.cpp -I /usr/include/ -L /usr/lib64/ -l python2.

执行指令:./test

输出:

arg1

arg2

Python提供C++调用的主要的API

void Py_Initialize(void)

初始化Python解释器,如果初始化失败,继续下面的调用会出现各种错误,可惜的是此函数没有返回值来判断是否初始化成功,如果失败会导致致命错误。

int Py_IsInitialized(void)

检查是否已经进行了初始化,如果返回0,表示没有进行过初始化。

void Py_Finalize()

反初始化Python解释器,包括子解释器,调用此函数同时会释放Python解释器所占用的资源。

int PyRun_SimpleString(const char *command)

实际上是一个宏,执行一段Python代码。

PyObject* PyImport_ImportModule(char *name)

导入一个Python模块,参数name可以是*.py文件的文件名。类似Python内建函数import。

PyObject* PyModule_GetDict( PyObject *module)

相当于Python模块对象的dict属性,得到模块名称空间下的字典对象。

PyObject* PyRun_String(const char* str, int start,PyObject* globals, PyObject* locals)

执行一段Python代码。

int PyArg_Parse(PyObject* args, char* format, …)

把Python数据类型解析为C的类型,这样C程序中才可以使用Python里面的数据。

PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)

返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name。

PyObject* Py_BuildValue(char* format, …)

和PyArg_Parse刚好相反,构建一个参数列表,把C类型转换为Python对象,使得Python里面可以使用C类型数据。

PyObject* PyEval_CallObject(PyObject* pfunc, PyObject*pargs)

此函数有两个参数,而且都是Python对象指针,其中pfunc是要调用的Python 函数,一般说来可以使用PyObject_GetAttrString()获得,pargs是函数的参数列表,通常是使用Py_BuildValue()来构建。

参数传递的各种例子

//1. 传送字符串和数据到python函数

void TestF1(void)

{

PyObject* pModule = NULL;

PyObject* pFunc = NULL;

PyObject* pArg = NULL;

pModule = PyImport_ImportModule("demo1"); //注意文件名字大小写

pFunc = PyObject_GetAttrString(pModule, "Hello");//获取函数名称

pArg = Py_BuildValue("(s)", "my is c++ test!"); //一个字符串参数

PyEval_CallObject(pFunc, pArg);//函数调用

pFunc = PyObject_GetAttrString(pModule, "Add"); //两个整形的参数

pArg = Py_BuildValue("(i,i)", 10, 25); // 变量格式转换成python格式

PyEval_CallObject(pFunc, pArg);

}

python文件: demo1.py

def Hello(s):

print("\n=======================")

print("demo1:hello")

print(s)

def Add(a, b):

print("\n=======================")

print("demo1:add")

print("{0}".format(a + b))

///

//2.列表作为参数的传送给python函数

void TestF2(void)

{

PyObject* pModule = NULL;

PyObject* pFunc = NULL;

PyObject* pArg = NULL;

pModule = PyImport_ImportModule("demo2"); //注意文件名字大小写

PyObject* pyFunc_printList = PyObject_GetAttrString(pModule, "printList");//获取函数名称

if (pModule && PyCallable_Check(pyFunc_printList))

{

PyObject* pyParams = PyList_New(0); //初始化一个列表

PyList_Append(pyParams, Py_BuildValue("d", 5));//列表添加元素值浮点数

PyList_Append(pyParams, Py_BuildValue("i", 2));

PyList_Append(pyParams, Py_BuildValue("i", 6));

PyList_Append(pyParams, Py_BuildValue("i", 8));

PyObject* args = PyTuple_New(1); //定义一个python变量

PyTuple_SetItem(args, 0, pyParams);// 变量格式转换成python格式

PyEval_CallObject(pyFunc_printList, args);//函数调用

}

}

python文件:demo2.py

def printList(l):

print("\n=======================")

print("demo2")

print(len(l))

print(l);

/

/

//3.python类的操作

/

void TestF3(void)

{

PyObject* pModule = NULL;

PyObject* pFunc = NULL;

PyObject* pArg = NULL;

PyObject* pClass = NULL;

PyObject* pObject = NULL;

pModule = PyImport_ImportModule("demo3"); //注意文件名字大小写

pClass = PyObject_GetAttrString(pModule, "Person"); //先获取类名

pArg = PyTuple_New(1); // 定义一个变量

PyTuple_SetItem(pArg, 0, Py_BuildValue("s", "Class:Jacky")); // 变量格式转换成python格式

pObject = PyEval_CallObject(pClass, pArg); //根据类名实例化对象

pFunc = PyObject_GetAttrString(pObject, "printName"); //根据对象得到成员函数

PyEval_CallObject(pFunc, NULL);//函数调用

}

python文件:demo3.py

class Person:

def __init__(self, name):

self.name = name

def printName(self):

print("\n=======================")

print("demo3")

print (self.name)

/

/

//4. Python程序返回参数的例子

/

void TestF4(void)

{

PyObject* pModule = PyImport_ImportModule("demo4");//注意文件名字大小写

PyObject* pyFunc_mix = PyObject_GetAttrString(pModule, "mix");

if (pModule && PyCallable_Check(pyFunc_mix))

{

PyObject* pyParams = PyTuple_New(2); //定义两个变量

PyTuple_SetItem(pyParams, 0, Py_BuildValue("i", 5));// 变量格式转换成python格式

PyTuple_SetItem(pyParams, 1, Py_BuildValue("i", 2));// 变量格式转换成python格式

int r1 = 0, r2 = 0;

PyObject* pyValue = PyObject_CallObject(pyFunc_mix, pyParams); //调用函数返回结果

PyArg_ParseTuple(pyValue, "i|i", &r1, &r2);//分析返回的元组值

if (pyValue)

{

printf("%d %d\n", r1, r2);

}

}

}

python文件:demo4.py

def mix(a,b):

print("\n=======================")

print("demo4")

r1 = a + b

r2 = a - b

return (r1, r2)

///

//5.c++数组转python的list

/

void TestF5(void)

{

//以下调用很重要,否则转换中会出现异常

if (_import_array() < 0)

{

PyErr_Print();

PyErr_SetString(PyExc_ImportError, "numpy.core.multiarray failed to import");

}

PyObject* pModule = NULL;

PyObject* pFunc = NULL;

pModule = PyImport_ImportModule("demo5");//注意文件名字大小写

PyObject* pyFunc_printList = PyObject_GetAttrString(pModule, "printList");//获取函数名称

float buf[2][3]; //定义二维数组

buf[0][0] = 0;

buf[0][1] = 1.233;

buf[0][2] = 2.222;

buf[1][0] = 4.222;

buf[1][1] = 5.333;

buf[1][2] = 6.333;

PyObject* pArgs = PyTuple_New(1);

npy_intp dims[2]={2,3}; //定义list的shape

int ND = 2;//指明list的维度

PyObject* pPyArray = PyArray_SimpleNewFromData(ND, dims, NPY_FLOAT, buf); //指明list的维度,shape,数量类型,缓冲区

PyTuple_SetItem(pArgs, 0, pPyArray);//变量转换

PyEval_CallObject(pyFunc_printList, pArgs);//函数调用

}

python文件:demo5.py

def printList(lis):

print("\n=======================")

print("demo5")

print(lis)



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。