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

发布时间 - 2026-01-10 22:46:30    点击率:

前言

大家都知道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  # 调用c语言  # python如何调用c  # python调用c  # 接口  # Python调用C/C++动态链接库的方法详解  # python调用c++传递数组的实例  # Python调用C/C++的方法解析  # python 与c++相互调用实现  # 在python中调用C/C++的三种方法  # 是在  # 第一个  # 数据结构  # 原生态  # 头文件  # 大家都  # 最多  # 不需要  # 则是  # 效率高  # 可以通过  # 要注意  # 第二个  # 能让  # 采用了  # 相辅相成  # 几种  # 几点  # 在对  # 这篇文章 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: Laravel如何使用软删除(Soft Deletes)功能_Eloquent软删除与数据恢复方法  如何挑选高效建站主机与优质域名?  WordPress 子目录安装中正确处理脚本路径的完整指南  如何基于云服务器快速搭建网站及云盘系统?  Python文件操作最佳实践_稳定性说明【指导】  Laravel中DTO是什么概念_在Laravel项目中使用数据传输对象(DTO)  电商网站制作价格怎么算,网上拍卖流程以及规则?  微信小程序制作网站有哪些,微信小程序需要做网站吗?  如何用狗爹虚拟主机快速搭建网站?  linux top下的 minerd 木马清除方法  如何快速辨别茅台真假?关键步骤解析  浅谈redis在项目中的应用  Laravel中间件起什么作用_Laravel Middleware请求生命周期与自定义详解  JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)  JavaScript中的标签模板是什么_它如何扩展字符串功能  如何在 Go 中优雅地映射具有动态字段的 JSON 对象到结构体  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  如何快速搭建自助建站会员专属系统?  Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程  零基础网站服务器架设实战:轻量应用与域名解析配置指南  智能起名网站制作软件有哪些,制作logo的软件?  Swift开发中switch语句值绑定模式  如何在建站之星绑定自定义域名?  实现点击下箭头变上箭头来回切换的两种方法【推荐】  Laravel的Blade指令怎么自定义_创建你自己的Laravel Blade Directives  javascript中的try catch异常捕获机制用法分析  Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置  JS去除重复并统计数量的实现方法  如何注册花生壳免费域名并搭建个人网站?  如何快速打造个性化非模板自助建站?  怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?  品牌网站制作公司有哪些,买正品品牌一般去哪个网站买?  如何在服务器上配置二级域名建站?  宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程  Laravel Seeder怎么填充数据_Laravel数据库填充器的使用方法与技巧  laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法  网站建设整体流程解析,建站其实很容易!  googleplay官方入口在哪里_Google Play官方商店快速入口指南  Laravel如何编写单元测试和功能测试?(PHPUnit示例)  如何获取免费开源的自助建站系统源码?  ,南京靠谱的征婚网站?  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  nodejs redis 发布订阅机制封装实现方法及实例代码  韩国网站服务器搭建指南:VPS选购、域名解析与DNS配置推荐  Laravel Debugbar怎么安装_Laravel调试工具栏配置指南  如何在万网主机上快速搭建网站?  Claude怎样写结构化提示词_Claude结构化提示词写法【教程】  如何在云主机上快速搭建网站?