Inheritance is a fundamental concept in object-oriented programming (OOP) that allows you to create new classes based on existing ones. This tutorial will cover single inheritance, multiple inheritance, the super() function, Method Resolution Order (MRO), and the diamond problem. Understanding these concepts will help you build more organized and reusable code.
Inheritance is a mechanism where a class inherits attributes and methods from another class. This promotes code reusability and establishes an "is-a" relationship between classes. For example, a Dog class can inherit from an Animal class because a dog is an animal.
Multiple inheritance allows a class to inherit from more than one base class. While powerful, it can also introduce complexity, especially with the diamond problem where two or more base classes share a common ancestor.
Single inheritance is the simplest form of inheritance where a derived class inherits from only one base class. This is the most straightforward way to establish an "is-a" relationship.
1# animal.py2class Animal:3def __init__(self, name):4self.name = name56def speak(self):7return "Some sound"
1# dog.py2from animal import Animal34class Dog(Animal):5def speak(self):6return "Woof!"
1# main.py2from dog import Dog34dog = Dog("Buddy")5print(dog.name) # Output: Buddy6print(dog.speak()) # Output: Woof!
Buddy Woof!
In this example, the Dog class inherits from the Animal class. The Dog class overrides the speak() method to provide its own implementation.
Multiple inheritance allows a class to inherit from more than one base class. This can be useful when you want to combine behaviors from different classes into a single class.
1# swimmer.py2class Swimmer:3def swim(self):4return "Swimming fast"
1# flyer.py2class Flyer:3def fly(self):4return "Flying high"
1# duck.py2from swimmer import Swimmer3from flyer import Flyer45class Duck(Swimmer, Flyer):6pass
1# main.py2from duck import Duck34duck = Duck()5print(duck.swim()) # Output: Swimming fast6print(duck.fly()) # Output: Flying high
Swimming fast Flying high
In this example, the Duck class inherits from both Swimmer and Flyer classes. It can use methods from both base classes.
super() FunctionThe super() function is used to call a method from a parent class in the inheritance hierarchy. This is particularly useful when you want to extend or modify the behavior of a base class method without completely overriding it.
super()1# animal.py2class Animal:3def __init__(self, name):4self.name = name56def speak(self):7return "Some sound"
1# dog.py2from animal import Animal34class Dog(Animal):5def __init__(self, name, breed):6super().__init__(name)7self.breed = breed89def speak(self):10return f"{super().speak()} and barks loudly"
1# main.py2from dog import Dog34dog = Dog("Buddy", "Golden Retriever")5print(dog.name) # Output: Buddy6print(dog.breed) # Output: Golden Retriever7print(dog.speak()) # Output: Some sound and barks loudly
Buddy Golden Retriever Some sound and barks loudly
In this example, the Dog class uses super() to call the __init__() method of the Animal class. It also extends the speak() method by adding additional behavior.
Method Resolution Order is the order in which Python looks for a method or attribute in an inheritance hierarchy. This is important in multiple inheritance scenarios to avoid ambiguity and ensure that methods are called correctly.
1# animal.py2class Animal:3def speak(self):4return "Animal sound"
1# dog.py2from animal import Animal34class Dog(Animal):5pass
1# cat.py2from animal import Animal34class Cat(Animal):5pass
1# pet.py2from dog import Dog3from cat import Cat45class Pet(Dog, Cat):6pass
1# main.py2from pet import Pet34pet = Pet()5print(pet.speak()) # Output: Animal sound6print(Pet.mro()) # Output: [<class '__main__.Pet'>, <class 'dog.Dog'>, <class 'cat.Cat'>, <class 'animal.Animal'>, <class 'object'>]
Animal sound [<class '__main__.Pet'>, <class 'dog.Dog'>, <class 'cat.Cat'>, <class 'animal.Animal'>, <class 'object'>]
In this example, the Pet class inherits from both Dog and Cat. The MRO shows the order in which Python will look for methods. Since Dog is listed before Cat, the speak() method of Animal is called.
The diamond problem occurs when two base classes inherit from a common ancestor, and a derived class inherits from both base classes. This can lead to ambiguity about which method should be called.
1# animal.py2class Animal:3def speak(self):4return "Animal sound"
1# bird.py2from animal import Animal34class Bird(Animal):5pass
1# mammal.py2from animal import Animal34class Mammal(Animal):5pass
1# dog_bird.py2from bird import Bird3from mammal import Mammal45class DogBird(Bird, Mammal):6pass
1# main.py2from dog_bird import DogBird34dog_bird = DogBird()5print(dog_bird.speak()) # Output: Animal sound6print(DogBird.mro()) # Output: [<class '__main__.DogBird'>, <class 'bird.Bird'>, <class 'mammal.Mammal'>, <class 'animal.Animal'>, <class 'object'>]
Animal sound [<class '__main__.DogBird'>, <class 'bird.Bird'>, <class 'mammal.Mammal'>, <class 'animal.Animal'>, <class 'object'>]
In this example, the DogBird class inherits from both Bird and Mammal, which both inherit from Animal. The MRO ensures that the speak() method of Animal is called.
Let's create a practical example that combines multiple inheritance, the super() function, and understanding the MRO.
1# book.py2class Book:3def __init__(self, title):4self.title = title56def display(self):7return f"Book: {self.title}"
1# electronic_book.py2from book import Book34class ElectronicBook(Book):5def __init__(self, title, format):6super().__init__(title)7self.format = format89def display(self):10return f"{super().display()} (Format: {self.format})"
1# audiobook.py2from book import Book34class Audiobook(Book):5def __init__(self, title, duration):6super().__init__(title)7self.duration = duration89def display(self):10return f"{super().display()} (Duration: {self.duration} minutes)"
1# multimedia_book.py2from electronic_book import ElectronicBook3from audiobook import Audiobook45class MultimediaBook(ElectronicBook, Audiobook):6def __init__(self, title, format, duration):7super().__init__(title, format)8self.duration = duration910def display(self):11return f"{super().display()} (Duration: {self.duration} minutes)"
1# main.py2from multimedia_book import MultimediaBook34multimedia_book = MultimediaBook("Python Programming", "PDF", 120)5print(multimedia_book.display()) # Output: Book: Python Programming (Format: PDF) (Duration: 120 minutes)6print(MultimediaBook.mro()) # Output: [<class '__main__.MultimediaBook'>, <class 'electronic_book.ElectronicBook'>, <class 'audiobook.Audiobook'>, <class 'book.Book'>, <class 'object'>]
Book: Python Programming (Format: PDF) (Duration: 120 minutes) [<class '__main__.MultimediaBook'>, <class 'electronic_book.ElectronicBook'>, <class 'audiobook.Audiobook'>, <class 'book.Book'>, <class 'object'>]
In this example, the MultimediaBook class inherits from both ElectronicBook and Audiobook. The MRO ensures that methods are called in the correct order, and the super() function is used to initialize attributes from base classes.
| Concept | Description |
|---|---|
| Single Inheritance | A class inherits from a single base class. |
| Multiple Inheritance | A class inherits from more than one base class. |
super() Function | Used to call methods from a parent class in the inheritance hierarchy. |
| Method Resolution Order (MRO) | The order in which Python looks for a method or attribute. |
| Diamond Problem | Ambiguity that occurs when two base classes inherit from a common ancestor. |
In the next tutorial, we will explore polymorphism and operator overloading, which allow objects of different classes to be treated as objects of a common superclass. This will further enhance your understanding of how Python handles object-oriented programming.
Stay tuned for more advanced topics in OOP with Python!