展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > boost.python笔记

boost.python笔记

Boost.python是Boost库的一部分,用于实现C++与Python无缝互操作,无需修改原有C++代码,但需手写封装代码。将C++模块封装为.so库,使Python直接调用,解决RPC调用性能瓶颈。通过定义导出模块、类、函数及成员变量,支持容器类型导出,如vector。

boost.python笔记

标签: boost.python,python, C++

boost.python笔记


简介

Boost.python是什么?

它是boost库的一部分,随boost一起安装,专门用来打通C++和Python之间的壁垒,让这两门语言能无缝协作。

用Boost.python有什么特别之处?

最大的优点是不需要动你原有的C++代码,而且对C++的各种特性支持得相当好。它不会像SWIG那样生成额外的Python代码,但代价是需要你亲手写一部分C++封装代码。

这里只用到它能力的一小部分——把C/C++实现的功能封装成Python可以直接调用的.so库。具体场景是这样的:有一个C++模块通过thrift封装成了RPC服务,Python代码通过RPC调用来请求服务。问题在于调用频率太高,RPC的开销成了性能瓶颈,所以干脆让Python直接调用原模块的功能。

之前了解过SWIG可以实现这个需求,文档都开始看了。转念一想,有没有别的办法?在stack overflow上搜了一圈,发现不少人推荐Boost.python,于是决定拿它来试试水。

如何使用Boost.python

首先,前提是开发环境得配齐:

安装了boost开发环境,头文件和动态库都得有。
安装了python开发环境,头文件和动态库也得有。

然后就是写代码了,这一步怎么都绕不过去!

需要动手的地方有两个。一个是xxxxxx_wrapper.cpp文件——文件名随便起,核心目的是定义要导出的Python模块名称,以及要暴露出去的类、函数等等。另一个是修改你的Makefile,用来编译、链接这个.so库。

先看看xxxxxx_wrapper.cpp长什么样。一般情况下,它的内容跟下面的代码差不多。

#include // 其他需要包含的头文件,与具体业务有关 namespace py = boost::python; // 其他函数,可能包括一些用于类型转换和封装的 BOOST_PYTHON_MODULE(my_module_name) { // 导出普通函数 def("fun_name_in_python", &fun_name_in_c); // 导出类及部分成员 class_("ClassNameInPython", init()) //类名,默认构造函数 .def(init()) //其他构造函数 .def("memberFunNameInPython", &ClassNameInCpp::memberFunNameInCpp) //成员函数 .def_readwrite("dataMemberInPython", &ClassNameInCpp::dataMemberInCpp) //普通成员变量 .def_readonly("dataMemberInPython_2", &ClassNameInCpp::dataMemberInCpp_2)//只读成员变量 ; }

这个文件的核心目的全在BOOST_PYTHON_MODULE里——定义要导出给Python的所有东西。

在Makefile里,需要加一条规则来编译导出的.so文件。通用的编译命令长这样,这里把编译和链接写在一起了。

g++ -o my_module_name.so -shared -fPIC -I${BOOST_INCLUDE_PATH} -I${PYTHON_INCLUDE_PATH} -L${BOOST_LIB_DIR} -lboost_python ${MY_SRC_FILES}

各个参数的作用如下,其他参数就得看具体项目的业务逻辑了:

-o my_module_name.so——这里的模块名必须和xxxxxx_wrapper.cpp里BOOST_PYTHON_MODULE(my_module_name)保持一致;
-I${BOOST_INCLUDE_PATH} -I${PYTHON_INCLUDE_PATH}是编译阶段需要的;
-L${BOOST_LIB_DIR} -lboost_python -shared -fPIC是链接阶段需要的;
${MY_SRC_FILES}包含了xxxxxxx_wrapper.cpp以及业务逻辑需要的其他.cpp、.c文件。

至此,my_module_name.so这个可以被Python调用的模块就诞生了。来测试一下效果:

>>>import my_moduel_name >>>help(my_module_name)

可以看到被导出的类及函数,然后就能像操作普通Python对象那样使用它们了。

如何写wrapper

用一个实例来讲解,内容涵盖普通函数、类、数据成员、成员函数、通过参数传递结果、容器。其他更复杂的特性这里没用到,也没有测试过。

先看看业务逻辑的代码。包含一个类、一个以类对象为参数的函数、一个通过引用修改类对象的函数。

