
Pydantic 模型继承时,若父类字段为 list[Parent],子类尝试覆写为 list[Child](Child 继承自 Parent),mypy 会报类型不兼容错误;根本原因是 list 在类型系统中为不变(invariant),应改用协变的 Sequence 或 tuple 等只读容器类型。
pydantic 模型继承时,若父类字段为 `list[parent]`,子类尝试覆写为 `list[child]`(child 继承自 parent),mypy 会报类型不兼容错误;根本原因是 `list` 在类型系统中为**不变(invariant)**,应改用协变的 `sequence` 或 `tuple` 等只读容器类型。
在 Python 类型系统中,容器类型的变性(variance) 决定了子类型关系能否传递到其元素类型上。list[T] 是不变的(invariant):即使 Child 是 Parent 的子类,list[Child] 也不被视为 list[Parent] 的子类型——因为 list 支持就地修改(如 append()、__setitem__),若允许协变赋值,可能破坏类型安全(例如向 list[Child] 中插入一个非 Child 的 Parent 实例)。
而 typing.Sequence[T] 是协变的(covariant),它仅提供只读操作(如 __getitem__、__len__、迭代),因此 Sequence[Child] 可安全地作为 Sequence[Parent] 使用。Pydantic 字段类型只需支持序列化/验证所需的读取行为,无需可变性,故 Sequence 是更合理且类型安全的选择。
✅ 正确做法:将 list[Name] 替换为 Sequence[Name]
from pydantic import BaseModel
from typing import Sequence
class Name(BaseModel):
data: str
class EnglishName(Name):
# 可选:添加特定字段或逻辑
pass
class Animal(BaseModel):
name: Sequence[Name] # 使用 Sequence 而非 list
class AmericaAnimal(Animal):
name: Sequence[EnglishName] # ✅ mypy 通过,类型兼容? 注意事项:
- Sequence 是抽象基类(ABC),支持 list、tuple、deque 等具体序列类型,Pydantic 能正常解析和序列化。
- 若业务逻辑必须使用可变列表(如需 .append()、.pop()),则不应在类型层面强制协变;此时建议保持 list[Name] 并在运行时做子类型校验,或通过 @field_validator 显式约束元素类型。
- 不要使用 typing.List(已弃用),也避免 list[Child] 直接覆写 list[Parent] —— 这是类型系统层面的硬性限制,非 Pydantic 特有。
- 对于需要协变且不可变的场景,tuple[Child, ...] 同样适用(tuple 也是协变的)。
总结:类型安全与面向对象继承需协同设计。当模型字段语义为「只读集合」时,优先选用协变类型(如 Sequence、tuple);若需可变性,则接受类型不变性约束,并通过运行时验证保障数据一致性。这是 mypy 与 Pydantic 协同工作的最佳实践。

















