Внедрение зависимостей: Python

Обзор

Внедрение зависимостей (DI) - это метод разработки программного обеспечения для определения зависимостей между объектами. По сути, это процесс предоставления ресурса, который требуется данному фрагменту кода. Требуемый ресурс называется зависимостью.
При написании кода определяются различные классы и объекты. В большинстве случаев эти классы зависят от других классов, чтобы выполнить свое предназначение. Эти классы, или, лучше говоря, «Компоненты», знают, какие ресурсы им нужны и как их получить. DI обрабатывает определение этих зависимых ресурсов и предоставляет способы их создания или создания извне. Контейнер зависимостей используется для реализации этого поведения и содержит карту зависимостей для компонентов.
Если объект A зависит от объекта B, объект A не должен создавать импорт объект Б напрямую. Вместо этого объект A должен обеспечивать способ внедрения объекта B. Ответственность за создание объекта и внедрение зависимостей делегируется внешнему коду.

Зачем использовать внедрение зависимостей в коде?

  • Гибкость конфигурируемых компонентов - поскольку компоненты конфигурируются извне, для компонента могут быть различные определения (управление структурой приложения).
  • Простое тестирование - создание экземпляров фиктивных объектов и интеграция с определениями классов проще.
  • Высокая согласованность - Код с уменьшенной сложностью модуля, повышенной возможностью повторного использования модуля.
  • Минималистичные зависимости - поскольку зависимости четко определены, легче устранить / уменьшить ненужные зависимости.

Реализация DI в Python

Внедрение зависимостей в Python немного отличается от общего статического языка DI. Python имеет библиотеку микрофреймворков для DI, которая называется dependency_injector. Этот пакет состоит из двух основных сущностей: контейнеров и поставщиков.
Провайдеры описывают, как осуществляется доступ к объектам. Контейнеры - это просто набор поставщиков. Наиболее часто используемые типы поставщиков: Singleton, Configuration и Factory.

Пример

В следующем примере демонстрируется использование и реализация DI в Python. Создайте файл с именем email_client.py, содержащий класс EmailClient, который зависит от объекта config.

Создайте новый файл с именем e mail_reader.py, который содержит класс EmailReader и зависит от объекта EmailClient.

Теперь, чтобы определить эти вышеупомянутые зависимости извне, создайте новый файл container.py. Импортируйте пакет dependency_injector и классы, которые будут использоваться в DI.

from dependency_injector import providers, containers
from email_client import EmailClient
from email_reader import EmailReader

Добавьте в файл класс Configs. Этот класс представляет собой контейнер с поставщиком конфигурации, который предоставляет все объекты конфигурации.

class Configs(containers.DeclarativeContainer):
    config = providers.Configuration('config')
    # other configs

Добавьте еще один класс Clients. Этот класс представляет собой контейнер, определяющий все типы клиентов. EmailClient создается с помощью одноэлементного провайдера, утверждающего единственный экземпляр этого класса и определяющего его зависимость от объекта config.

class Clients(containers.DeclarativeContainer):
    email_client = providers.Singleton(EmailClient, Configs.config)
    # other clients 

Третий контейнер - это класс Readers, определяющий зависимость класса EmailReader от класса EmailClient.

class Readers(containers.DeclarativeContainer):
    email_reader = providers.Factory(EmailReader, client=Clients.email_client)
    # other readers 

Чтобы запустить пример, создайте файл main.py со следующим кодом.

В файле main.py объект config заменяется заданным объектом словаря. Создан экземпляр класса EmailReader без создания экземпляра класса EmailClient в основном файле, что устраняет накладные расходы на его импорт или создание. Об этой части заботится файл контейнеров.

Рабочий пример см. Здесь.

Любые предложения или мысли, дайте мне знать:
Insta + Twitter + LinkedIn + Medium | Шивам Аггарвал