如何为整合typeguard.check_type的ensure_type编写兼容mypy的类型提示
解决
ensure_type函数的mypy类型提示问题 typing.cast(type, obj)虽实用,但缺少运行时类型检查,因此我实现了ensure_type函数——先用typeguard.check_type做运行时类型校验,通过后再用typing.cast返回值:
from types import GenericAlias, UnionType from typing import Any, cast from annotated_types import T from typeguard import check_type def ensure_type(value, expected_type): # noqa: ANN401 This function should hold Any value """Check the type and return value only if the types are matched. Otherwise, raise TypeError. """ if check_type(value, expected_type): return cast("T", value) msg = f"Type check failed: type({value}) is {type(value)}, expected {expected_type}" raise TypeError(msg)
使用对比
obj = ensure_type(..., type)的写法比嵌套if check_type(obj, type)更简洁:
基于ensure_type的写法
# 使用 ensure_type data = ensure_type(request_some_data(), dict[str]) key = ensure_type(data.get("key"), PromisedKey) print(key)
直接使用check_type的写法
# 直接用 check_type data = request_some_data() if check_type(data, dict[str]): key = data.get("key") if check_type(key, PromisedKey): print(key)
类型提示的困扰
我尝试给ensure_type添加类型提示,但无法让mypy正确识别:
def ensure_type(value: Any, expected_type: type[T] | GenericAlias | UnionType) -> <the_same_type_of_expected_type>:
需要正确的类型提示写法,让mypy能正确推导返回值类型与expected_type的对应关系。
正确的类型提示写法
要让mypy正确识别,需利用标准TypeVar绑定泛型,并调整参数与返回值的类型标注,修改后的代码如下:
from types import GenericAlias, UnionType from typing import Any, TypeVar, cast, Type from typeguard import check_type T = TypeVar("T") def ensure_type(value: Any, expected_type: Type[T] | GenericAlias | UnionType) -> T: """Check the type and return value only if the types are matched. Otherwise, raise TypeError. """ check_type(value, expected_type) return cast(T, value)
关键说明
- 替换
annotated_types.T为标准TypeVar("T"),这是泛型类型推导的核心 - 参数
expected_type标注为Type[T] | GenericAlias | UnionType,覆盖了类类型、泛型别名(如dict[str])、联合类型(如int | str)三类场景 - 返回值直接标注为
T,mypy会根据传入的expected_type自动推导返回值的具体类型 - 简化逻辑:
check_type本身会在类型不匹配时抛出TypeError,无需额外if判断
修改后,mypy就能正确识别:比如ensure_type(request_some_data(), dict[str])会被推导为dict[str]类型,ensure_type(data.get("key"), PromisedKey)会被推导为PromisedKey类型。
内容的提问来源于stack exchange,提问作者Tsukimaru Oshawott
相关产品推荐
相关产品推荐

