Gyaan

Abstract Classes and Interfaces

intermediate ABC abstract interfaces contracts

An abstract class is a class that can’t be instantiated on its own — it exists only to be a base for other classes. Think of it like a contract: “if you inherit from me, you must implement these methods.”

Why Do We Need Them?

Say we’re building a payment system. We want every payment processor to have a process() method. Without enforcement, someone might forget and we’d only find out at runtime.

# Without ABC — no enforcement
class PaymentProcessor:
    def process(self, amount):
        raise NotImplementedError  # only catches at runtime

class StripeProcessor(PaymentProcessor):
    pass  # forgot to implement process() — no error until we call it

Using ABC

The abc module gives us proper enforcement. If a subclass doesn’t implement the required methods, Python raises an error at instantiation time, not when we call the method.

from abc import ABC, abstractmethod

class PaymentProcessor(ABC):
    @abstractmethod
    def process(self, amount):
        """Process a payment of the given amount."""
        pass

    @abstractmethod
    def refund(self, transaction_id):
        """Refund a transaction."""
        pass

    def log(self, message):  # concrete method — inherited as-is
        print(f"[Payment] {message}")

Now let’s try to use it:

# This fails immediately
p = PaymentProcessor()  # TypeError: Can't instantiate abstract class

# This also fails — we didn't implement refund()
class BadProcessor(PaymentProcessor):
    def process(self, amount):
        print(f"Processing ${amount}")

bp = BadProcessor()  # TypeError: Can't instantiate abstract class

We must implement all abstract methods:

class StripeProcessor(PaymentProcessor):
    def process(self, amount):
        print(f"Stripe: charging ${amount}")

    def refund(self, transaction_id):
        print(f"Stripe: refunding {transaction_id}")

sp = StripeProcessor()  # works!
sp.log("Payment received")  # [Payment] Payment received — inherited

Abstract Properties

We can also make properties abstract.

class Shape(ABC):
    @property
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    @property
    def area(self):  # must implement as a property
        return 3.14159 * self.radius ** 2

Duck Typing vs ABC

Python is famous for duck typing — “if it walks like a duck and quacks like a duck, it’s a duck.” We don’t need formal interfaces most of the time. Just call the method and trust it’s there.

ABCs are for when we want stricter guarantees — like framework code, plugin systems, or team projects where we need to enforce a contract.

Protocol (Structural Typing)

Python 3.8 introduced Protocol as a lighter alternative. It’s like an interface that doesn’t require inheritance — it just checks if the methods exist.

from typing import Protocol

class Drawable(Protocol):
    def draw(self) -> None: ...

def render(shape: Drawable):  # any object with draw() works
    shape.draw()

The difference: ABCs require explicit inheritance (class Foo(MyABC)). Protocols just check the shape of the object — no inheritance needed.

In simple language, ABCs let us say “you must have these methods” and Python enforces it the moment we try to create an object. Use them when duck typing isn’t strict enough.