展开菜单
首页 精品内容 本月促销 装机必备 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软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。

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

    Copyright ©2018-2026