Python Overriding: Complete Guide from Beginner to Pro

目次

1. Introduction

Python is a programming language that is supported by a wide range of users, from beginners to advanced programmers. Among its features, “override” is one of the fundamental concepts of object‑oriented programming and plays an important role in many situations. In this article, we will explain Python’s override feature, covering everything from basic concepts to advanced usage in a way that is easy for beginners to understand.

What Is Override?

Override refers to redefining a method that was defined in a parent (base) class within a child (derived) class. Redefining it provides the following benefits:
  • Improved flexibility: Leverage inheritance to increase code reusability.
  • Code customization: Instead of using the parent class’s functionality as‑as, you can modify it as needed.
  • Improved maintainability: The code structure becomes more organized, making future modifications easier.
For example, in the Django web‑application framework, it is common to override class‑based views to add custom processing. Such examples demonstrate how crucial knowledge of overriding is in real‑world Python development.

Purpose of This Article

This guide will walk through the following topics step by step:
  1. Basic concepts and mechanics of override
  2. Concrete implementation methods in Python
  3. Common pitfalls and how to avoid errors
  4. Practical code examples
We aim to provide foundational material for beginners and advanced topics for intermediate users, creating an article valuable to programmers of any level. Now, let’s take a closer look at “What Is Override?” in the next section.

2. What is Override

In Python, overriding (Override) is one of the core concepts of object-oriented programming and an important feature that enhances code flexibility and reusability. This section explains the basic definition of overriding, its characteristics, and the differences from overloading.

Basic Concept of Override

Override refers to redefining a method defined in a parent (base) class within a child (derived) class. Redefining provides the following benefits:
  • Maintain parent class functionality while customizing It is very useful when you want to add processing specific to the child class.
  • Change behavior while preserving consistency You can provide a common interface while implementing different behavior.
Below is a basic example of overriding.
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        print("Hello from Child!")

# Example
parent = Parent()
child = Child()

parent.greet()  # Output: Hello from Parent!
child.greet()   # Output: Hello from Child!
In this example, the greet method is defined in both the parent and child classes. Because the child class’s greet method overrides the parent’s, calling it from an instance of the child class executes the new behavior.

Difference from Overload

A common point of confusion for beginners is the difference between “override” and “overload.” Although the names are similar, they represent different concepts.
  • Override Redefining a method defined in a parent class within a child class. Behavior is determined at runtime.
  • Overload Defining methods or functions with the same name but different sets of parameters. Python does not directly support overloading (similar behavior can be achieved with the @overload decorator, etc.).
Below is a way to emulate overloading in Python.
from typing import overload

class Calculator:
    @overload
    def add(self, x: int, y: int) -> int: ...

    @overload
    def add(self, x: str, y: str) -> str: ...

    def add(self, x, y):
        return x + y

calc = Calculator()
print(calc.add(2, 3))      # Output: 5
print(calc.add("a", "b"))  # Output: ab

Common Use Cases for Override

Override is commonly used in the following scenarios:
  1. GUI programming Customizing the behavior of buttons and widgets.
  2. Web frameworks Used when extending class-based views in Django, Flask, etc.
  3. Game development Inheriting and modifying the behavior of characters or objects.
侍エンジニア塾

3. How to Implement Overrides in Python

Python implementing overrides is very straightforward, but you need to have a precise understanding of the relationship between parent and child classes and how to use super(). This section explains everything from basic override procedures to considerations in multiple inheritance.

Implementing Basic Overrides

In Python, you can achieve overriding simply by defining a method with the same name as the parent class’s method in the child class. Below is a basic override example.
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        print("Hello from Child!")

# Example
parent = Parent()
child = Child()

parent.greet()  # Output: Hello from Parent!
child.greet()   # Output: Hello from Child!
In this example, the Child class redefines the Parent class’s greet method. By doing so, when an instance of the Child class calls greet, the child class’s implementation takes precedence.

Overrides Using super()

When overriding, you may completely replace a parent class’s method, but sometimes you want to reuse the parent class’s behavior while extending it. In such cases, the super() function is handy. Below is an example using super().
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        super().greet()
        print("And Hello from Child!")

# Example
child = Child()
child.greet()
# Output:
# Hello from Parent!
# And Hello from Child!
In this example, the Child class’s greet method calls super().greet() to execute the parent class’s greet method, then adds processing specific to the child class.

Difference When Not Using super()

When you don’t use super(), you need to call the parent class’s method explicitly.
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        Parent.greet(self)
        print("And Hello from Child!")

# Example
child = Child()
child.greet()
# Output:
# Hello from Parent!
# And Hello from Child!
Unlike super(), explicitly specifying the parent class can more easily cause errors when there are multiple parent classes or the inheritance hierarchy is complex. super() is recommended to avoid such issues.

Overrides and MRO in Multiple Inheritance

Python supports multiple inheritance, but in such cases you need to understand which class’s method will be invoked. This is determined by the MRO (Method Resolution Order).
class A:
    def greet(self):
        print("Hello from A!")

class B(A):
    def greet(self):
        print("Hello from B!")

class C(A):
    def greet(self):
        print("Hello from C!")

class D(B, C):
    pass

# Example
d = D()
d.greet()  # Output: Hello from B!
In this example, class D inherits from B and C, but the MRO gives priority to B‘s greet method.

How to Inspect the MRO

You can inspect the MRO using the __mro__ attribute or the mro() method.
print(D.__mro__)
# Output: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
From this output, you can see that methods are resolved in the order D -> B -> C -> A -> object.

4. Practical! Python Override Code Examples

Here, to deepen your understanding of overriding, we present several concrete code examples. We cover a wide range from basic method overriding to overriding __init__ and multiple inheritance scenarios.

1. Method Overriding

Method overriding is the most common form of overriding in Python. By redefining a parent class’s method in a child class, you can add custom behavior.
class Animal:
    def speak(self):
        return "I make a sound"

class Dog(Animal):
    def speak(self):
        return "Woof!"

 Example
animal = Animal()
dog = Dog()

print(animal.speak())  # Output: I make a sound
print(dog.speak())     # Output: Woof!
In this example, the Dog class’s spreak method overrides the method from the Animal class, so when a Dog object is called, its unique behavior is executed.

2. Constructor (__init__) Overriding

If you want to change a class’s initialization process, override the __init__ method. Using super() allows you to inherit the parent class’s initialization.
class Person:
    def __init__(self, name):
        self.name = name

    def greet(self):
        return f"Hello, my name is {self.name}"

class Student(Person):
    def __init__(self, name, student_id):
        super().__init__(name)
        self.student_id = student_id

    def greet(self):
        return f"Hello, my name is {self.name} and my student ID is {self.student_id}"

# Example
student = Student("Alice", "S12345")
print(student.greet())
# Output: Hello, my name is Alice and my student ID is S12345
In this example, the Student class’s __init__ method inherits the initialization from the parent class Person while adding a new student_id attribute.

3. Overriding in Multiple Inheritance and MRO

In multiple inheritance, which class’s method is executed is determined by the MRO (Method Resolution Order).
class Vehicle:
    def description(self):
        return "This is a vehicle"

class Car(Vehicle):
    def description(self):
        return "This is a car"

class Boat(Vehicle):
    def description(self):
        return "This is a boat"

class AmphibiousVehicle(Car, Boat):
    pass

# Example
amphibious = AmphibiousVehicle()
print(amphibious.description())
# Output: This is a car
In this example, AmiousVehicle inherits from both Car and Boat, but the MRO gives priority to the Car class’s description method. Be sure to check the MRO as well.
print(AmphibiousVehicle.__mro__)
# Output: (<class '__main__.AmphibiousVehicle'>, <class '__main__.Car'>, <class '__main__.Boat'>, <class '__main__.Vehicle'>, <class 'object'>)4. Practical Override Example: Django View Classes
In the Python web framework Django, it is common to override class‑based views to add custom processing.
from django.views import View
from django.http import HttpResponse

class MyView(View):
    def get(self, request):
        return HttpResponse("This is a GET request")

class CustomView(MyView):
    def get(self, request):
        response = super().get(request)
        return HttpResponse(response.content + b" Customized!")

# In this example, CustomView extends MyView's GET request handling.

Key Takeaways

  • Method overriding is a fundamental mechanism for separating and customizing behavior between a parent class and its child class.
  • Using super() allows you to extend functionality while inheriting the parent class’s behavior.
  • When using multiple inheritance, it is important to write code with the MRO in mind.
  • In practice, overriding is frequently used to implement custom behavior.
侍エンジニア塾

5. Overriding Cautions

Overriding is a very handy feature, but using it incorrectly can cause issues with code maintainability and runtime behavior. This section explains the points to watch out for when overriding in Python.

Proper Use of super()

Using super() lets you call a parent class’s method, but misuse can cause it not to work as expected.

Recommended Usage

  • Use super() when the subclass extends rather than completely replaces the parent class’s method.
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        super().greet()  # Call parent class method
        print("And Hello from Child!")

child = Child()
child.greet()
# Output:
# Hello from Parent!
# And Hello from Child!

Common Pitfalls

  1. Misunderstandings in Multiple Inheritance In multiple inheritance, super() calls the next class according to the MRO (Method Resolution Order). Explicitly specifying a parent class requires caution.
class A:
    def greet(self):
        print("Hello from A!")

class B(A):
    def greet(self):
        print("Hello from B!")
        super().greet()

class C(A):
    def greet(self):
        print("Hello from C!")

class D(B, C):
    def greet(self):
        print("Hello from D!")
        super().greet()

d = D()
d.greet()
# Output:
# Hello from D!
# Hello from B!
# Hello from C!
# Hello from A!
  1. Omitting super() Explicitly specifying the parent class to call a method makes the code more complex and prone to errors.
# Deprecated example
class Child(Parent):
    def greet(self):
        Parent.greet(self)
        print("And Hello from Child!")

Multiple Inheritance and MRO (Method Resolution Order)

In multiple inheritance, the MRO determines which class’s method is called. For complex inheritance structures, you need to understand the MRO accurately.

How to Inspect the MRO

You can view the MRO via the __mro__ attribute or the mro() method.
class A:
    def greet(self):
        print("Hello from A!")

class B(A):
    def greet(self):
        print("Hello from B!")

class C(A):
    def greet(self):
        print("Hello from C!")

class D(B, C):
    pass

print(D.__mro__)
# Output: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

Drawbacks of Excessive Overriding

If you override most of the parent class’s methods in a subclass, the benefits of inheritance diminish and code maintainability suffers.

Improvement Suggestions

  • Override Only Where Necessary Instead of overriding everything, preserve the reusability of the parent class.
  • Consider Composition When appropriate, use composition (a structure that holds other classes as attributes) instead of inheritance.
class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()

    def start(self):
        self.engine.start()
        print("Car is ready to go!")

car = Car()
car.start()
# Output:
# Engine started
# Car is ready to go!

Debugging Tips

If an overridden method is not behaving correctly, check the following:
  • Whether the subclass correctly calls the parent class’s method.
  • Whether super() is used correctly.
  • Whether the inheritance order (MRO) is as expected.

6. Comparison with Overload

Override is often confused with “overload,” but they are different concepts. In Python, override is commonly used, while overload plays an important role in other programming languages. This section explains the differences between the two, the current state of overload in Python, and its alternatives.

1. What is Override?

Override refers to redefining a method defined in a parent class within a child class. This allows you to retain the base functionality of the parent class while adding custom behavior in the child class.

Features

  • Applied at runtime.
  • Class inheritance is a prerequisite.
  • The child class changes behavior while preserving the parent class’s interface.
Example:
class Parent:
    def greet(self):
        return "Hello from Parent!"

class Child(Parent):
    def greet(self):
        return "Hello from Child!"

parent = Parent()
child = Child()

print(parent.greet())  # Output: Hello from Parent!
print(child.greet())   # Output: Hello from Child!

2. What is Overload?

Overload refers to defining multiple methods or functions with the same name but different arguments. Overload is usually resolved at compile time (build time).

Example in Other Languages (Java)

class Calculator {
    int add(int a, int b) {
        return a + b;
    }

    double add(double a, double b) {
        return a + b;
    }
}
In this example, the add method with the same name is defined with different argument types. The appropriate method is selected at call time.

3. Overload in Python

Python does not support formal overload. Because functions and methods are dynamically typed, redefining a function with the same name later overwrites the previous definition.

Example in Python

class Calculator:
    def add(self, a, b):
        return a + b

    # Redefinition (override)
    def add(self, a, b, c):
        return a + b + c

calc = Calculator()
# calc.add(1, 2)  # Error: No method exists that matches two arguments
In the code above, the second add method overwrites the first, leaving only the add method that takes three arguments.

4. Ways to Achieve Overload in Python

In Python, the following alternatives are used to emulate overload.

(1) Using Variable-Length Arguments

class Calculator:
    def add(self, *args):
        return sum(args)

calc = Calculator()
print(calc.add(1, 2))       # Output: 3
print(calc.add(1, 2, 3))    # Output: 6
Using *args allows handling any number of arguments.

(2) Using the @overload Decorator

The Python typing module provides a @overload decorator that allows you to achieve overload-like behavior using type hints. However, this is only for type checking and has no effect at runtime.
from typing import overload

class Calculator:
    @overload
    def add(self, x: int, y: int) -> int: ...
    @overload
    def add(self, x: str, y: str) -> str: ...

    def add(self, x, y):
        return x + y

calc = Calculator()
print(calc.add(1, 2))       # Output: 3
print(calc.add("a", "b"))   # Output: ab
The @overload decorator only provides type hints, so the actual logic is implemented in a single add method.

5. Choosing Between Override and Overload

  • Override is used when class inheritance is assumed and you want to modify or extend the functionality of a parent class.
  • Overload is useful when you want to use the same method name for different purposes. However, in Python, using @overload or variable-length arguments is the common approach, considering type checking and flexibility.

7. Summary

So far, we have provided a detailed explanation of Python overriding, covering basic concepts, implementation methods, cautions, and even the differences from overloading. In this section, we will briefly recap the entire article and organize key points for effectively using overriding.

Fundamental Role of Overriding

  • Overriding allows flexible customization by redefining a method defined in a parent class within a child class.
  • This enables you to maintain a common interface while implementing different behaviors.

How to Implement Overriding in Python

  • You can easily override by defining a method with the same name in the child class.
  • Using super() lets you call the parent class’s method while adding additional processing.
  • When using multiple inheritance, it’s important to check the MRO (Method Resolution Order) to ensure methods are invoked in the intended order.

Cautions When Using Overriding

  • Using super(): Use super() correctly to properly inherit the parent class’s behavior.
  • Avoid Excessive Overriding: Do not override every method; re‑define only the parts that need to change, which is best practice.
  • Designing Multiple Inheritance: When using multiple inheritance, be careful not to let the inheritance hierarchy become overly complex.

Differences from Overloading and How to Use Them

  • Overriding and overloading have similar names but serve completely different purposes.
  • Overriding: Redefining a parent class’s method in a child class.
  • Overloading: Defining multiple methods with the same name but different parameter sets (not officially supported in Python).
  • In Python, you can use @overload or variable‑length arguments as alternatives to overloading.

Practical Uses of Overriding

  • Web frameworks: Add custom behavior in class‑based views of Django or Flask.
  • GUI programming: Customize event handling for buttons and widgets.
  • Game development: Inherit and modify the behavior of characters or objects.

Conclusion

Overriding is an essential skill for understanding and practicing object‑oriented programming in Python. Grasping its core mechanics and how to apply it enables you to write maintainable, flexible code. Use the concepts learned in this article to incorporate overriding in your work and projects.

8. FAQ (Frequently Asked Questions)

We’ve compiled the points about Python overriding that readers often find confusing. From beginners to intermediate users, we concisely explain common questions and their answers.

Q1: What is the main difference between overriding and overloading?

A:
  • Overriding refers to redefining a method defined in a parent class within a child class. This assumes class inheritance.
  • Example: Change the behavior of the parent class’s greet() in the child class.
  • Overloading is defining multiple methods with the same name but different argument sets. Python does not officially support overloading, but you can achieve similar behavior using the @overload decorator or variable-length arguments.

Q2: Should super() always be used?

A:
  • It is generally recommended. Using super() allows you to call a parent class’s method safely and accurately. Especially when using multiple inheritance, the appropriate parent method is called according to the MRO (Method Resolution Order).
  • In exceptional cases, you might call the parent class explicitly without using super(). However, this is limited to situations where the inheritance hierarchy is simple.

Q3: How can I completely disable a parent class’s method?

A: If you want to completely disable a parent class’s method, override it in the child class with a method that does nothing.
class Parent:
    def greet(self):
        print("Hello from Parent!")

class Child(Parent):
    def greet(self):
        pass  # Disabled in child class

child = Child()
child.greet()  # No output

Q4: Is there a way to achieve overloading in Python?

A: Python does not directly support overloading, but you can emulate similar behavior using the following methods:
  1. Use variable-length arguments:
   class Calculator:
       def add(self, *args):
           return sum(args)

   calc = Calculator()
   print(calc.add(1, 2))       # Output: 3
   print(calc.add(1, 2, 3))    # Output: 6
  1. Use the @overload decorator (explicitly indicate behavior with type hints):
   from typing import overload

   class Calculator:
       @overload
       def add(self, x: int, y: int) -> int: ...
       @overload
       def add(self, x: str, y: str) -> str: ...

       def add(self, x, y):
           return x + y

   calc = Calculator()
   print(calc.add(1, 2))       # Output: 3
   print(calc.add("a", "b"))   # Output: ab

Q5: Overriding doesn’t work correctly with multiple inheritance. What should I do?

A: In multiple inheritance, methods are resolved according to the MRO (Method Resolution Order). If things don’t work as expected, check the following:
  1. Check the MRO: Use ClassName.__mro__ or ClassName.mro() to view the resolution order.
   print(ClassName.__mro__)
  1. Correct use of super(): Ensure that calls to parent class methods follow the MRO.
  2. Reconsider the inheritance order: Simplify the design if necessary.

Q6: Is there a way to customize code without using overriding or inheritance?

A: If you want to customize code without using overriding, composition is effective. Composition is a design approach where one class is used as an attribute of another class.
class Engine:
    def start(self):
        print("Engine started")

class Car:
    def __init__(self):
        self.engine = Engine()

    def start(self):
        self.engine.start()
        print("Car is ready to go!")

car = Car()
car.start()
# Output:
# Engine started
# Car is ready to go!
Composition offers greater flexibility than inheritance and helps avoid excessive overriding.