> Что такое Dependency Injection (DI) (Python)

Уровень: junior · Роль: backend · Язык: Python · Категория: Технические вопросы

Компании: Точка, ProFinansy, ООО Диджитал Сектор Поддержка, Спортлевел, Black Wall Group (BWG), Т1, Московский метрополитен

Стек: Python

> Пример ответа

Короткий ответ

Dependency Injection (DI) - это паттерн проектирования, при котором объект получает свои зависимости извне, а не создаёт их сам. Вместо MyService() внутри класса, зависимость передаётся через конструктор, сеттер или параметр метода. Это делает код слабо связанным, упрощает тестирование и позволяет легко заменять реализации. В Python DI часто реализуется вручную или через фреймворки вроде FastAPI, где зависимости объявляются в сигнатуре функции.

Подробное объяснение

Основная идея DI - инверсия управления (IoC): не класс решает, какую реализацию зависимости использовать, а внешний код (контейнер или вызывающий код) предоставляет её. Без DI класс жёстко привязан к конкретной реализации, что затрудняет его переиспользование и тестирование.

В Python DI выглядит естественно благодаря динамической типизации: можно передавать любой объект с нужным интерфейсом. Три основных способа внедрения:

  • Constructor injection - зависимость передаётся в __init__, самый распространённый вариант.
  • Setter injection - зависимость устанавливается через метод или атрибут после создания объекта.
  • Method injection - зависимость передаётся как параметр конкретного метода.

DI-контейнер (например, dependency-injector, injector) автоматизирует создание и связывание объектов, но для простых проектов достаточно ручного внедрения.

На практике

В реальном Python-коде DI чаще всего используется в веб-фреймворках. FastAPI автоматически резолвит зависимости из сигнатур функций. В Django DI применяется реже - там обычно используют сервисный слой с ручным внедрением через конструктор.

Типичный сценарий: сервис, который работает с базой данных. Без DI он создаёт подключение сам, что мешает юнит-тестам. С DI вы передаёте мок-репозиторий в тесте.

Для простых приложений не стоит сразу подключать DI-контейнер - начните с ручного внедрения через конструктор. Контейнер оправдан, когда граф зависимостей становится сложным.

Пример кода

PYTHON
# Без DI - жёсткая связь
class UserService:
def __init__(self):
self.db = PostgreSQLDatabase() # конкретная реализация
# С DI через конструктор
class UserService:
def __init__(self, db):
self.db = db # любая реализация с нужным интерфейсом
# Использование
db = PostgreSQLDatabase()
service = UserService(db)
# Тест с моком
class MockDB:
def get_user(self, user_id):
return {"id": user_id, "name": "Test"}
service = UserService(MockDB())

Как отвечать на собеседовании

Начните с определения: DI - это передача зависимостей извне. Затем объясните, зачем это нужно: слабая связанность, тестируемость, гибкость. Приведите простой пример с конструктором. Упомяните, что в Python DI реализуется проще, чем в статически типизированных языках, из-за duck typing. Если спросят про контейнеры - скажите, что это инструмент автоматизации, но не обязательная часть паттерна.

Что проверяет интервьюер

Интервьюер оценивает понимание принципа инверсии управления и умение объяснить, как DI влияет на архитектуру. Важно показать, что вы понимаете разницу между DI и DI-контейнером. Также проверяется знание, как DI помогает в тестировании - это ключевой практический аспект для backend-разработчика.

Типичные ошибки

  • Путать DI с DI-контейнером - это разные вещи.
  • Говорить, что DI - это только про фреймворки, хотя это просто паттерн.
  • Не упоминать тестирование - главный практический плюс DI.
  • Приводить пример только с FastAPI, не показывая базовый механизм.
  • Утверждать, что DI обязателен - для маленьких проектов это overengineering.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью