Clean Python Architecture: Decoupling Code with Dependency Injection
Beyond Rigid Constructors
Many developers trap themselves by initializing dependencies directly inside a class. This creates tight coupling, where a change in a low-level service forces a rewrite of high-level logic. For instance, an EmailSender class that creates its own
The Dependency Injection Pattern
__init__ method. By injecting a service that follows a specific send_email method.
Code Walkthrough: Before and After
The Coupled Approach
In the rigid version, an if-else block determines which service to instantiate. This grows uncontrollably as you add new providers like
class EmailSender:
def send_email(self, service_type, to, subject, body):
if service_type == "mailchimp":
service = MailChimp(attachment=True)
elif service_type == "sendgrid":
service = SendGrid()
service.send(to, subject, body)
The Injected Approach
By moving the service creation outside the class, we achieve a clean, single-purpose method.
class EmailSender:
def __init__(self, service: EmailService):
self.service = service
def send_email(self, to, subject, body):
self.service.send(to, subject, body)
Syntax and Best Practices
Use EmailSender logic in isolation without dealing with

Fancy watching it?
Watch the full video and context