如何在mypy中指定函数一个参数为另一参数类型的子类
实现参数类型约束的解决方案
首先说明两个核心问题的背景:
- 你尝试将
T2的bound绑定到另一个TypeVarT的写法报错,是因为Python的类型系统(遵循PEP 484规范)不允许TypeVar的约束条件使用其他TypeVar做参数,所以会抛出Constraints cannot be parametrized by type variables错误。 - 单个TypeVar的写法无法达到预期,是因为类型检查器做类型推导时,会自动取两个参数的最小公共父类作为TypeVar的实际类型,比如调用
f(B(), A())时,TypeVar会被推导为A,自然就通过了检查,没法约束第二个参数必须是第一个参数类型的子类。
可落地的实现方案
方案1:通用兼容方案(支持所有Python 3.6+版本)
利用不变泛型的特性强制类型推导优先取第一个参数的精确类型,禁止自动向上转型,实现成本很低:
from typing import TypeVar, Generic T = TypeVar('T') # 不变泛型包装类,不声明协变/逆变即为默认不变,禁止参数类型向上/向下转型推导 class InvariantWrap(Generic[T]): __slots__ = ('val',) def __init__(self, val: T): self.val = val def f(a: InvariantWrap[T], b: T) -> None: # 业务逻辑中通过a.val取用第一个参数的原始值 ... # 调用测试 f(InvariantWrap(A()), B()) # 类型检查通过 f(InvariantWrap(B()), A()) # 类型检查报错 f(InvariantWrap(A()), C()) # 类型检查报错
方案2:精简方案(仅适用于入参为类对象的场景)
如果你可以调整函数逻辑,直接接收类对象而非实例,写法可以更简单:
from typing import TypeVar T = TypeVar('T') def f(a: type[T], b: type[T]) -> None: ... # 调用测试 f(A, B) # 类型检查通过 f(B, A) # 类型检查报错 f(A, C) # 类型检查报错
内容的提问来源于stack exchange,提问作者Anton Ovsyannikov
相关产品推荐
相关产品推荐

