Board Formulas
🐍 PythonπŸ“… Day 20

Inheritance in Python

Reuse and extend classes with inheritance: single, multilevel and multiple inheritance, super(), and method overriding.

🎯

Learning objectives

  • β†’Create a child class that inherits from a parent class
  • β†’Call the parent's __init__ and methods with super()
  • β†’Override a method to change its behaviour in a child class
  • β†’Recognise single, multilevel and multiple inheritance, and check relationships with isinstance() and issubclass()

πŸ’‘ Key points

  • Inheritance lets a new class (child or subclass) reuse the attributes and methods of an existing class (parent or base class).
  • Syntax: class Child(Parent): β€” the parent class goes in the brackets. A child IS-A kind of parent: a Student is a Person.
  • super().__init__(...) runs the parent's constructor so the parent's attributes get set up too.
  • Overriding: a method in the child with the same name as one in the parent replaces it for child objects.
  • Single: one parent. Multilevel: a chain, A β†’ B β†’ C. Multiple: one child with two or more parents, class C(A, B).
  • Python looks for a method in the object's own class first, then in its parents from left to right. This search order is the MRO.
  • isinstance(obj, Class) and issubclass(Child, Parent) check relationships. Every class ultimately inherits from object.

πŸ’» Code examples(6)

#1Single inheritance
python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def introduce(self):
        print(f"I am {self.name}, {self.age} years old")

class Student(Person):     # Student IS-A Person
    pass

s = Student("Amit", 16)
s.introduce()              # inherited method
print(s.name)
Output
I am Amit, 16 years old
Amit
Student has no code of its own, yet it gets __init__ and introduce() from Person. pass just means 'nothing extra here'.
#2super() and new attributes
python
# uses the Person class from example 1
class Student(Person):
    def __init__(self, name, age, roll, marks):
        super().__init__(name, age)  # parent's part
        self.roll = roll             # Student's part
        self.marks = marks

    def result(self):
        return "Pass" if self.marks >= 33 else "Fail"

s = Student("Priya", 17, 12, 88)
s.introduce()
print(s.roll, s.marks, s.result())
Output
I am Priya, 17 years old
12 88 Pass
The child adds its own attributes and methods, but lets Person set name and age instead of repeating that code.
#3Method overriding
python
# uses the Person class from example 1
class Teacher(Person):
    def __init__(self, name, age, subject):
        super().__init__(name, age)
        self.subject = subject

    def introduce(self):             # overrides
        super().introduce()          # parent's version
        print(f"I teach {self.subject}")

people = [Person("Ravi", 15),
          Teacher("Mrs. Sharma", 42, "Physics")]
for p in people:
    p.introduce()
Output
I am Ravi, 15 years old
I am Mrs. Sharma, 42 years old
I teach Physics
The same call, p.introduce(), does different things depending on the object's class. That is polymorphism, one of the OOP pillars from Day 10.
#4Multilevel inheritance
python
class Animal:
    def __init__(self, name):
        self.name = name
    def breathe(self):
        return f"{self.name} breathes"

class Mammal(Animal):
    def feed(self):
        return f"{self.name} drinks milk as a baby"

class Dog(Mammal):
    def sound(self):
        return f"{self.name} says Woof"

d = Dog("Moti")
print(d.breathe())     # from Animal
print(d.feed())        # from Mammal
print(d.sound())       # its own
print(isinstance(d, Animal), issubclass(Dog, Mammal))
Output
Moti breathes
Moti drinks milk as a baby
Moti says Woof
True True
Dog inherits from Mammal, which inherits from Animal, so a Dog object can use methods from every level of the chain.
#5Multiple inheritance and the MRO
python
class Father:
    def drive(self):
        return "can drive"
    def hobby(self):
        return "gardening"

class Mother:
    def cook(self):
        return "can cook"
    def hobby(self):
        return "painting"

class Child(Father, Mother):
    pass

c = Child()
print(c.drive(), "and", c.cook())
print(c.hobby())         # Father is listed first
print([k.__name__ for k in Child.__mro__])
Output
can drive and can cook
gardening
['Child', 'Father', 'Mother', 'object']
Child gets methods from both parents. When both define hobby(), the parent listed first in class Child(Father, Mother) wins.
#6Bank accounts: overriding with super()
python
class Account:
    def __init__(self, holder, balance=0):
        self.holder = holder
        self.balance = balance

    def withdraw(self, amt):
        if amt > self.balance:
            print("Insufficient balance")
        else:
            self.balance -= amt
            print(f"Withdrew β‚Ή{amt}, left β‚Ή{self.balance}")

class SavingsAccount(Account):
    MIN_BALANCE = 500

    def withdraw(self, amt):
        if self.balance - amt < self.MIN_BALANCE:
            print(f"Must keep β‚Ή{self.MIN_BALANCE}")
        else:
            super().withdraw(amt)

    def __str__(self):
        return f"{self.holder}: β‚Ή{self.balance}"

s = SavingsAccount("Amit", 2000)
s.withdraw(1200)
s.withdraw(400)
print(s)
Output
Withdrew β‚Ή1200, left β‚Ή800
Must keep β‚Ή500
Amit: β‚Ή800
SavingsAccount adds one extra rule, then hands the real work to the parent with super().withdraw(). The parent's code is reused, not copied.

🎯 Practice

Q1. What is printed? class A: def show(self): print('A') class B(A): def show(self): print('B') B().show()+

B. B overrides show(), so its own version runs.

Q2. What does super().__init__(name) do inside a child class's __init__?+

It calls the parent class's __init__, so the parent's attributes (here, name) are set up on the new object.

Q3. class A: ..., class B(A): ..., class C(B): ... β€” which type of inheritance is this?+

Multilevel inheritance: C inherits from B, which inherits from A.

Q4. In class C(A, B), both A and B define greet(). Which one does C().greet() run?+

A's greet(). Python searches the parents from left to right, and A is listed first.

Q5. Using the Rectangle class from Day 10, write a Square class that only needs one side length.+

class Square(Rectangle): def __init__(self, side): super().__init__(side, side) print(Square(4).area()) # 16

πŸ“ Notes

Types of inheritance

Single        Multilevel      Multiple       Hierarchical

  A              A            A     B             A
  |              |             \   /            /   \
  B              B               C             B     C
                 |
                 C
  • Single: class B(A)
  • Multilevel: class B(A) and class C(B)
  • Multiple: class C(A, B)
  • Hierarchical: several children of one parent, such as Student(Person) and Teacher(Person) in today's examples

Overriding is not overloading

Some languages let you write two methods with the same name but different parameters (overloading). Python does not: if a class defines the same method name twice, the last definition simply replaces the first. Use default arguments (Day 9) instead.

Checking what an object is

t = Teacher("Mrs. Sharma", 42, "Physics")
print(isinstance(t, Teacher))       # True
print(isinstance(t, Person))        # True
print(issubclass(Person, Teacher))  # False

A Teacher is a Person, but a Person is not necessarily a Teacher.

Common mistakes

  • Forgetting super().init(): if the child defines its own __init__ without calling the parent's, attributes like self.name are never created, and using them raises AttributeError: 'Student' object has no attribute 'name'.
  • Passing self to super(): write super().__init__(name), not super().__init__(self, name).
  • Misspelling an overriding method: def introduse(self) adds a new method; the parent's introduce() still runs.
  • Using inheritance for "has-a" relationships: a Car has an Engine, it is not a kind of Engine. Store an Engine object as an attribute instead.

Next: practise days 11–20 together by building a small student record system that uses classes, a dictionary, exception handling and a CSV file.