Python调用C++程序的方法详解


Posted in Python onJanuary 24, 2017

前言

大家都知道Python的优点是开发效率高,使用方便,C++则是运行效率高,这两者可以相辅相成,不管是在Python项目中嵌入C++代码,或是在C++项目中用Python实现外围功能,都可能遇到Python调用C++模块的需求,下面列举出集中c++代码导出成Python接口的几种基本方法,一起来学习学习吧。

原生态导出

Python解释器就是用C实现,因此只要我们的C++的数据结构能让Python认识,理论上就是可以被直接调用的。我们实现test1.cpp如下

#include <Python.h>

int Add(int x, int y)
{
 return x + y;
}

int Del(int x, int y)
{
 return x - y;
}

PyObject* WrappAdd(PyObject* self, PyObject* args)
{
 int x, y;
 if (!PyArg_ParseTuple(args, "ii", &x, &y))
 {
  return NULL;
 }
 return Py_BuildValue("i", Add(x, y));
}

PyObject* WrappDel(PyObject* self, PyObject* args)
{
 int x, y;
 if (!PyArg_ParseTuple(args, "ii", &x, &y))
 {
  return NULL;
 }
 return Py_BuildValue("i", Del(x, y));
}
static PyMethodDef test_methods[] = {
 {"Add", WrappAdd, METH_VARARGS, "something"},
 {"Del", WrappDel, METH_VARARGS, "something"},
 {NULL, NULL}
};

extern "C"
void inittest1()
{
 Py_InitModule("test1", test_methods);
}

编译命令如下

g++ -fPIC -shared test1.cpp -I/usr/include/python2.6 -o test1.so

运行Python解释器,测试如下

>>> import test1
>>> test1.Add(1,2)
3

这里要注意一下几点

  1. 如果生成的动态库名字为test1,则源文件里必须有inittest1这个函数,且Py_InitModule的第一个参数必须是“test1”,否则Python导入模块会失败
  2. 如果是cpp源文件,inittest1函数必须用extern "C"修饰,如果是c源文件,则不需要。原因是Python解释器在导入库时会寻找initxxx这样的函数,而C和C++对函数符号的编码方式不同,C++在对函数符号进行编码时会考虑函数长度和参数类型,具体可以通过nm test1.so查看函数符号,c++filt工具可通过符号反解出函数原型

通过boost实现

我们使用和上面同样的例子,实现test2.cpp如下

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;

int Add(const int x, const int y)
{
 return x + y;
}

int Del(const int x, const int y)
{
 return x - y;
}

BOOST_PYTHON_MODULE(test2)
{
 def("Add", Add);
 def("Del", Del);
}

其中BOOST_PYTHON_MODULE的参数为要导出的模块名字

编译命令如下

g++ test2.cpp -fPIC -shared -o test2.so -I/usr/include/python2.6 -I/usr/local/include -L/usr/local/lib -lboost_python

注意: 编译时需要指定boost头文件和库的路径,我这里分别是/usr/local/include和/usr/local/lib

或者通过setup.py导出模块

#!/usr/bin/env python
from distutils.core import setup
from distutils.extension import Extension

setup(name="PackageName",
 ext_modules=[
  Extension("test2", ["test2.cpp"],
  libraries = ["boost_python"])
 ])

Extension的第一个参数为模块名,第二个参数为文件名

执行如下命令

python setup.py build

这时会生成build目录,找到里面的test2.so,并进入同一级目录,验证如下

>>> import test2
>>> test2.Add(1,2)
3
>>> test2.Del(1,2)
-1

导出类

test3.cpp实现如下

#include <boost/python.hpp>
using namespace boost::python;

class Test
{
public:
 int Add(const int x, const int y)
 {
  return x + y;
 }

 int Del(const int x, const int y)
 {
  return x - y;
 }
};

BOOST_PYTHON_MODULE(test3)
{
 class_<Test>("Test")
  .def("Add", &Test::Add)
  .def("Del", &Test::Del);
}

注意:BOOST_PYTHON_MODULE里的.def使用方法有点类似Python的语法,等同于

class_<Test>("Test").def("Add", &Test::Add);
class_<Test>("Test").def("Del", &Test::Del);

编译命令如下

g++ test3.cpp -fPIC -shared -o test3.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python

测试如下

>>> import test3
>>> test = test3.Test()
>>> test.Add(1,2)
3
>>> test.Del(1,2)
-1

导出变参函数

test4.cpp实现如下

#include <boost/python.hpp>
using namespace boost::python;

class Test
{
public:
 int Add(const int x, const int y, const int z = 100)
 {
  return x + y + z;
 }
};

int Del(const int x, const int y, const int z = 100)
{
 return x - y - z;
}

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(Add_member_overloads, Add, 2, 3)
BOOST_PYTHON_FUNCTION_OVERLOADS(Del_overloads, Del, 2, 3)

BOOST_PYTHON_MODULE(test4)
{
 class_<Test>("Test")
  .def("Add", &Test::Add, Add_member_overloads(args("x", "y", "z"), "something"));
 def("Del", Del, Del_overloads(args("x", "y", "z"), "something"));
}

这里Add和Del函数均采用了默认参数,Del为普通函数,Add为类成员函数,这里分别调用了不同的宏,宏的最后两个参数分别代表函数的最少参数个数和最多参数个数

编译命令如下

g++ test4.cpp -fPIC -shared -o test4.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python

测试如下

>>> import test4
>>> test = test4.Test()
>>> print test.Add(1,2)
103
>>> print test.Add(1,2,z=3)
6
>>> print test4.Del(1,2)
-1
>>> print test4.Del(1,2,z=3)
-1

