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

Python Pydantic解析YAML配置对象列表ValidationError报错排查

错误原因

核心矛盾是Pydantic模型定义的字段约束和实际YAML解析出的数据结构完全不匹配:
你定义的Entry模型把entry1和entry2都设为了必填字段,意味着每一个Entry实例必须同时包含这两个键。但你提供的YAML解析后得到的是两个独立的单键字典:第一个字典只有entry1键,第二个字典只有entry2键,循环实例化时,处理第一个字典会报缺entry2,处理第二个会报缺entry1,自然抛出校验错误。
你之前注释掉entry2字段后单条数据能跑通,只是刚好测试数据和简化后的模型结构碰巧匹配,不代表原有逻辑正确。

现存问题
  • 数据模型映射错误:没有对齐实际YAML的层级结构,把分属不同列表项的互斥键,错误定义成了同一对象下的并列必填字段。
  • YAML读取逻辑存在隐患:直接调用open()没有用with上下文管理器,文件读取完成后不会自动关闭,会造成文件句柄泄漏;另外直接使用yaml.load()没有指定安全加载模式,存在执行恶意代码的风险。
  • 解析逻辑冗余:Pydantic本身支持直接传入嵌套结构完成批量校验,不需要手动写循环逐层级解包。
正确实现方案

根据你实际的业务需求,二选一调整即可:

方案1:保留现有YAML结构(entry1、entry2为独立列表项)

如果你的业务场景就是需要在列表中存放任意数量的、键名不固定的条目(比如后续可能加entry3、entry4),直接调整模型定义,用字典类型接收动态键即可,不需要单独定义Entry类:

from pydantic import BaseModel
from typing import Dict, List
from pathlib import Path
import yaml
import sys

# 条目值模型保持不变
class EntryValues(BaseModel):
    attribute: str
    amount: int
    price: float

# 根模型直接接收「元素为单键字典的列表」
class Config(BaseModel):
    __root__: List[Dict[str, EntryValues]]

# 路径配置示例,替换成你实际的CWD值即可
CWD = Path(__file__).parent

def get_cfg_path() -> Path:
    return CWD

def read_cfg(file_name: str, file_path: Path = None):
    if not file_path:
        file_path = get_cfg_path()
    target_file = file_path / file_name
    if not target_file.exists():
        raise Exception(f"Config file {file_name} not found!")
    try:
        # 用with上下文自动管理文件关闭,用safe_load避免安全风险
        with open(target_file, "r", encoding="utf-8") as f:
            return yaml.safe_load(f)
    except Exception as e:
        print(f"read file {file_name} failed: {e}")
        sys.exit(1)

# 直接解析,不需要手动循环
if __name__ == "__main__":
    yaml_content = read_cfg("your_config.yaml")
    config = Config.parse_obj(yaml_content)
    
    # 读取数据示例
    for entry in config.__root__:
        for entry_name, entry_detail in entry.items():
            print(f"条目名:{entry_name}")
            print(f"属性:{entry_detail.attribute}, 数量:{entry_detail.amount}, 价格:{entry_detail.price}")

方案2:保留原有模型定义(entry1、entry2为同一项下的并列属性)

如果你本来的设计是每个配置项同时包含entry1和entry2两个条目,那不需要改模型,只需要修正YAML的缩进结构,把两个键放到同一个列表项里即可:

# 修正后的YAML结构
- entry1:
    attribute: "Test1"
    amount: 1
    price: 123.45
  entry2:
    attribute: "Test2"
    amount: 10
    price: 56.78

读取和解析逻辑和方案1一致,直接调用Config.parse_obj(yaml_content)即可完成自动校验和实例化,不需要手动写循环处理。

内容的提问来源于stack exchange,提问作者arodin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:12:20