当前位置:

首页 > 编程开发 > python invoking c++

python invoking c++

利用Boost.Python和pybind11可在Python中调用C++模块。Boost.Python成熟稳定,需手动处理类型转换与生命周期;pybind11语法现代简洁,支持自动处理结构体和成员暴露。两种方案均需编写包装代码并链接对应库,编译命令简洁,调用方式接近原生Python对象。

本文目录

    在Python中调用C++模块,这事说难不难,说简单也不简单。难在跨语言调用的坑太多,比如类型转换、对象生命周期、异常处理,一不小心就踩进去。简单在像Boost.Python和pybind11这样的工具已经相当成熟,把C++代码暴露给Python,很多时候就是写一个wrapper的事。

    下面这份材料,就是把两种方案的「最小可行」路径给你跑了一遍,从代码到构建,清晰明了。

    invoking c/c++ module from python

    我们先从老牌工具Boost.Python看起。

    boost python

    Boost.Python的功力是经过时间验证的,很多老项目都在用它。下面这个代码就是一个典型的封装示例,把底层的C++接口 c_module.h 优雅地包装成了Python可调用对象。

    code

    核心的 wrapper 文件 model_wrapper.cpp。注意看上面对 write 函数的处理——它用了 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS 宏,允许在Python里传2个或3个参数,第三个参数 expire 自带默认值0。这种细节,恰恰是生产级代码里需要的。

    #include 
    #include 
    #include 
    #include 
    #include 
    #include "module_py.h"
    
    using namespace boost::python;
    
    BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(write_overloads, MyModulePy::write, 2, 3);
    
    BOOST_PYTHON_MODULE(module_py)
    {
        boost::python::scope().attr("__version__") = "v20180123.1";
    
        class_("MyModulePy")
            .def("read", &MyModulePy::read)
            .def("batch_read", &MyModulePy::batch_read)
            .def("write_read", &MyModulePy::batch_write)
            .def("write", &MyModulePy::write, write_overloads(args("key", "value", "expire"), "put key-value with a expire time"))
            .def("remove", &MyModulePy::remove)
            .def("config", &MyModulePy::config)
        ;
    }

    好,那接下来一个问题就是,MyModulePy 这个Python类是怎么对接底层C++库的?module_py.h 给出了答案。这里有一点值得留意:batch_read 和 batch_write 中,作者手动处理了字典和列表的转换。这是最绕也是最容易出错的地方——记住,迭代Python字典时,千万不要用 const std::string& k = ... 这种引用捕获方式,否则极大概率会踩到生命周期问题的坑。

    #include "c_module.h" // header of libmodule.so
    
    struct MyModulePy
    {
        MyModulePy() {}
    
        std::string read(const std::string& key)
        {
            // do read
            return mModule.Read(key);
        }
    
        boost::python::dict batch_read(const boost::python::list& keys)
        {
            std::vector ckeys(boost::python::len(keys));
            for (int i = 0; i < boost::python::len(keys); i++)
            {
                ckeys[i] = boost::python::extract(keys[i]);
            }
            std::map cvalues = mModule.BatchRead(ckeys);
            boost::python::dict values;
            for (auto it = cvalues.begin(); it != cvalues.end(); ++it)
            {
                values[it->first] = it->second;
            }
            return values;
        }
    
        void bach_write(const boost::python::dict& keyValues)
        {
            auto skeys = keyValues.keys();
            // http://www.boost.org/doc/libs/1_34_0/libs/python/doc/v2/dict.html
            int num = boost::python::len(skeys);
            std::map datas;
            for (int i = 0; i < num; i++) // TODO: how to iterate a boost::python::dict ?
            {
                string k = boost::python::extract(skeys[i]);
                // NOTE: do not use 'const string& k = '
                string v = boost::python::extract(subKeyValues[skeys[i]]);
                datas[k] = v;
            }
            return mModule.batch_write(datas);
        }
    
        void write(const std::string& key, const std::string& value, const int expire = 0)
        {
            // do write
            mModule.Write(key, value, expire);
        }
    
        void remove(const std::string& key)
        {
            // do remove
            mModule.Delete(key);
        }
    
        std::string config()
        {
            return mModule.GetConfigInfo();
        }
    
        Module mModule; // class provided by libmodule.so
    };

    至于Python端的使用方式,就非常自然了。实例化MyModulePy,调用读写,就像在操作一个纯粹的Python对象。

    import time
    from module_py import MyModulePy
    
    m = MyModulePy()
    
    key = 'testkey_%s' % time.time()
    value = 'testvalue_%s' % time.time()
    
    try:
        print 'config:', m.config()
        m.write(key, value)
        m.write(key, value, 10)
    
        print 'write:', key, value
        print 'read:', key, m.read(key)
    
        print 'delete:', key, m.remove(key)
    
        for i in xrange(0, 3):
            mytair.write('batch-%s' % i, str(i))
    
        keys = ['batch-%s' % i for i in xrange(0, 3)]
        print mytair.batch_read(keys)
    
        for each in keys:
            mytair.remove(each)
    
        print 'read:', key, m.read(key) # exception
    
    except Exception, e:
        print e

    build

    编译命令很简单,关键在于链接 -lboost_python 和你的本地库。

    g++ model_wrapper.cpp -o module_py.so -shared -lmodule -lboost_python

    pybind11

    说完老兵,再来聊聊新锐。pybind11 的语法更现代,上手也更快。项目结构也非常清晰。

    layout

    /home/admin/pybind11_sample/
    |---- py_sample.cpp
    |---- sample.py
    |---- build.sh
    |---- include/
    |       |---- pybind11/
    |       i installed pybind11 at here
    |       |---- text_processor/
    |       c++ module

    code

    py_sample.cpp 里,你会发现 pybind11 用起来要简洁得多。比如 .def_readonly 直接暴露C++成员变量为Python只读属性,省去了写getter的麻烦。返回值是一个自定义结构体 InfoWrapper,pybind11 也能自动处理。

    class TextProcessorWrapper
    {
    public:
        struct InfoWrapper
        {
            std::string simhash_code;
            std::string ancestor_code;
        };
    
    public:
        TextProcessorWrapper(const std::string& data_dir)
        {
            std::map conf;
            conf["data_dir"] = data_dir;
            if (!mTextDedup.Init(conf))
            {
                throw std::runtime_error("failed to init");
            }
        }
    
        ~TextProcessorWrapper()
        {
        }
    
        InfoWrapper process(const std::string& text, const std::string& title)
        {
            TextInfo info;
            mTextProcessor.Process(text, title, info);
            InfoWrapper _info;
            _info.simhash_code = info.simhashCode;
            _info.ancestor_code = info.ancestorCode;
            return _info;
        }
    
    protected:
        TextProcessor mTextProcessor; // define in libtext_processor_st.a
    };
    
    PYBIND11_MODULE(py_sample, m) {
        m.doc() = "text processor"; // optional module docstring
    
        // apy class, __init__(), process()
        py::class_(m, "TextProcessor")
            .def(py::init())
            .def("process", &TextProcessorWrapper::process);
    
        // py class, read only attributes
        py::class_(m, "TextInfo")
            .def_readonly("simhash_code", &TextProcessorWrapper::InfoWrapper::simhash_code)
            .def_readonly("ancestor_code", &TextProcessorWrapper::InfoWrapper::ancestor_code);
    }

    同样地,看看Python侧是怎么用的——创建一个 TextProcessor 实例,传入数据目录,然后调用 process 就能拿到 simhash_code 和 ancestor_code,非常直观。

    #!/usr/bin/env python
    # -*- coding=utf-8 -*-
    import os
    import py_textdedup
    
    data_dir = './data'
    dedup = py_sample.TextProcessor(data_dir)
    info1 = dedup.process("成都—成温邛高速—温江到寿安的丁字路口左转—成青快速通道—过金马河第一个十字路口右转直行即到",
                         "成都看银杏了")
    print info.simhash_code, info.ancestor_code

    build

    pybind11 的编译命令同样不复杂,核心是链接你的静态库 ltext_processor_st 和指定 -std=c++14。

    g++ py_sample.cpp -o py_sample.so -O3 -Wall -shared -std=c++14 -fPIC -I ./include -I /usr/local/include/python2.7 -ltext_processor_st -Wl,--rpath=$$ORIGIN/libs -Wl,--rpath=$$ORIGIN

    ref

    如果想深入了解 pybind11,官方文档是最好的老师。另外,网上也有不少中英文的实战笔记可以参考,基本能覆盖从零到一的全部问题。

    references

    最后,把 Boost.Python 的官方文档链接也列一下,方便查证一些更高级的特性,比如重载、索引套件等。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Python
    上一篇: python编译安装
    相关文章 更多
    python删除一个列表里的重复元素的方法与代码示例
    python删除一个列表里的重复元素的方法与代码示例

    学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

    Python写接口的步骤及完整代码示例
    Python写接口的步骤及完整代码示例

    详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

    codex怎么读取word文档及docx文件操作教程
    codex怎么读取word文档及docx文件操作教程

    介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

    怎么在Python中调用C语言代码提升性能
    怎么在Python中调用C语言代码提升性能

    详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

    Python与C语言的性能差异及底层原理
    Python与C语言的性能差异及底层原理

    深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

    Python和C语言哪个更适合编程入门
    Python和C语言哪个更适合编程入门

    客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
    大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

    针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

    langgraph python guide中文入门教程详解
    langgraph python guide中文入门教程详解

    本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

    Windows 安装 Python:从官方入口到虚拟环境的可复现实践
    Windows 安装 Python:从官方入口到虚拟环境的可复现实践

    面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

    查看更多
    精品专题 更多
    装机必备
    装机必备

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

    Windows
    Windows

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

    PDF教程
    PDF教程

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

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

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

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

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

    Aperty macOS版
    Aperty macOS版
    macOS

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

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

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

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

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

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。