• Python用C++开发Python库


    前言

    很多系统为了保证数据在系统上下游的自动校验,避免数据结构异常带来的系统稳定性问题,都会用 json 格式进行数据交互,可以采用 json-schema 来定义 json接口 ,并利用 json-schema-validator 来校验接口响应的结构的合法性。(文末送读者福利)

    然而系统中不同子系统的实现(编程语言)并非总是一致,虽然各种语言都提供了 json-schema-validator 的具体实现,但是不同语言支持的 json-schema-validator 标准的版本并非完全一致,这会对后续的使用带来一些混乱,例如:

    Java: json-schema-validator 支持 Draft 4
    C++: json-schema-validator 支持 Draft 7
    Python jsonschema 支持 Draft 7

    目前大多数语言,例如:Java, Golang, Php, Python, Lua等都支持C/C++的扩展。因此,可以用C/C++来为其他语言提供统一的扩展库支持,本文就是介绍怎么利用 Boost::Python 库提供 json-schema-validator 的Python支持,并介绍如何利用 distutils 来编译&分发Python库。

    Python调用C/C++的方式

    有两种方式可以实现Python调用C/C++编写的库:

    ctypes
    
    • 1

    ctypes加载so文件

    ctype 是Python的外部函数库。它提供了C兼容的数据类型,并允许在DLL或共享库中调用函数。

    ctype 是Python封装的API函数库。其中 cdll = 是一个库加载器对象,调用 cdll.LoadLibrary 便可调用C/C++的so库。

    此处不再对如何使用 ctype 模块加载so文件做过多的介绍,具体可以参考其 官方文档 。

    使用Python扩展

    该方式是Python为整合其它语言而提供的一种扩展机制,并且该机制不局限于C/C++,也可以用于其它语言。Python的可扩展性具有如下的优点:

    1、方便为语言增加新功能
    2、具有可定制性
    3、可以实现代码复用
    ……
    该方式的具体使用此处也不再做过多介绍,具体信息可以直接参考Python的官方文档 Building C and C++ Extensions 来了解。接下来要讲的例子就是利用了 可以实现代码复用 的优点。

    如 Building C and C++ Extensions 所示,Python提供了 Python/C++ API 用来实现Python和C++的交互。然而,直接使用这些API来完成Python和C/C++的交互还是会存在很多重复工作的。 Boost::Python 则对 Python/C++ API 进行了抽象和包装,从而使得Python和C++的交互更加方便。

    Boost::Python封装C/C++扩展

    接下来我们介绍我们是如何利用Boost::Python来为
    nlohmann_json_schema_validator 增加Python扩展。

    nlohmann_json_schema_validator is a C++ library for validating JSON documents based on a JSON Schema which itself should validate with draft-7 of JSON Schema Validation .

    编译nlohmann json schema validator库

    nlohmann json schema validator 支持产出可执行的bin文件以及可供其他项目使用的动态库。为了可以将该扩展包装成Python扩展,我们需要生成该库的动态库。

    首先根据 nlohmann json schema validator 的 编译文档 编译出 nlohmann json schema validator 的动态库。
    在这里插入图片描述

    Boost::Python封装C/C++代码

    在安装Boost的时候,虽然Boost的头文件中存在Boost::Python相关的hpp文件,但是默认却没有该动态库。因此,在使用Boost::Python之前,首先需要安装该库。

    $ brew install boost-python3
    
    • 1

    然后,我们用C++编写 class json_validator_python; 来封装 nlohmann json schema validator 库,并利用Boost::Python来导出,具体如下:

    // jsv_python.cpp
    
    #include 
    #include 
    
    #include 
    #include 
    
    using namespace boost::python;
    
    class JSON_SCHEMA_VALIDATOR_API json_validator_python
    {
    private:
        nlohmann::json_schema::json_validator validator;
    
    public:
        json_validator_python() {}
        void set_root_schema(const std::string &json_string) 
        {
            validator.set_root_schema(nlohmann::json::parse(json_string.begin(), json_string.end()));
        }
    
        void validate(const std::string &json_string) const
        {
            validator.validate(nlohmann::json::parse(json_string.begin(), json_string.end()));
        }
    };
    
    // json_schema_validator为module名,必需和生成的so库名一样
    BOOST_PYTHON_MODULE(json_schema_validator)
    {
        class_ ("json_validator_python")
                .def("set_root_schema", &json_validator_python::set_root_schema)
                .def("validate", &json_validator_python::validate)
                ;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    如上所示的 BOOST_PYTHON_MODULE 代码,目的是导出类及成员方法,这些导出的类和方法可以在Python中调用。

    关于Boost::Python更详细的使用,可以参考其 官方文档 。

    编译并产出Python扩展

    g++ --std=c++11 -fPIC -c jsv_python.cpp \
    -I${json-schema-validator_PATH}/src \
    -I${nlohmann-json_PATH} \
    -I${Boost_PATH}/include \
    -I${Python_INCLUDE_PATH}
    
    g++ --std=c++11 -shared \
    -L${json-schema-validator_LIB_PATH} \
    -L${Python_LIB_PATH} \
    -L${Boost_Python_LIB_PATH} \
    -lnlohmann_json_schema_validator \
    -lboost_python38 -lpython3.8 \
    -o json_schema_validator.so jsv_python.o
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    如上的指令,会生成封装之后的Python扩展: json_schema_validator.so 。

    测试python扩展

    在当前目录执行如下的Python代码,可以发现,我们封装的扩展已经可以当做Python扩展来导入并使用了。

    import json_schema_validator as jsv
    
    validator = jsv.json_validator_python()
    
    
    isValidator = True
    try:
        validator.set_root_schema('{"type":"object", "properties": {"a":{"type": "string"}}}')
        validator.validate('{"a":"1"}');
    except:
        isValidator = False
    
    print(isValidator)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    使用distutils编译并分发扩展

    为了使用方便,使用 Building C and C++ Extensions 介绍的 distutils模块 编译Python扩展。

    from distutils.core import setup, Extension
    import os
    
    os.environ["CC"] = "g++"
    os.environ["CXX"] = "g++"
    
    module1 = Extension('json_schema_validator',
                        include_dirs = ['../../src',
                            '../../',
                            '/usr/local/Cellar/boost/1.72.0_3/include',
                            '/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/include/python3.8'],
                        libraries = ['boost_python38', 'python3.8',
                            'nlohmann_json_schema_validator'],
                        library_dirs = ['/usr/local/opt/python@3.8/Frameworks/Python.framework/Versions/3.8/lib',
                            '/usr/local/Cellar/boost-python3/1.72.0_1/lib',
                            '.'],
                        sources = ['jsv_python.cpp'],
                        extra_compile_args=['--std=c++11'],
                        extra_link_args=['--std=c++11'])
    
    setup (name = 'json-schema-validator',
           version = '1.0',
           description = 'json schema validator',
           ext_modules = [module1])
    $ python3 setup.py build
    $ python3 setup.py install
    $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/python3.7/site-packages/json_schema_validator
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    然后就可以在任意位置,执行一节的测试代码啦。

    大家平时学习Python的时候肯定会遇到很多问题,小编我为大家准备了Python学习资料,将这些免费分享给大家!如果想要的可以找我领取

    读者福利:知道你对Python感兴趣,便准备了这套python学习资料,

    对于0基础小白入门:

    如果你是零基础小白,想快速入门Python是可以考虑培训的。

    一方面是学习时间相对较短,学习内容更全面更集中。

    零基础Python学习资源介绍

    👉Python学习路线汇总👈

    Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(学习教程文末领取哈)

    👉Python必备开发工具👈

    温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

    👉Python学习视频600合集👈

    观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

    👉实战案例👈

    光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

    👉100道Python练习题👈

    检查学习结果。

    👉面试刷题👈



    在这里插入图片描述

    资料领取

    上述这份完整版的Python全套学习资料已经上传网盘,朋友们如果需要可以微信扫描下方二维码输入“领取资料” 即可自动领取
    或者

    点此链接】领取

    好文推荐

    了解python的前景: https://blog.csdn.net/weixin_49892805/article/details/127196159

    python有什么用: https://blog.csdn.net/weixin_49892805/article/details/127214402

  • 相关阅读:
    C/C++空格分开输出 2019年12月电子学会青少年软件编程(C/C++)等级考试一级真题答案解析
    助力工业物联网,工业大数据之服务域:node_exporter插件【三十七】
    【数据结构】静态分配的顺序表的按值查找和按位查找
    前端工作总结249-uni-关闭onshow的加载方法uni.hideLoading
    Kafka在SpringBoot中的实践
    Vuex:辅助函数:mapState,mapMutations,mapActions,mapGetters
    字节面试流程及面试题无私奉献,吐血整理
    分治:循环比赛
    swin_transformer源码详解
    苹果ios系统IPA包企业签名手机下载应用可以有几种方式可以下载到手机?
  • 原文地址:https://blog.csdn.net/weixin_49892805/article/details/127707653