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

使用ruamel.yaml的RoundTripLoader加载YAML时,如何获取完整属性创建Pydantic模型?

问题解决:ruamel.yaml RoundTripLoader 锚点别名属性缺失及Pydantic适配

问题场景

你使用ruamel.yaml的RoundTripLoader(typ='rt')加载包含锚点与合并键的YAML文件:

- database: dev_db
  <<: &defaults
    adapter: postgres
    host: localhost
    username: postgres
    password: password
  
- database: test_db
  <<: *defaults
- database: prod_db
  <<: *defaults

编写的Python代码如下:

from pydantic import BaseModel
from ruamel.yaml import YAML

yaml = YAML(typ='rt')
with open('config.yaml', 'r') as file:
    envs = yaml.load(file)

for env in envs:
  print(env)

运行后输出仅显示database字段,缺失锚点引用的属性:

{'database': 'dev_db'}
{'database': 'test_db'}
{'database': 'prod_db'}

但切换为safe loader(typ='safe')时能正确输出所有属性,你需要基于YAML条目创建Pydantic数据模型,同时保留RoundTripLoader的特性。

原因分析

RoundTripLoader的核心设计是保留YAML原始结构、注释、格式,因此默认不会自动展开<<(合并键)引用的锚点内容——这是为了保证后续将数据序列化回写时,能完全还原原YAML的结构。而safe loader则会直接解析合并所有关联属性,不保留原始结构信息。

解决方案

1. 手动展开合并键获取完整属性

RoundTripLoader加载后的每个条目是ruamel.yaml.comments.CommentedMap类型,该类型提供了merge()方法,可手动触发合并键的展开:

from pydantic import BaseModel
from ruamel.yaml import YAML

yaml = YAML(typ='rt')
with open('config.yaml', 'r') as file:
    envs = yaml.load(file)

for env in envs:
    env.merge()  # 展开<<引用的属性
    print(dict(env))  # 输出完整属性

运行后即可得到包含所有字段的输出:

{'database': 'dev_db', 'adapter': 'postgres', 'host': 'localhost', 'username': 'postgres', 'password': 'password'}
{'database': 'test_db', 'adapter': 'postgres', 'host': 'localhost', 'username': 'postgres', 'password': 'password'}
{'database': 'prod_db', 'adapter': 'postgres', 'host': 'localhost', 'username': 'postgres', 'password': 'password'}

2. 转换为Pydantic数据模型

先定义对应的数据模型,再将展开后的CommentedMap转为字典,传入模型构造方法:

from pydantic import BaseModel
from ruamel.yaml import YAML

# 定义Pydantic数据模型
class DBConfig(BaseModel):
    database: str
    adapter: str
    host: str
    username: str
    password: str

yaml = YAML(typ='rt')
with open('config.yaml', 'r') as file:
    envs = yaml.load(file)

# 处理每个条目并转换为模型
db_configs = []
for env in envs:
    env.merge()
    config = DBConfig(**dict(env))
    db_configs.append(config)

# 验证模型数据
for config in db_configs:
    print(config)

输出示例:

database='dev_db' adapter='postgres' host='localhost' username='postgres' password='password'
database='test_db' adapter='postgres' host='localhost' username='postgres' password='password'
database='prod_db' adapter='postgres' host='localhost' username='postgres' password='password'

补充说明

  • 如果不需要保留YAML原始格式、注释,直接使用typ='safe'更简便,无需手动调用merge();
  • 调用merge()后,原CommentedMap会被修改,若需保留原始结构,可先创建副本再执行合并:env_copy = env.copy(); env_copy.merge()。

内容的提问来源于stack exchange,提问作者Sirish Kumar Bethala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 20:57:19