• Java开发者的Python进修指南:JSON利器之官方json库、demjson和orjson的实用指南


    JSON

    JSON作为目前最流行的传输格式,在Python中也有相应的实现方式。由于JSON格式的文本可以跨平台并且简单易用,因此被广泛传播。因此,我们今天的主要讨论内容是如何熟练地应用Python的JSON库来处理将JSON映射到文本,以及如何从文本映射到对象中。现在,让我们开始探讨这个话题。

    官方json库

    在Python中,官方提供了多个JSON库,包括标准库中的json、marshal和pickle。其中,我个人比较喜欢使用json库,因为pickle存在一些反序列化漏洞,并且它处理的是二进制类型的数据。相比之下,json更类似于我们在Java中使用的fastjson,但它们之间仍然存在一些明显的差异。接下来,我们继续深入了解一下。

    简单用法

    import json
    
    json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
    # '["foo", {"bar": ["baz", null, 1.0, 2]}]'
    print(json.dumps("\"foo\bar"))
    # "\"foo\bar"
    print(json.dumps('\u1234'))
    # "\u1234"
    print(json.dumps('\\'))
    # "\\"
    print(json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True))
    # {"a": 0, "b": 0, "c": 0}
    from io import StringIO
    io = StringIO()
    json.dump(['streaming API'], io)
    io.getvalue()
    # '["streaming API"]'
    

    上面提到的是官方提供的一些JSON库的示例,我们不再深入讨论。现在,让我们来讲解一下在工作中如何使用JSON进行对象的序列化和反序列化。

    进阶用法

    当前端返回给后端一串JSON文本时,我们可以使用json.loads()方法将其正确映射到Python对象中。这个过程称为反序列化。使用对象来处理数据会更规范一些,尽管对于一些快速开发来说,直接使用字典可能更方便。不过,我可以给你演示一下如何使用对象进行反序列化。

    首先,我们可以定义一个类来表示我们要映射的对象,然后利用json.loads()方法将JSON文本转换为字典。接着,我们可以使用字典的键值对来为对象的属性赋值。这样,我们就成功地将JSON文本映射到了对象中。让我来给你演示一下:

    {"status":1,"info":"成功","data":{"id":"52","age":"70"}}

    上面是我们接收的参数,我们需要对其进行处理,将其映射到相应的对象中。

    import json
    
    class Response_data:
        def __init__(self, id, feed_id):
            super().__init__()
            self.id = id
            self.feed_id = feed_id
    
    class Response:
    
        def __init__(self, status=None, info=None, data=None) -> None:
            super().__init__()
            self.status = status
            self.info = info
            self.data = data
    
        def to_json(self):
            return {
                "status": self.status,
                "info": self.info,
                "data": self.data.__dict__ if self.data else None
            }
    
        @staticmethod
        def object_hook(d):
            if "status" in d :
                return Response(d['status'], d['info'], d['data'])
            else:
                return Response_data(d['id'],d['feed_id'])
    
    
    body = '{"status":1,"info":"发布成功","data":{"id":"52","feed_id":"70"}}'
    
    resp = json.loads(body, object_hook=Response.object_hook)
    print(json.dumps(resp.to_json(),ensure_ascii=False))
    

    在上述代码中,我们使用了object_hook参数。object_hook参数的主要作用是用来自定义解码函数。它的入参是标准反序列化后的字典,我们可以根据自己的规则将其转换为所需的格式。

    为什么我需要在object_hook中编写if判断呢?这是因为object_hook参数在反序列化时是递归的。由于我的JSON文本是嵌套的结构,所以每一层嵌套都会递归一次。因此,我需要先封装好Response_data,然后才能继续封装Response。这与Java中的JSON序列化有很大的不同。在Java中,我们不需要关注这么多细节。但是在Python中,我们不仅需要指定参数名称,还需要处理好嵌套结构。

    如果你在解析中文时遇到问题,很可能是由于默认的编码格式不支持中文字符。为了解决这个问题,你可以尝试使用ensure_ascii=False参数。通过设置这个参数,可以禁用ASCII编码,从而保留中文字符的原始形式。

    多说一句

    json库是在Python2.6版中引入的,因此如果您使用的是更早版本的Python,您可以通过PyPI获取simplejson库来实现相同的功能。

    json 类型转换到 python 的类型对照表:

    JSON Python
    object dict
    array list
    string unicode
    number (int) int, long
    number (real) float
    true True
    false False
    null None

    三方json库

    demjson

    Demjson是一个Python的第三方模块库,它提供了编码和解码JSON数据的功能,并且还包含了JSONLint的格式化和校验功能。此外,Demjson还支持hook,可以通过decode函数配置和set_hook函数配置两种方式进行配置。

    你可以在以下网址找到Demjson的Github地址:https://github.com/dmeranda/demjson。同时,你也可以在官方地址http://deron.meranda.us/python/demjson/上了解更多关于Demjson的信息。

    decode函数是Demjson提供的一个功能强大的函数,它可以接受多个参数,其中包括hook函数。通过键值对的方式指定hook函数,键是hook函数的名称,而值是hook函数本身。

    如果你在安装Demjson时遇到了报错,可能是因为需要降低setuptools的版本到57.5.0。不过我就不进行实验和验证了。

    orjson

    在日常的开发工作中,我们经常需要将一些数据存储为JSON格式。而最常用的方法是使用Python原生的JSON库。然而,我们发现该库的速度较慢,特别是当数据量过大时,使用起来非常不便。幸运的是,我们发现了orjson这个强大的工具,它不仅支持多种类型的数据序列化,还可以根据开发者的需求进行定制化输出。与其他第三方JSON库相比,orjson具有更高的效率,因此在处理大量数据时,它是一个更好的选择。

    我们来看一下它是如何运作的。下面是一个使用dataclasses模块的示例代码:

    from dataclasses import dataclass
    
    @dataclass
    class Person:
        name: str
        age: int
    
    # 假设您有一个包含 JSON 数据的字符串
    json_data = '{"name": "xiaoyu", "age": 18}'
    
    # 使用 orjson 反序列化 JSON 数据
    import orjson
    
    data_dict = orjson.loads(json_data)
    
    # 将字典转换为 Person 对象
    person = Person(**data_dict)
    
    # 现在,您可以像访问对象属性一样访问 person 对象的属性
    print(person.name)  # 输出 "xiaoyu"
    print(person.age)   # 输出 18
    

    经过仔细观察,我发现这两种方式看起来确实非常相似,官方的JSON模块也能实现相同的功能。但是当我们尝试将person对象转换成字符串时,官方的JSON模块无法完成这个任务,而orjson则可以轻松胜任。

    orjson.dumps(person)
    

    option参数

    orjson还支持使用option参数来定制序列化的结果。当然,还有很多其他的选项可以使用,但是由于太多了,我就不一一列举了。不过,我可以简单举一个日期格式的例子,因为在我们的工作中,通常需要对日期格式进行处理。

    option=orjson.OPT_OMIT_MICROSECONDS: 序列化的日期时间对象将以字符串形式呈现,而不是默认的 ISO 8601 格式。这个选项在某些情况下可能更加便利,尤其是在与其他系统进行数据交换时。通过使用该选项,您可以确保日期时间对象的格式与其他系统的要求相匹配,从而简化数据交换的过程。

    import orjson
    from datetime import datetime
    
    data = {"name": "xiaoyu", "dob": datetime(2020, 5, 1)}
    json_data = orjson.dumps(data, option=orjson.OPT_OMIT_MICROSECONDS)
    print(json_data.decode())
    

    为什么需要进行解码呢?原因主要在于orjson返回的是二进制数据,而我们需要将其转换为字符串类型,因此需要进行解码操作。

    总结

    JSON是一种流行的数据传输格式,Python中有多种处理JSON的方式。官方的json库是最常用的,它提供了简单的用法来序列化和反序列化JSON文本。此外,它还支持自定义解码函数,可以将JSON映射到对象中。

    在使用官方json库时,可以使用dumps函数将Python对象转换为JSON文本,也可以使用loads函数将JSON文本转换为Python对象。如果需要自定义解码函数,可以使用object_hook参数来实现。

    除了官方的json库,还有一些第三方的库可供选择。例如,demjson库提供了JSON数据的编码和解码功能,并支持hook函数。另外,orjson库是一个高效的JSON库,支持多种数据类型的序列化,并提供了定制化输出的选项。

    总之,掌握Python的JSON处理库对于处理JSON数据非常重要,可以帮助我们在项目开发中更加高效地处理JSON数据。

  • 相关阅读:
    【LeetCode】每日一题:反转链表
    Dotnet工具箱:开源、免费的纯前端工具网站,带你探索10大工具分类和73个实时在线小工具
    VMware和Debian下载
    LeetCode每日两题02:字符串的排列 (均1200道)方法:哈希表-双指针-滑动窗口
    Java序列化流的奇妙之旅
    基于scikit-learn支持向量机(Support vector machine)的实现
    STM32项目 -- 选题分享(部分)
    《Bayes-Optimal Hierarchical Multi-label Classificaiton》-TKDE
    1024程序员狂欢节特辑 | ELK+ 协同过滤算法构建个性化推荐引擎,智能实现“千人千面”
    简单的python爬虫工具,B站视频爬虫
  • 原文地址:https://www.cnblogs.com/guoxiaoyu/p/17975802