导出带Python对象的接口

既然是导出为Python接口,调用者难免会使用Python特有的数据结构,比如tuple,list,dict,由于原生态方法太麻烦,这里只记录boost的使用方法,假设要实现如下的Python函数功能

def Square(list_a)
{
 return [x * x for x in list_a]
}

即对传入的list每个元素计算平方,返回list类型的结果

代码如下

#include <boost/python.hpp>

boost::python::list Square(boost::python::list& data)
{
 boost::python::list ret;
 for (int i = 0; i < len(data); ++i)
 {
  ret.append(data[i] * data[i]);
 }

 return ret;
}

BOOST_PYTHON_MODULE(test5)
{
 def("Square", Square);
}

编译命令如下

g++ test5.cpp -fPIC -shared -o test5.so -I/usr/include/python2.6 -I/usr/local/include/boost -L/usr/local/lib -lboost_python

测试如下

>>> import test5
>>> test5.Square([1,2,3])
[1, 4, 9]

boost实现了boost::python::tuple, boost::python::list, boost::python::dict这几个数据类型,使用方法基本和Python保持一致,具体方法可以查看boost头文件里的boost/python/tuple.hpp及其它对应文件

另外比较常用的一个函数是boost::python::make_tuple() ,使用方法如下

boost::python::tuple(int a, int b, int c)
{
 return boost::python::make_tuple(a, b, c);
}

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

Python 相关文章推荐
python自动化测试实例解析
Sep 28 Python
python中__call__内置函数用法实例
Jun 04 Python
python基于pyDes库实现des加密的方法
Apr 29 Python
Django rest framework基本介绍与代码示例
Jan 26 Python
为什么选择python编程语言入门黑客攻防 给你几个理由!
Feb 02 Python
python 自动重连wifi windows的方法
Dec 18 Python
python列表每个元素同增同减和列表元素去空格的实例
Jul 20 Python
PyTorch和Keras计算模型参数的例子
Jan 02 Python
python输出第n个默尼森数的实现示例
Mar 08 Python
python使用Thread的setDaemon启动后台线程教程
Apr 25 Python
基于pycharm实现批量修改变量名
Jun 02 Python
工程师必须了解的LRU缓存淘汰算法以及python实现过程
Oct 15 Python
python中import学习备忘笔记
Jan 24 #Python
用python实现简单EXCEL数据统计的实例
Jan 24 #Python
Python如何import文件夹下的文件(实现方法)
Jan 24 #Python
利用Python脚本实现ping百度和google的方法
Jan 24 #Python
解决python2.7用pip安装包时出现错误的问题
Jan 23 #Python
浅谈终端直接执行py文件,不需要python命令
Jan 23 #Python
在Linux命令行终端中使用python的简单方法(推荐)
Jan 23 #Python
You might like
MYSQL环境变量设置方法
2007/01/15 PHP
laravel5.6 框架邮件队列database驱动简单demo示例
2020/01/26 PHP
JS宝典学习笔记(下)
2007/01/10 Javascript
javascript鼠标滑动评分控件完整实例
2015/05/13 Javascript
js实现延迟加载的方法
2015/06/24 Javascript
Vue.js每天必学之过滤器与自定义过滤器
2016/09/07 Javascript
JS创建对象的写法示例
2016/11/04 Javascript
微信小程序搜索框样式并实现跳转到搜索页面(小程序搜索功能)
2020/03/10 Javascript
vue 输入电话号码自动按3-4-4分割功能的实现代码
2020/04/30 Javascript
Electron+vue从零开始打造一个本地播放器的方法示例
2020/10/27 Javascript
Python访问MySQL封装的常用类实例
2014/11/11 Python
Matplotlib中文乱码的3种解决方案
2018/11/15 Python
在Python中关于使用os模块遍历目录的实现方法
2019/01/03 Python
python,Django实现的淘宝客登录功能示例
2019/06/12 Python
python画图把时间作为横坐标的方法
2019/07/07 Python
Django中在xadmin中集成DjangoUeditor过程详解
2019/07/24 Python
Python完成哈夫曼树编码过程及原理详解
2019/07/29 Python
django 使用 PIL 压缩图片的例子
2019/08/16 Python
pytorch:torch.mm()和torch.matmul()的使用
2019/12/27 Python
解决django 向mysql中写入中文字符出错的问题
2020/05/18 Python
pandas按条件筛选数据的实现
2021/02/20 Python
Europcar美国/加拿大:预订汽车或卡车租赁服务
2018/11/13 全球购物
大学生家政服务项目创业计划书
2014/01/30 职场文书
中学生期末评语
2014/02/03 职场文书
《我要的是葫芦》教学反思
2014/02/23 职场文书
教师爱岗敬业演讲稿
2014/05/05 职场文书
倡议书范文格式
2014/05/12 职场文书
机关党建工作汇报材料
2014/08/20 职场文书
2014年服装销售工作总结
2014/11/27 职场文书
幼儿园大班毕业评语
2014/12/31 职场文书
建国大业电影观后感
2015/06/01 职场文书
Golang Gob编码(gob包的使用详解)
2021/05/07 Golang
Python中使用ipython的详细教程
2021/06/22 Python
vue的项目如何打包上线
2022/04/13 Vue.js
VMware虚拟机安装 Windows Server 2022的详细图文教程
2022/09/23 Servers
Win11 vmware不兼容怎么办?Win11与VMware虚拟机不兼容的解决方法
2023/01/09 数码科技