如何将Python dataclass转换为带@前缀key的指定格式JSON
Python dataclass 自定义JSON序列化实现方案
实现思路
- 递归遍历dataclass实例,读取每个类内部定义的
Meta属性生成指定键名 - 优先处理
RType类型的字段,生成带@前缀的@r_type键 - 嵌套dataclass自动递归序列化,保证所有层级都符合格式要求
- 完全依赖Python标准库,无需引入第三方依赖
完整实现代码
from dataclasses import is_dataclass import json from dataclasses import dataclass def serialize(obj): # 非dataclass类型直接返回原值 if not is_dataclass(obj): return obj res = {} # 遍历所有字段处理 for field_name in obj.__dataclass_fields__: field_val = getattr(obj, field_name) serialized_val = serialize(field_val) # 处理RType类的特殊映射规则 if is_dataclass(field_val) and hasattr(field_val, 'Meta'): meta = field_val.Meta if hasattr(meta, 'name') and hasattr(meta, 'content'): res[meta.name] = getattr(field_val, meta.content) continue # 处理当前类的Meta配置规则 if hasattr(obj, 'Meta'): meta = obj.Meta if hasattr(meta, 'name') and hasattr(meta, 'content') and field_name == meta.content: res[meta.name] = serialized_val continue # 普通字段直接用字段名作为键 res[field_name] = serialized_val return res # 原有业务dataclass定义 @dataclass class RType: type_name: str class Meta: name = '@r_type' content = 'type_name' @dataclass class Options: type: RType content: str class Meta: name = 'options' content = 'content'
测试验证
示例1测试代码
# 构造示例1对应数据 rtype_init = RType(type_name='init') rtype_options = RType(type_name='options') options = Options(type=rtype_options, content='some_options') # 定义匹配示例1结构的顶层dataclass @dataclass class InitRoot: type: RType options: Options root = InitRoot(type=rtype_init, options=options) # 输出JSON结果 print(json.dumps(serialize(root), indent=2, ensure_ascii=False))
示例1输出结果
{ "@r_type": "init", "options": { "@r_type": "options", "options": "some_options" } }
示例2测试代码
# 定义匹配示例2结构的Directory类 @dataclass class Directory: type: RType content: str class Meta: name = 'directory' content = 'content' # 构造示例2对应数据 rtype_dir_init = RType(type_name='dir_init') rtype_directory = RType(type_name='directory') directory = Directory(type=rtype_directory, content='path_to') # 定义匹配示例2结构的顶层dataclass @dataclass class DirRoot: type: RType directory: Directory root = DirRoot(type=rtype_dir_init, directory=directory) # 输出JSON结果 print(json.dumps(serialize(root), indent=2, ensure_ascii=False))
示例2输出结果
{ "@r_type": "dir_init", "directory": { "@r_type": "directory", "directory": "path_to" } }
扩展说明
如果需要支持列表、字典等复合类型字段,只需在serialize函数中增加对应类型的判断逻辑,递归处理容器内的每个元素即可。
内容的提问来源于stack exchange,提问作者goGOgo
相关产品推荐
相关产品推荐

