View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All

Understanding Inheritance in Python Using Examples

Updated on 29/05/20255,893 Views

In the world of object-oriented programming, inheritance is the magical rope that ties generations of code together—just like how your surname ties you to your family lineage. Whether you're a beginner learning Python or preparing for that campus placement interview, understanding inheritance isn't just helpful—it's essential. It allows classes to borrow properties and behavior from other classes, reducing redundancy and making your code more modular, efficient, and elegant. In short, inheritance lets you write less but do more.

Imagine your father, Rajat, being a proud owner of a Royal Enfield, and you—his daughter, Arushi—inheriting not just the bike but also his biking skills and road sense. You didn’t have to start from scratch; you simply inherited the goodies. Similarly, classes in Python can inherit attributes and methods from other classes. This forms the backbone of object-oriented design in Python and helps in building complex programs that are easy to understand and maintain. Let's dive into the mechanics of inheritance in Python, one concept at a time—starting with what it really means.

Pursue our Software Engineering courses to get hands-on experience!

What is Inheritance in Python?

In simple terms, Inheritance in Python allows one class (called the child class or subclass) to derive the properties and behaviors of another class (called the parent class or superclass). This helps you avoid duplicating code and encourages code reusability—something every smart developer strives for. Think of it like a ready-made dosa batter—why grind from scratch when you can build on what's already there?

Python supports inheritance right out of the box, making it an essential part of its object-oriented programming features. You can use inheritance to extend or customize existing classes without altering them, which keeps your base logic intact and your subclasses flexible.

Step up your game by exploring these high-impact programs.

Let’s look at a simple example to bring the concept to life:

Example: Basic Inheritance

class Father:
    def skills(self):
        print("Can drive and cook.")

class Son(Father):
    pass

aniket = Son()
aniket.skills()

Output:

Can drive and cook.

Explanation: The Son class inherits from the Father class. Since it doesn’t define its own skills() method, it automatically uses the one from Father. No code duplication, no fuss—just pure Python elegance.

How Does Inheritance in Python Work Behind the Scenes?

Inheritance in Python operates through a mechanism called the method resolution order (MRO). When you create a subclass that inherits from a parent class, Python follows a specific order to look up attributes and methods. If the subclass doesn’t have a method or attribute, Python checks its parent class, then the parent’s parent, and so on, until it either finds the requested method or raises an error.

Think of it as a family tree search: if your name isn’t on the guest list, you ask your parents, and if they don’t know, you ask your grandparents, until someone knows the answer. This order helps Python efficiently find the right method to call and ensures your code behaves predictably.

Python stores this lookup order in the __mro__ attribute (Method Resolution Order). Let’s see a quick example to understand this better.

Example: Understanding Method Resolution Order (MRO)

class Grandfather:
    def heritage(self):
        print("Inheritance from Grandfather")

class Father(Grandfather):
    def heritage(self):
        print("Inheritance from Father")

class Son(Father):
    pass

sarthak = Son()
sarthak.heritage()

print(Son.__mro__)

Output:

Inheritance from Father

(<class '__main__.Son'>, <class '__main__.Father'>, <class '__main__.Grandfather'>, <class 'object'>)

Explanation:

  • The Son class doesn’t have its own heritage() method, so Python looks up in Father.
  • Since Father defines heritage(), that method runs.
  • The __mro__ shows the order Python searches for methods: Son - Father - Grandfather - object.
  • This is how Python decides which method to call in an inheritance chain.

Understanding how Python handles attribute lookup will also help when dealing with instance variables in Python, which are often inherited or overridden.

What are the Different Types of Inheritance in Python?

Inheritance in Python comes in several flavors, each suited to different scenarios. Understanding these types helps you design your classes efficiently and avoid common pitfalls.

1. Single Inheritance

A child class inherits from a single parent class.

class Father:
    def skills(self):
        print("Father can drive.")

class Son(Father):
    pass

vicky = Son()
vicky.skills()

Output:

Father can drive.

Explanation: The Son class inherits from Father. Since Son does not have its own skills() method, it uses the one from Father. This is the simplest form of inheritance—one child, one parent.

