Skip to main content

Abstraction: Abstract Base Classes in Python

Abstraction is the OOP pillar that hides complex implementation details while showing only essential features through a contract. Python's abc module implements abstraction via Abstract Base Classes (ABCs) — incomplete templates that force subclasses to implement specific methods, ensuring design consistency and preventing misuse.

Key Takeaways

  • Abstract Base Classes cannot be instantiated: You cannot create an instance of an ABC directly; it serves only as a template for subclasses
  • @abstractmethod decorator enforces implementation: Subclasses must provide a concrete implementation for every abstract method or Python raises TypeError when instantiating them
  • ABCs create contracts: An ABC defines the interface (required methods) that all subclasses must fulfill, improving code reliability and team communication
  • Use from abc import ABC, abstractmethod — ABC is the base class, @abstractmethod marks methods that subclasses must override

What Is Abstraction and How Does It Relate to Object-Oriented Design?

Abstraction is the process of hiding implementation complexity and exposing only essential behavior. Think of a TV remote: its simple interface (buttons) hides the complex internal circuitry — you press a button without knowing how the signal travels or how the TV processes it. In object-oriented programming, an Abstract Base Class (ABC) is like that remote's design specification: it defines what methods must exist and what they should do, but leaves the how to subclasses.

This serves four purposes:

  1. Contract enforcement: Any class inheriting from an ABC guarantees the presence of specific methods
  2. Design consistency: Prevents developers from accidentally creating incomplete implementations
  3. Polymorphic safety: Callers can treat all subclasses uniformly, trusting that required methods exist
  4. Intent clarity: The ABC communicates the intended interface to readers and team members
from abc import ABC, abstractmethod

# An ABC defines an interface without implementation
class Animal(ABC):
"""Abstract blueprint for all animals."""

@abstractmethod
def make_sound(self):
"""Every subclass must implement make_sound()."""
pass

@abstractmethod
def move(self):
"""Every subclass must implement move()."""
pass

# Cannot instantiate the abstract class directly
# animal = Animal() # TypeError: Can't instantiate abstract class Animal...

# Concrete subclasses must implement all abstract methods
class Dog(Animal):
def make_sound(self):
return "Woof!"

def move(self):
return "Running on four legs"

# Now instantiation works
dog = Dog()
print(dog.make_sound()) # Woof!

How Do You Create an Abstract Base Class With the abc Module?

Python's abc (Abstract Base Class) module provides two key tools: the ABC class and the @abstractmethod decorator. You inherit from ABC to mark a class as abstract, and you decorate methods with @abstractmethod to require subclass implementation.

Creating an Abstract Base Class

from abc import ABC, abstractmethod

class Shape(ABC):
"""
Abstract blueprint for geometric shapes.
Defines the interface all shapes must implement.
"""

def __init__(self, name):
self.name = name

@abstractmethod
def area(self):
"""Calculate and return the shape's area. Must be implemented by subclasses."""
pass

@abstractmethod
def perimeter(self):
"""Calculate and return the shape's perimeter. Must be implemented by subclasses."""
pass

Key observations:

  • Inherit from ABC to make the class abstract
  • Use @abstractmethod decorator above each method that subclasses must implement
  • Abstract methods can have bodies (often just pass), but subclasses override them completely
  • Cannot create an instance: Shape() raises TypeError: Can't instantiate abstract class Shape with abstract methods area, perimeter

Abstract Methods Can Have Default Implementation

In rare cases, you can provide a default implementation that subclasses can call with super():

from abc import ABC, abstractmethod

class DataProcessor(ABC):

@abstractmethod
def process(self, data):
"""
Process the data. Subclasses must call super().process()
to use this base implementation before their own logic.
"""
print(f"Starting to process data...")
# Some common preprocessing logic
return data.strip() if isinstance(data, str) else data

class JSONProcessor(DataProcessor):

def process(self, data):
# Call parent's implementation first
cleaned = super().process(data)
# Then add specific JSON logic
import json
return json.loads(cleaned)

processor = JSONProcessor()
result = processor.process('{"key": "value"}')
# Output: Starting to process data...
print(result) # {'key': 'value'}

How Do Subclasses Implement Abstract Methods and What Happens If They Don't?

A concrete subclass must provide implementations for all abstract methods inherited from the ABC. If any abstract method lacks implementation, Python raises a TypeError when you attempt to instantiate the subclass.

Proper Implementation of All Abstract Methods

import math

class Circle(Shape):
"""Concrete implementation of Shape for circles."""

def __init__(self, radius):
super().__init__("Circle")
self.radius = radius

# Must implement area() — this is required
def area(self):
return math.pi * (self.radius ** 2)

# Must implement perimeter() — this is also required
def perimeter(self):
return 2 * math.pi * self.radius

class Square(Shape):
"""Concrete implementation of Shape for squares."""

def __init__(self, side_length):
super().__init__("Square")
self.side_length = side_length

def area(self):
return self.side_length ** 2

def perimeter(self):
return 4 * self.side_length

# Both concrete classes can be instantiated
circle = Circle(5)
square = Square(10)

print(f"Circle area: {circle.area():.2f}") # Circle area: 78.50
print(f"Square perimeter: {square.perimeter()}") # Square perimeter: 40

What Happens if You Forget an Implementation

class Triangle(Shape):
"""Incomplete implementation — missing perimeter()."""

def __init__(self, a, b, c):
super().__init__("Triangle")
self.a, self.b, self.c = a, b, c

def area(self):
# Using Heron's formula
s = (self.a + self.b + self.c) / 2
return math.sqrt(s * (s - self.a) * (s - self.b) * (s - self.c))

# Forgot to implement perimeter() !

# Attempting to instantiate raises TypeError
try:
triangle = Triangle(3, 4, 5)
except TypeError as e:
print(e)
# TypeError: Can't instantiate abstract class Triangle with abstract method perimeter

Python refuses to instantiate Triangle because perimeter remains unimplemented. This forces completeness and prevents silent bugs.


How Can You Use Abstract Classes to Enable Polymorphic Behavior?

ABCs enable powerful polymorphism: you can treat all subclass instances uniformly because the ABC guarantees they all have the required methods.

from abc import ABC, abstractmethod

class Vehicle(ABC):
"""Abstract blueprint for all vehicles."""

@abstractmethod
def start(self):
pass

@abstractmethod
def stop(self):
pass

class Car(Vehicle):
def start(self):
return "Engine starts with a roar!"

def stop(self):
return "Hydraulic brakes engaged"

class Bicycle(Vehicle):
def start(self):
return "Pedaling begins"

def stop(self):
return "Coaster brake activated"

class Skateboard(Vehicle):
def start(self):
return "Rolling forward"

def stop(self):
return "Foot drags on the ground"

# Polymorphism in action: treat all as Vehicle, but each behaves differently
vehicles = [Car(), Bicycle(), Skateboard()]

for vehicle in vehicles:
print(f"Starting: {vehicle.start()}")
print(f"Stopping: {vehicle.stop()}")
print()

# Output:
# Starting: Engine starts with a roar!
# Stopping: Hydraulic brakes engaged
#
# Starting: Pedaling begins
# Stopping: Coaster brake activated
#
# Starting: Rolling forward
# Stopping: Foot drags on the ground

This code works because every object in the vehicles list is guaranteed to have start() and stop() methods — the ABC enforces it. Without ABCs, you'd risk calling methods that don't exist.


Frequently Asked Questions

Can an abstract method have a body in Python?

Yes, abstract methods can have implementations. Subclasses can call the parent implementation using super(), then add their own logic. This is rare but useful for shared preprocessing or validation.

What's the difference between an ABC and a regular class?

A regular class can be instantiated even if incomplete; callers might use it incorrectly. An ABC cannot be instantiated until all abstract methods are implemented, forcing completeness and making the intent explicit. ABCs are better for defining mandatory interfaces.

Can you have abstract properties and class methods?

Yes, use @property with @abstractmethod, or @classmethod with @abstractmethod:

from abc import ABC, abstractmethod

class Base(ABC):

@property
@abstractmethod
def name(self):
"""Subclasses must have a name property."""
pass

@classmethod
@abstractmethod
def from_string(cls, string):
"""Subclasses must implement a class method."""
pass

Can you inherit from multiple abstract classes?

Yes, a subclass can inherit from multiple ABCs. It must implement abstract methods from all parent ABCs.

Is an ABC the same as an interface in other languages?

Similar, but not identical. ABCs can have concrete methods and state; interfaces (in Java/TypeScript) traditionally define only method signatures. Python ABCs are more flexible.


Further Reading