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.