//test_class.h // 定义一个类 class A { public: A(){privateVal=0;}//默认构造函数 A(int val){privateVal=val;} //带参数的构造函数 void set(int val){privateVal=val;}//成员函数 int get() const {return privateVal;}; //成员函数 int publicVal;//公共数据成员 private: int privateVal; //私有数据成员 }; int addA(A &a, int addVal); //普通函数,有返回值,通过引用修改参数 void printA(const A& a);

//test_class.cpp #include #include "test_class.h" int addA(A &a, int addVal){ int val = a.get(); val += addVal; a.set(val); return val; } void printA(const A& a){ printf("%d\n", a.get()); }

然后是wrapper.cpp文件,这里实际叫test_class_wrapper.cpp。

//test_class_wrapper.cpp #include #include "test_class.h" BOOST_PYTHON_MODULE(test_class){ using namespace boost::python; // 导出类 class_("A", init<>())//如果默认构造函数没有参数,可以省略 .def(init()) //其他构造函数 .def("get", &A::get)//成员函数 .def("set", &A::set)//成员函数 .def_readwrite("publicVal", &A::publicVal)//数据成员,当然是公共的 ; def("printA", &printA); def("addA", &addA); }

用Python命令行测试一下:

>>>import test_class >>>a = test_class.A(5) >>>ret = addA(a, 10) >>>print ret 15 >>>print a.get() 15

到目前为止,整个过程相当顺畅。需要额外写的代码很少,也很规整,接近某种IDL的写法——只需要“声明”一下,剩下的事情都交给编译器和库去处理。但有些时候就没这么顺利了,可能需要额外写一些转换和封装代码。比如前面提到过的容器,上面的例子就没有涉及。

接下来,对上面的例子做了一些扩展。第一,给类A增加了一个vector成员,需要在Python代码里引用这个成员;第二,增加了一个以vector为参数的函数,需要在Python代码里直接调用。下面就来解释容器相关的导出。

#include class B; class A{ public: A(){privateVal=0;}//默认构造函数 A(int val){privateVal=val;} //带参数的构造函数 void set(int val){privateVal=val;}//成员函数 int get() const {return privateVal;}; //成员函数 int publicVal;//公共数据成员 std::vector m_vB; private: int privateVal; //私有数据成员 }; class B{ public: B(){} ~B(){} int pos; int len; }; int accumulate(const std::vector& v_A); int addA(A &a, int addVal); //普通函数,有返回值,通过引用修改参数 void printA(const A& a);

#include #include "test_class.h" int addA(A &a, int addVal){ int val = a.get(); val += addVal; a.set(val); return val; } void printA(const A& a){ printf("%d\n", a.get()); } int accumulate(const std::vector& v_A){ int ret = 0; for (size_t i = 0; i < v_A.size(); i++){ ret += v_A[i].get(); } return ret; }

首先,得明白一点:C++里的vector不等于Python里的list,虽然它们看起来挺像的。Boost.python里有与Python的list对应的东西,叫boost::python::list。如果在Python代码里以list为参数调用某个方法,C++代码里这个参数会被自动映射成boost::python::list,而不是vector。那问题来了:如果不想修改原有的C++代码,又想调用以vector为参数的函数,怎么办?

目前了解的方法有两种:

在C++代码里对以vector为参数的函数做一层封装,封装成以boost::python::list为参数的函数,然后导出封装后的函数。在函数里通过boost::python::extract_对list里的每个成员进行提取,把它们从boost::python::object对象变成T类型的对象,存入vector中,再调用以vector为参数的函数。如果需要返回list,或者原函数对vector参数的内容做了修改,还需要把调用函数后的vector里的每个元素再放回list里。

直接导出vector类型。这样一来,vector本身作为一个类型被导出给Python代码,跟普通的类平起平坐。但和普通类不同的是,它通过模板vector_indexing_suite >()导出,自动实现了append、slice、__len__等方法,在Python里可以像操作list那样操作这个导出的vector类。而且,以vector为参数的函数,在通过def导出给Python时,参数会被自动映射成vector_indexing_suite >。同理,Python代码传入的通过vector_indexing_suite导出的容器对象,也会在C++代码里被自动转换成vector,不需要显式写转换函数。

下面的wrapper代码使用了第二种方法——直接导出vector类型。

为什么选它?因为A里有个vector成员,要导出这个成员,就必须导出vector这个类型。否则只能对类A再做一层封装,让它包含一个boost::python::list成员,那就太麻烦了。

