Method Overriding in Python (with Examples)

Method overriding occurs when a subclass provides a specific implementation of a method that is already defined in its super-class. The method in the subclass overrides the method in the super-class. In Python, for method overriding simply define a method with the same name and signature in the subclass, which will override the method in the parent class.

Method Overriding in Python

In Python, method overriding is a concept where a subclass provides a specific implementation of a method that is already defined in its super-class. The overridden method in the subclass replaces the behavior of the parent class’s method. There are different techniques to implement method overriding in Python, along with variations to customize the behavior.

  1. Basic Method Overriding – Redefine a method in the subclass.
  2. Using super() – Extend the parent class’s method in the subclass.
  3. Overriding Constructors (__init__) – Redefine constructors with super().
  4. Overriding Class Methods – Override class methods using @classmethod.
  5. Overriding Static Methods – Override static methods using @staticmethod.
  6. Overriding Properties – Customize or extend properties using @property.
  7. Overriding Magic Methods – Override special dunder methods (e.g., __str__, __eq__).
  8. Multiple Inheritance Overriding – Override methods in classes with multiple inheritance.
  9. Using super() in MRO – Handle method calls based on the Method Resolution Order (MRO) in multiple inheritance.
  10. Overriding Private Methods – Technically possible, but involves name mangling.

Basic Method Overriding

For basic method overriding, we define a method in the subclass with the same name and signature as a method in the parent class. The subclass’s method overrides the parent class’s method when called on an instance of the subclass.

# Basic Method Overriding
# Parent class
class Course:
    def course_details(self):
        raise NotImplementedError("Subclasses must implement this method")

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    def course_details(self):   # override definition of course_details function from Course class
        print("Course: Python Programming\nDuration: 8 Weeks")

# Child class 2
class PowerBICourse(Course):    # Inherits from Course
    def course_details(self):   # override definition of course_details function from Course class
        print("Course: Power BI for Data Analysis\nDuration: 6 Weeks")

python_course = PythonCourse()
powerbi_course = PowerBICourse()
python_course.course_details()   # Output => Course: Python Programming\nDuration: 8 Weeks
powerbi_course.course_details()  # Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks

In this example, Child classes PythonCourse and PowerBICourse inherits the parent class Course and override its method course_details() to provide course specific details.

Method Overriding – Using super()

This is another technique for method overriding calling parent class’s method using super(). We can call the overridden method from the parent class using the super() function within the subclass method. This allows us to extend the parent class’s functionality.

# Method Overriding - Using super()
# Parent class
class Course:
    def course_details(self):
        return "Course completion certification"

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    def course_details(self):   # override definition of course_details function from Course class
        # Call the parent class's method using super()
        parent_course_details = super().course_details()
        return "Course: Python Programming\nDuration: 8 Weeks\n" + parent_course_details

# Child class 2
class PowerBICourse(Course):    # Inherits from Course
    def course_details(self):   # override definition of course_details function from Course class
        # Call the parent class's method using super()
        parent_course_details = super().course_details()
        return "Course: Power BI for Data Analysis\nDuration: 6 Weeks\n" + parent_course_details

python_course = PythonCourse()
powerbi_course = PowerBICourse()
print(python_course.course_details())
# Output => Course: Python Programming\nDuration: 8 Weeks\nCourse completion certification

print(powerbi_course.course_details())
# Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks\nCourse completion certification

In this example, Child classes PythonCourse and PowerBICourse inherits the parent class Course and override its method course_details() to provide course specific details. course_details() method in child classes calls the parent class method using super().course_details() and add the generic details in each course.

Method Overriding – Using Constructors (__init__)

We can override constructors in subclasses by redefining the __init__ method. It’s common to use super().__init__() to inherit and extend the parent class constructor.

# Method Overriding - Using Constructors (__init__)
# Parent class
class Course:
	def __init__(self, name, duration):  # parent class constructor
		self.name = name
		self.duration = duration

# Child class 1
class PythonCourse(Course):     # Inherits from Course
	def __init__(self, name, duration):
		super().__init__(name, duration)                 # call the parent class's constructor
		self.course_syllabus = "Python course syllabus"  # sets another attribute

	def course_details(self):    # method to get complete course details
		return f"{self.name}, {self.duration}, {self.course_syllabus}"

python_course = PythonCourse("Python Programming", "Duration: 8 Weeks")
print(python_course.course_details())
# Output => Python Programming, Duration: 8 Weeks, Python course syllabus

In this example, Child classe PythonCourse inherits the parent class Course. __init__ method in child classes calls the parent class method using super().__init__() and sets the common attribute values for each course. Using the course_details() method we got all the attribute values of the course.

Method Overriding – Using @classmethod

In previous sections, we have seen the method overriding for class method which were called using the class objects or class instances. e.g we called python_course.course_details() using the PythonCourse class object.

Similar to that, class methods can also be overridden. Class methods are defined using the @classmethod decorator and cls as the first parameter.

# Method Overriding - Using @classmethod
# Parent class
class Course:
    @classmethod                # Convert a function to be a class method.
    def course_details(cls):    # first parameter as cls
        return "Course completion certification"

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    @classmethod                # Convert a function to be a class method.
    def course_details(cls):    # override course_details function from Course class
        return "Course: Python Programming\nDuration: 8 Weeks"

# Child class 2
class PowerBICourse(Course):    # Inherits from Course
    @classmethod                # Convert a function to be a class method.
    def course_details(cls):    # override course_details function from Course class
        return "Course: Power BI for Data Analysis\nDuration: 6 Weeks"

print(PythonCourse.course_details())
# Output => Course: Python Programming\nDuration: 8 Weeks

print(PowerBICourse.course_details())
# Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks
  • In this example, Child classes PythonCourse and PowerBICourse inherits the parent class Course and override its method course_details() to provide course specific details.
  • course_details() method in parent class and child classes is annotated with @classmethod and first parameter is cls.
  • This makes course_details() method as class method. It means, to call this method we don’t need to create class object.
  • We can call course_details() method directly using the class like PythonCourse.course_details() and PowerBICourse.course_details().

Method Overriding – Using @staticmethod

Static methods (defined using the @staticmethod decorator) can also be overridden in sub-classes. These methods don’t rely on instance or class references.

# Method Overriding - Using @staticmethod
# Parent class
class Course:
    @staticmethod            # Convert a function to static method.
    def course_details():    # first parameter as cls
        return "Course completion certification"

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    @staticmethod               # Convert a function to static method.
    def course_details():       # override course_details function from Course class
        return "Course: Python Programming\nDuration: 8 Weeks"

# Child class 2
class PowerBICourse(Course):    # Inherits from Course
    @staticmethod               # Convert a function to static method.
    def course_details():       # override course_details function from Course class
        return "Course: Power BI for Data Analysis\nDuration: 6 Weeks"

print(PythonCourse.course_details())
# Output => Course: Python Programming\nDuration: 8 Weeks

print(PowerBICourse.course_details())
# Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks
  • In this example, Child classes PythonCourse and PowerBICourse inherits the parent class Course and override its method course_details() to provide course specific details.
  • course_details() method in parent class and child classes is annotated with @staticmethod
  • @staticmethod annotation makes course_details() method as static method. It means, we can call this method using the class and don’t need class object to call this method.
  • We can call course_details() method directly using the class like PythonCourse.course_details() and PowerBICourse.course_details().

Overriding Properties Using @property

Properties in Python can be overridden using the @property decorator. Sub-classes can redefine or extend property behavior.

# Overriding Properties Using @property
# Parent class
class Course:
    @property                    # define property
    def course_details(self):
        return "Course completion certification"

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    @property                   # define property
    def course_details(self):   # override course_details function from Course class
        return "Course: Python Programming\nDuration: 8 Weeks\n" + super().course_details

# Child class 2
class PowerBICourse(Course):     # Inherits from Course
    @property                    # define property
    def course_details(self):    # override course_details function from Course class
        return "Course: Power BI for Data Analysis\nDuration: 6 Weeks\n" + super().course_details

python_course = PythonCourse()
powerbi_course = PowerBICourse()

print(python_course.course_details)
# Output => Course: Python Programming\nDuration: 8 Weeks\nCourse completion certification

print(powerbi_course.course_details)
# Output => Course: Power BI for Data Analysis\nDuration: 6 Weeks\nCourse completion certification
  • In this example, Child classes PythonCourse and PowerBICourse inherits the parent class Course and override its property course_details to provide course specific details.
  • course_details() function in parent class and child classes is annotated with @property
  • @property annotation makes course_details as property of the class, which is overridden in child classes.
  • Child class property is calling the parent class property using super().course_details
  • We can call course_details property on the class objects like python_course.course_details and powerbi_course.course_details.

Overriding Magic (Dunder) Methods

