旧版写法
@app.get('/student/{age}')
async def get_student(age: int=Path(...,ge=10,le=120,description="年龄大于等于10岁,小于等于120岁")):
return {'msg': f'年龄{age}'}
...
缺点
...(Ellipsis省略号)极易遗忘- 路径参数必须写
Path(..., ge=1) - 漏写
...写成Path(ge=1),会把ge=1当作default默认值,直接运行时异常,坑非常多。
- 路径参数必须写
- 类型注解与元数据耦合在一起
- 真正的类型
int和校验元数据Path()被=赋值绑定。 - 阅读代码时,要跳到等号右边才能看到校验规则。
- 真正的类型
- 类型提示工具容易乱
IDE/mypy 有时候推断类型出错;Path(...)返回的是Param对象,靠FastAPI内部做剥离。 - 无法复用类型定义,每处都复制粘贴一长串,重复代码,修改要改多处。
Path()底层使用 Pydantic v2,与其新设计理念不一致。Pydantic v2大量使用Annotated存放校验元数据,旧写法属于兼容遗留模式。
例子:重新实现上面的校验
from fastapi import FastAPI,Path
from typing_extensions import Annotated
app = FastAPI()
@app.get('/student/{age}')
async def get_student(age: Annotated[int,Path(ge=10,le=120,description="年龄大于等于10岁,小于等于120岁")]):
return {'msg': f'年龄{age}'}
...
例子:可以复用
定义全局公共类型,多处接口复用,如下:
StudentName = Annotated[str,Path(min_length=2,max_length=3,description="姓名数量在2-3之间")]
代码
from fastapi import FastAPI,Path
from typing_extensions import Annotated
app = FastAPI()
# 定义校验,可以复用
StudentName = Annotated[str,Path(min_length=2,max_length=3,description="姓名数量在2-3之间")]
@app.get('/student/{name}')
async def get_student(name: StudentName):
"""根据姓名获取学生信息"""
return {
'name': name,
'age': 21,
}
@app.get('/score/{name}')
async def get_score(name: StudentName):
"""根据姓名获取分数信息"""
return {
'name': name,
'数学': 88,
}
优点
- 彻底干掉
...省略号
Path内部不再接收default位置参数;路径参数天然必填,不用再写...,减少低级错误。 - 类型与校验元数据分离
Annotated[真实类型, 元数据(Path/Query/Field)]
一眼看到基础类型,后面是校验规则,代码可读性高。 - 支持类型别名复用(企业项目最大收益)
把一套“类型+校验”抽成类型别名,多处直接引用;修改只改一处。 - IDE、mypy静态类型检查更稳定
真正的业务类型写在第一个位置,工具识别更准确。 - 统一编码范式
和Pydantic v2Annotated+Field、Query、Header、Cookie语法完全统一。- Path:
Annotated[int, Path(ge=1)] - Query:
Annotated[int, Query(ge=1)] = None - Body字段:
Annotated[int, Field(ge=1)]
整套项目一套写法,记忆负担小。
- Path:
- 默认值语义清晰
查询参数的默认值写在函数参数的等号后面,不再塞到Query/Path函数内部:# 查询参数可选,默认None q: Annotated[str, Query(max_length=20)] = None
新版缺点
- 需要导入
Annotated(python3.9+标准库;低版本需要typing_extensions) - 老教程、老项目大部分是旧写法,网上复制代码容易两种写法混用,造成混乱。
对比
| 对比项 | 旧版 = Path(..., **kwargs) |
新版 Annotated[T, Path(**kwargs)] |
|---|---|---|
| 必填标记 | 必须写...,极易漏写 |
不需要... |
| default位置 | Path第一个位置参数 | default写在函数参数=后面 |
| 类型可读性 | 类型和元数据分离在等号两边 | 基础类型放在最前面,一目了然 |
| 类型别名复用 | 不支持,只能复制粘贴 | ✅支持抽别名,全局复用 |
| 静态类型检查 | 偶尔IDE推断异常 | IDE/mypy表现稳定 |
| 范式统一 | 和Field写法不一致 | 与Query/Header/Field完全统一 |
| 学习成本 | 要记忆...含义 |
需要理解Annotated概念 |
| 适用场景 | 老项目兼容 | 新项目、企业开发推荐 |
企业开发建议
- 新项目全部使用 Annotated;
- 老项目维护:可以继续旧写法,但务必注意
Path(...,)的三个点; - 公共参数(学号、id、编码等)抽成
Annotated类型别名,多处接口直接引用。
补充:Annotated只是语法糖,运行时性能无差别,全部还是交给Pydantic做校验。