2. Multiple Inheritance

A child class inherits from more than one parent class.

class Mother:
    def cooking(self):
        print("Mother can cook.")

class Father:
    def driving(self):
        print("Father can drive.")

class Child(Mother, Father):
    pass

pooja = Child()
pooja.cooking()
pooja.driving()

Output:

Mother can cook.

Father can drive.

Explanation: The Child class inherits from both Mother and Father. It gains access to methods from both parents, showcasing multiple inheritance.

3. Multilevel Inheritance

A child class inherits from a parent class, which itself inherits from another parent class, forming a chain.

class Grandfather:
    def gardening(self):
        print("Grandfather can garden.")

class Father(Grandfather):
    def driving(self):
        print("Father can drive.")

class Son(Father):
    pass

sarthak = Son()
sarthak.gardening()
sarthak.driving()

Output:

Grandfather can garden.

Father can drive.

Explanation: Son inherits from Father, which in turn inherits from Grandfather. This chain represents multilevel inheritance.

4. Hierarchical Inheritance

Multiple child classes inherit from a single parent class.

class Father:
    def skills(self):
        print("Father can drive.")

class Son(Father):
    pass

class Daughter(Father):
    pass

prasun = Son()
arushi = Daughter()
prasun.skills()
arushi.skills()

Output:

Father can drive.

Father can drive.

Explanation: Multiple child classes (Son and Daughter) inherit from a single parent class (Father). Both have access to the same skills() method.

5. Hybrid Inheritance

A combination of two or more types of inheritance.

class Mother:
    def cooking(self):
        print("Mother can cook.")

class Father:
    def driving(self):
        print("Father can drive.")

class Child1(Mother):
    pass

class Child2(Father):
    pass

class GrandChild(Child1, Child2):
    pass

sarita = GrandChild()
sarita.cooking()
sarita.driving()

Output:

Mother can cook.

Father can drive.

Explanation: Hybrid inheritance combines multiple and multilevel inheritance. Here, GrandChild inherits from two classes, which themselves inherit from different parents.

If you're not yet confident about how methods are defined and reused, brush up with our guide on functions in Python—they’re the building blocks you’ll be extending through inheritance.

How to Implement Inheritance in Python with Real-Life Examples?

To truly grasp inheritance, it helps to connect it with everyday life. Imagine Rajat, who learns cooking skills from his mother and driving skills from his father. In Python, Rajat’s abilities can be modeled with inheritance, where his class inherits traits from both parents.

Let’s see how you can implement this in Python with real-life examples that are easy to relate to.

Example: Modeling Rajat’s Skills through Inheritance

class Mother:
    def cooking(self):
        print("Mother can cook traditional Indian meals.")

class Father:
    def driving(self):
        print("Father can drive a car.")

class Rajat(Mother, Father):
    pass

rajat = Rajat()
rajat.cooking()
rajat.driving()

Output:

Mother can cook traditional Indian meals.

Father can drive a car.

Explanation: The Rajat class inherits from both Mother and Father. This means Rajat can both cook and drive without defining these methods himself. This is a practical use of multiple inheritance, showing how Python lets you combine traits easily.

Example: Adding New Skills to Rajat

Rajat also learns how to code, a skill unique to him. Let’s add that:

class Rajat(Mother, Father):
    def coding(self):
        print("Rajat can code in Python.")

rajat = Rajat()
rajat.coding()

Output:

Rajat can code in Python.

Explanation: Here, the Rajat class extends inherited abilities by adding a new method coding(). This shows how child classes can add their own unique features on top of inherited ones.

Example: Overriding Parent Methods

Suppose Rajat is a better cook than his mother, and he wants to show that. He can override the cooking() method:

class Rajat(Mother, Father):
    def cooking(self):
        print("Rajat cooks fusion dishes.")

rajat = Rajat()
rajat.cooking()

Output:

Rajat cooks fusion dishes.

Explanation: By redefining the cooking() method, Rajat overrides the parent’s method. This is called method overriding—a powerful feature to customize inherited behavior.

