自学内容网 自学内容网

【测试语言篇四】Python进阶篇之json模块

一、json模块介绍

JSON(JavaScript对象表示法)是一种轻量级数据格式,用于数据交换。 在Python中具有用于编码和解码JSON数据的内置 json 模块。 只需导入它,就可以使用JSON数据了:

import json

JSON的一些优点:

  • JSON作为“字节序列”存在,在我们需要通过网络传输(流)数据的情况下非常有用。
  • 与XML相比,JSON小得多,可转化为更快的数据传输和更好的体验。
  • JSON非常文本友好,因为它是文本形式的,并且同时也是机器友好的。

信息表示格式为:

  • 数据在名称 / 值对中。
  • 数据由逗号分隔。
  • 大括号保存对象。
  • 方括号保存数组。

JSON格式

{
    "firstName": "Jane",
    "lastName": "Doe",
    "hobbies": ["running", "swimming", "singing"],
    "age": 28,
    "children": [
        {
            "firstName": "Alex",
            "age": 5
        },
        {
            "firstName": "Bob",
            "age": 7
        }
    ]
}

JSON支持基本类型(字符串,数字,布尔值)以及嵌套的数组和对象。 根据以下转换,将简单的Python对象转换为JSON:

|Python|JSON| |—|—| |dict|object| |”list, tuple”|array| |str|string| |”int, long, float”|number| |True|true| |False|false| |None|null|

二、从Python到JSON(序列化,编码)

使用 json.dumps() 方法将Python对象转换为JSON字符串。函数原型如下:

json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

其中,obj表示需要序列化的json对象,其他参数用于控制序列化过程。常用参数解释如下:
参数名 | 含义
------- | -------
skipkeys| 如果遇到某些非法格式的Python数据类型,则抛出TypeError异常。如果skipkeys为True,这些非法格式的数据类型将被跳过,不会引发TypeError异常,默认值为False。
ensure_ascii| 默认True,它保证输出的每个字符都是ASCII字符。如果有些字符不能被编码成ASCII字符,它们会被转义为Unicode转义字符。
indent| 顾名思义,这个参数用于控制缩进格式。如果它的值是一个非负整数,输出的JSON字符串就会分行缩进,而且每次缩进两个空格。如果它的值为None,默认不缩进。

separators| 序列化之后的字符串中不同部分的分隔符。默认为(‘,’, ‘:’)。

sort_keys| 用于指定是否按照键进行排序,默认为False。

import json

person = {"name": "John", "age": 30, "city": "New York", "hasChildren": False, "titles": ["engineer", "programmer"]}

# 转为 JSON:
person_json = json.dumps(person)
# 使用不用的格式
person_json2 = json.dumps(person, indent=4, separators=("; ", "= "), sort_keys=True)

# 结果为 JSON 字符串
print(person_json) 
print(person_json2)
    {"name": "John", "age": 30, "city": "New York", "hasChildren": false, "titles":["engineer", "programmer"]}
    {
        "age"= 30; 
        "city"= "New York"; 
        "hasChildren"= false; 
        "name"= "John"; 
        "titles"= [
            "engineer"; 
            "programmer"
        ]
    }

或将Python对象转换为JSON对象,然后使用 json.dump() 方法将其保存到文件中。

import json

person = {"name": "John", "age": 30, "city": "New York", "hasChildren": False, "titles": ["engineer", "programmer"]}

with open('person.json', 'w') as f:
    json.dump(person, f) # 你也可以设置缩进等

三、从JSON到Python(反序列化,解码)

使用 json.loads() 方法将JSON字符串转换为Python对象。 结果将是一个Python字典。

import json
person_json = """
{
    "age": 30, 
    "city": "New York",
    "hasChildren": false, 
    "name": "John",
    "titles": [
        "engineer",
        "programmer"
    ]
}
"""
person = json.loads(person_json)
print(person)
    {'age': 30, 'city': 'New York', 'hasChildren': False, 'name': 'John', 'titles': ['engineer', 'programmer']}
或从文件加载数据,然后使用 json.load()方法将其转换为Python对象。

import json

with open('person.json', 'r') as f:
    person = json.load(f)
    print(person)
    {'name': 'John', 'age': 30, 'city': 'New York', 'hasChildren': False, 'titles': ['engineer', 'programmer']}

使用自定义对象

编码

使用默认的 JSONEncoder 编码自定义对象将引发 TypeError。 我们可以指定一个自定义的编码函数,该函数将类名和所有对象变量存储在字典中。 将此函数用作 json.dump() 方法中的 default 参数。

import json
def encode_complex(z):
    if isinstance(z, complex):
        # 只是类名的键很重要,值可以是任意的。
        return {z.__class__.__name__: True, "real":z.real, "imag":z.imag}
    else:
        raise TypeError(f"Object of type '{z.__class__.__name__}' is not JSON serializable")

z = 5 + 9j
zJSON = json.dumps(z, default=encode_complex)
print(zJSON)
    {"complex": true, "real": 5.0, "imag": 9.0}

你还可以创建一个自定义的 Encoder 类,并覆盖 default() 方法。 将其用于 json.dump() 方法中的 cls 参数,或直接使用编码器。

