Dependency Injection

Posted on April 10, 2025
Profile
Gastón Gaitan
April 10, 2025 · 2 months ago
Dependency Injection

Dependency Injection in Python

Dependency Injection is a simple but powerful principle: instead of creating dependencies inside a class, we provide them externally, usually through the constructor. This makes our code more testable, modular, and scalable.

Without Dependency Injection

In this case, the controller is tightly coupled to the service class. It creates the instance itself, which makes it harder to test or replace.

class UserController: def __init__(self): self.user_service = UserService() # tightly coupled def get_user(self, user_id): return self.user_service.find_user(user_id)

With Dependency Injection

Here, the service is passed as a parameter. This makes it easier to test with mocks or change implementations later on.

class UserController: def __init__(self, user_service): self.user_service = user_service def get_user(self, user_id): return self.user_service.find_user(user_id)

Example: Notification Service

Here, we inject a notification system so the user class doesn't need to know how the notification works internally.

class EmailNotifier: def send(self, message): print(f"Sending email: {message}") class UserService: def __init__(self, notifier): self.notifier = notifier def create_user(self, name): # logic to create user... self.notifier.send(f"User {name} created") notifier = EmailNotifier() user_service = UserService(notifier) user_service.create_user("Alice")

Example: Repository Pattern with Dependency Injection

We inject a repository into a service so we can swap the database implementation without changing the service logic.

class UserRepository: def get_user(self, user_id): # simulate DB lookup return {"id": user_id, "name": "John Doe"} class UserService: def __init__(self, repository): self.repository = repository def get_user_profile(self, user_id): user = self.repository.get_user(user_id) return f"User {user['name']} loaded" repo = UserRepository() service = UserService(repo) print(service.get_user_profile(123))

Why Use Dependency Injection?

  • Testability: Easily inject mock objects for testing.
  • Flexibility: Swap implementations without changing core logic.
  • Scalability: Better suited for growing applications.
  • Single Responsibility: Classes don't manage their own dependencies.

Key Takeaway

Dependency Injection is about separating concerns. It's not about complexity — it's about control. You decide what your class needs, and you pass it in, instead of creating it inside.