The super()
function in Python is a built-in function that allows you to access methods from a parent or sibling class. It is most commonly used within the context of inheritance, especially when you are overriding methods in a subclass and want to call the method from the parent class.
Understanding Inheritance and super( )
Inheritance is a fundamental concept in object-oriented programming that allows a class to inherit attributes and methods from another class. The class being inherited from is called the parent or superclass, and the class that inherits is called the child or subclass.
When overriding a method in a subclass, it is often necessary or beneficial to call the same method from the parent class. This is where super()
comes in handy.
Basic Syntax of super( )
The basic syntax of super()
is as follows:
super().method_name(args)
Here, method_name
is the method from the parent class that you want to call, and args
are the arguments that this method requires.
How super( ) Works
When you use super()
, Python is actually looking for the next class in the method resolution order (MRO). The MRO is a list that defines the order in which base classes are searched when executing a method. First, it looks in the current class, and if it doesn’t find the method, it then looks in the classes that the current class inherits from, in the order they are listed in the class definition.
In a classic inheritance scenario where a subclass inherits from one superclass, super()
will simply refer to the superclass.
Advantages of Using super( )
- Maintainability: Using
super()
makes your code more maintainable because you don’t have to hard-code the name of the superclass into every method call. - Support for Multiple Inheritance:
super()
is designed to handle complex multiple inheritance scenarios seamlessly. Withoutsuper()
, multiple inheritance can result in the same superclass being called more than once, leading to a variety of problems, one of which is the diamond problem. - Dynamic Dispatch:
super()
supports dynamic dispatch (which is the selection of a method at runtime) because it doesn’t hard-code the superclass. This is essential in cases where the class hierarchy is subject to change.
Using super( ) in Single Inheritance
To understand the use of super()
in single inheritance, it’s important to first grasp the basic concept of inheritance in object-oriented programming. Inheritance allows a class (known as a subclass) to inherit attributes and methods from another class (known as a superclass or parent class).
Single Inheritance
Single inheritance occurs when a subclass inherits from one superclass only. Here’s an example to illustrate single inheritance in Python:
class Parent:
def __init__(self, value):
self.value = value
print("Parent class's __init__ method")
def method_a(self):
print("Parent class's method_a")
class Child(Parent):
def __init__(self, value, extra):
super().__init__(value)
self.extra = extra
print("Child class's __init__ method")
def method_b(self):
print("Child class's method_b")
In this example, Child
is a subclass that inherits from Parent
. The Parent
class has an __init__
method that initializes the object with a value, and a method named method_a
. The Child
class has its own __init__
method and an additional method named method_b
.
Using super( ) in __init__ Method
The Child
class uses super()
to call the __init__
method of the Parent
class. This is crucial because it allows the Child
class to initialize part of its state in terms of the Parent
class’s initialization. Here is what happens when you create an instance of Child
:
child_instance = Child(10, 'extra data')
- The
__init__
method ofChild
is called with10
and'extra data'
as arguments. - Inside
Child
‘s__init__
method,super().__init__(value)
is called. Thesuper()
function returns a temporary object of the superclass (Parent
) which then allows you to call its methods. - The
Parent
class’s__init__
method is called with10
as the argument, settingself.value
to10
. - Control returns to the
Child
class’s__init__
method, and theself.extra
attribute is set to'extra data'
. - Finally, the message “Child class’s init method” is printed.
This sequence of operations ensures that the Child
object is properly initialized with the state defined in both the Parent
and Child
classes.
Using super( ) with Other Methods
You can also use super()
to call other methods of the superclass, not just __init__
. This is often used when you want to extend or modify the behavior of a method from the superclass. Here’s how it’s done:
class Parent:
def method_a(self):
print("Parent class's method_a")
class Child(Parent):
def method_a(self):
super().method_a() # Calls the same method from the Parent class
print("Extension by Child class's method_a")
child_instance = Child()
child_instance.method_a()
When you call method_a
on an instance of Child
, here is what will happen:
- The overridden
method_a
of theChild
class is executed. - Inside this method,
super().method_a()
calls themethod_a
method from theParent
class, which will print “Parent class’s method_a”. - After the
super()
call, the next lineprint("Extension by Child class's method_a")
will execute, printing “Extension by Child class’s method_a”.
So, the output will be:
Parent class's method_a
Extension by Child class's method_a
Using super( ) in Multiple Inheritance
Multiple inheritance is a feature in object-oriented programming where a class can inherit attributes and methods from more than one parent class. Python supports multiple inheritance and provides the super()
function to allow you to call methods in a parent class in the context of multiple inheritance.
How Multiple Inheritance Works in Python
In Python, when a class inherits from multiple parent classes, it creates a complex hierarchy where the interpreter needs a way to determine which parent class to refer to when a method is called. This is resolved using the Method Resolution Order (MRO).
The MRO is a rule-based system that Python uses to determine the order in which to look up a method. It’s a linearization of the hierarchy tree. Python uses the C3 linearization algorithm to determine the MRO in multiple inheritance scenarios.
Using super( ) in Multiple Inheritance
The super()
function is used to call the next method in the MRO. Here’s an example that illustrates the use of super()
in multiple inheritance:
class Base:
def __init__(self):
print("Base init")
class A(Base):
def __init__(self):
super().__init__()
print("A init")
class B(Base):
def __init__(self):
super().__init__()
print("B init")
class C(A, B):
def __init__(self):
super().__init__()
print("C init")
In the above classes:
Base
is the base class.A
andB
are subclasses that inherit fromBase
.C
inherits from bothA
andB
.
When you create an instance of C
, the __init__
method of C
is called, which in turn uses super()
to call the __init__
method of the next class in the MRO, which is A
. A
‘s __init__
method is then called, which also calls super()
, leading to B
‘s __init__
method, and so on until the base class’s __init__
method is reached.
MRO and super( )
The MRO for class C
will look like this: [C, A, B, Base, object]
. Here’s how the MRO affects the calls:
C.__init__()
callsA.__init__()
, becauseA
is the first class afterC
in the MRO.A.__init__()
callsB.__init__()
, notBase.__init__()
, because of how the MRO is computed.B.__init__()
then callsBase.__init__()
, which is the next in line in the MRO.- Finally,
Base.__init__()
executes, and the initialization chain is complete.
Benefits of Using super( ) in Multiple Inheritance
- No Hardcoding Required:
super()
eliminates the need to hardcode the superclass’s name, which can make changes to the inheritance hierarchy easier. - Consistent Method Resolution:
super()
follows the MRO, ensuring that the methods are called in the order Python intends based on the class hierarchy. - Avoids Duplicating Calls: In complex inheritance hierarchies,
super()
prevents the same superclass method from being called multiple times unintentionally.
Practical Example
Imagine you have a system where a C
class represents a widget that inherits from two classes: A
for touch functionality and B
for drawable functionality:
class Touch:
def __init__(self):
print("Touch capability added")
class Drawable:
def __init__(self):
print("Drawable capability added")
class Widget(Touch, Drawable):
def __init__(self):
super().__init__()
print("Widget created with both capabilities")
When an instance of Widget
is created, it will print out the capabilities as they are initialized:
widget = Widget()
Output:
Touch capability added
Widget created with both capabilities
The output will reflect the order defined by the MRO of Widget
.
In multiple inheritance, super()
is an essential tool for calling superclass methods in a way that respects the MRO and avoids common pitfalls associated with multiple inheritance, such as duplicated method calls or the diamond problem. It ensures that each method in the inheritance hierarchy is called in a predictable and controlled manner, which is crucial for maintaining clean and functional object-oriented code in Python.
Conclusion
The super()
function is a powerful feature of Python that facilitates a cooperative method call dispatching mechanism. It is a critical part of the language’s support for inheritance, allowing for a clean and maintainable way to invoke superclass methods. The super()
function not only handles simple single inheritance but is also designed to operate correctly in complex scenarios with multiple inheritance, ensuring that each superclass’s methods are called in the order defined by the MRO. This makes super()
an essential tool for any Python programmer working with object-oriented code.