All Courses
Object-Oriented Programming

Python Abstract Classes

What is an Abstract Class?

An abstract class is a class that: - Is never instantiated directly — no instances of it should ever be created - Serves purely as a base / parent class for other classes - Provides common implementation shared across all child classes - Defines abstract methods that child classes must implement

⚠️ Python has no built-in abstract keyword. By convention, prefix the class name with Abstract to signal it should never be instantiated.


Abstract Methods

An abstract method is a method defined in the abstract class that has no real implementation — it raises NotImplementedError to force child classes to override it:

def play(self):
    raise NotImplementedError("You must provide an implementation for play")
  • If a child class inherits from the abstract class but does not override this method, calling it raises a NotImplementedError
  • This acts as a contract: "any class inheriting from me must implement these methods"

Abstract Class vs Concrete Class

Abstract Class Concrete Class
Instantiated? ❌ Never ✅ Yes
Has abstract methods? ✅ Yes (raises NotImplementedError) ❌ No — all methods implemented
Purpose Define a template / framework Actual usable implementation
Example AbstractGame RandomGuesser

Full Example — AbstractGame

import random

class AbstractGame:

    def start(self):
        while True:
            start = input("Would you like to play? ").lower()
            if start == "yes":
                break
        self.play()

    def end(self):
        print("The game has ended.")
        self.reset()

    # --- Abstract methods (must be implemented by child classes) ---

    def play(self):
        raise NotImplementedError("You must provide an implementation for play")

    def reset(self):
        raise NotImplementedError("You must provide an implementation for reset")
  • start and end are concrete — fully implemented and shared by all games
  • play and reset are abstract — each game must define its own version
  • start calls self.play() and end calls self.reset() — these only work once a child class implements them

Implementing a Concrete Child Class

class RandomGuesser(AbstractGame):

    def __init__(self, rounds):
        self.rounds = rounds
        self.round = 0

    def reset(self):
        self.round = 0

    def play(self):
        while self.round < self.rounds:
            self.round += 1
            print(f"Welcome to round {self.round}! Let's begin.")
            random_num = random.randint(0, 10)
            while True:
                guess = input("Enter a number between 1 and 10: ")
                if int(guess) == random_num:
                    print("You got it!")
                    break
        self.end()
game = RandomGuesser(2)
game.start()   # asks "Would you like to play?", then runs play(), then end()/reset()

What happens step by step: 1. game.start() — prompts user, then calls self.play() 2. play() — runs the game logic for the set number of rounds, then calls self.end() 3. end() — prints "The game has ended", then calls self.reset() 4. reset() — resets self.round = 0 so the game can be replayed


What Happens Without Implementing Abstract Methods

If a child class inherits but doesn't implement play or reset:

class AnotherGame(AbstractGame):
    pass   # no play or reset defined

game = AnotherGame()
game.start()   # user says yes → calls self.play() → 💥 NotImplementedError
NotImplementedError: You must provide an implementation for play

Real-World Use Case — Playing Multiple Games

Because all games inherit from AbstractGame, you can treat them uniformly:

games = [RandomGuesser(2), AnotherGame()]

for game in games:
    game.start()   # works for every game — start() is guaranteed to exist

This is the main power of abstract classes: a common interface across many different implementations.


Key Design Principles

Concrete methods (like start and end) belong in the abstract class when: - The behaviour is identical across all child classes - They rely on abstract methods to do their specific work

Abstract methods belong in the abstract class when: - The behaviour is different for every child class - They represent something the abstract class can't know how to do on its own


Key Takeaways & Recap

Concept Summary
Abstract class Never instantiated; used only as a base class
Abstract method Raises NotImplementedError; must be overridden by child classes
Concrete method Fully implemented in the abstract class; shared by all children
Naming convention Prefix with Abstract (e.g. AbstractGame) to signal intent
NotImplementedError Python's way of enforcing that a method must be overridden
Purpose Provide a framework; enforce a contract; avoid duplicate code