You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:03:54