如何用Pydantic与Mypy正确标注typing.Annotated的返回类型?
环境
python 3.13 pydantic 2.10.5 mypy 1.16.0
问题描述
使用mypy作为类型检查器时,如何正确标注typing._SpecialForm(特指typing.Annotated)的返回类型?
代码示例
from functools import partial from typing import Annotated from pydantic import AfterValidator, BaseModel def validate_smth(value: str, context: str) -> str: if value == "test": print(f"Validated {value}") else: raise ValueError(f"Value {value} is not allowed in context {context}") return value def return_annotated_type(context: str = "") -> type: # error: 不兼容的返回值类型(得到"<typing special form>", 预期"type") [return-value] validator = partial(validate_smth, context=context) return Annotated[str, AfterValidator(validator)] class MyModel(BaseModel): field: return_annotated_type(context="test") # error: 无效的类型注释或标注 [valid-type] # note: 建议:使用return_annotated_type[...]代替return_annotated_type(...) MyModel.model_validate({"field": "test"})
尝试方案及问题
- 标注返回类型为
Annotated[str, AfterValidator]时,报错:error: 不兼容的返回值类型(得到"<typing special form>", 预期"str") [return-value]def return_annotated_type(context: str = "") -> Annotated[str, AfterValidator]: # error: 不兼容的返回值类型(得到"<typing special form>", 预期"str") [return-value] - 标注返回类型为
Any时无报错,但类型范围过宽,不符合需求def return_annotated_type(context: str = "") -> Any: # 此处无报错,但Any范围太广,不符合需求
解决方案
方法1:使用TypeAlias标注返回类型
Python 3.10+和新版mypy支持用typing.TypeAlias标注返回值为类型别名,能让mypy正确识别Annotated返回的特殊类型:
from typing import Annotated, TypeAlias def return_annotated_type(context: str = "") -> TypeAlias: validator = partial(validate_smth, context=context) return Annotated[str, AfterValidator(validator)]
方法2:用TypeAliasType精确定义(Python 3.12+)
Python 3.12引入了TypeAliasType,可以更清晰地定义动态生成的类型别名,同时消除mypy报错:
from typing import Annotated, TypeAliasType def return_annotated_type(context: str = "") -> TypeAliasType: validator = partial(validate_smth, context=context) # 自定义类型别名名称,便于类型检查时识别 return TypeAliasType(f"ValidatedStr_{context}", Annotated[str, AfterValidator(validator)])
方法3:提前赋值类型别名再使用
针对模型字段的valid-type报错,可以先将生成的类型赋值给变量,再在模型中引用:
# 提前生成类型别名 ValidatedTestStr = return_annotated_type(context="test") class MyModel(BaseModel): field: ValidatedTestStr
这种方式能让mypy正确解析字段的类型标注。
内容的提问来源于stack exchange,提问作者Alexander Konukhov
相关产品推荐
相关产品推荐

