Ответ
В Python внедрение зависимостей (Dependency Injection) можно реализовать несколькими способами без привлечения специализированных фреймворков, следуя принципу "явное лучше неявного".
-
Через конструктор (Constructor Injection) Это самый распространенный и предпочтительный способ. Зависимости передаются как аргументы в метод
__init__.class DatabaseClient: def query(self, sql: str) -> list: # ... логика запроса к БД return [{"id": 1}] class UserService: def __init__(self, db_client: DatabaseClient): self._db_client = db_client def get_user(self, user_id: int): return self._db_client.query(f"SELECT * FROM users WHERE id={user_id}") # Явное внедрение зависимости при создании объекта db = DatabaseClient() user_service = UserService(db_client=db) -
Через метод (Method/Setter Injection) Зависимость передается через отдельный метод уже после создания объекта. Менее предпочтителен, так как объект может находиться в невалидном состоянии до вызова сеттера.
class ReportGenerator: _formatter = None def set_formatter(self, formatter): self._formatter = formatter def generate(self, data): if not self._formatter: raise ValueError("Formatter not set") return self._formatter.format(data) -
Через фабричную функцию Функция или метод, который инкапсулирует логику создания объекта и его зависимостей.
def create_user_service() -> UserService: db_client = DatabaseClient() return UserService(db_client=db_client) # Использование user_service = create_user_service()
Основной принцип — инверсия контроля (IoC): класс не создает свои зависимости сам, а получает их извне. Это упрощает тестирование (можно подменить реальную БД на mock-объект) и повышает модульность кода.
Ответ 18+ 🔞
Слушай, а вот этот ваш Dependency Injection в Python, ну, это ж просто пиздец как очевидно, если подумать головой, а не жопой! Ну правда, блядь, зачем городить огород, когда можно просто передать одну херню в другую? Ёпта, вот смотри.
Первый способ — через конструктор, или, как я это называю, "в лоб, без церемоний". Это когда ты, сука, сразу говоришь: "На, держи свою зависимость, и не ной". Самый нормальный способ, честно.
class DatabaseClient:
def query(self, sql: str) -> list:
# ... тут какая-то магия с базой, похуй
return [{"id": 1}]
class UserService:
def __init__(self, db_client: DatabaseClient): # Вот тут, смотри, прямо в ебало засовываем!
self._db_client = db_client
def get_user(self, user_id: int):
return self._db_client.query(f"SELECT * FROM users WHERE id={user_id}")
# А создаём мы это вот так, явно, без подвохов!
db = DatabaseClient()
user_service = UserService(db_client=db) # На, жри, UserService, вот тебе база данных!
Вот и вся философия, блядь! Объект не сам себе базу ищет, как последний распиздяй, а получает её готовенькой. Красота!
Второй способ — через отдельный метод.
А это уже для тех, кто любит поизвращаться. Создал объект, а он, сука, нерабочий, как мартышлюшка без банана. Пока не вызовешь волшебный метод set_чего-то_там — нихуя не работает. Ну такое, на любителя, честно говоря.
class ReportGenerator:
_formatter = None # Смотри-ка, пустота, пиздец!
def set_formatter(self, formatter): # А вот тут прибегает спаситель!
self._formatter = formatter
def generate(self, data):
if not self._formatter: # И если не прибежал — всё, пизда!
raise ValueError("Formatter not set, иди нахуй")
return self._formatter.format(data)
Чувствуешь? Объект как бы говорит: "Я, блядь, могу работать, но только если ты мне сначала дашь то, что нужно. А иначе — в рот меня чих-пых!". Не очень-то надёжно, если честно.
Третий способ — фабричная функция. Ну это когда ты, такой весь из себя умный, создаёшь отдельную функцию, которая делает всю грязную работу по сборке. Типа "я не буду пачкать руки, пусть эта функция пачкает".
def create_user_service() -> UserService:
db_client = DatabaseClient() # Она тут создаёт все зависимости...
return UserService(db_client=db_client) # ...и запихивает их куда надо!
# А ты потом просто вызываешь её, и всё готово, как в хорошем ресторане.
user_service = create_user_service()
Удобно, блядь! Особенно если там зависимостей — овердохуища. Всё в одном месте собрал, и нигде больше не паришься.
А главная фишка всего этого цирка, ёпта, — инверсия контроля. Это когда класс не сам себе ищет, чем ему питаться, а получает еду с кухни. И тогда его, сука, легко тестировать! Хочешь — подсовываешь ему настоящую базу данных, хочешь — какую-нибудь хуйню-заглушку, которая только делает вид, что работает. И всё летает!
Короче, ничего сложного, просто не надо быть мудаком и создавать зависимости внутри класса, как последний олух. Передавай их снаружи, и будет тебе счастье. Всё, лекция окончена, можете расходиться.