Mastering Dependency Inversion in Python with Abstract Base Classes

Overview of Dependency Inversion

(the 'D' in
SOLID
) transforms how components interact. Instead of high-level modules depending directly on low-level implementation details, both rely on abstractions. This decoupling ensures that changing a specific tool or library doesn't break the core logic of your application. It’s the difference between a house wired directly to one specific brand of lightbulb and a house using a standard socket that accepts any bulb.

Prerequisites

To follow this tutorial, you should understand

class syntax and basic inheritance. Familiarity with
Object-Oriented Programming
(OOP) concepts like methods and constructors will help you grasp how objects communicate.

Key Libraries & Tools

  • abc
    (Abstract Base Classes):
    A built-in Python module used to define blueprints for other classes. It ensures subclasses implement specific methods.
  • Mypy
    :
    A static type checker that helps developers catch type-related errors before the code runs.

Code Walkthrough

1. Defining the Abstraction

First, we create an interface using the abc module. This defines what it means to be "switchable" without worrying about the device type.

from abc import ABC, abstractmethod

class Switchable(ABC):
    @abstractmethod
    def turn_on(self):
        pass

    @abstractmethod
    def turn_off(self):
        pass

2. Implementing the Subclasses

Now, we create a

and a
Fan
. Both inherit from Switchable, making them compatible with any switch.

class LightBulb(Switchable):
    def turn_on(self):
        print("LightBulb: on")

    def turn_off(self):
        print("LightBulb: off")

class Fan(Switchable):
    def turn_on(self):
        print("Fan: spinning")

    def turn_off(self):
        print("Fan: stopped")

3. The Decoupled Power Switch

The

no longer cares if it's holding a bulb or a fan; it only cares that the object is Switchable.

class PowerSwitch:
    def __init__(self, client: Switchable):
        self.client = client
        self.on = False

    def press(self):
        if self.on:
            self.client.turn_off()
            self.on = False
        else:
            self.client.turn_on()
            self.on = True

Syntax Notes

The @abstractmethod decorator is a safeguard. If you inherit from ABC but forget to implement a decorated method, Python raises a TypeError the moment you try to instantiate the subclass. This enforces a strict contract between your components.

Tips & Gotchas

Always use type hints to signal your intent to other developers. While the Python interpreter ignores them, they are invaluable for documentation. A common mistake is trying to instantiate the abstract class itself; remember, Switchable is a blueprint, not a concrete object. Use this pattern whenever you find yourself writing code that is too tightly coupled to a specific implementation.

Mastering Dependency Inversion in Python with Abstract Base Classes

Fancy watching it?

Watch the full video and context

3 min read