Free demoJob-oriented courses at Debugshala, Old Palasia, Indore. Freshers, non-IT and year-gap welcome.Book a free demo +91-8982385539

Python Inheritance: Parent and Child Classes, super() and MRO

Lesson 40 of 52 · 8 min · Updated 13 Nov 2026

Learn Python inheritance: parent and child classes, method overriding, super(), multilevel and multiple inheritance, MRO, mixins and composition.

Think about how Indian Railways builds coaches. Every passenger coach shares a basic design: the same bogies, couplings, braking system and doors. An AC 3-tier coach takes that base and adds air conditioning and berths with curtains. A pantry car takes the same base and adds a kitchen.

Nobody redesigns the couplings for each coach type. If engineers improve the braking system in the base design, every coach type built from it gets the improvement. Each special coach only describes what is different about it.

That is inheritance. The base coach design is the parent class. The AC coach and pantry car are child classes. Adding a kitchen is extending, and replacing standard seats with berths is overriding.

Inheritance in Python is a way to define a new class (child or subclass) that automatically gets all attributes and methods of an existing class (parent or base class), so the child only needs to define what it adds or changes.

You should be comfortable with Python classes and objects before reading on. Examples target Python 3.12+.

What is inheritance in Python?

Put the parent's name in brackets after the child's name. The child class can be empty and still work, because every method it lacks is looked up in the parent.

Python
class Report:
    def __init__(self, title, rows):
        self.title = title
        self.rows = rows

    def total(self):
        return sum(r["amount"] for r in self.rows)

    def render(self):
        return f"{self.title}: {len(self.rows)} rows, total {self.total()}"

class SalesReport(Report):
    pass                                  # inherits everything

rows = [{"amount": 1450}, {"amount": 980}, {"amount": 2300}]
r = SalesReport("November sales", rows)
print(r.render())
print(isinstance(r, SalesReport), isinstance(r, Report))
print(issubclass(SalesReport, Report))

isinstance(r, Report) is True because a SalesReport is a Report. Any code written for reports will accept a sales report. This is the same rule that lets except DataQualityError catch its subclasses in Python custom exceptions.

How do you override a method in Python?

Define a method in the child with the same name as one in the parent. When Python looks up the method on a child object, it finds the child's version first and stops searching.

Python
class Report:
    def __init__(self, title, rows):
        self.title, self.rows = title, rows

    def total(self):
        return sum(r["amount"] for r in self.rows)

class ReturnsReport(Report):
    def total(self):                      # override: refunds reduce revenue
        return -sum(r["amount"] for r in self.rows)

rows = [{"amount": 450}, {"amount": 1200}]
print(Report("Gross", rows).total())
print(ReturnsReport("Refunds", rows).total())
Python inheritance method lookup: a GstSalesReport object searches its own class, then SalesReport, then Report, then object for each method

Python searches upward from the object's own class and uses the first match it finds.

What does super() do in Python?

Often you want to extend a parent method rather than replace it. super() returns a stand-in for the parent, so super().__init__(...) runs the parent's setup and super().render() gets the parent's result, which you then build on.

Python
class Report:
    def __init__(self, title, rows):
        self.title, self.rows = title, rows

    def total(self):
        return sum(r["amount"] for r in self.rows)

    def render(self):
        return f"{self.title}: total {self.total()}"

class GstReport(Report):
    def __init__(self, title, rows, gst_rate):
        super().__init__(title, rows)     # parent sets title and rows
        self.gst_rate = gst_rate          # child adds its own attribute

    def render(self):
        base = super().render()           # reuse the parent's text
        gst = round(self.total() * self.gst_rate, 2)
        return f"{base}, GST {gst}"

rows = [{"amount": 1450}, {"amount": 980}]
print(GstReport("Indore outlet", rows, 0.18).render())

If a child defines __init__ and forgets to call super().__init__(), the parent's attributes are never created. The first method that uses self.rows then fails with an AttributeError. Forgetting this call is the most common inheritance bug.

Quick check

A child class defines __init__ but never calls super().__init__(). What happens?

Types of inheritance in Python

Type Shape Example
Single One parent, one child SalesReport(Report)
Multilevel A chain of parents GstSalesReport(SalesReport), which inherits from Report
Hierarchical One parent, many children SalesReport and StockReport both inherit Report
Multiple One child, several parents ExportableReport(Report, CsvMixin)

Single and hierarchical inheritance cover most real code. Multilevel chains deeper than two or three levels become hard to follow, because a reader must open every ancestor to know what a method does.

Multiple inheritance and the MRO

A class can list several parents. Python then needs a rule for which parent to search first. That rule is the method resolution order, or MRO, stored on every class as __mro__. Python computes it with an algorithm called C3 linearisation. In practice: children come before parents, and parents keep the left-to-right order you wrote.

Python
class Report:
    def describe(self):
        return ["Report"]

class Monthly(Report):
    def describe(self):
        return ["Monthly"] + super().describe()

class Regional(Report):
    def describe(self):
        return ["Regional"] + super().describe()

class MonthlyRegional(Monthly, Regional):
    def describe(self):
        return ["MonthlyRegional"] + super().describe()

