Inheritance in Python is a fundamental concept in object-oriented programming (OOP) that helps you build new classes based on existing ones. It allows you to reuse and extend code, making your programs more organized and easier to manage.
What is Inheritance in Python?
Inheritance in Python is a mechanism where a new class (called the child class or subclass) derives attributes and methods from an existing class (called the parent class or superclass).
It helps you avoid writing duplicate code. You define common behaviors in a parent class. Then, child classes can inherit these behaviors and add their own specific functionalities. This promotes code reuse and creates a clear hierarchy in your program.
Here’s how you can master inheritance in 3 steps:
1. Understand the Basics of Class Inheritance
You define a parent class with common attributes and methods. Then, you create a child class that inherits from this parent.
Parent Class Definition
First, create a basic Vehicle
class. This class will have general attributes like make
and model
, and a method to display this information.
class Vehicle:
def __init__(self, make, model):
self.make = make
self.model = model
def display_info(self):
print(f"Make: {self.make}, Model: {self.model}")
Child Class Definition
Next, create a Car
class. This Car
class will inherit from Vehicle
. It gets all the attributes and methods of Vehicle
automatically. You also add specific attributes like num_doors
and a display_info
method for cars.
class Car(Vehicle):
def __init__(self, make, model, num_doors):
super().__init__(make, model) # Call the parent class's __init__
self.num_doors = num_doors
def display_info(self):
super().display_info() # Call the parent's display_info
print(f"Number of Doors: {self.num_doors}")
When you create a Car
object, it has make
, model
, and num_doors
. When you call display_info()
on a Car
object, it first prints the Vehicle
information, then its own specific num_doors
. This shows how you reuse code from the parent and extend it in the child.
2. Explore Types of Inheritance
Python supports different ways to structure inheritance. Understanding these helps you choose the right approach for your project.
Single Inheritance
Single inheritance is the simplest type. A child class inherits from only one parent class.
class Animal:
def speak(self):
return "Animal makes a sound"
class Dog(Animal):
def speak(self):
return "Woof!"
my_dog = Dog()
print(my_dog.speak())
# Output: Woof!
The Dog
class inherits from Animal
. It can use speak()
from Animal
or provide its own version, as shown.
Multiple Inheritance
Multiple inheritance allows a child class to inherit from multiple parent classes. This means it can combine behaviors from several sources.
class Swimmer:
def swim(self):
return "Can swim"
class Walker:
def walk(self):
return "Can walk"
class Amphibian(Swimmer, Walker):
pass
frog = Amphibian()
print(frog.swim())
print(frog.walk())
# Output:
# Can swim
# Can walk
The Amphibian
class inherits swim()
from Swimmer
and walk()
from Walker
.
Multilevel Inheritance
Multilevel inheritance involves a chain of inheritance. A child class inherits from another child class.
class LivingBeing:
def breathe(self):
return "Breathing..."
class Animal(LivingBeing):
def eat(self):
return "Eating..."
class Mammal(Animal):
def nurse(self):
return "Nursing young"
lion = Mammal()
print(lion.breathe())
print(lion.eat())
print(lion.nurse())
# Output:
# Breathing...
# Eating...
# Nursing young
Mammal
inherits from Animal
, which inherits from LivingBeing
. Mammal
gets methods from both Animal
and LivingBeing
.
Hierarchical Inheritance
In hierarchical inheritance, multiple child classes inherit from a single parent class.
class Shape:
def __init__(self, color):
self.color = color
class Circle(Shape):
def __init__(self, color, radius):
super().__init__(color)
self.radius = radius
class Rectangle(Shape):
def __init__(self, color, length, width):
super().__init__(color)
self.length = length
self.width = width
red_circle = Circle("Red", 5)
blue_rectangle = Rectangle("Blue", 4, 6)
print(red_circle.color)
print(blue_rectangle.color)
# Output:
# Red
# Blue
Both Circle
and Rectangle
inherit from Shape
. They share the color
attribute.
Hybrid Inheritance
Hybrid inheritance combines two or more types of inheritance. This creates complex class structures.
class A:
def method_a(self):
return "Method A"
class B(A):
def method_b(self):
return "Method B"
class C(A):
def method_c(self):
return "Method C"
class D(B, C):
def method_d(self):
return "Method D"
obj_d = D()
print(obj_d.method_a())
print(obj_d.method_b())
print(obj_d.method_c())
print(obj_d.method_d())
# Output:
# Method A
# Method B
# Method C
# Method D
Here, D
uses multiple inheritance from B
and C
, while B
and C
use single inheritance from A
.
3. Master Advanced Inheritance Concepts
You can do more than just inherit methods. Python offers features for overriding and managing complex inheritance scenarios.
Method Overriding
Method overriding means a child class provides its own implementation for a method already defined in its parent class. When you call that method on the child object, Python uses the child’s version.
class Animal:
def make_sound(self):
print("Generic animal sound")
class Cat(Animal):
def make_sound(self):
print("Meow!")
my_cat = Cat()
my_cat.make_sound()
# Output: Meow!
The Cat
class overrides the make_sound
method from Animal
.
Using super()
The super()
function helps you call methods from the parent class, even if you override them in the child class. This is useful for extending parent functionality without rewriting it.
class Parent:
def __init__(self, name):
self.name = name
def greet(self):
print(f"Hello from Parent, {self.name}!")
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # Call parent's __init__
self.age = age
def greet(self):
super().greet() # Call parent's greet
print(f"Hello from Child, {self.name} (age {self.age})!")
child_obj = Child("Alice", 10)
child_obj.greet()
# Output:
# Hello from Parent, Alice!
# Hello from Child, Alice (age 10)!
super().__init__(name)
calls the Parent
class’s constructor. super().greet()
calls the Parent
class’s greet
method.
Method Resolution Order (MRO)
In multiple inheritance, Python needs a way to decide which parent’s method to call if multiple parents have methods with the same name. This is handled by the Method Resolution Order (MRO). Python uses the C3 Linearization algorithm to determine the MRO.
You can check the MRO of a class using .__mro__
attribute or the mro()
method.
class A:
def show(self):
print("Method from A")
class B(A):
def show(self):
print("Method from B")
class C(A):
def show(self):
print("Method from C")
class D(B, C):
pass
obj_d = D()
obj_d.show()
print(D.__mro__)
# Output:
# Method from B
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
The show()
method from B
is called because B
appears before C
in the MRO of class D
. The MRO explicitly lists the search order.
Benefits of Inheritance
Inheritance offers several advantages:
- Code Reusability: You write common code once in a parent class and reuse it across multiple child classes.
- Modularity: It breaks down your code into logical, hierarchical units, making it easier to understand and manage.
- Extensibility: You can add new features or child classes without changing existing code.
- Reduced Maintenance: Changes to the parent class automatically apply to all child classes, simplifying updates.
When to Use Inheritance
Use inheritance when objects have a clear “is-a” relationship. For example, a Dog is an Animal. A Car is a Vehicle.
Avoid using inheritance just for code reuse when there isn’t a strong “is-a” relationship. In such cases, composition (where one class contains an instance of another) is often a better choice.