























PEP 593 引入的 Annotated(在 typing 模块中)主要作用是:
给类型附加额外的元数据(metadata),同时不改变原有类型语义。
它的形式是:
from typing import Annotated
x: Annotated[int, metadata]
这里:
int 是真实类型(静态类型检查器仍认为它是 int)metadata 是附加信息,供框架、库、运行时工具使用。以前:
类型提示只负责:
age: int
只能表达“这是 int”。
但现实中经常需要表达:
单靠类型系统无法表达。
Annotated 就是把这些信息塞进去:
from typing import Annotated
age: Annotated[int, "must be positive"]
常见于 Pydantic
from typing import Annotated
from pydantic import BaseModel, Field
class User(BaseModel):
age: Annotated[int, Field(gt=0, lt=150)]
这里:
int
还是类型;
Field(gt=0)
是元数据。
作用:
比如 FastAPI:
from typing import Annotated
from fastapi import Header
async def endpoint(
token: Annotated[str, Header()]
):
...
str 是类型。
Header() 表示:
这个参数来自 HTTP Header。
非常优雅。
from typing import Annotated
UserId = Annotated[int, "primary key"]
id: UserId = 42
你可以附加业务语义。
甚至:
class Range:
def __init__(self, min_, max_):
self.min = min_
self.max = max_
Score = Annotated[int, Range(0, 100)]
这是 PEP 593 的核心设计思想。
类型检查器:
Annotated[int, xxx]
默认等价于:
int
元数据不会破坏类型系统。
而运行时工具可读取:
from typing import get_type_hints
print(get_type_hints(obj, include_extras=True))
可以拿到:
Annotated[int, ...]
普通:
name: str
只有类型。
Annotated:
name: Annotated[str, MaxLen(20)]
类型 + 元数据。
类型本身 + 注释插件
以前常这样:
from pydantic import Field
age: int = Field(gt=0)
约束和默认值混在一起。
PEP 593 后更干净:
age: Annotated[int, Field(gt=0)]
类型和元数据分离。
可以叠:
from typing import Annotated
x: Annotated[
int,
"positive",
"database index",
]
多个框架可以各取所需。
from typing import Annotated
from fastapi import Query
async def search(
q: Annotated[str, Query(min_length=3)]
):
...
相当于:
str全放在一个声明里。
from typing import Annotated
x: Annotated[int, "foo"]
y: int = x # 没问题
像 mypy 通常把它当 int。
不是新类型:
Annotated[int, ...]
不是 PositiveInt 这种新类型。
只是给 int 加说明。
像数据库:
age INT
只是类型。
而:
age INT CHECK(age > 0)
类型 + 元信息/约束。
Annotated 很像这个。
主要是为:
适合:
不适合:
只是普通变量注释时没必要:
x: int
够了。
from typing import Annotated
from pydantic import BaseModel, Field
PositiveInt = Annotated[int, Field(gt=0)]
class Product(BaseModel):
price: PositiveInt
非常常见。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。