Python Programming from First Principles: Learn to Code, Think Computationally, and Solve Real-World Problems
PDFEPUB
BOOK 000 · CHAPTER 7 · Abstract Classes

Abstract Classes

On this pageRequire an OperationAttempt Abstract InstantiationShare Concrete BehaviorRequire a PropertyCheck Whether a Class Is ConcreteCoding Challenge: Abstract Class for a Notification System

An abstract base class can combine required operations with reusable behavior. A class with unresolved abstract members cannot be instantiated.

UML italicizes the abstract class and required operation. The hollow triangle shows that Dog inherits from Animal and supplies sound().

Animal+sound()Dog+sound()

Require an Operation

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def sound(self):
        pass
Listing 335 — Require an Operation

Defines Animal; no visible output.

class Dog(Animal):
    def sound(self):
        return "Bark"

dog = Dog()
print(dog.sound())
Listing 336 — Require an Operation

Output

Bark

Dog supplies sound, so it is concrete and can be instantiated.

Attempt Abstract Instantiation

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

try:
    animal = Animal()
except TypeError:
    print("TypeError: Animal still has an abstract method")
Listing 337 — Attempt Abstract Instantiation

Output

TypeError: Animal still has an abstract method

The intentional TypeError is caught. No Animal instance is created. An abstract method may contain implementation code and still require an override.

Share Concrete Behavior

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

    def move(self):
        return "The animal moves."
Listing 338 — Share Concrete Behavior

Defines Animal; no visible output.

class Dog(Animal):
    def make_sound(self):
        return "Bark"

dog = Dog()
print(dog.move())        # inherited concrete method
print(dog.make_sound())  # Dog's implementation
Listing 339 — Share Concrete Behavior

Output

The animal moves.
Bark

Dog inherits move and implements make_sound.

Require a Property

Place @property above @abstractmethod, so the abstract marker applies to the getter.

The italic class name marks the abstract base; /species is a derived, read-only UML attribute. In Python the abstract requirement is implemented by a property getter, supplied by Dog.

Animal+/species: str {readOnly}Dog+/species: str {readOnly}Python requires a concrete species getter.
from abc import ABC, abstractmethod

class Animal(ABC):
    @property
    @abstractmethod
    def species(self):
        pass
Listing 340 — Require a Property

Defines Animal; no visible output.

class Dog(Animal):
    @property
    def species(self):
        return "Canine"

dog = Dog()
print(dog.species)
Listing 341 — Require a Property

Output

Canine

The property is read as dog.species, without parentheses.

Check Whether a Class Is Concrete

from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def make_sound(self):
        pass

try:
    animal = Animal()
except TypeError:
    print("TypeError: Animal still has an abstract method")
Listing 342 — Check Whether a Class Is Concrete

Output

TypeError: Animal still has an abstract method

An ABC with no unresolved abstract members can be instantiated. Abstract checks enforce required names, not the correctness of their behavior.

Coding Challenge: Abstract Class for a Notification System

Define NotificationChannel with a required send(target, message) method, a required read-only name property and a shared logging method. Implement Email and SMS subclasses. Each send must print its simulated action, then call the shared logger. Send the same message through both.

Target output for your solution

[Email] Sending to user@example.com: System update at 18:00
[LOG] Email delivered: System update at 18:00

[SMS] Sending to +4912345678: System update at 18:00
[LOG] SMS delivered: System update at 18:00

These are console simulations, not actual email or SMS delivery. Confirm that the abstract base cannot be instantiated.

The examples so far use one base class. Multiple inheritance introduces a class with more than one base and explains how Python resolves its methods.