Посты
Может ли внедрение зависимостей сделать меня лучшим Python-программистом?
16 февраля 2025 г. • 3 мин чтения

Внедрение зависимостей является основой в статических языках, но имеет ли смысл использовать его в Python? Сделает ли это меня лучшим Python-программистом?
И, подождите, что такое внедрение зависимостей, опять же?
Сначала давайте ответим на вопрос: Что такое внедрение зависимостей (DI)?
Внедрение зависимостей — это паттерн, который при использовании выносит создание объекта за пределы класса. Вместо этого класс принимает зависимость от абстракции.
В статических языках, таких как C# и Java, внедрение зависимостей широко используется для уменьшения связанности и облегчения тестирования. Фактически, вы найдете фреймворки внедрения зависимостей, единственная цель которых — поддерживать зависимости и их отношения друг с другом.
Внедрение зависимостей служит двум основным целям:
Во-первых, оно уменьшает сложность, принимая зависимость от абстракции.
Во-вторых, зависимость от абстракции позволяет передавать различные реализации, включая моки для тестирования, в класс или функцию.
Позвольте мне продемонстрировать это с помощью кода:
# До
class User:
def __init__(self):
self.database = SqlServerDatabase()
def get_details(self, user_id: int):
self.database.get_user_details(user_id)
# После
class User:
def __init__(self, database: Database):
self.database = database
def get_details(self, user_id: int):
self.database.get_user_details(user_id)
Это внедрение зависимостей в его простейшей форме. Хотя концепция проста, её сила заключается в обеспечении гибкого дизайна.
В примере До
класс User
тесно связан с классом SqlServerDatabase
. Если мы хотим протестировать класс User
, нам нужно создать новый экземпляр SqlServerDatabase
.
В примере После
класс User
слабо связан с абстракцией Database
. Мы можем передать другую реализацию абстракции Database
в класс User
.
Позвольте мне продемонстрировать эту гибкость на практическом примере, который показывает, как мы можем переключаться между различными реализациями базы данных:
date_string = "2023-10-01" # Example date string
date_format = "%Y-%m-%d" # Input string format
birthday = datetime.strptime(date_string, date_format)
turn_of_the_century = datetime.strptime('2000-01-01', date_format)
database = PostgresDatabase("")
if birthday < turn_of_the_century:
database = SqlServerDatabase("")
user = User(database=database)
user.get_details(user_id=1)
На строке 6 (birthday < turn_of_the_century
) внедрение зависимостей позволяет нам легко менять реализации в зависимости от различных условий. Хотя эта гибкость ценна для производственного кода, одним из наиболее распространенных применений внедрения зависимостей, особенно в статических языках, является тестирование.
Вот пример:
class UserTests(unittest.TestCase):
def test_is_authenticated(self):
database = MockDatabase('connection_string')
is_authenticated = User(database).is_authenticated('user', 'pass')
self.assertTrue(is_authenticated)
Это простой пример с использованием класса MockDatabase
. В Python мы также могли бы использовать встроенный класс Mock
для достижения того же результата.
Интересно, что внедрение зависимостей не было широко распространено в Python-проектах, над которыми я работал. Приходя из мира статических языков, я был удивлен — и это казалось противоречивым.
Однако есть причина для такого ограниченного принятия. Встроенная функциональность patch в Python уже обеспечивает отличные возможности тестирования, устраняя одно из основных преимуществ внедрения зависимостей. Хотя внедрение зависимостей все еще может помочь уменьшить сложность, Python имеет другие подходы для достижения той же цели.
Я не говорю, что внедрение зависимостей не следует использовать в Python. Наоборот, как и все инструменты и паттерны, есть место и время для их использования. И внедрение зависимостей — это просто еще один инструмент в вашем арсенале, который улучшит качество вашего кода.
Я думаю, что внедрение зависимостей в целом повысило бы качество кода в большинстве Python-проектов.
Если вас интересует дальнейшее изучение внедрения зависимостей, я рекомендую ознакомиться с двумя популярными Python-фреймворками:
- Injector (github.com/python-injector/injector)
- Dependency Injector (python-dependency-injector.ets-labs.org)
Автор: Чак Конвей специализируется на разработке программного обеспечения и генеративном ИИ. Свяжитесь с ним в социальных сетях: X (@chuckconway) или посетите его на YouTube.