Для начала, Dependency Injection (DI) - это паттерн проектирования, который позволяет управлять зависимостями объектов в приложении. DI контейнер - это инструмент, который облегчает внедрение зависимостей в объекты и управление их жизненным циклом.
В Python существует несколько библиотек для работы с DI, таких как injector
, pycontainer
, Hypodermic
, или вы можете использовать встроенные инструменты, такие как модуль inspect
для поиска зависимостей класса и явного их внедрения.
Давайте рассмотрим пример внедрения базы данных в класс с использованием DI контейнера. Допустим, у нас есть класс UserRepository
, который зависит от объекта базы данных для выполнения операций с пользователями.
class UserRepository: def __init__(self, db): self.db = db def get_user(self, user_id): return self.db.query("SELECT * FROM users WHERE id = ?", user_id) def add_user(self, user_data): return self.db.execute("INSERT INTO users (name, email) VALUES (?, ?)", user_data['name'], user_data['email'])
Теперь давайте создадим DI контейнер и внедрим базу данных в UserRepository
.
class Database: def __init__(self, connection_string): self.connection_string = connection_string def query(self, query, *args): # Реализация метода query pass def execute(self, query, *args): # Реализация метода execute pass db = Database("sqlite:///:memory:") # Пример подключения к SQLite базе данных # DI контейнер container = { 'db': db } def get_instance(cls): dependencies = {k: container[k] for k in cls.__init__.__code__.co_varnames if k in container} return cls(**dependencies) user_repository = get_instance(UserRepository)
В данном примере мы создали экземпляр базы данных db
и поместили его в DI контейнер. Функция get_instance
принимает класс, извлекает необходимые зависимости из контейнера и возвращает экземпляр класса с внедренными зависимостями.
Таким образом, при использовании DI контейнера мы можем изолировать зависимости класса, что упрощает тестирование, повторное использование кода и делает приложение более гибким и масштабируемым.