如何为支持UnionType的safe_cast函数编写正确的Type Hint?
解决safe_cast支持UnionType的类型检查问题
问题根源
你遇到的mypy报错,核心原因是type[T]约束仅接受单个具体类型的类对象(比如str、int),而str | int这类UnionType实例并不属于type[T]的范畴。虽然Python运行时的isinstance天然支持联合类型检查,但类型检查器无法将UnionType匹配到Type[T]的参数约束,因此抛出类型不兼容错误。
正确解决方案:使用重载+可变参数泛型
通过@overload为safe_cast定义多套类型签名,分别处理单个类型、Python 3.10+的UnionType(str | int)以及旧版Union写法的场景,同时结合可变参数泛型让mypy正确推断返回类型。
完整实现代码:
from typing import TypeVar, Any, cast, overload, Union, Type from types import UnionType # 单个类型的泛型变量 T = TypeVar('T') # 用于捕获联合类型中的成员类型 Ts = TypeVar('Ts', bound=object) @overload def safe_cast(t: Type[T], value: Any) -> T: """处理单个类型的安全转换""" ... @overload def safe_cast(t: UnionType, value: Any) -> Union[Ts, ...]: """处理Python 3.10+的UnionType(如str | int)""" ... @overload def safe_cast(t: Union[Type[Ts], ...], value: Any) -> Ts: """处理旧版Union[Type[T1], Type[T2], ...]写法""" ... def safe_cast(t: Type[T] | UnionType | Union[Type[Ts], ...], value: Any) -> T | Ts: if isinstance(value, t): return cast(T | Ts, value) raise TypeError(f"无法将 {repr(value)} 转换为类型 {t}")
代码说明
- 重载签名:
- 第一个重载保持原有单个类型的处理逻辑,兼容原生类型的转换场景。
- 第二个重载专门匹配
UnionType(如str | int),告诉mypy返回对应的联合类型。 - 第三个重载兼容旧版
Union[str, int]的写法,确保类型推断一致性。
- 运行时逻辑:无需修改核心检查逻辑,因为Python的
isinstance天然支持联合类型的实例判断。
测试示例
# 单个类型转换,mypy无报错 string = "test" casted_str: str = safe_cast(str, string) # UnionType转换,类型推断正确 casted_union: str | int = safe_cast(str | int, string) # 旧版Union写法,同样支持 casted_old_union: Union[str, int] = safe_cast(Union[str, int], string) # 转换失败时抛出TypeError try: safe_cast(int, "not_a_number") except TypeError: pass
内容的提问来源于stack exchange,提问作者Jonathan Herrera
相关产品推荐
相关产品推荐

