如何用Python泛型为同类型(int/str)参数函数添加合规类型注解?
解决泛型函数中同类型int/str参数的mypy类型检查问题
需求是实现一个仅接受同类型int或str参数的函数,返回同类型结果,同时通过mypy静态类型检查,避免运行时类型不匹配的情况。以下是针对你遇到的问题的解决方案及分析:
问题分析
combine1的缺陷:允许传入不同类型参数(如int+str),且需要嵌套match做冗余类型检查,无法在静态阶段拦截错误。combine2的缺陷:mypy无法在match分支中自动推断T的具体类型——虽然泛型约束了a和b同属T,但mypy不会主动关联分支内a和b的类型,导致返回值和操作数类型报错。
可行解决方案
方案1:使用TypeGuard做类型窄化
将类型检查逻辑封装为TypeGuard函数,明确告诉mypy参数的类型关系:
from typing import TypeGuard, TypeVar T = TypeVar("T", int, str) def is_both_int(a: T, b: T) -> TypeGuard[int, int]: return isinstance(a, int) and isinstance(b, int) def is_both_str(a: T, b: T) -> TypeGuard[str, str]: return isinstance(a, str) and isinstance(b, str) def combine(a: T, b: T) -> T: if is_both_int(a, b): return a + b elif is_both_str(a, b): return a + b else: # 静态检查阶段不会触发,因为T只能是int/str且参数同类型 raise TypeError("参数必须同为int或同为str")
方案2:用assert辅助类型推断
利用泛型约束的特性,通过assert给mypy明确的类型提示:
from typing import TypeVar T = TypeVar("T", int, str) def combine(a: T, b: T) -> T: if isinstance(a, int): assert isinstance(b, int) return a + b elif isinstance(a, str): assert isinstance(b, str) return a + b else: raise TypeError("参数必须同为int或同为str")
注:运行时assert不会触发错误,因为静态检查已拦截不同类型参数的传入。
方案3:用cast手动断言类型
适合不想添加额外函数的场景,通过cast告诉mypy参数的具体类型:
from typing import TypeVar, cast T = TypeVar("T", int, str) def combine(a: T, b: T) -> T: match a: case int(): return cast(T, a + cast(int, b)) case str(): return cast(T, a + cast(str, b)) case _: raise TypeError("参数必须同为int或同为str")
方案对比
TypeGuard方案:逻辑清晰,类型检查可复用,静态检查最严格,适合复杂场景。assert方案:代码简洁,无需额外函数,适合简单场景。cast方案:无需额外逻辑,但需手动保证断言安全性,适合快速实现。
内容的提问来源于stack exchange,提问作者Pierre-olivier Gendraud
相关产品推荐
相关产品推荐

