如何将带type字段的JSON结构转换为嵌套Python dataclass对象树
嵌套带type标识的JSON转dataclass对象树实现
原代码问题分析
- 未接收递归调用的返回值,转换后的子对象没有回填到父对象的字段中
- 处理字典类型时,遍历第一个字段就提前返回,剩余字段完全未处理
- 列表类型处理逻辑没有返回转换后的列表,上层无法拿到子元素的转换结果
- 直接修改传入的json_obj会污染原始数据,建议先拷贝再操作
完整实现代码
import json from abc import ABC from dataclasses import dataclass from typing import List, Dict, Type, Any # 全局注册器 game_object_registry: Dict[str, Type["GameObject"]] = {} # 自动注册装饰器,无需手动往注册器中添加类 def register_game_object(cls: Type["GameObject"]) -> Type["GameObject"]: game_object_registry[cls.__name__] = cls return cls # 业务类定义 @register_game_object @dataclass class GameObject(ABC): pass @register_game_object @dataclass class Character(GameObject): name: str @register_game_object @dataclass class Wave(GameObject): enemies: List[Character] @register_game_object @dataclass class Wizard(Character): pass @register_game_object @dataclass class Archer(Character): pass @register_game_object @dataclass class Map(GameObject): name: str @register_game_object @dataclass class SquareRoom(Map): width: int height: int @register_game_object @dataclass class Level(GameObject): waves: List[Wave] map: Map @register_game_object @dataclass class Game(GameObject): levels: List[Level] # 修正后的递归转换函数 def json_to_game_object(json_obj: Any, registry: Dict[str, Type[GameObject]]) -> Any: # 处理字典类型:先递归转换所有字段值,再生成对应类实例 if isinstance(json_obj, dict): # 拷贝数据避免修改原始输入对象 obj_dict = json_obj.copy() obj_type_name = obj_dict.pop("type") obj_cls = registry[obj_type_name] # 遍历所有字段完成递归转换 for k, v in obj_dict.items(): obj_dict[k] = json_to_game_object(v, registry) # 所有字段处理完成后生成实例返回 return obj_cls(**obj_dict) # 处理列表类型:递归转换每个元素,返回新的转换后列表 elif isinstance(json_obj, list): return [json_to_game_object(item, registry) for item in json_obj] # 基础类型直接返回 else: return json_obj # 测试逻辑 if __name__ == "__main__": json_data_str = """ { "type" : "Game", "levels" : [ { "type": "Level", "map" : { "type" : "SquareRoom", "name" : "Level 1", "width" : 100, "height" : 100 }, "waves" : [ { "type" : "Wave", "enemies" : [ { "type" : "Wizard", "name" : "Gandalf" }, { "type" : "Archer", "name" : "Legolass" } ] } ] } ] } """ json_data = json.loads(json_data_str) game = json_to_game_object(json_data, game_object_registry) print(game) # 输出与预期完全一致: # Game(levels=[Level(waves=[Wave(enemies=[Wizard(name='Gandalf'), Archer(name='Legolass')])], map=SquareRoom(name='Level 1', width=100, height=100))])
内容的提问来源于stack exchange,提问作者Blue7
相关产品推荐
相关产品推荐