#include #include #include "test_class.h" bool operator==(const B& left, const B& right); bool operator==(const A& left, const A& right){ if (left.get() != right.get() || left.publicVal != right.publicVal) return false; if (left.m_vB.size() != right.m_vB.size()) return false; for (size_t i = 0; i < left.m_vB.size(); i ++) { if (!(left.m_vB[i] == right.m_vB[i])) return false; } return true; } bool operator==(const B& left, const B& right){ return (left.pos == right.pos && left.len == right.len); } BOOST_PYTHON_MODULE(test_class){ using namespace boost::python; class_("A", init<>())//如果默认构造函数没有参数,可以省略 .def(init()) //其他构造函数 .def("get", &A::get)//成员函数 .def("set", &A::set)//成员函数 .def_readwrite("publicVal", &A::publicVal)//数据成员,当然是公共的 .def_readwrite("vB", &A::m_vB); class_ >("VecA") .def(vector_indexing_suite >()); class_("B") .def_readwrite("pos", &B::pos) .def_readwrite("len", &B::len); class_ >("VecB") .def(vector_indexing_suite >()); def("printA", &printA); def("addA", &addA); def("accumulate", &accumulate); }

从BOOST_PYTHON_MODULE内的代码开始看:

class_的定义和之前的例子相比没什么差别,只是多导出了一个成员.def_readwrite("vB", &A::m_vB)。即使这个成员变量是vector类型的,也不需要特殊对待;
class_就是导出一个类,包含两个公共数据成员,没什么特别的;
class_ >("VecA")和class_ >("VecB")是本例的重点——导出了两个不同的vector类型。因为在C++里,vector是一个类模板,vector
和vector才是两个具体的类型;
printA、addA、accumulate是三个导出的函数。即使参数是vector
类型,也无需特别对待。

另外,注意为类型A和B定义了==操作符。这是Boost.python在导出某种类型的vector时需要的——内部某个地方会用到==操作符。如果只导出类型本身,不导出类型的向量,是不需要==操作符的,就像前面的例子那样。编译链接完成后,再来看看Python命令行的测试结果:

>>>import test_class >>>a1 = test_class.A() >>>b1 = test_class.B() # 实例化一个B >>>b1.pos = 1 >>>b1.len = 1 >>>b2 = test_class.B()# 实例化另一个B >>>b2.pos = 2 >>>b2.len = 2 >>>a1.vB.append(b1)# a1.vB是vector在python中对应类型的对象,接口类似list,但只能添加B类型的对象 >>>a1.vB.append(b2) >>>print a1.vB[-1].len# a1.vB支持list的下标引用 2 >>>a1.set(1) >>>a2 = test_class.A(2) >>>a3 = test_class.A(3) >>>vA = test_class.VecA()# vector在python中对应的类型 >>>vA.append(a1) >>>vA.append(a2) >>>vA.append(a3) >>>print accumulate(vA)# 调用以vector为参数的函数 6

对于导出的Python模块来说,一切会在Python代码里被引用的变量,其所属类型(基本数据类型除外)都需要被明确导出——也就是说,都得在BOOST_PYTHON_MODULE里定义。比如本例中的vector,虽然没有函数以该类型为参数,但如果想在Python代码里引用A的成员vB,就必须导出它,否则会抛异常。反过来,如果不需要在Python代码里引用这个成员,就不需要导出vector这个类型,而且class_定义中的.def_readwrite("vB", &A::m_vB)也应该去掉。如果不导出vector类型,却在class_定义中通过.def_readwrite("vB", &A::m_vB)导出了该成员,编译不会出问题,使用Python模块也不会出问题——但只要代码引用到A.vB就会抛异常,这相当于埋了一个坑。

从实用的角度看,这样的流程可能会比较有效:首先确定需要导出的函数及类型;然后检查函数(包括成员函数)参数及返回值的类型,非基本类型需要被导出;再检查导出的类成员变量,如果不是基本类型,其类型也要导出。如此反复,直到没有新的类型需要被添加为止。

总结

Boost.python的官方文档感觉不算多,很多问题和trick都是在stack overflow上看到再自己试验的。据了解,Boost.python支持的C++特性比这丰富得多,这里只用到了一小部分而已。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发 Python
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
WPS Office macOS版
WPS Office macOS版

WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,

Shapr3D macOS版
Shapr3D macOS版

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

Adobe After Effects macOS版
Adobe After Effects macOS版

Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

Adobe Audition macOS版
Adobe Audition macOS版

Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

