Abstract Classes
Abstract classes define interfaces that subclasses must implement. Using Python's
abc module, you can create classes that cannot be instantiated directly and enforce
that child classes implement specific methods. This is Python's way of creating formal contracts
between classes.
What Are Abstract Classes?
- Abstract class: A class that cannot be instantiated directly
- Abstract method: A method with no implementation that must be overridden
- Concrete method: A regular method with implementation (can be inherited)
- Subclasses must implement ALL abstract methods to be instantiable
Abstract Class Basics
Inherit from ABC and use @abstractmethod to define methods that
subclasses must implement. Trying to instantiate an incomplete class raises TypeError.
Click Run to execute your code
Concrete Methods in Abstract Classes
Abstract classes can have concrete (implemented) methods too. These are inherited normally. Use this for shared functionality that all subclasses need, while still enforcing that specific methods must be customized.
Abstract Properties
You can also define abstract properties that subclasses must implement. Stack
@property and @abstractmethod decorators (property first).
Click Run to execute your code
Decorator Order Matters
When combining decorators, @property must come before @abstractmethod:
@property
@abstractmethod
def name(self):
pass
Practical Examples
Abstract classes are ideal for defining interfaces in plugin systems, database drivers, payment processors, and other extensible systems.
Click Run to execute your code
Template Method Pattern
Abstract classes enable the Template Method pattern: define the skeleton of an algorithm in a concrete method, calling abstract methods that subclasses customize. The abstract class controls the flow while subclasses provide specific behavior.
Abstract Classes vs Duck Typing
Python offers both explicit interfaces (ABC) and implicit interfaces (duck typing). Understanding when to use each is key to Pythonic design.
Click Run to execute your code
typing.Protocol (Python 3.8+)
For the best of both worlds, consider Protocol from the typing module. It provides
structural subtyping (duck typing) with type checker support - no inheritance required, but
still documents the expected interface.
Common Mistakes
1. Forgetting to inherit from ABC
# Wrong - @abstractmethod does nothing without ABC!
class Shape:
@abstractmethod
def area(self):
pass
s = Shape() # Works! No enforcement
# Correct - must inherit from ABC
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
s = Shape() # TypeError! Can't instantiate
2. Wrong decorator order for abstract properties
# Wrong order!
class Vehicle(ABC):
@abstractmethod
@property
def speed(self): # This won't work correctly
pass
# Correct - @property first, then @abstractmethod
class Vehicle(ABC):
@property
@abstractmethod
def speed(self):
pass
3. Not implementing all abstract methods
class Animal(ABC):
@abstractmethod
def speak(self): pass
@abstractmethod
def move(self): pass
# Incomplete - missing move()
class Dog(Animal):
def speak(self):
return "Woof"
d = Dog() # TypeError: Can't instantiate - move() not implemented
# Complete - both methods implemented
class Dog(Animal):
def speak(self):
return "Woof"
def move(self):
return "Run"
4. Calling super() on abstract methods that raise NotImplementedError
# Problem - abstract method raises error
class Base(ABC):
@abstractmethod
def process(self):
raise NotImplementedError
class Child(Base):
def process(self):
super().process() # This raises NotImplementedError!
return "processed"
# Better - abstract method with pass or documentation
class Base(ABC):
@abstractmethod
def process(self):
"""Process the data. Override in subclass."""
pass # or just docstring
5. Using ABC when duck typing would suffice
# Over-engineered - simple interface doesn't need ABC
class Printable(ABC):
@abstractmethod
def to_string(self): pass
# Pythonic - just document the expected interface
def print_item(item):
"""Print item. Item must have to_string() method."""
print(item.to_string())
# ABC is best for complex interfaces, frameworks, or team codebases
Exercise: Notification System
Task: Create an abstract notification system with multiple notification types.
Requirements:
- Abstract
Notifierclass with abstractsend()andnameproperty - Concrete
notify()method that prints "[name] Sending..." then calls send() EmailNotifier,SMSNotifier,PushNotifierimplementationsnotify_all()function to send to multiple notifiers
Click Run to execute your code
Show Solution
from abc import ABC, abstractmethod
class Notifier(ABC):
@property
@abstractmethod
def name(self):
pass
@abstractmethod
def send(self, message):
pass
def notify(self, message):
print(f"[{self.name}] Sending...")
result = self.send(message)
print(result)
class EmailNotifier(Notifier):
def __init__(self, email_address):
self.email_address = email_address
@property
def name(self):
return "Email"
def send(self, message):
return f"Email sent to {self.email_address}: {message}"
class SMSNotifier(Notifier):
def __init__(self, phone_number):
self.phone_number = phone_number
@property
def name(self):
return "SMS"
def send(self, message):
return f"SMS sent to {self.phone_number}: {message}"
class PushNotifier(Notifier):
def __init__(self, device_id):
self.device_id = device_id
@property
def name(self):
return "Push"
def send(self, message):
return f"Push notification to device {self.device_id}: {message}"
def notify_all(notifiers, message):
for notifier in notifiers:
notifier.notify(message)
# Test
notifiers = [
EmailNotifier("[email protected]"),
SMSNotifier("+1234567890"),
PushNotifier("device-abc-123")
]
notify_all(notifiers, "Your order has shipped!")
Summary
from abc import ABC, abstractmethodto use abstract classes- Inherit from
ABCto make a class abstract @abstractmethodmarks methods that must be overridden- Can't instantiate abstract classes or classes with unimplemented abstract methods
- Abstract classes can have concrete methods (template method pattern)
- Use
@propertybefore@abstractmethodfor abstract properties - Consider
typing.Protocolfor structural (duck) typing with type hints
What's Next?
Now that you understand abstract classes, learn about Dataclasses - Python's
@dataclass decorator that automatically generates __init__,
__repr__, __eq__, and more for data-holding classes.
Enjoying these tutorials?