Table of Contents

Python ABC

Python ABC (Abstract Base Classes) from the abc module let you define classes that can't be instantiated directly and require subclasses to implement specific methods. They enforce interface contracts without the overhead of multiple inheritance, making it clear what methods subclasses must provide.

Use ABCs to define plugin interfaces, enforce method implementation, or document expected behavior for subclasses.

Example

This example shows ABCs enforcing method implementation and interface contracts.

# run: python3 abc.py
# description: abstract base classes for interface enforcement
 
from abc import ABC, abstractmethod
 
class Handler(ABC):
    """Abstract handler that subclasses must implement."""
 
    @abstractmethod
    def handle(self, data):
        """Process data. Subclasses must implement."""
        pass
 
    @abstractmethod
    def validate(self, data):
        """Validate data format. Subclasses must implement."""
        pass
 
    def process(self, data):
        """Template method: validate then handle."""
        if self.validate(data):
            return self.handle(data)
        raise ValueError("Invalid data")
 
# Can't instantiate ABC directly
try:
    h = Handler()
except TypeError as e:
    print(f"Error: {e}")
 
# Subclass must implement all abstract methods
class JsonHandler(Handler):
    def handle(self, data):
        return f"Handled JSON: {data}"
 
    def validate(self, data):
        return isinstance(data, dict)
 
class CsvHandler(Handler):
    def handle(self, data):
        return f"Handled CSV: {data}"
 
    def validate(self, data):
        return isinstance(data, str)
 
# Instantiation works now
json_h = JsonHandler()
csv_h = CsvHandler()
 
print(f"JSON: {json_h.process({'key': 'value'})}")
print(f"CSV: {csv_h.process('a,b,c')}")
 
# Abstract properties
class Database(ABC):
    @property
    @abstractmethod
    def connection_string(self):
        """Subclasses must implement this property."""
        pass
 
    @classmethod
    @abstractmethod
    def from_config(cls, config):
        """Factory method subclasses must implement."""
        pass
 
class PostgresDB(Database):
    @property
    def connection_string(self):
        return "postgresql://localhost/db"
 
    @classmethod
    def from_config(cls, config):
        return cls()
 
db = PostgresDB()
print(f"Connection: {db.connection_string}")

Common patterns

Defining abstract methods:

Abstract properties:

Abstract class methods and static methods:

Concrete methods in ABC:

Template method pattern:

Multiple inheritance:

Structural subtyping (duck typing with ABCs):

isinstance() and ABCs:

When to use:

When duck typing is better: