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

在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 18:30:18