SYS.ACTIVE
Tharana-dev
CPU: 12% | MEM: 44%
[ PYTHON / OOP ]

Abstract Base Classes

Contracts, not containers — and why Python refuses to run an incomplete class.

I learned about Abstract Base Classes today. I wrote this the moment it clicked, while the confusion was still fresh — because that's the best time to explain something to the next beginner.

What is an ABC?

An Abstract Base Class is a class that cannot be instantiated. It cannot hold data. It is a blueprint — a strict contract. It says: "Any class that inherits from me MUST write its own version of these specific methods, or Python will refuse to run it."

Think of a standard wall socket. It's a contract. The wall socket says: "I will provide electricity if you have two prongs." It doesn't care whether you plug in a toaster, a phone charger, or a lamp. It only cares that your device has the right shape.

Why does it exist?

Because humans make mistakes. If you hand a project to a junior developer and say, "Write a macOS collector," they might name the method get_cpu_usage() instead of get_cpu_snapshot(). Without an ABC, the app runs fine — until it hits that Mac, and then crashes with an AttributeError deep in the app, hours after the mistake was made.

With an ABC, Python stops the developer the moment they try to use their Mac class, saying: "Hey, you forgot to implement get_cpu_snapshot()." It catches bugs before they happen.

When should you use it?

Use it when you want to do the same work in different ways. For example, the sounds different animals make are different from animal to animal, and it's painful to write:

if animal == "dog":
    sound = "woof"
elif animal == "bird":
    sound = "tweet"
elif animal == "cat":
    sound = "meow"
# ... and so on, forever

It gets worse if the same if/elif/else block has to be repeated in several places. Instead, we define an ABC Animal that inherits from ABC, and we declare the abstract methods on it. Then we define one class per animal, each inheriting from Animal and filling in the blanks:

from abc import ABC, abstractmethod


class Animal(ABC):
    @abstractmethod
    def speak(self) -> str:
        ...

    @abstractmethod
    def move(self) -> str:
        ...

Why can't you just instantiate it?

Because an ABC is incomplete — a skeleton without a body. If we try to instantiate it without the predefined methods, Python throws an error. Try this:

animal = Animal()

Mypy / Pylance will show:

Cannot instantiate abstract class "Animal"
  "Animal.speak" is not implemented
  "Animal.move" is not implemented

PylancereportAbstractUsage
Cannot instantiate abstract class "Animal" with abstract attributes "move" and "speak"

Mypyabstract
class Animal()

And the terminal will show:

Traceback (most recent call last):
  File "/home/tharana/telemetry-engine/practice/practice_abc.py", line 14, in <module>
    animal = Animal()
TypeError: Can't instantiate abstract class Animal without an implementation for abstract methods 'move', 'speak'

So we inherit from the ABC and fill in the predefined blanks. Note: implementing only some of the abstract methods still fails. Try this:

class Dog(Animal):
    def speak(self) -> str:
        return "Woof"

d = Dog()

Mypy / Pylance will show:

Cannot instantiate abstract class "Dog"
  "Animal.move" is not implemented

PylancereportAbstractUsage
Name "dog" is not defined

Mypyname-defined
class Dog()

Because move was still abstract. Fill in both, and it works:

class Dog(Animal):
    def speak(self) -> str:
        return "Woof"

    def move(self) -> str:
        return "Runs"


class Bird(Animal):
    def speak(self) -> str:
        return "Tweet"

    def move(self) -> str:
        return "Flies"


d = Dog()
print(d.speak())  # Woof
print(d.move())   # Runs

b = Bird()
print(b.speak())  # Tweet
print(b.move())   # Flies

Do you need super().__init__()?

If the ABC has an __init__ method (for example, setting up self.path = "/proc"), then yes — the child class must call super().__init__() to run the parent's setup. If the ABC has no __init__, you don't need it.

Why this matters for testing

If you create a FakeAnimal that inherits from Animal, it is guaranteed to expose the exact same shape as real data. So you don't have to manually mock file reads or wire up unittest.mock. The ABC is the interface, so any fake that satisfies it is a legitimate substitute.

ABC vs Dataclass — a common confusion

They are not the same thing. They operate in completely different domains.

A dataclass is for data. It is a dumb container. Its job is to hold variables (like total_gb or used_pct) and generate boilerplate code like __init__ and __repr__. Think of it as a labeled cardboard box.

An ABC is for behavior. It is a smart contract. Its job is to enforce rules on functions and methods. It holds no data. Think of it as a job description.

An ABC is the difference between hoping your code works and knowing it will. It's the contract you write to your future self — and to anyone else who touches this code.

Tharana Nimsara

✅ VERIFIED AUTHOR

SHA256: a2c9d4...f8e1

ESC
tharana@dev: ~

Welcome to TharanaOS v1.0.0

Type 'help' to see available commands.

➜ ~
Hello, user.
(o_o)