C++ 调用 Python
使用 C++ 调用 Python 脚本,并实现各种类型参数的传递。
前言
C++ 可以把 Python 当成文本形式的动态链接库,需要的时候可以改一改脚本,不需要编译。调 Python 提供了丰富的 C API 函数,通过使用自带的API接口可以实现对 Python 脚本文件中的函数、类的访问以及调用。从而可以使得我们可以方便的使用 Python 代码快速得实现一些额外的需求。比如使用 Terson Flow 进行开发。
本文主要介绍 C++ 对 Python 函数的调用,C++ 对 Python 类的调用以及 C++ 与 Python 之间数组的相互传递。
C++ 对 Python 简单函数的调用
通过调用 python 脚本中的函数,来实现一些简单的功能扩展。先编写一个 Python 脚本文件名为 pytest.py。在此之前需要安装 python 环境。
def Add(a,b):
print "in python function add"
print "a = " + str(a)
print "b = " + str(b)
print "ret = " + str(a+b)
return a+b
下面是 C++ 代码对其进行调用,在编译时需要加入 Python 的 include 路径和动态库的库接路径。
LIBS += -L/usr/lib/python2.7/config-x86_64-linux-gnu -lpython2.7
INCLUDEPATH += /usr/include/python2.7
# include <Python.h>
int main( int argc, char * argv[] ) {
// 在使用Python系统前,必须使用Py_Initialize
Py_Initialize();
// 检查初始化是否成功
if ( !Py_IsInitialized() ) {
return -1;
}
// 载入Python的内建模块并添加系统路径
PyRun_SimpleString( "import sys" );
PyRun_SimpleString( "print '---import sys---'" );
PyRun_SimpleString( "sys.path.append('./')" );
PyObject * pName = NULL;
PyObject * pModule = NULL;
PyObject * pDict = NULL;
PyObject * pFunc = NULL;
PyObject * pArgs = NULL;
// 载入名为pytest的脚本
pName = PyString_FromString( "pytest" );
pModule = PyImport_Import( pName) ;
if ( !pModule ) {
printf("can't find pytest.py");
getchar();
return -1;
}
pDict = PyModule_GetDict(pModule);
if ( !pDict ) {
return -1;
}
// 找出函数名为add的函数
printf("----------------------\n");
pFunc = PyDict_GetItemString( pDict, "Add" );
if ( !pFunc || !PyCallable_Check( pFunc ) ) {
printf("can't find function [add]");
getchar();
return -1;
}
// 参数进栈
*pArgs;
pArgs = PyTuple_New(2);
// PyObject* Py_BuildValue(char *format, ...)
// 把C++的变量转换成一个Python对象。当需要从
// C++传递变量到Python时,就会使用这个函数。此函数
// 有点类似C的printf,但格式不同。常用的格式有
// s 表示字符串,
// i 表示整型变量,
// f 表示浮点数,
// O 表示一个Python对象。
PyTuple_SetItem( pArgs, 0, Py_BuildValue( "l", 3 ) );
PyTuple_SetItem( pArgs, 1, Py_BuildValue( "l", 4 ) );
// 调用Python函数
PyObject * pyRet = PyObject_CallObject( pFunc, pArgs );
// 获取返回值
int reval = -1;
int retok = PyArg_Parse( pyRet, "i", &reval );
printf( "返回结果: %d\n", reval );
Py_DECREF( pModule );
Py_DECREF( pDict );
Py_DECREF( pFunc );
Py_DECREF( pArgs );
Py_DECREF( pName );
return 0;
}
C++ 对 Python 类的成员函数的调用
Python 代码如下:
class tester:
def add(self, a, b):
return a + b
C++ 代码调用时调用如下
// 调用类
// 从字典中查找tester类
PyObject * pyCls = PyDict_GetItemString( pDict, "tester" );
// 创建一个tester类
PyObject * PyIns = PyInstance_New( pyCls, NULL, NULL );
// 调用tester.add方法,传入2个int型参数
pyRet = PyObject_CallMethod( PyIns, "add", "ii", 5, 6 );
retok = PyArg_Parse( pyRet, "i", &reval );
printf( "调用类的函数,返回结果: %d\n", reval );
从 Python 函数中返回List数组
如果我们在 C/C++ 文件中调用的 Python 函数返回的是 List 数组,那么我们这里主要用到的是 Python C API 中的 List Object 来处理返回的数据,主要用到 List Object 里面的这些函数:
-
int PyList_Check( PyObject * list ) 函数判断一个 PyObject 指针对象是不是一个 List 对象;
-
Py_ssize_t PyList_Size( PyObject * list ) 函数计算一个 List 对象的大小;
-
PyObject * PyList_GetItem( PyObject * list, Py_ssize_t index ) 函数返回 List对象中第 index 个元素的 PyObject 指针。
Python 代码如下
def testList():
IList = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
return IList;
在 C/C++ 文件中调用这个 Python 函数时,将返回 List 对象,在 C/C++ 文件中进行如下的接收操作:
// 省略……
PyObject * pFun = PyDict_GetItemString( pDict, "testList" );
PyObject * pFunRet = PyObject_CallObject( pFun, nullptr );//返回List对象
if( PyList_Check( pFunRet ) ) { //检查是否为List对象
int sizeOfList = PyList_Size( pFunRet ); //list的长度
for( idx = 0; idx < sizeOfList; idx++ ) {
// 获取 List 对象中的每一个元素
PyObject * listItem = PyList_GetItem( pFunRet, idx );
// List对象子元素的大小,这里NumOfItems = 3
int NumOfItems = PyList_Size( listItem );
for( Index_k = 0; Index_k < NumOfItems; Index_k++ ){
//遍历List对象中子元素中的每个元素
PyObject * item = PyList_GetItem( listItem, Index_k );
cout << PyInt_AsLong( item ) <<" "; //输出元素
Py_DECREF( Item ); //释放空间
}
Py_DECREF( ListItem ); //释放空间
}
cout<<endl;
}
else {
cout<<"Not a List"<<endl;
}
// 省略……
C++ 向 Python 函数中返回List数组
现在我们的需求是我们要将 C/C++文件中的数组传递给 Python 文件的某个函数,那么我们将借助 List Object 和 Tuple Object 来封装我们的数据,从而传递给 Python 文件中的函数。
Python 代码如下:
def PrintList( l ):
print l;
在 C++ 文件里调用如下:
double CArray[] = { 1.2, 4.5, 6.7, 8.9, 1.5, 0.5 };
// 定义一个与数组等长的PyList对象数组
PyObject * PyList = PyList_New( 6 );
// 定义一个Tuple对象,Tuple对象的长度与Python函数参数个数一直,
// 上面Python参数个数为1,所以这里给的长度为1
PyObject * ArgList = PyTuple_New( 1 );
for( i = 0; i < PyList_Size( PyList ); ++i ){
PyList_SetItem( PyList, Index_i, PyFloat_FromDouble( CArray[i] ) );
}
PyObject * pFuncFour = PyDict_GetItemString( pDict, "PrintList" );
cout << "C Array Pass Into The Python List:" << endl;
PyTuple_SetItem( ArgList, 0, PyList ); // 将PyList对象放入PyTuple对象中
PyObject_CallObject( pFuncFour, ArgList ); // 调用函数,完成传递
Comments are closed.