如何为类typeguard.check_type的Python函数编写兼容Union的类型注解?
自定义类型检查函数的类型注解方案(兼容Pyright和Mypy)
问题背景
需要实现一个类似typeguard.check_type的类型检查函数,失败时生成项目定制报告,要求类型注解同时兼容Pyright和Mypy。
尝试的代码如下:
from typing import Type, TypeVar, Any from typeguard import check_type T = TypeVar('T') def my_check_type(s: Any, t: Type[T]) -> T: return check_type(s, t) x = my_check_type(10, float | int)
这段代码对简单类型正常,但传入float | int这类Union类型时,Pyright报错:
Argument of type "type[float] | type[int]" cannot be assigned to parameter "t" of type "type[T@my_check_type]" in function "my_check_type" (Pyright reportArgumentType)
问题原因
Type[T]仅能接受单一类的类型对象(如int、float),而float | int是UnionType实例,不属于Type[T]的范畴,导致类型不匹配。
解决方案
要兼容Union、泛型(如list[int])等复合类型,需放宽第二个参数的类型限制。以下是两种可靠方案:
方案1:使用Any作为参数类型(最稳妥)
直接用Any接受所有类型表达式,依赖类型检查器对返回值的推断:
from typing import TypeVar, Any from typeguard import check_type T = TypeVar('T') def my_check_type(s: Any, expected_type: Any) -> T: try: result = check_type(s, expected_type) # 此处添加自定义失败报告逻辑(比如记录日志、抛出定制异常) return result except TypeError as e: # 生成项目定制报告的逻辑 print(f"类型检查失败:{e}") raise
调用示例:
x = my_check_type(10, float | int) # Pyright和Mypy均能推断x的类型为float | int y = my_check_type([1,2,3], list[int]) # 支持泛型类型
方案2:显式声明支持的类型类别(更精确)
如果不想用Any,可以显式列出支持的类型类别(需注意_GenericAlias是私有类型,仅在特定环境下可用):
from typing import TypeVar, Any, Type, UnionType from typing_extensions import _GenericAlias from typeguard import check_type T = TypeVar('T') def my_check_type(s: Any, expected_type: Type[T] | UnionType | _GenericAlias | type[None]) -> T: try: result = check_type(s, expected_type) # 自定义报告逻辑 return result except TypeError as e: print(f"定制报告:类型不匹配 - {e}") raise
这种方式更精确,但依赖typing_extensions的私有类型,长期稳定性不如方案1。
关键说明
- 两种方案均能让Pyright和Mypy正确推断返回值类型,同时支持Union、泛型等复合类型。
- 方案1的通用性更强,无需依赖私有类型,推荐作为首选。
内容的提问来源于stack exchange,提问作者Parantapa Bhattacharya
相关产品推荐
相关产品推荐