What is the Role of super() in Inheritance in Python?

The super() function is like a polite middleman—it helps a child class call methods from its parent class without explicitly naming the parent. This is especially handy when you want to extend or modify parent behavior while still preserving the original functionality.

Example: Using super() to Extend Parent Methods

class Father:
    def skills(self):
        print("Father can drive.")

class Rajat(Father):
    def skills(self):
        print("Rajat is learning new skills.")
        super().skills()

rajat = Rajat()
rajat.skills()

Output:

Rajat is learning new skills.

Father can drive.

Explanation: In this example, Rajat overrides the skills() method but uses super().skills() to call the original method from Father. This allows Rajat to add his own message before or after the parent’s method runs.

How Does Method Overriding Work in Python?

Method overriding allows a child class to provide a specific implementation of a method that is already defined in its parent class. This is crucial when the child class needs to modify or enhance the behavior inherited from the parent.

When to Override and Why

Overriding is used when the default behavior of a parent class method does not fit the child class’s requirements. For example, imagine Priya inherits a method to greet people formally, but Priya wants to greet with a more casual tone. She can override the method in her child class to customize it without altering the parent class.

Overriding promotes flexibility and polymorphism, allowing different classes to respond differently to the same method call.

Example

class Father:
    def greet(self):
        print("Good morning, sir!")

class Priya(Father):
    def greet(self):
        print("Hey! What's up?")

priya = Priya()
priya.greet()

Output:

Hey! What's up?

Explanation: Although Priya inherits from Father, it overrides the greet() method. When calling priya.greet(), Python uses the child class’s version, showing the power of method overriding to customize behavior.

How Do Constructors Behave in Inheritance in Python?

Constructors play a vital role in initializing objects. When inheritance comes into play, understanding how constructors behave and how to properly chain them using super() is essential to avoid unexpected results.

init and Constructor Chaining with super()

In Python, the __init__ method acts as a constructor. When a child class inherits from a parent class, the parent’s constructor is not called automatically unless you explicitly call it. This can lead to partially initialized objects if you miss invoking the parent constructor.

Using super().__init__() allows the child class to call the parent class’s constructor, ensuring all necessary initialization happens in the right order — a process known as constructor chaining.

Example: Constructor Chaining with super()

class Father:
    def __init__(self):
        print("Father's constructor called")

class Rajat(Father):
    def __init__(self):
        super().__init__()
        print("Rajat's constructor called")

rajat = Rajat()

Output:

Father's constructor called

Rajat's constructor called

Explanation: Here, Rajat explicitly calls the parent Father’s constructor using super().__init__(). This ensures both constructors run in sequence, properly initializing the object.

Tips & Tricks for Mastering Inheritance in Python

Inheritance can feel like climbing a steep hill—challenging at first, but rewarding once you reach the top. Here are some student-friendly tips to make your inheritance journey smoother and more effective:

1. Understand “Is-A” Relationship Clearly

Before using inheritance, ask yourself: Is the child truly a type of the parent? For example, a Son is a Father’s child, so inheritance fits. But a Car is not a Person—don’t force inheritance where it doesn’t logically belong.

2. Keep Your Classes Focused and Simple

Don’t create mega parent classes with too many responsibilities. Follow the Single Responsibility Principle — it keeps your code clean and easy to debug.

3. Use super() Smartly

Always prefer super() to call parent methods, especially constructors. It avoids hard-coding parent class names and supports multiple inheritance without breaking code.

4. Avoid Deep Inheritance Trees

Long inheritance chains can confuse even experienced coders. If you find yourself with many levels, consider composition or interfaces instead of inheritance.

5. Practice with Real-Life Indian Examples

Try modeling things around you—like school classes, family relations (Rajat, Priya, Anjali), or even cricket teams. This contextual practice solidifies concepts better than abstract examples.

6. Watch Out for Method Overriding Pitfalls

Be careful when overriding methods—if you override a method but forget to call the parent version when needed, you might lose important functionality.

Pro Tip: Think of inheritance as your family legacy — use it to build on the past, but don’t let it chain you down! Write clean, readable code that future you (or your friends) will thank you for.

