Python3如何从JSON字符串初始化含嵌套子对象的复杂类实例
嵌套JSON反序列化自定义类的简便实现方案
Python原生json模块默认只反序列化为dict、list、str、int等基础数据类型,不会自动识别类型注解映射到自定义类实例,所以才会出现嵌套属性是dict、无法用点号访问的问题。不需要逐字段手写转换逻辑,有两种成熟方案可以直接用:
方案1:使用Pydantic(体验最接近Java Jackson,推荐)
这是目前Python生态里最常用的方案,不需要写任何转换逻辑,只要按结构定义模型类,自动完成嵌套对象的序列化/反序列化,还自带类型校验。
先安装依赖:pip install pydantic
对应示例改造后的代码如下:
from pydantic import BaseModel from typing import List class Person(BaseModel): name: str age: int class Address(BaseModel): street_name: str street_num: int class Home(BaseModel): id: str personList: List[Person] address: Address # 初始化对象 address = Address(street_name="name street", street_num=1) person1 = Person(name="Bob", age=20) person2 = Person(name="Jhon", age=35) home = Home(id="0", personList=[person1, person2], address=address) # 序列化:直接转JSON字符串,不需要手动写default=lambda o:o.__dict__ jsonStr = home.model_dump_json(indent=4) # 反序列化:一行完成,所有嵌套对象自动转为对应类实例 my_home = Home.model_validate_json(jsonStr) # 可以直接用点号访问属性,正常运行不报错 print(my_home.address.street_name) print(my_home.personList[0].name)
这个方案基本和Jackson的使用体验一致,不需要额外写转换逻辑,字段类型不匹配时还会抛出明确的错误提示,适合绝大多数业务场景。
方案2:无第三方依赖的轻量通用实现
如果不想引入第三方库,可以写一个通用的序列化混入类,利用Python的类型注解自动完成嵌套对象转换,所有需要序列化的类只要继承这个混入类即可,不需要每个类单独写转换逻辑:
import json from typing import get_type_hints, get_origin, get_args, List class JsonSerializable: def to_json(self, indent=4): return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=indent) @classmethod def from_json(cls, json_str: str): raw_data = json.loads(json_str) return cls._build_instance(raw_data) @classmethod def _build_instance(cls, data: dict): type_map = get_type_hints(cls) init_params = {} for k, v in data.items(): attr_type = type_map.get(k) if not attr_type: init_params[k] = v continue # 处理单个嵌套自定义类 if isinstance(v, dict) and issubclass(attr_type, JsonSerializable): init_params[k] = attr_type._build_instance(v) # 处理列表类型里的嵌套自定义类 elif get_origin(attr_type) == list and v: item_type = get_args(attr_type)[0] if issubclass(item_type, JsonSerializable): init_params[k] = [item_type._build_instance(item) for item in v] else: init_params[k] = v else: init_params[k] = v return cls(**init_params) # 自定义类继承JsonSerializable即可 class Person(JsonSerializable): def __init__(self, name: str, age: int): self.name = name self.age = age class Address(JsonSerializable): def __init__(self, street_name: str, street_num: int): self.street_name = street_name self.street_num = street_num class Home(JsonSerializable): def __init__(self, id: str, personList: List[Person], address: Address): self.id = id self.personList = personList self.address = address # 使用示例 address = Address("name street", 1) person1 = Person("Bob", 20) person2 = Person("Jhon", 35) home = Home("0", [person1, person2], address) jsonStr = home.to_json() my_home = Home.from_json(jsonStr) # 点号访问正常运行 print(my_home.address.street_name) print(my_home.personList[1].age)
注意:这个轻量实现默认定义的类型注解和实际结构一致,没有做复杂异常兼容,适合简单场景使用。
内容的提问来源于stack exchange,提问作者MrStan12
相关产品推荐
相关产品推荐

