Skip to content

An In-Depth Guide to Superclasses and Subclasses in Python

Updated: at 04:34 AM

Superclasses and subclasses are key concepts in object-oriented programming that allow code reuse through inheritance. A superclass, also called a base class or parent class, contains attributes and methods that are common to a set of related classes. A subclass, also known as a derived class or child class, inherits from the superclass and specializes or extends its capabilities.

This article provides a comprehensive, step-by-step guide on using superclasses and subclasses in Python. We will cover the following topics in-depth:

Table of Contents

Open Table of Contents

Defining Superclasses and Subclasses

In Python, a superclass or base class is defined just like a regular class using the class keyword. The superclass contains attributes and methods that are common to a group of related classes:

class Vehicle:
    """A superclass base class for all vehicles"""

    def __init__(self, make, model, fuel):
        """Initialize attributes common to all vehicles"""
        self.make = make
        self.model = model
        self.fuel = fuel

    def drive(self):
        """Drive the vehicle"""
        print(f"The {self.model} is now driving")

The Vehicle class defined above contains the common make, model, and fuel attributes, along with a drive() method.

A subclass or derived class inherits from the superclass by specifying the superclass name in parentheses after the subclass name:

class Car(Vehicle):
    """A subclass inheriting from Vehicle superclass"""

    def __init__(self, make, model, fuel="gasoline"):
        """Initialize Car attributes"""
        super().__init__(make, model, fuel)

class Motorcycle(Vehicle):
    """Another subclass inheriting from Vehicle"""

    def __init__(self, make, model, fuel="gasoline"):
        """Initialize Motorcycle attributes"""
        super().__init__(make, model, fuel)

The Car and Motorcycle subclasses inherit the attributes and methods of Vehicle using the (Vehicle) notation.

Inheriting Attributes and Methods

A key benefit of subclassing is code reuse - subclasses inherit the data attributes and behaviors of the superclass.

For example, the Car and Motorcycle subclasses above inherit the make, model and fuel attributes from Vehicle:

car = Car("Toyota", "Prius")
print(car.make) # Outputs "Toyota"

bike = Motorcycle("Honda", "Nighthawk")
print(bike.fuel) # Outputs "gasoline"

The subclasses also inherit the drive() method, allowing us to call it directly on subclass instances:

car.drive() # The Prius is now driving

bike.drive() # The Nighthawk is now driving

This inheritance enables code reuse without having to reimplement identical attributes and behaviors in each subclass.

Overriding Inherited Methods

While subclasses inherit the superclass methods, they can also override inherited methods to provide specialized implementations.

To override a method, the subclass defines a method with the same name:

class Car(Vehicle):

    # Override drive() method
    def drive(self):
        print("Switch gears and drive the car")

class Motorcycle(Vehicle):

    # Override drive() method
    def drive(self):
        print("Rev up the engine and drive the motorcycle")

Now when we call drive() on each subclass instance, the specialized method is used:

car = Car(...)
car.drive() # Calls overridden method: Switch gears and drive the car

bike = Motorcycle(...)
bike.drive() # Calls overridden method: Rev up the engine and drive the motorcycle

Method overriding allows subclasses to extend superclass behaviors while reusing common logic.

The super() Function

The super() function gives access to superclass methods that have been overridden in the subclass. This allows you to leverage the inheritance hierarchy.

For example, we can call the superclass drive() method as follows:

class Car(Vehicle):

    def drive(self):
        super().drive() # Call superclass drive() method
        print("Switch gears and drive the car")

class Motorcycle(Vehicle):

    def drive(self):
        super().drive() # Call superclass drive()
        print("Rev up the engine and drive the motorcycle")

Now the superclass drive() method is called before the subclass-specific implementations.

We can also access superclass attributes using super():

class ElectricCar(Car):

    def __init__(self, make, model, battery):
        super().__init__(make, model)
        self.battery = battery

This leverages reuse while limiting code duplication.

Abstract Base Classes

Python allows defining abstract base classes that provide a common interface for subclasses to implement. This is done by importing ABC and abstractmethod from abc:

from abc import ABC, abstractmethod

class Vehicle(ABC):

    @abstractmethod
    def drive(self):
        pass

Any subclass of Vehicle must now implement drive(), otherwise it will raise a TypeError. Abstract base classes enforce standard interfaces.

Multiple Inheritance

Python supports multiple inheritance, where a subclass can inherit from multiple superclasses:

class GasPoweredEngine:

    def start_engine(self):
        print("Starting gasoline engine")

class ElectricPoweredEngine:

    def start_engine(self):
        print("Starting electric engine")

class HybridCar(GasPoweredEngine, ElectricPoweredEngine):
    pass

The HybridCar subclass inherits from both GasPoweredEngine and ElectricPoweredEngine, gaining the behaviors of both.

The superclass order matters - if a method appears in multiple superclasses, the first one takes precedence.

Key Differences between Superclasses and Subclasses

Some key differences between superclasses and subclasses:

When to Use Subclassing

Some cases where subclassing is useful in Python:

However, subclassing is not always the best approach when:

Best Practices for Effective Subclassing

Some best practices to follow for effective subclassing:

Following these practices will ensure clean inheritance hierarchies and maintainable code.

Conclusion

This guide covered a comprehensive overview of superclasses and subclasses in Python, including defining inheritance relationships, overriding methods, using super(), abstract classes, multiple inheritance, best practices, and more. Proper use of subclassing creates maintainable code by reusing logic, avoiding duplication, and enabling extensibility through specialization. Mastering these key Python OOP concepts will level up your ability to design flexible and scalable program architectures.