Python Inheritance: Parent and Child Classes, super() and MRO
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.
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.
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 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.
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?
Defining __init__ in the child replaces the parent's. Call super().__init__() to run the parent's setup.
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.
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.
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.
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?
Children come before parents, and parents keep the order written in the class statement, so Base comes last.
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.
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. Usesuper(). - 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.
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