为何实例化Model2时会打印‘Validator for B1’?
问题:泛型Pydantic模型实例化时意外触发无关Mixin验证器的原因
代码示例
from typing import Any, Dict, Generic, TypeVar, get_args import pydantic class Mixin(pydantic.BaseModel): @pydantic.root_validator(pre=True) def print(cls, values: Dict[str, Any]): print(f"Validator for {cls.__name__}") return values class B1(Mixin): ... class B2(Mixin): ... BT = TypeVar("BT", B1, B2) class BaseModel(Generic[BT], pydantic.BaseModel): b: BT @pydantic.root_validator(pre=True) def fill_defaults(cls, values: Dict[str, Any]): b_type = get_args(cls.__orig_bases__[0])[0] print(f"Filling defaults for {b_type.__name__}") if "b" not in values: values["b"] = b_type() return values class Model1(BaseModel[B1]): ... class Model2(BaseModel[B2]): ... Model2()
实际输出
Filling defaults for B2 Validator for B2 Validator for B1
原因解释
这是因为Pydantic在处理泛型类时会缓存泛型基类的验证器关联链,导致不同泛型实例的验证器上下文出现交叉污染:
- 当定义
Model1(BaseModel[B1])时,Pydantic会将B1的Mixin验证器加入到泛型基类BaseModel的验证器链中并缓存。 - 后续定义
Model2(BaseModel[B2])时,Pydantic没有完全清空泛型基类的验证器缓存,B1的验证器仍留在链中。实例化Model2时,虽然创建的是B2对象,但缓存里的B1验证器也被误触发。
另外,代码中通过__orig_bases__手动获取泛型参数的方式不够规范,这种操作会干扰Pydantic内部的泛型处理逻辑,进一步加剧了验证器缓存的混乱问题。
内容的提问来源于stack exchange,提问作者Ziyuan
相关产品推荐
相关产品推荐

