Короткий ответ
FastAPI по умолчанию кэширует результат зависимости в пределах одного запроса по идентичности callable, поэтому при использовании одной и той же функции-зависимости в нескольких местах она вызывается один раз; поведение можно явно отключить через use_cache=False.
Как это работает подробнее
Внутри одного запроса FastAPI строит граф зависимостей и для каждого уникального callable (с одинаковыми параметрами вызова) хранит результат в локальном кэше запроса. Если два разных эндпоинта или две разные зависимости ссылаются на Depends(get_db), функция get_db выполнится один раз, а не дважды.
Пример кода
example.py
from fastapi import FastAPI, Depends
app = FastAPI()
calls = {"count": 0}
def get_db():
calls["count"] += 1
db = "db-session"
try:
yield db
finally:
calls["closed"] = True
def get_repo(db=Depends(get_db)):
return db
@app.get("/check")
def check(db=Depends(get_db), repo=Depends(get_repo)):
return {"calls": calls["count"]}
# После одного GET /check calls["count"] == 1, а не 2,
# т.к. get_db закэширован в пределах запроса.Что использовать на практике
- Практика. Это полезно для подключения к БД, кэша текущего пользователя, открытия транзакции — важно, чтобы разные части кода работали с одним и тем же объектом сессии в рамках запроса. Если нужно гарантированно вызвать зависимость повторно (например, для генерации нового значения), используют
Depends(func, use_cache=False).
Подводные камни
- Риск. Создают несколько разных функций-обёрток с одинаковой логикой открытия сессии, ожидая, что они будут «общим» кэшированным ресурсом — кэшируется по идентичности функции, а не по семантике; не закрывают ресурс в
finally/yield-зависимости, из-за чего соединения не освобождаются даже при единственном вызове.