Skip to content
Laviyx Learn

Try

Python course menu

Python Abstraction: Abstract Base Classes (ABC) and abstractmethod

Learn abstraction in Python: hide implementation details behind simple interfaces, define abstract base classes with the abc module and @abstractmethod, enforce required methods in subclasses, and combine abstraction with polymorphism.

Intermediate8 min readUpdated
On this page

Abstraction means exposing what an object does while hiding how it does it. You call payment.pay(499) without knowing whether the money moves by UPI, card or wallet. Python supports abstraction with abstract base classes (ABCs): classes that define a required interface but cannot be used on their own.

The four pillars of OOP#

Abstraction is the last of the four ideas that make up object-oriented programming:

PillarIdeaLesson
Encapsulationbundle data with the methods that protect itEncapsulation
Inheritancereuse and extend existing classesInheritance
Polymorphismone interface, many implementationsPolymorphism
Abstractionhide details behind a simple, required interfacethis lesson

An abstract base class#

The abc module provides ABC and the @abstractmethod decorator:

Python
from abc import ABC, abstractmethod

class PaymentMethod(ABC):
    @abstractmethod
    def pay(self, amount):
        ...

    def receipt(self, amount):
        return f"Paid ₹{amount} via {self.pay(amount)}"

class UPI(PaymentMethod):
    def __init__(self, upi_id):
        self.upi_id = upi_id

    def pay(self, amount):
        return f"UPI ({self.upi_id})"

class Card(PaymentMethod):
    def __init__(self, last4):
        self.last4 = last4

    def pay(self, amount):
        return f"card ending {self.last4}"

for m in [UPI("asha@okbank"), Card("4321")]:
    print(m.receipt(499))
Output
Paid ₹499 via UPI (asha@okbank)
Paid ₹499 via card ending 4321
  • PaymentMethod declares that every payment method must have pay().
  • It can still provide shared, concrete methods like receipt().
  • receipt() calls self.pay() without knowing which kind of payment it is: abstraction and polymorphism working together.

Abstract classes cannot be created#

An ABC is a template, not a finished class:

Python
PaymentMethod()
Output
TypeError: Can't instantiate abstract class PaymentMethod without an implementation for abstract method 'pay'

Subclasses must implement every abstract method#

If a subclass forgets one, Python refuses to create it, at creation time, not later when the missing method is finally called:

Python
class Cash(PaymentMethod):
    pass

Cash()
Output
TypeError: Can't instantiate abstract class Cash without an implementation for abstract method 'pay'

This is the main advantage over a plain base class whose method just raises NotImplementedError: mistakes surface immediately.

Designing with interfaces#

Abstraction lets the rest of your program depend on an interface instead of a specific implementation. A storage example:

Python
from abc import ABC, abstractmethod

class Storage(ABC):
    @abstractmethod
    def save(self, key, value): ...

    @abstractmethod
    def load(self, key): ...

class MemoryStorage(Storage):
    def __init__(self):
        self.data = {}

    def save(self, key, value):
        self.data[key] = value

    def load(self, key):
        return self.data.get(key)

store = MemoryStorage()
store.save("theme", "dark")
print(store.load("theme"), store.load("font"))
Output
dark None

Later you could add FileStorage or DatabaseStorage. Any code written against Storage keeps working, and tests can use the fast MemoryStorage.

When to use an ABC#

  • Several classes must provide the same set of methods (payment methods, storage back-ends, file exporters).
  • You want missing methods caught as early as possible.
  • You are writing a framework or library that others will extend.

For one or two small classes, plain inheritance or duck typing is usually enough.

Common mistakes#

Practice#

Practice exercise

Create an abstract Shape class with abstract methods area() and perimeter(), and a concrete describe() method returning Circle: area=12.57, perimeter=12.57 style text (2 decimal places). Implement Circle(r) and Rect(w, h) and describe a circle of radius 2 and a 3 × 4 rectangle.

Show hint

describe can use type(self).__name__ and call self.area() and self.perimeter().

Show solution
Python
from abc import ABC, abstractmethod
import math

class Shape(ABC):
    @abstractmethod
    def area(self): ...

    @abstractmethod
    def perimeter(self): ...

    def describe(self):
        return (f"{type(self).__name__}: area={self.area():.2f}, "
                f"perimeter={self.perimeter():.2f}")

class Circle(Shape):
    def __init__(self, r):
        self.r = r
    def area(self):
        return math.pi * self.r ** 2
    def perimeter(self):
        return 2 * math.pi * self.r

class Rect(Shape):
    def __init__(self, w, h):
        self.w, self.h = w, h
    def area(self):
        return self.w * self.h
    def perimeter(self):
        return 2 * (self.w + self.h)

for s in [Circle(2), Rect(3, 4)]:
    print(s.describe())
Output
Circle: area=12.57, perimeter=12.57
Rect: area=12.00, perimeter=14.00

For a circle of radius 2, the area (4π) and the circumference (4π) happen to be equal.

Key takeaway#

Finished this lesson?