Ответ
Библиотека dependency-injector
реализует паттерн Внедрение зависимостей (Dependency Injection, DI) и помогает управлять Инверсией контроля (Inversion of Control, IoC) в Python-приложениях.
Основная проблема, которую она решает, — это жесткая связанность (tight coupling) компонентов. Вместо того чтобы компонент сам создавал свои зависимости (например, коннектор к базе данных или API-клиент), он получает их извне из специального контейнера.
Пример:
from dependency_injector import containers, providers
from dependency_injector.wiring import inject, Provide
# 1. Определяем компоненты
class ApiClient:
def __init__(self, api_key: str):
self._api_key = api_key
class MyService:
def __init__(self, client: ApiClient):
self._client = client
# 2. Создаем контейнер для управления зависимостями
class Container(containers.DeclarativeContainer):
config = providers.Configuration()
# Провайдер Singleton гарантирует, что будет создан только один экземпляр ApiClient
api_client = providers.Singleton(
ApiClient,
api_key=config.api.key
)
# Провайдер Factory будет создавать новый экземпляр MyService при каждом запросе
my_service = providers.Factory(
MyService,
client=api_client
)
# 3. Используем контейнер в приложении
@inject
def main(service: MyService = Provide[Container.my_service]):
# ... здесь логика, использующая сервис
pass
if __name__ == "__main__":
container = Container()
container.config.api.key.from_env("API_KEY", required=True)
container.wire(modules=[__name__]) # Связываем контейнер с текущим модулем
main()
Основные преимущества:
- Слабая связанность (Loose Coupling): Компоненты не зависят от конкретных реализаций своих зависимостей.
- Упрощение тестирования: В тестах легко подменить реальные зависимости (например,
ApiClient
) на мок-объекты. - Централизованная конфигурация: Все зависимости и их настройки собраны в одном месте — контейнере.