装饰器 · Depends

Depends 严格说是参数默认值而非 @ 装饰器,但与路由装饰器配套使用,本目录按「声明式注入」一并收录。

0. 一句话定位

维度 内容
作用对象 函数参数(路由端点 / 其他依赖)
使用场景 依赖
来源 第三方 fastapi.Depends
语法形式 param: T = Depends(get_x)

段末注释:依赖注入(Dependency Injection,DI) 把 DB 会话、当前用户等横切依赖从业务函数中拆出,由框架解析并注入。

1. 做什么

FastAPI 在调用端点前解析 Depends(...) 声明的依赖树:先执行依赖函数,将返回值注入参数;依赖可嵌套(依赖的依赖);同一请求内相同依赖可缓存(默认 use_cache=True)。

2. 重点参数

参数 类型 默认值 作用 配置建议
dependency callable / None 必填 依赖函数或类 无参 callable 最常见
use_cache bool True 同请求内是否复用结果 DB session 通常 True;每次要新对象设 False

依赖函数常用参数:也可声明 RequestHTTPAuthorizationCredentials 等,FastAPI 自动注入。

类作为依赖:实现 __call__ 的 callable 类。

3. 最小可运行示例

1
2
3
4
5
6
7
8
9
10
11
from typing import Annotated
from fastapi import Depends, FastAPI

app = FastAPI()

def get_settings():
return {"debug": True}

@app.get("/info")
async def info(settings: dict = Depends(get_settings)):
return settings

推荐写法(Python 3.9+)

1
2
3
4
5
SettingsDep = Annotated[dict, Depends(get_settings)]

@app.get("/info2")
async def info2(settings: SettingsDep):
return settings

依赖链

1
2
3
4
5
6
7
8
9
10
11
12
13
def get_db():
db = connect()
try:
yield db
finally:
db.close()

def get_user(db=Depends(get_db)):
return db.query_user()

@app.get("/me")
async def me(user=Depends(get_user)):
return user

4. 常见变体

路由级 / 路由器级依赖

1
2
3
4
5
6
7
8
9
10
from fastapi import APIRouter

async def verify_token():
...

router = APIRouter(dependencies=[Depends(verify_token)])

@app.get("/admin", dependencies=[Depends(verify_token)])
async def admin():
return {"ok": True}

Security + OAuth2

1
2
3
4
5
6
7
from fastapi import Security
from fastapi.security import OAuth2PasswordBearer

oauth2 = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2)):
...

yield 依赖(资源清理)

1
2
3
4
5
6
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

5. 适用 / 不适用

适用

  • DB Session、当前用户、权限、分页参数等复用逻辑
  • 测试时用 app.dependency_overrides[get_db] = fake_db 替换依赖

不适用

  • 每个请求都不同的纯 Path/Query → 直接函数参数 + 类型注解
  • 全局横切(日志、CORS)→ 中间件更合适

6. 易踩坑

  • Depends(get_db) 不要写成 Depends(get_db())(后者会立即调用)
  • 生成器依赖 yield 之后的代码在响应发送后执行 teardown
  • 循环依赖(A 依赖 B、B 依赖 A)会报错,需重构
  • 同步依赖函数在 async 端点中会在线程池运行(有开销)

7. 近邻替代

替代 何时用
@app.middleware 全请求横切、不注入业务参数
全局变量 不推荐,难测试
手动在端点内 get_db() 小脚本;大项目用 Depends

8. 参考

-------------本文结束感谢您的阅读-------------