print([c.__name__ for c in MonthlyRegional.__mro__])
print(MonthlyRegional().describe())

This is the diamond shape: two parents share one grandparent. super() does not mean "my parent". It means "the next class in the MRO of the object". That is why Monthly's super() call reaches Regional, not Report, and why Report runs once rather than twice.

Python multiple inheritance diamond: MonthlyRegional inherits Monthly and Regional, which both inherit Report; the MRO visits each class once

The MRO is a straight line through the diamond: each class appears once, children before parents.

Mixins: small classes that add one ability

The most useful form of multiple inheritance is the mixin: a small class with one or two methods and no __init__, designed to be combined with a main class. The one below adds CSV export using csv.DictWriter, covered in Python CSV files.

Python
import csv, io

class CsvExportMixin:
    def to_csv(self):
        out = io.StringIO()
        writer = csv.DictWriter(out, fieldnames=list(self.rows[0]))
        writer.writeheader()
        writer.writerows(self.rows)
        return out.getvalue()

class Report:
    def __init__(self, title, rows):
        self.title, self.rows = title, rows

class ExportableReport(CsvExportMixin, Report):
    pass

r = ExportableReport("Top cities", [{"city": "Indore", "orders": 412},
                                    {"city": "Bhopal", "orders": 298}])
print(r.to_csv())

Quick check

For class C(A, B), where A and B both inherit from Base, what is the MRO?

Inheritance vs composition

Inheritance models "is a": a GST report is a report. Composition models "has a": a report has a formatter. With composition, you store another object as an attribute and call it, instead of inheriting from it.

Python
class RupeeFormatter:
    def fmt(self, amount):
        return f"Rs {amount:,.2f}"

class Report:
    def __init__(self, rows, formatter):
        self.rows = rows
        self.formatter = formatter        # has-a, not is-a

    def render(self):
        return self.formatter.fmt(sum(self.rows))

print(Report([145000, 98050.5], RupeeFormatter()).render())

Composition lets you swap the formatter without touching Report. A useful rule: if you cannot honestly say "child is a parent", or you inherit only to borrow one method, choose composition.

Common mistakes with inheritance

  • Not calling super().__init__(). The parent's attributes never exist.
  • Calling Parent.method(self) directly in multiple inheritance. It skips classes in the MRO. Use super().
  • Deep chains. Five levels of reports are hard to debug. Keep hierarchies shallow.
  • Inheriting to reuse one helper. That is a "has-a" case. Use composition or a plain function.
  • Changing the meaning of an overridden method. If total() returns rupees in the parent, it should not return a count in the child.

Key takeaways

  • A child class inherits every attribute and method of its parent.
  • Override by defining a method with the same name in the child.
  • super() calls the next class in the MRO, usually the parent.
  • Always call super().__init__() when the child defines __init__.
  • The MRO lists children before parents and keeps your left-to-right order.
  • Prefer composition when the relationship is "has a", not "is a".

The next lesson, Python polymorphism, shows how overridden methods let one piece of code work with many classes. Structuring report code with base classes and mixins is part of the project work in the Python and reporting modules of Debugshala's analytics course.

Take the free Python Programming quiz10 quick questions with explanations. No sign-up needed, and you can come back to this lesson after.

FAQ

What is inheritance in Python with an example?

Inheritance lets one class reuse another's code. In class SalesReport(Report):, SalesReport is the child and Report is the parent. A SalesReport object can call every method defined in Report, such as total(), and the child can add new methods or override existing ones with its own versions.

What is the use of super() in Python?

super() calls a method from the next class in the method resolution order, usually the parent. Its most common use is super().__init__(...) inside a child's __init__, so the parent's attributes are set up before the child adds its own. It also lets an overriding method extend, rather than replace, the parent's result.

Does Python support multiple inheritance?

Yes. A class can inherit from several parents, as in class ExportableReport(CsvExportMixin, Report). Python resolves name conflicts with the method resolution order, which you can inspect through ClassName.__mro__. Multiple inheritance works best for small mixin classes that each add one ability.

What is the difference between inheritance and composition?

Inheritance creates an "is-a" link: the child is a specialised version of the parent and shares its interface. Composition creates a "has-a" link: one object holds another as an attribute and delegates work to it. Composition is usually more flexible, because you can swap the inner object without changing the outer class.

How can I practise Python inheritance for interviews?

Interviewers often ask you to predict MRO output or spot a missing super() call. Rewrite the examples above with your own classes, then solve inheritance and OOP quizzes on Debugshala Test. Debugshala's Old Palasia campus in Indore also runs a free demo class for its data analytics course.

From the team behind this site

Go further with the Data Analytics Course at Debugshala

These tutorials are written by Debugshala, a training and placement institute at Old Palasia, Indore. The classroom course adds live mentoring, real projects and interview preparation.

  • Offline classes at Old Palasia, Indore
  • Free demo class before you pay
  • Non-IT, fresher and year-gap friendly
  • Placement assistance

700+ students placed · 200+ hiring partners · 4.9★ Google rating

Python Classes and Objects: __init__, self, Attributes, MethodsPython Polymorphism: Duck Typing, Method Overriding and ABCs