from json import JSONEncoder
class ComplexEncoder(JSONEncoder):
    
    def default(self, o):
        if isinstance(z, complex):
            return {z.__class__.__name__: True, "real":z.real, "imag":z.imag}
        # 让基类的默认方法处理其他对象或引发TypeError
        return JSONEncoder.default(self, o)
    
z = 5 + 9j
zJSON = json.dumps(z, cls=ComplexEncoder)
print(zJSON)
# 或者直接使用编码器
zJson = ComplexEncoder().encode(z)
print(zJSON)
    {"complex": true, "real": 5.0, "imag": 9.0}
    {"complex": true, "real": 5.0, "imag": 9.0}

解码

可以使用默认 JSONDecoder 解码自定义对象,但是它将被解码为字典。 编写一个自定义解码函数,该函数将以字典作为输入,并在可以在字典中找到对象类名称的情况下创建自定义对象。 将此函数用于 json.load() 方法中的 object_hook 参数。

# 可能但解码为字典
z = json.loads(zJSON)
print(type(z))
print(z)

def decode_complex(dct):
    if complex.__name__ in dct:
        return complex(dct["real"], dct["imag"])
    return dct

# 现在,对象在解码后的类型为complex
z = json.loads(zJSON, object_hook=decode_complex)
print(type(z))
print(z)
    <class 'dict'>
    {'complex': True, 'real': 5.0, 'imag': 9.0}
    <class 'complex'>
    (5+9j)

模板编码和解码函数

如果在 __init__ 方法中提供了所有类变量,则此方法适用于所有自定义类。

class User:
# 自定义类在 __init__() 中包含所有类变量
    def __init__(self, name, age, active, balance, friends):
        self.name = name
        self.age = age
        self.active = active
        self.balance = balance
        self.friends = friends
        
class Player:
    # 其他自定义类
    def __init__(self, name, nickname, level):
        self.name = name
        self.nickname = nickname
        self.level = level
          
            
def encode_obj(obj):
    """
    接受一个自定义对象,并返回该对象的字典表示形式。 此字典表示形式还包括对象的模块和类名称。
    """
  
# 用对象元数据填充字典
    obj_dict = {
      "__class__": obj.__class__.__name__,
      "__module__": obj.__module__
    }
  
    # 用对象属性填充字典
    obj_dict.update(obj.__dict__)
  
    return obj_dict

def decode_dct(dct):
    """
    接受字典并返回与该字典关联的自定义对象。
    它利用字典中的 "__module__" 和 "__class__" 元数据来了解要创建的对象类型。
    """
    if "__class__" in dct:
        # Pop ensures we remove metadata from the dict to leave only the instance arguments
        class_name = dct.pop("__class__")
        
        # Get the module name from the dict and import it
        module_name = dct.pop("__module__")
        
        # We use the built in __import__ function since the module name is not yet known at runtime
        module = __import__(module_name)
        
        # Get the class from the module
        class_ = getattr(module,class_name)

        # Use dictionary unpacking to initialize the object
        # Note: This only works if all __init__() arguments of the class are exactly the dict keys
        obj = class_(**dct)
    else:
        obj = dct
    return obj

# User 类适用于我们的编码和解码方法
user = User(name = "John",age = 28, friends = ["Jane", "Tom"], balance = 20.70, active = True)

userJSON = json.dumps(user,default=encode_obj,indent=4, sort_keys=True)
print(userJSON)

user_decoded = json.loads(userJSON, object_hook=decode_dct)
print(type(user_decoded))

# Player 类也适用于我们的编码和解码方法
player = Player('Max', 'max1234', 5)
playerJSON = json.dumps(player,default=encode_obj,indent=4, sort_keys=True)
print(playerJSON)

player_decoded = json.loads(playerJSON, object_hook=decode_dct)
print(type(player_decoded))
    {
        "__class__": "User",
        "__module__": "__main__",
        "active": true,
        "age": 28,
        "balance": 20.7,
        "friends": [
            "Jane",
            "Tom"
        ],
        "name": "John"
    }
    <class '__main__.User'>
    {
        "__class__": "Player",
        "__module__": "__main__",
        "level": 5,
        "name": "Max",
        "nickname": "max1234"
    }
    <class '__main__.Player'>

四、总结

        Python的JSON模块是一个内置标准库,是python标准库中不可或缺的一部分,可以方便地将python中的数据转换为JSON格式数据,并支持将JSON格式数据转换为python中的数据类型。同时,json模块也支持自定义转换过程,以满足更加复杂的应用场景。
        JSON模块中主要的函数有:dumps()、dump()、loads()和load()。其中dumps()函数将Python内置数据类型转换为JSON字符串,dump()函数将Python内置数据类型转换为JSON格式数据并输出到文件中,loads()函数将JSON字符串转化为Python内置数据类型,load()函数将文件中的JSON格式数据转化为Python内置数据类型。
除此之外,JSON模块中的其他函数还包括:Python对象转化为JSON对象。
        在使用JSON模块的过程中,需注意JSON的标准格式。同时,JSON模块在对Python内置数据类型进行解析或者生成数据时,会调用特定对象的 json() 方法,所以在使用JSON模块的时候,需要注意Python对象的定义,尽量满足 json() 方法的调用要求,以实现更好的数据序列化与反序列化效果。


原文地址:https://blog.csdn.net/m0_37135615/article/details/143587566

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!