
本文介绍在 attrs 中为联合类型(如 int | str)定义字段时,如何绕过 mypy 对 attrs.validators.or_() 的类型推断失败问题,推荐使用 instance_of((str, int)) 实现简洁、安全且兼容静态类型的校验方案。
本文介绍在 attrs 中为联合类型(如 `int | str`)定义字段时,如何绕过 mypy 对 `attrs.validators.or_()` 的类型推断失败问题,推荐使用 `instance_of((str, int))` 实现简洁、安全且兼容静态类型的校验方案。
在使用 attrs 构建数据类时,若需对某个字段支持多种类型(例如 int | str),直觉上会选用 attrs.validators.or_() 组合多个 instance_of 校验器。然而,当前版本的 mypy(尤其是 1.10+)无法为 or_[T] 正确推断泛型参数,导致报错:
error: Cannot infer type argument 1 of "or_" [misc]
尽管该代码运行时完全正常,但破坏了类型检查的完整性,不利于团队协作和 CI 流程中的静态分析。
✅ 推荐解决方案:使用元组形式的 instance_of
attrs.validators.instance_of 支持传入类型元组(如 (str, int)),语义等价于“是其中任一类型”,且 mypy 能准确识别其类型契约:
import attrs
@attrs.define
class C:
val: int | str = attrs.field(
validator=attrs.validators.instance_of((str, int))
)
该写法:
- ✅ 完全通过 mypy 检查(无
misc或arg-type报错); - ✅ 运行时行为与
or_(instance_of(int), instance_of(str))一致; - ✅ 更简洁,减少嵌套,提升可读性;
- ✅ 兼容 Python 3.10+ 的联合类型语法(
int | str)及旧式Union[int, str]。
⚠️ 注意事项:
- 不要误写为
instance_of([str, int])(列表),必须使用元组(...),否则会触发运行时TypeError; - 若需更复杂的逻辑(如自定义错误消息、条件校验或组合其他验证器),仍可保留
or_,但需显式添加类型注解(较繁琐,不推荐):from typing import TYPE_CHECKING if TYPE_CHECKING: from attrs.validators import _OrValidator # 需手动构造类型,维护成本高,非必要不采用
? 总结:对于“字段接受多个具体类型”的常见场景,优先使用 instance_of((TypeA, TypeB)) 替代 or_(instance_of(TypeA), instance_of(TypeB)) —— 它是 mypy 友好、语义清晰、零运行时开销的最佳实践。










