Python Inheritance
1Python Inheritance: overview
Inheritance lets a new class (the child) start with all the attributes and methods of an existing class (the parent) and then add to them or change them, so shared code is written only once.
Before this lesson: Python Functions, Python Classes and Objects
2Python Inheritance: diagram
3Python Inheritance: explained step by step
When several classes need the same attributes and methods, copying that code into each one makes every later change painful. Inheritance lets you write the shared part once in a parent class (also called a base class or superclass) and build child classes (subclasses) on top of it.
Creating a child class
Put the parent's name in parentheses after the child's name. The child immediately has every method of the parent, even if its own body is empty:
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
class Dog(Animal):
pass
rex = Dog("Rex")
print(rex.speak())
print(isinstance(rex, Animal))Overriding a method
If the child defines a method with the same name as one in the parent, the child's version wins for child objects. This is called overriding. Python searches for a method in the object's own class first and only moves up to the parent when it doesn't find it there.
Extending __init__ with super()
Often a child needs everything the parent's __init__ does plus a few extra attributes. Instead of copying the parent's lines, call super().__init__(...). It runs the parent's version on the same object; then you add your own attributes:
class Cat(Animal):
def __init__(self, name, indoor):
super().__init__(name) # the parent sets self.name
self.indoor = indoor # the child adds its own attribute
If a child defines __init__ and forgets to call super().__init__(), the parent's setup never runs and attributes like self.name simply won't exist. You can use super() in any method, not just __init__, to build on the parent's version instead of replacing it.
Polymorphism
Polymorphism means "many forms": different classes provide a method with the same name, so one piece of code can work with all of them. The loop below doesn't care which kind of shape it gets — it just calls area(), and each object runs its own version:
class Shape:
def area(self):
return 0
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return round(3.14159 * self.radius ** 2, 2)
for shape in [Square(3), Circle(1), Shape()]:
print(type(shape).__name__, shape.area())Checking types with isinstance()
isinstance(obj, SomeClass) returns True if obj was made from that class or from any of its children. A Square is a Shape, but a plain Shape is not a Square.
Encapsulation by convention
Python has no truly private attributes. Instead, a name that starts with one underscore, like self._balance, means "internal detail — please use the methods instead". Python won't stop anyone from touching it; it is an agreement between programmers.
When to use inheritance
Use it for genuine "is a" relationships: a Manager is an Employee. When one thing merely has another — a car has an engine — store the other object as an attribute instead.
Quick reference: Python Inheritance
- Python OOP Cheat Sheet: Classes, Inheritance, Dunder Methods — In Python OOP you define a `class` as a blueprint, build objects with it, store data in attributes set in `__…
- Python isinstance() Function — `isinstance(obj, classinfo)` returns `True` if `obj` is an instance of the class (or of any class in a tuple …
4Python Inheritance: syntax
class Parent:
def __init__(self, a):
self.a = a
def method(self):
return "parent version"
class Child(Parent): # Child inherits from Parent
def __init__(self, a, b):
super().__init__(a) # run Parent's __init__ first
self.b = b # then add something new
def method(self): # override the parent's method
return "child + " + super().method()
isinstance(Child(1, 2), Parent) # True
5Python Inheritance: run the example
Press Run (or Ctrl + Enter). The output (step 6) appears directly below the code. Change anything and run it again.
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def yearly_pay(self):
return self.salary * 12
class Manager(Employee):
def __init__(self, name, salary, bonus):
super().__init__(name, salary)
self.bonus = bonus
def yearly_pay(self):
return super().yearly_pay() + self.bonus
staff = [Employee("Asha", 3000), Manager("Ben", 4000, 5000)]
for person in staff:
print(person.name, person.yearly_pay(), isinstance(person, Manager))
print("Is Ben an Employee?", isinstance(staff[1], Employee))Expected outputAsha 36000 False
Ben 53000 True
Is Ben an Employee? True
7Python Inheritance: how the example works
Hover or tap a step to highlight its lines in the example above.
- Line 1-4The parent class
Employeestores a name and a monthly salary on every new object. - Line 6-7
yearly_pay()returns twelve months of salary. Every employee — and every child class — gets this method. - Line 9
class Manager(Employee):creates a child class. AManagerautomatically has everything anEmployeehas. - Line 10-12
Managerneeds an extrabonus, so it defines its own__init__.super().__init__(name, salary)runs the parent's setup, then the child addsself.bonus. - Line 14-15The child overrides
yearly_pay(). Instead of repeating the maths, it calls the parent's version withsuper().yearly_pay()and adds the bonus. - Line 17One list holds both kinds of objects.
- Line 18-19Polymorphism: the same call
person.yearly_pay()runsEmployee's version for Asha (36000) andManager's version for Ben (48000 + 5000).isinstanceshows which objects are managers. - Line 20A
Manageris also anEmployee, becauseisinstance()counts parent classes too.
8Python Inheritance: common mistakes
Forgetting to call super().__init__()
✗ Wrong
class Vehicle:
def __init__(self, wheels):
self.wheels = wheels
class Bike(Vehicle):
def __init__(self, brand):
self.brand = brand
trek = Bike("Trek")
print(trek.wheels)✓ Right
class Vehicle:
def __init__(self, wheels):
self.wheels = wheels
class Bike(Vehicle):
def __init__(self, brand):
super().__init__(2)
self.brand = brand
trek = Bike("Trek")
print(trek.wheels)The child's __init__ replaces the parent's, so the parent's setup never ran. Call super().__init__(...) inside the child's __init__.
Passing self to super().__init__()
✗ Wrong
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name):
super().__init__(self, name)
rex = Dog("Rex")✓ Right
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name):
super().__init__(name)
rex = Dog("Rex")
print(rex.name)super() already knows which object it is working on, so self is passed automatically. Pass only the other arguments.
Misspelling the method you meant to override
✗ Wrong
class Shape:
def area(self):
return 0
class Square(Shape):
def __init__(self, side):
self.side = side
def Area(self):
return self.side ** 2
print(Square(4).area())✓ Right
class Shape:
def area(self):
return 0
class Square(Shape):
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
print(Square(4).area())Overriding only happens when the names match exactly (Python is case-sensitive). Area is a brand-new method, so area() still comes from Shape.
9Python Inheritance: exercises
Write your answer, then press Check. The checks run in your browser.
1. Create a Cat class
Write code Easy ✓ CompletedCreate a class Cat that inherits from Animal and overrides speak() so it returns "<name> says meow" — for example "Tom says meow". Do not change Animal.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
# create class Cat here
kitty = Cat("Tom")
print(kitty.speak())
class Cat(Animal): and define only speak(self). The __init__ from Animal is inherited automatically.class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return f"{self.name} makes a sound"
class Cat(Animal):
def speak(self):
return f"{self.name} says meow"
kitty = Cat("Tom")
print(kitty.speak())
2. Fix the savings account
Fix the bug Medium ✓ CompletedSavingsAccount should have an owner, a balance that starts at 0 and an interest rate. The program crashes with an AttributeError. Fix the child class so the parent's setup runs.
class Account:
def __init__(self, owner):
self.owner = owner
self.balance = 0
class SavingsAccount(Account):
def __init__(self, owner, rate):
self.rate = rate
def add_interest(self):
self.balance += self.balance * self.rate
savings = SavingsAccount("Asha", 0.05)
savings.balance = 200
savings.add_interest()
print(savings.owner, savings.balance)
__init__, which replaces Account.__init__. One line with super() brings the parent's setup back.class Account:
def __init__(self, owner):
self.owner = owner
self.balance = 0
class SavingsAccount(Account):
def __init__(self, owner, rate):
super().__init__(owner)
self.rate = rate
def add_interest(self):
self.balance += self.balance * self.rate
savings = SavingsAccount("Asha", 0.05)
savings.balance = 200
savings.add_interest()
print(savings.owner, savings.balance)
2 more exercises → 4 more examples
Questions learners ask
What does super() do in Python?
super() gives you access to the parent class's methods from inside a child class. super().init(...) runs the parent's setup on the current object, and super().method() calls the parent's version of a method you have overridden, so you can extend it instead of rewriting it.
When should I use inheritance instead of an attribute?
Use inheritance when the child really is a special kind of the parent (a Manager is an Employee) and should work anywhere the parent works. If one object only uses or contains another (a Car has an Engine), store it as an attribute instead; this is called composition and is often simpler.
Does Python have private attributes?
Not truly. A single leading underscore (_balance) is a convention meaning internal, please don't touch. Two leading underscores (__balance) make Python rename the attribute to _ClassName__balance, which avoids accidental clashes in child classes but still isn't real privacy.
Further reading
10Next lesson
Up nextPython Polymorphism and Duck TypingPolymorphism means different kinds of objects respond to the same method call in their own way, and in Python duck typi…Related:
Python Polymorphism and Duck TypingPython Multiple Inheritance and MROPython Composition: Has-A vs Is-A
← Python Dunder (Magic) Methods · All Object-Oriented Python lessons · Practise in the IDE