Inheritance is easier to practice once you’re confident in using object-oriented programming in Python. It covers principles that apply directly to your use cases here.

Conclusion – What’s Your Takeaway from Inheritance in Python?

Inheritance in Python is a cornerstone of object-oriented programming that empowers you to build modular, reusable, and scalable code. It mirrors real-life relationships, making your programs easier to design and understand. By mastering inheritance, you unlock the ability to create elegant hierarchies where child classes extend or customize parent class behavior efficiently.

Remember, while inheritance offers immense power, it demands disciplined use—stick to clear “is-a” relationships, leverage super() for clean constructor and method chaining, and avoid deep inheritance trees that complicate your codebase. With these best practices, you’ll not only write better code but also think like a seasoned developer.

So, take a leaf from Rajat, Priya, and their families—inherit the best, innovate boldly, and keep your Python codebase both robust and readable!

Now that you've tackled inheritance, why not explore encapsulation in Python—another core pillar of OOP that goes hand-in-hand with inheritance.

FAQs

1. What is inheritance in Python?

Inheritance allows a child class to inherit attributes and methods from a parent class, enabling code reuse and hierarchical relationships.

2. How does method overriding work in Python?

Method overriding lets a child class provide a specific implementation of a method already defined in its parent, allowing customization of inherited behavior.

3. When should I use inheritance instead of composition?

Use inheritance when there is a clear “is-a” relationship between classes. Use composition when you want to build complex objects by combining simpler ones without inheriting from them.

4. What is the Diamond Problem in Python?

The Diamond Problem occurs in multiple inheritance when two parent classes inherit from the same base class, causing ambiguity. Python solves this using the Method Resolution Order (__mro__), which defines the order in which classes are searched.

5. How does the super() function help in inheritance?

super() allows child classes to call methods from their parent classes, facilitating constructor chaining and method extension without explicitly naming parent classes.

6. What happens if I don’t use super() in constructors?

If you omit calling the parent constructor, the parent’s initialization code won’t run, potentially leaving your object partially initialized and causing bugs.

7. How do I use issubclass() and isinstance()?

issubclass(Sub, Parent) checks if Sub is a subclass of Parent. isinstance(obj, Class) checks if obj is an instance of Class or its subclasses.

8. What is the purpose of the __mro__ attribute?

__mro__ (Method Resolution Order) shows the order Python uses to look up methods in a class hierarchy, especially important in multiple inheritance to avoid ambiguity.

9. Can multiple inheritance be dangerous?

Yes, if not handled carefully, multiple inheritance can create complex and confusing hierarchies, especially without understanding MRO and super(). Always design with clarity.

10. What are common mistakes beginners make with inheritance?

Common mistakes include overusing inheritance, deep inheritance trees, forgetting to call parent constructors, and overriding methods without calling the parent version when needed.

11. How do constructors behave in inheritance?

Parent constructors are not called automatically in Python inheritance; you must explicitly call them using super() or by directly invoking the parent’s __init__.

12. What is constructor chaining?

Constructor chaining is the practice of calling parent constructors from child constructors using super(), ensuring all parts of the object are properly initialized.

13. Why is the “is-a” relationship important in inheritance?

The “is-a” relationship ensures logical correctness. Only use inheritance when a child truly is a type of the parent, avoiding forced or incorrect class hierarchies.

14. Can I override a method but still use the parent’s method functionality?

Yes, by overriding the method and calling the parent’s version using super(), you can extend or modify behavior without losing the original implementation.

15. What should I keep in mind while designing inheritance hierarchies?

Keep inheritance shallow and focused, prefer composition when appropriate, use clear naming, always call parent constructors, and leverage super() to maintain clean, maintainable code

image

Take our Free Quiz on Python

Answer quick questions and assess your Python knowledge

right-top-arrow
image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
advertise-arrow

Free Courses

Explore Our Free Software Tutorials

upGrad Learner Support

Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)

text

Indian Nationals

1800 210 2020

text

Foreign Nationals

+918068792934

Disclaimer

1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.

2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.