在Python(含attrs库)中导出YAML时能否修改字段名称?
解决代码变量名与YAML导出字段名不一致的问题
方案一:基于 attrs 的通用解决方案
利用 attrs 的字段元数据(metadata)存储YAML字段名,再写一个通用转换函数,自动将 attrs 对象转为符合YAML键名要求的字典,最后导出YAML。这种方式支持嵌套结构,新增字段只需添加元数据即可。
import attrs import yaml from typing import List from attrs import define, field def attrs_to_yaml_dict(obj): """将attrs对象转换为带指定YAML键名的字典""" yaml_dict = {} for f in attrs.fields(obj.__class__): value = getattr(obj, f.name) # 优先用metadata里的yaml_key,没有则保留原字段名 yaml_key = f.metadata.get("yaml_key", f.name) # 递归处理嵌套的attrs对象或列表 if attrs.has(type(value)): yaml_dict[yaml_key] = attrs_to_yaml_dict(value) elif isinstance(value, list) and value and attrs.has(type(value[0])): yaml_dict[yaml_key] = [attrs_to_yaml_dict(item) for item in value] else: yaml_dict[yaml_key] = value return yaml_dict @define class Task: id: int @define class Data: # 通过metadata指定YAML导出时的键名为tasks all_tasks: List[Task] = field(metadata={"yaml_key": "tasks"}) x: int = field(default=5) if __name__ == '__main__': list_of_tasks = [Task(1), Task(2), Task(3)] d = Data(list_of_tasks, 10) print(yaml.dump(attrs_to_yaml_dict(d)))
运行输出:
tasks: - id: 1 - id: 2 - id: 3 x: 10
方案二:不使用 attrs,基于 dataclasses 的解决方案
如果不想依赖 attrs,可以用Python标准库的dataclasses,同样通过元数据+转换函数实现需求。
方法1:通用字典转换函数
import yaml from dataclasses import dataclass, fields, field from typing import List def dataclass_to_yaml_dict(obj): yaml_dict = {} for f in fields(obj): value = getattr(obj, f.name) yaml_key = f.metadata.get("yaml_key", f.name) # 递归处理嵌套dataclass或列表 if hasattr(type(value), "__dataclass_fields__"): yaml_dict[yaml_key] = dataclass_to_yaml_dict(value) elif isinstance(value, list) and value and hasattr(type(value[0]), "__dataclass_fields__"): yaml_dict[yaml_key] = [dataclass_to_yaml_dict(item) for item in value] else: yaml_dict[yaml_key] = value return yaml_dict @dataclass class Task: id: int @dataclass class Data: all_tasks: List[Task] = field(metadata={"yaml_key": "tasks"}) x: int = 5 if __name__ == '__main__': list_of_tasks = [Task(1), Task(2), Task(3)] d = Data(list_of_tasks, 10) print(yaml.dump(dataclass_to_yaml_dict(d)))
方法2:自定义YAML序列化器
直接给YAML注册专属序列化器,让它自动识别dataclass并按指定键名输出:
import yaml from dataclasses import dataclass, fields, field from typing import List def dataclass_representer(dumper, obj): yaml_dict = {} for f in fields(obj): value = getattr(obj, f.name) yaml_key = f.metadata.get("yaml_key", f.name) yaml_dict[yaml_key] = value return dumper.represent_mapping('tag:yaml.org,2002:map', yaml_dict) @dataclass class Task: id: int @dataclass class Data: all_tasks: List[Task] = field(metadata={"yaml_key": "tasks"}) x: int = 5 # 给dataclass注册序列化器 yaml.add_representer(Data, dataclass_representer) yaml.add_representer(Task, dataclass_representer) if __name__ == '__main__': list_of_tasks = [Task(1), Task(2), Task(3)] d = Data(list_of_tasks, 10) print(yaml.dump(d))
方案三:手动字典映射(最简场景)
如果你的数据结构简单、字段不多,直接转换字典键名最省事:
import attrs import yaml from typing import List from attrs import define @define class Task: id: int @define class Data: all_tasks: List[Task] x: int = 5 if __name__ == '__main__': list_of_tasks = [Task(1), Task(2), Task(3)] d = Data(list_of_tasks, 10) # 转字典后替换键名 data_dict = attrs.asdict(d) data_dict["tasks"] = data_dict.pop("all_tasks") print(yaml.dump(data_dict))
内容的提问来源于stack exchange,提问作者Roberto Morávia
相关产品推荐
相关产品推荐