Adobe Bridge macOS版
Adobe Bridge macOS版

Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

Adobe Illustrator macOS版
Adobe Illustrator macOS版

Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

Adobe InDesign macOS版
Adobe InDesign macOS版

Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

Adobe Lightroom Classic macOS版
Adobe Lightroom Classic macOS版

Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

Adobe Media Encoder macOS版
Adobe Media Encoder macOS版

Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

Adobe Photoshop macOS版
Adobe Photoshop macOS版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

WINDOWS 更多
Autodesk Fusion Windows版
Autodesk Fusion Windows版

Autodesk Fusion 是面向产品设计与制造的云连接开发平台,在统一环境中整合三维 CAD、CAM、CAE、PCB、工程图、数据管理和团队协作功能,适合产品设计师、机械工程师、电子工程师及加工制造团队完成从概念建模、验证分析到生产交

Archicad Windows版
Archicad Windows版

Archicad 是 Graphisoft 面向建筑师、设计师、工程师及 BIM 团队开发的建筑信息模型平台。它把三维建筑建模、施工文档、数据管理、专业协调、实时协作和可视化集中在统一项目环境中,适合从概念方案到施工交付的完整建筑设计流程。

Vectorworks Architect Windows版
Vectorworks Architect Windows版

Vectorworks Architect 是面向建筑师、室内设计师和建筑顾问的综合设计与BIM平台,覆盖概念草图、二维制图、三维建模、施工文档、数据报表、可视化及开放式协作。它强调自由造型与数据化建筑对象并存,

Shapr3D Windows版
Shapr3D Windows版

Shapr3D 是一款基于 Siemens Parasolid 几何内核的专业三维CAD软件,可在 Windows 电脑和平板设备上完成草图绘制、实体建模、参数化修改、模型可视化及技术图纸制作。软件提供免费基础方案,

FreeCAD Windows版
FreeCAD Windows版

FreeCAD 是面向机械设计、产品开发、建筑建模和创客项目的免费开源参数化三维 CAD 工具。它可在 Windows 上完成约束草图、实体零件、装配、工程图、BIM、有限元分析及 CAM 等任务,

Twinmotion Windows版
Twinmotion Windows版

Twinmotion 是 Epic Games 推出的实时三维可视化工具,可导入常见 CAD、BIM 与三维模型,通过材质、环境、植被、灯光及动画资源快速构建场景,并输出图片、视频、全景图和交互演示。

BricsCAD Windows版
BricsCAD Windows版

BricsCAD 是以 DWG 为核心格式的专业 CAD 平台,可用于二维制图、三维建模、工程文档与设计协作。产品按 Lite、Pro、BIM、Mechanical 和 Ultimate 等层级提供不同工具,

Ableton Live Windows版
Ableton Live Windows版

Ableton Live 是面向音乐创作、录音、编曲、声音设计、混音与现场演出的数字音频工作站。它将适合即兴触发素材的 Session 视图与传统时间线编曲结合,并提供音频变速、MIDI工具、软件乐器、效果器和声音资源,

FL Studio Windows版
FL Studio Windows版

FL Studio 是 Image-Line 推出的数字音频工作站,面向音乐制作人、编曲者、歌手及声音设计人员。它将步进音序、钢琴卷帘、音频录制、剪辑、混音、自动化和插件宿主整合在统一环境中,并提供大量乐器、效果器、采样与预设。

Pro Tools Windows版
Pro Tools Windows版

Pro Tools 是 Avid 推出的专业数字音频工作站,提供多轨录音、音频剪辑、MIDI编曲、插件处理、自动化混音及影视声音制作能力。它适合音乐人、录音师、制作人和音频后期团队使用,并提供免费入门版、订阅方案及永久授权选择。

Adobe Audition Windows版
Adobe Audition Windows版

Adobe Audition 是面向播客、影视后期、广播与音乐制作的专业音频工作站,提供波形编辑、多轨混音、频谱分析、录音、降噪修复和效果处理等功能。Windows 版通过 Adobe Creative Cloud 安装和管理,

REAPER Windows版
REAPER Windows版

REAPER 是 Cockos 推出的数字音频工作站,适用于录音、MIDI 编曲、音频编辑、混音、母带制作及声音设计。软件安装包小巧,支持多轨录制、灵活路由、自动化、第三方插件和脚本扩展,并提供完整功能的 60 天免费评估期。

网站备案号:苏ICP备2026018738号-1 联系邮箱:bd@zhengruan.com

Copyright ©2018-2026