Гайды
Внедрение зависимостей в Python и FastAPI Depends
Зачем DI, Depends и yield, контейнеры, dependency_overrides в тестах и антипаттерн глобалов.
~9 мин чтения
Внедрение зависимостей в Python и FastAPI Depends
В Python внедрение зависимостей чаще явное: функции/классы получают зависимости аргументами или через контейнер при старте. В FastAPI — Depends. Параллель в других стеках — конструкторы в Spring, Django сервис-слой. Маршруты и DI в FastAPI — Маршрутизация и Dependency Injection; контейнеры приложения — Docker: контейнеризация (не путать с IoC-контейнером).
1. Зачем DI
Тестируемость (моки), единая точка создания DB pool, config, HTTP client с lifecycle.
2. FastAPI Depends
def get_repo() -> OrderRepo:
return SqlOrderRepo(pool)
@app.post("/orders")
def create(repo: OrderRepo = Depends(get_repo), body: OrderCreate = ...):
return repo.create(body)
Depends на классе — __call__ без параметров для «класс-зависимость».
Сессия БД с yield — стандартный паттерн: создать сессию, отдать в обработчик, после ответа закрыть/откатить при ошибке:
from collections.abc import Generator
from sqlalchemy.orm import Session
def get_session() -> Generator[Session, None, None]:
session = SessionLocal()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
@app.get("/items")
def list_items(session: Session = Depends(get_session)):
return session.query(Item).all()
FastAPI вызывает генератор до yield при входе в запрос и код после yield при завершении (в т.ч. после отправки ответа для sync-эндпоинтов — см. документацию по async и блокирующим операциям в teardown).
3. Контейнеры в Python
dependency-injector, punq, wired — если нужна граф-зависимостей крупнее, чем удобно выразить Depends.
4. Антипаттерн: глобалы
Модули уровня db = connect() при импорте усложняют тесты и переиспользование.
5. Вложенные Depends и sub-dependencies
Depends(get_session) внутри get_repo(session=Depends(get_session)) строит граф автоматически; кэширование одного запроса — один вызов get_session на request. Используйте Annotated (Annotated[Session, Depends(get_session)]) для читаемости в Python 3.9+.
6. Security scopes и контекст
Security(HTTPBearer()) с scopes комбинируется с Depends для проверки прав до бизнес-логики. Выносите разбор JWT в одну зависимость, а проверку ролей — в отдельную, чтобы переиспользовать в роутерах.
7. Чек-лист
- Зависимости с
yieldдля ресурсов — корректный teardown. - Не тащить request-scoped данные в singleton без очистки.
- В тестах —
app.dependency_overrides. - Не выполнять тяжёлую работу в
Dependsбез кэша на уровень запроса. - Документировать в OpenAPI через
dependencies=[]на роутере при общих требованиях.
Дальше: Быстрый старт с FastAPI