约 5857 字

约 29 分钟

#Python 中使用 JSON

JSON(JavaScript Object Notation)是用于将结构化数据表示为 JavaScript 对象的标准格式,通常用于在网站上表示和传输数据(例如从服务器向客户端发送一些数据,因此可以将其显示在网页上)。 虽然 JSON 源自 JavaScript,但几乎所有编程语言都有存取 JSON 的 API。

在 Python 中,可以使用内置的 json 模块将对象序列化为 JSON 字符串或将 JSON 字符串反序列化为对象。

函数说明
dumps将对象序列化为 str
loads将 str 反列化为对象
dump将对象序列化为 str 并写入文件
laod读取文件中的 str 并反列化为对象

函数说明:

def dumps(obj) -> str:
    '''
    将对象序列化为 JSON 字符串

    :param obj: 要序列化的对象
    :return: 序列化后的 JSON 字符串
    '''
    pass

def loads(json_str:str):
    '''
    将 JSON 字符串反列化为对象

    :param json_str: 要反序列化的 JSON 字符串
    :return: 反序列化后的对象
    '''
    pass

def dump(obj, fp) -> str:
    '''
    将对象序列化为 JSON 字符串并存入文件中

    :param obj: 要序列化的对象
    :param fp: 要写入的字节流
    :return: 序列化后的 JSON 字符串
    '''
    pass

def load(fp):
    '''
    读取文件中的 JSON 字符串并反列化为对象

    :param fp: 要读取的字节流
    :return: 反序列化后的对象
    '''
    pass

Python 中的值和 JSON 中的表示方式按照下表的对应关系互相转换:

Python 中的类型JSON 中的表示方法备注
int 或 float3.1415926-
True/Falsetrue/false-
Nonenull-
str"hello world"JSON 中必须使用双引号
dict{ "key": value }JSON 中必须使用双引号
list 或 tuple[ value1, value2 ]-

示例:

import json

# 数据
player_state:dict = {
    'name': 'link',
    'max_hp': 10,
    'current_hp': 7,
}

# 通过 json.dumps 转换为字符串
with open("save.data", "w", encoding='utf-8') as fp:
    json.dump(player_state, fp)

# ...

# 下次启动,通过 json.loads 加载数据
with open("save.data", "r", encoding='utf-8') as fp:
    backup_state = json.load(fp)

# 查看数据
print(backup_state)

>>> Establishing WebAssembly Runtime.

>>> Standby.

Powered by Shift.

#自定义类与 JSON 的转换

如下表所示,JSON 本身只支持少数基本类型,虽然通过它们的组合,能够满足一切数据结构,但使用起来并不方便。

Python 中的类型JSON 中的表示方法备注
int 或 float3.1415926-
True/Falsetrue/false-
Nonenull-
str"hello world"JSON 中必须使用双引号
dict{ "key": value }JSON 中必须使用双引号
list 或 tuple[ value1, value2 ]-

如果直接尝试序列化一个自定义类的对象,会产生一个 TypeError 的异常。

json.dumps 和 json.dump 函数包含一个名为 default 的参数,定义将对象转换为 dict 的函数,然后 json 模块负责将 dict 转换为 JOSN 字符串。

将对象转换为 dict 的函数非常简单,直接返回对象的 __dict__ 属性即可,一行 lambda obj:obj.__dict__ 就能实现。

json.loads 和 json.load 函数包含一个名为 object_hook 的参数,定义将 dict 转换为对象的函数,然后 json 模块负责将 JOSN 字符串转换为 dict。

实现 dict 转换为对象则相对麻烦,一个较为简单的实现如下:

def make_dict_to_obj(cls):
    '''
    创建字典转对象的函数

    :cls: 对象的类型
    :return: 转换函数
    '''

    def dict_to_obj(dict_data:dict):
        '''
        将字典转换为对象

        :param dict_data: 要转换的字典
        :return: 转换后的对象
        '''

        # 创建一个 cls 类型的对象
        obj = cls()

        # 遍历字典
        for key in dict_data:
            # 将 obj 的 key 属性设为 dict_data[key]
            setattr(obj, key, dict_data[key])

        # 返回对象
        return obj

    # 返回创建的转换函数
    return dict_to_obj

这个实现无脑将字典的所有元素都塞给了对象,可能缺少了类需要的属性或包含了类不需要的属性,这通常不是什么问题。

缺少的属性在创建对象时已经设置了初始值,多余的属性通常没有影响,也可以在 setattr 之前通过 hasattr 判断,在实际开发中应当根据实际需求决定处理逻辑。

示例:

import json

def make_dict_to_obj(cls):
    '''
    创建字典转对象的函数

    :cls: 对象的类型
    :return: 转换函数
    '''

    def dict_to_obj(dict_data:dict):
        '''
        将字典转换为对象

        :param dict_data: 要转换的字典
        :return: 转换后的对象
        '''

        # 创建一个 cls 类型的对象
        obj = cls()

        # 遍历字典
        for key in dict_data:
            # 将 obj 的 key 属性设为 dict_data[key]
            setattr(obj, key, dict_data[key])

        # 返回对象
        return obj

    # 返回创建的转换函数
    return dict_to_obj

# 自定义类
class PlayerState:
    def __init__(self):
        self.name = 'link'
        self.max_hp = 10
        self.current_hp = 7

# 创建对象
player_state = PlayerState()

# 修改属性值
player_state.name = 'zelda'
player_state.max_hp = 20
player_state.current_hp = 2

# 序列化为 JSON 字符串
json_str:str = json.dumps(player_state, default=lambda obj:obj.__dict__)    # 通过 __dict__ 属性返回对象的字典
print(json_str)

# 反序列化为对象
backup_state = json.loads(json_str, object_hook=make_dict_to_obj(PlayerState)) # 通过 make_dict_to_obj 创建字典到类的转换函数
print(backup_state.name)
print(backup_state.max_hp)
print(backup_state.current_hp)

>>> Establishing WebAssembly Runtime.

>>> Standby.

Powered by Shift.

如果完全不需要考虑字段的缺失和冗余,转换函数还有一种更简单的写法,通过内置函数 type 创建对象。

def dict_to_obj(dict_data:dict):
    '''
    将字典转换为对象

    :param dict_data: 要转换的字典
    :return: 转换后的对象
    '''

    # 创建并返回一个自定义对象
    return type('CustomType', (), dict_data)

示例:

import json

def dict_to_obj(dict_data:dict):
    '''
    将字典转换为对象

    :param dict_data: 要转换的字典
    :return: 转换后的对象
    '''

    # 创建并返回一个自定义对象
    return type('CustomType', (), dict_data)

# 自定义类
class PlayerState:
    def __init__(self):
        self.name = 'link'
        self.max_hp = 10
        self.current_hp = 7

# 创建对象
player_state = PlayerState()

# 修改属性值
player_state.name = 'zelda'
player_state.max_hp = 20
player_state.current_hp = 2

# 序列化为 JSON 字符串
json_str:str = json.dumps(player_state, default=lambda obj:obj.__dict__)    # 通过 __dict__ 属性返回对象的字典
print(json_str)

# 反序列化为对象
backup_state = json.loads(json_str, object_hook=dict_to_obj) # 通过 dict_to_obj 将字典转换为对象
print(backup_state.name)
print(backup_state.max_hp)
print(backup_state.current_hp)

>>> Establishing WebAssembly Runtime.

>>> Standby.

Powered by Shift.

更新: 2025/6/6

作者: PlanC

创建: 2025/6/6