如何用Pydantic将单值字段统一解析为列表?
使用Pydantic统一解析单值/数组类型的配置字段
问题场景
我有一个需要解析配置的应用,配置字段可能是单个值或数组,例如YAML格式:
fruit: apple vegetable: - tomato - cucumber
希望解析后内部统一将fruit处理为['apple'],vegetable保持['tomato', 'cucumber'],且需满足以下要求:
- 类型检查(mypy)和运行时,字段类型均为
list[str](或对应类型的列表) - 多类使用时,每个字段最多一行声明
- 方案可推广至任意类型,不限于字符串
已尝试方案的不足
fruit: Union[str, list[str]]:使用时需处处检查类型,违背统一解析的初衷- 每个字段单独写
@validator("fruit", pre=True):重复代码多,每个字段需额外3行冗余代码
最优解决方案
步骤1:定义通用的类型转换工具
利用Pydantic的Annotated和BeforeValidator实现通用的单值转列表逻辑,支持任意类型:
from typing import TypeVar, Any from pydantic import BeforeValidator, Annotated # 定义泛型变量,支持任意类型 T = TypeVar('T') def single_to_list(v: Any) -> list[Any]: """将非列表值转为单元素列表,列表值保持不变""" if not isinstance(v, list): return [v] return v # 封装为通用类型注解,底层类型为list[T] SingleOrList = Annotated[list[T], BeforeValidator(single_to_list)]
步骤2:在Pydantic模型中声明字段
每个字段只需一行代码,直接使用SingleOrList[T]即可,类型检查会识别为list[T]:
from pydantic import BaseModel class Config(BaseModel): fruit: SingleOrList[str] vegetable: SingleOrList[str] # 推广至其他类型示例 class NumericConfig(BaseModel): count: SingleOrList[int] threshold: SingleOrList[float]
验证效果
解析示例YAML配置:
import yaml yaml_content = """ fruit: apple vegetable: - tomato - cucumber """ config_data = yaml.safe_load(yaml_content) config = Config(**config_data) print(config.fruit) # 输出: ['apple'] print(config.vegetable) # 输出: ['tomato', 'cucumber'] print(type(config.fruit)) # 输出: <class 'list'>
方案优势
- 类型安全:mypy会将
SingleOrList[str]识别为list[str],无需额外类型断言 - 代码简洁:每个字段仅需一行声明,无重复验证逻辑
- 通用性强:替换
str为任意类型(如int、bool甚至自定义类)即可适配不同场景
内容的提问来源于stack exchange,提问作者Koterpillar
相关产品推荐
相关产品推荐

