如何通过Typing与Mypy在泛型中严格区分基类与派生类
解决方案
要让Mypy检测到fun(x1=B(), x2=A())和fun(x1=A(), x2=B())这类混合类型传参的错误,你可以通过以下两种方式实现精确类型匹配:
方法一:利用类型断言+Mypy严格检查
这种方式不需要修改函数的参数结构,只需调整内部逻辑并开启Mypy的严格类型断言检查:
修改代码
from typing import TypeVar import dataclasses @dataclasses.dataclass class A: pass @dataclasses.dataclass class B(A): pass T = TypeVar("T", A, B) def fun( x1: T, x2: T, ) -> int: # 断言两个参数的精确类型完全一致,Mypy会基于此分析类型兼容性 assert type(x1) is type(x2), "must be same type!" # 改用isinstance做类型判断,更符合Python类型规范 if isinstance(x1, B): return 10 elif isinstance(x1, A): return 5 else: raise TypeError("Type not handled") fun(x1=A(), x2=A()) # 正常通过 fun(x1=B(), x2=B()) # 正常通过 fun(x1=B(), x2=A()) # Mypy会报错:Assertion always fails fun(x1=A(), x2=B()) # Mypy会报错:Assertion always fails
运行Mypy时开启严格类型断言
执行Mypy时添加--strict-type-predicates参数(或直接用--strict模式,该模式包含此参数):
mypy --strict-type-predicates your_script.py
方法二:显式传入类型参数(无需额外Mypy选项)
如果不想依赖命令行参数,可以通过显式传入类类型参数来锁定精确类型,让Mypy直接检测不匹配的情况:
from typing import TypeVar, Type import dataclasses @dataclasses.dataclass class A: pass @dataclasses.dataclass class B(A): pass T = TypeVar("T", bound=A) def fun( x1: T, x2: T, *, # 强制关键字参数,避免位置传参混淆 cls: Type[T], ) -> int: if type(x1) is not cls or type(x2) is not cls: raise TypeError("must be same type!") if cls is A: return 5 elif cls is B: return 10 else: raise TypeError("Type not handled") fun(x1=A(), x2=A(), cls=A) # 正常通过 fun(x1=B(), x2=B(), cls=B) # 正常通过 fun(x1=B(), x2=A(), cls=A) # Mypy报错:x1类型为B,不符合预期的A fun(x1=A(), x2=B(), cls=B) # Mypy报错:x2类型为A,不符合预期的B
这种方式通过cls参数明确指定函数要处理的精确类型,Mypy会直接校验x1、x2的类型是否与cls匹配,无需额外命令行配置。
内容的提问来源于stack exchange,提问作者newandlost
相关产品推荐
相关产品推荐

