Inheritance in Python

Flask Tutorial

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.

Avatar photo
Great Learning Editorial Team
The Great Learning Editorial Staff includes a dynamic team of subject matter experts, instructors, and education professionals who combine their deep industry knowledge with innovative teaching methods. Their mission is to provide learners with the skills and insights needed to excel in their careers, whether through upskilling, reskilling, or transitioning into new fields.

Academy Pro Subscription

Grab 50% off
on Top Courses - Free Trial Available

×
Scroll to Top