super()?in Python is a built-in function that provides a way to call methods and access attributes from a parent class in an object-oriented programming context, particularly in situations involving inheritance. It allows you to achieve method overriding and multiple inheritance while maintaining control over the method resolution order (MRO).
In essence,?super()?returns a temporary object that represents the parent class in the current class’s context. This allows you to call methods and access attributes of the parent class without explicitly naming the parent class, which is especially useful when dealing with complex class hierarchies and multiple inheritance.
The general syntax for using?super()?is:
class ChildClass(ParentClass)
????def some_method(self):
????????super().method_name():
Here are some key points about?super():
- Method Resolution Order (MRO): Python follows the C3 linearization algorithm to determine the order in which classes are searched for a method or attribute.?super()?respects this order and ensures that methods are called in the correct sequence.
- Passing Arguments: When using?super()?to call a method from a parent class, you don’t need to pass?self?as an argument explicitly. The?super()?call automatically includes the current instance as the first argument.
- Multiple Inheritance:?super()?is particularly useful in multiple inheritance scenarios, where a class inherits from multiple parent classes. It helps in avoiding ambiguity when accessing methods from parent classes with the same name.
- Mixin Classes:?super()?can be useful in situations where you have “mixin” classes that provide specific behavior, and you want to compose these mixins together while retaining the ability to call methods from the individual mixins.
- Flexibility:?super()?provides flexibility by allowing you to control which parent class’s method you want to call. You can specify a particular parent class when calling?super(), which enables you to navigate the class hierarchy and choose the desired method.
- Cooperative Hierarchies:?super()?encourages cooperative method overriding and helps avoid code duplication by promoting a clear and systematic way of accessing and extending parent class methods.
Let us take an example code
class Bird
????def __init__(self, name):
????????self.name = name
?
????def speak(self):
????????return f"{self.name} speaks"
?
?
class Sparrow(Bird):
????def speak(self):
????????return super().speak() + " as chirp chirp"
?
?
robin = Sparrow('robin')
print(robin.speak()):
In the above code, how the code works:
- Defining the?Bird?Class: The?Bird?class is defined with an?__init__?method that takes a?name?parameter and initializes the instance variable?name?with the provided name. Additionally, it has a?speak?method that returns a string indicating that the bird is speaking.
- Defining the?Sparrow?Class: The?Sparrow?class is derived from the?Bird?class using inheritance. It overrides the?speak?method to provide its own implementation of bird speech. In this case, it calls?super().speak()?to invoke the?speak?method of the parent class (Bird) and then appends ” as chirp chirp” to indicate the specific sound of a sparrow.
- Creating an Instance of?Sparrow: An instance of the?Sparrow?class is created and assigned to the variable?robin. The constructor of the?Sparrow?class (__init__?method) is called with the argument?'robin'?to set the?name?attribute of the?robin?instance.
- Calling the?speak?Method: The?speak?method of the?robin?instance is called using?robin.speak(). Here’s what happens:
- The overridden?speak?method of the?Sparrow?class is executed.
- Inside the?Sparrow?class’s?speak?method,?super().speak()?is called. This invokes the?speak?method of the parent class (Bird).
- The?Bird?class’s?speak?method returns the string?"robin speaks".
- The?Sparrow?class’s?speak?method appends ” as chirp chirp” to the returned string, resulting in?"robin speaks as chirp chirp".
- Printing the Result:?robin speaks as chirp chirp
Let us try a multiple inheritance
class Bird
????def __init__(self, name):
????????self.name = name
?
????def speak(self):
????????return f"{self.name} speaks"
class FlyingBird(Bird)
????def fly(self):
????????return f" and {self.name} can fly"
?
?
class SwimmingBird(Bird):
????def ability(self):
????????return?? f"? {self.name} can swim"
?
?
class Swan(SwimmingBird, FlyingBird):
????def feature(self):
????????return super().speak() + " woo woo " + super().ability() + super().fly()
??????????
?
lenny = Swan('lenny')
print(lenny.feature()):
Let’s break down the code step by step:
- FlyingBird: This class defines a method called?fly, which returns a string indicating that the bird can fly. It inherits from the?Bird?class, although the?Bird?class definition isn’t provided in the code snippet.
- SwimmingBird: This class defines a method called?ability, which returns a string indicating that the bird can swim. Similar to?FlyingBird, it’s expected that this class inherits from the?Bird?class.
- Swan: The?Swan?class inherits from both?SwimmingBird?and?FlyingBird?using multiple inheritance. It defines a method called?feature, where you intend to use?super()?to call methods from the parent classes.
- Creating an Instance:An instance of the?Swan?class is created and assigned to the variable?lenny. The constructor of the?Swan?class isn’t provided in the code snippet, but we’ll assume that the?__init__?method of the?Bird?class is used to initialize the?name?attribute.
- Calling the?feature?Method:The?feature?method of the?lenny?instance is called using?lenny.feature(). Here’s what happens:
- Inside the?feature?method of the?Swan?class:
- super().speak(): This calls the?speak?method of the parent class in the method resolution order (MRO). Since?Bird?is the parent class that defines the?speak?method, it returns a string indicating that?lenny?speaks.
- super().ability(): This calls the?ability?method of the parent class in the MRO, which is?SwimmingBird?in this case. It returns a string indicating that?lenny?can swim.
- super().fly(): This calls the?fly?method of the parent class in the MRO, which is?FlyingBird. It returns a string indicating that?lenny?can fly.
- Concatenating Results:The results of the three?super()?calls are concatenated together with spaces between them using the?+?operator.
- Printing the Result:The concatenated result of the?super()?calls is printed using the?print()?function.
Hence the output will be :
lenny speaks woo woo lenny can swim and lenny can fly
return super().speak() + " woo woo " + super().ability() + super().fly()
first time super().speak() reference the parent class Bird() and then invoke the speak() method, then second and third time, it reference to the parent classes FlyingBird() and SwimmingBird() then invokes methods ability() and fly()
So we can understand how super() can be used to access the methods from different and multiple parent classes
This demonstrates how the?super()?function allows you to access methods from parent classes in a multiple inheritance scenario, preserving the method resolution order and allowing for customization of behavior.
It’s important to understand that while?super()?is a powerful tool, it should be used with care to prevent unexpected behavior, especially in complex class hierarchies.