Magic (or “dunder”) methods (e.g., __str__, __repr__, __eq__) can be overridden to customize object behavior.

# Overriding Magic (Dunder) Methods
# Parent class
class Course:
    def __str__(self):          # define __str__ method
        return "Course completion certification"

# Child class 1
class PythonCourse(Course):     # Inherits from Course
    def __str__(self):          # override __str__ method
        return "Course: Python Programming\nDuration: 8 Weeks"

course = Course()
python_course = PythonCourse()
print(course)          # Output => Course completion certification
print(python_course)   # Output => Course: Python Programming\nDuration: 8 Weeks
  • In this example, Child class PythonCourse inherits the parent class Course and override method __str__.
  • __str__ method is directly called on the class object. We don’t need to specify its method call.
  • __str__ method is called on the class object when we print course and python_course.

Method Overriding – Multilevel Inheritance

In multilevel inheritance, class inheritance is in multiple levels. The child class inherits from a parent class, which itself is a child of another class. Ex. Child class inherits from Parent class and Parent class itself inherits from GrandParent class.

# Method Overriding - Multilevel Inheritance
# GrandParent class
class Shbytes:
    def course_info(self):             # defined function
        print("Generic course info.")

# Parent class (inherits from Shbytes)
class Courses(Shbytes):
    def course_info(self):             # override function from Shbytes class
        print("Courses: Offering a variety of tech and business courses.")

# Child class (inherits from Courses)
class PythonCourse(Courses):
    def course_info(self):             # override function from Courses class
        print("Python Course: A detailed course on Python programming.")

# Creating an object of the grandchild class
python_course = PythonCourse()
python_course.course_info()    # Method of PythonCourse (Child class)
# Output => Python Course: A detailed course on Python programming.
  • The Shbytes class contains a method course_info().
  • The Courses class inherits from Shbytes and override its method course_info().
  • The PythonCourse class, which inherits from Courses, override method course_info().
  • PythonCourse class has override method from Courses class and Shbytes class.

Method Overriding – Using super() in Multiple Inheritance (MRO)

The Method Resolution Order (MRO) is the order in which Python looks for methods when they are called using super(). We can check the MRO of any class using the __mro__ attribute or the mro() method.

  • ClassName.__mro__ => Returns tuple of class method resolution order
  • ClassName.mro() => Returns list of class method resolution order
# Method Overriding - Using super() in Multiple Inheritance (MRO)
# GrandParent class
class Shbytes:
    def course_info(self):
        return "courses@shbytes.com"

# Parent class
class Course(Shbytes):
    def course_info(self):
        return "Course completion certification - " + super().course_info()

# Child class
class PythonCourse(Course):     # Inherits from Course
    def course_info(self):   # override course_details function from Course class
        return "Course: Python Programming\nDuration: 8 Weeks\n" + super().course_info()

python_course = PythonCourse()
print(python_course.course_info())
# Output: Course => Python Programming\nDuration: 8 Weeks\nCourse completion certification - courses@shbytes.com
  • In this example PythonCourse class inherits Course class which inherits Shbytes class.
  • course_info() method override from parent class. This method calls the parent class method using super().course_info()
  • super() ensures that all classes in a hierarchy are properly initialized and called in the correct order, especially in the case of multiple inheritance.
  • It avoids to hardcode the parent class, leading to more maintainable and extendable code.

Private Methods Not Overriden

Private methods (methods with a name starting with __) can be overridden in sub-classes, though it’s less common. Since they are name-mangled, they are overridden by matching the mangled name. Private methods can be tricky to override due to name mangling, and it’s not recommended to rely on this approach heavily.

# Method Overriding - Private Methods
class Course(Shbytes):
    def __course_info(self):      # define private method for Course class
        return "Course completion certification"

    def get_course_info(self):    # method calling private method
        return self.__course_info()

class PythonCourse(Course):
    def __course_info(self):     # define private method for PythonCourse class
        return "Course: Python Programming\nDuration: 8 Weeks"

python_course = PythonCourse()
print(python_course.get_course_info())
# Output: Course completion certification (private method not overridden)

In this example, __course_info method in PythonCourse class is trying to override private method from Course class. But, from the output when we called python_course.get_course_info() we got the response from the parent method itself. Private method is not overridden.

Summary

In this article, we learned about various techniques for Method Overriding in Python. Following topics were covered:

Code – Github Repository

All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.

Python Topics


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *