0% found this document useful (0 votes)
3 views9 pages

Python Phase3 Lesson12 Inheritance

This document provides a comprehensive guide on inheritance in Python, explaining how child classes can inherit attributes and methods from parent classes. It covers key concepts such as method overriding, polymorphism, and the use of super() to access parent methods. Additionally, it includes practical examples and common mistakes to avoid when implementing inheritance in object-oriented programming.

Uploaded by

drk6284
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views9 pages

Python Phase3 Lesson12 Inheritance

This document provides a comprehensive guide on inheritance in Python, explaining how child classes can inherit attributes and methods from parent classes. It covers key concepts such as method overriding, polymorphism, and the use of super() to access parent methods. Additionally, it includes practical examples and common mistakes to avoid when implementing inheritance in object-oriented programming.

Uploaded by

drk6284
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd

Python Mastery — Phase 3: Object-Oriented Programming Inheritance

Python Mastery
Phase 3, Lesson 12 — Inheritance
A complete beginner's guide · Written for 10th grade and up

What you learned in Lesson 11: classes and objects — class definitions, __init__, self, instance and
class attributes, and instance methods. Today you learn inheritance — how one class can build on
another, getting all its features for free and adding or changing what it needs.

1. What is inheritance?
Inheritance lets a child class automatically receive all the attributes and methods of a parent class. The
child can then add new features or change existing ones — without touching or duplicating the parent's
code.

Real-life analogy
Think of a job description at a company.
'Manager' inherits all the responsibilities of 'Employee' — name, ID, salary, clock_in().
'Manager' then adds extra responsibilities: approve_leave(), performance_review().
You don't rewrite the Employee description inside Manager. You just say 'Manager is an
Employee, plus...'

The problem inheritance solves


# Without inheritance — repeated code
class Dog:
def __init__(self, name, age):
[Link] = name
[Link] = age
def describe(self):
return f'{[Link]}, age {[Link]}'

class Cat:
def __init__(self, name, age): # IDENTICAL to Dog
[Link] = name
[Link] = age
def describe(self): # IDENTICAL to Dog
return f'{[Link]}, age {[Link]}'

# With inheritance — write once, reuse everywhere


class Animal:
def __init__(self, name, age):
[Link] = name
[Link] = age

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 1


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

def describe(self):
return f'{[Link]}, age {[Link]}'

class Dog(Animal): # inherits everything


def fetch(self): # adds new behaviour
print(f'{[Link]} fetches!')

class Cat(Animal):
def purr(self):
print(f'{[Link]} purrs...')

2. Key terms and concepts


Term Meaning Example
Parent class The class being inherited from class Animal:

Child class The class that inherits class Dog(Animal):

Inheritance Child gets all parent attrs and Dog gets name, age, describe()
methods
super() Calls the same method on the super().__init__(name, age)
parent
Override Child redefines a method from the def speak(self): return
parent 'Woof!'

Polymorphism Same method call, different [Link]() -> 'Woof!' or


behaviour 'Meow!'

isinstance() True if obj is that class or any parent isinstance(dog, Animal) ->
True

issubclass() True if class inherits from another issubclass(Dog, Animal) ->


True

What a child class inherits


What Inherited? Notes
Instance attributes (self.x) Yes Child calls super().__init__() to get them
Instance methods Yes Child can override any method by redefining
it
Class attributes Yes Shared — child can access [Link]
__init__ Yes Override by defining your own __init__ +
super()
Private attrs (__x) No Name-mangled — not accessible in child
directly

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 2


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

3. Basic inheritance — using the parent as-is


The simplest form of inheritance: the child class adds new methods but uses everything from the parent
unchanged. The parent's __init__ runs automatically if the child has no __init__ of its own.

class Animal:
def __init__(self, name, age):
[Link] = name
[Link] = age

def describe(self):
return f'{[Link]}, age {[Link]}'

class Dog(Animal): # inherits __init__ and describe()


def fetch(self): # Dog's own method
print(f'{[Link]} fetches the ball!')

class Cat(Animal):
def purr(self):
print(f'{[Link]} purrs...')

dog = Dog('Rex', 3) # uses Animal's __init__


print([Link]()) # Rex, age 3 — Animal's method
[Link]() # Rex fetches the ball!

cat = Cat('Bella', 5)
print([Link]()) # Bella, age 5
[Link]() # Bella purrs...

4. super() — calling the parent's methods


When a child class needs its own __init__ (because it has extra attributes), it must also call the parent's
__init__ to set up the inherited attributes. super() is how you do this cleanly.

Always call super().__init__() first


Call super().__init__() as the FIRST line inside your child's __init__.
This runs the parent's __init__, setting up all inherited attributes.
Then add your child's extra attributes below it.
If you forget super(), attributes like [Link] and [Link] are never created.

super().__init__() in action
class Animal:
def __init__(self, name, age):
[Link] = name
[Link] = age

class Dog(Animal):
def __init__(self, name, age, breed):
super().__init__(name, age) # sets [Link], [Link]

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 3


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

[Link] = breed # Dog's extra attribute

def describe(self):
return f'{[Link]} ({[Link]}), age {[Link]}'

dog = Dog('Rex', 3, 'Labrador')


print([Link]) # Rex — set by Animal.__init__
print([Link]) # Labrador — set by Dog.__init__
print([Link]()) # Rex (Labrador), age 3

super() in other methods — not just __init__


class Animal:
def describe(self):
return f'Name: {[Link]}, Age: {[Link]}'

class Dog(Animal):
def describe(self):
base = super().describe() # get parent's text
return base + f', Breed: {[Link]}' # add to it

dog = Dog('Rex', 3, 'Labrador')


print([Link]())
# Name: Rex, Age: 3, Breed: Labrador

5. Method overriding and polymorphism


When a child class defines a method with the same name as one in the parent, the child's version
replaces the parent's version for that class. This is called method overriding. When different child
classes override the same method differently, it is called polymorphism.

Pattern Use when Code


No override Parent version is fine as-is class Dog(Animal): pass

Full override Child needs completely def speak(self): return


different logic 'Woof!'

Extend with super() Child wants parent's output + base = super().method();


more return base + '...'

Polymorphism in action
class Animal:
def __init__(self, name):
[Link] = name

def speak(self): # parent — generic


return f'{[Link]} makes a sound.'

class Dog(Animal):
def speak(self): # overrides parent
return f'{[Link]} says: Woof!'
Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 4
Python Mastery — Phase 3: Object-Oriented Programming Inheritance

class Cat(Animal):
def speak(self): # overrides parent
return f'{[Link]} says: Meow!'

class Fish(Animal):
pass # no override — uses parent

animals = [Dog('Rex'), Cat('Bella'), Fish('Nemo')]

for a in animals:
print([Link]())

# Output:
# Rex says: Woof!
# Bella says: Meow!
# Nemo makes a sound.

Polymorphism — the big idea


The same line of code — [Link]() — does different things depending on the type of a.
You do not need to check what type a is. You just call speak() and Python figures it out.
This lets you write one loop that handles Dog, Cat, Fish, and any future animal you add.
You never have to change the loop — just add a new class with a speak() method.

6. isinstance() and issubclass()


These two built-in functions let you check class relationships at runtime. isinstance() checks whether an
object belongs to a class or any of its parents. issubclass() checks whether one class inherits from
another.

class Animal: pass


class Dog(Animal): pass
class Cat(Animal): pass

rex = Dog()

# isinstance — checks object type (includes parent classes)


print(isinstance(rex, Dog)) # True — rex is a Dog
print(isinstance(rex, Animal)) # True — Dog inherits from Animal
print(isinstance(rex, Cat)) # False — rex is not a Cat

# issubclass — checks class hierarchy


print(issubclass(Dog, Animal)) # True — Dog inherits Animal
print(issubclass(Cat, Dog)) # False — Cat does not inherit Dog
print(issubclass(Animal, Animal))# True — a class is a subclass of itself

Practical use — filtering by type


animals = [Dog('Rex'), Cat('Bella'), Dog('Max'), Cat('Luna')]

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 5


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

# Filter only dogs


dogs = [a for a in animals if isinstance(a, Dog)]
print(f'Dogs: {len(dogs)}') # Dogs: 2

# Call type-specific methods safely


for a in animals:
if isinstance(a, Dog):
[Link]() # only dogs have fetch()

7. Full worked example — Bank account hierarchy


This is the most important example in the lesson. BankAccount is the parent. SavingsAccount and
CurrentAccount are children that inherit the core logic but add or override behaviour as needed.

class BankAccount:
def __init__(self, owner, balance=0):
[Link] = owner
[Link] = balance

def deposit(self, amount):


if amount <= 0:
raise ValueError('Deposit must be positive')
[Link] += amount
print(f'Deposited {amount}. Balance: {[Link]}')

def withdraw(self, amount): # parent version


if amount > [Link]:
print('Insufficient funds')
else:
[Link] -= amount
print(f'Withdrew {amount}. Balance: {[Link]}')

def statement(self):
print(f'{type(self).__name__} — {[Link]}: Rs {[Link]}')

class SavingsAccount(BankAccount):
def __init__(self, owner, balance=0, rate=0.04):
super().__init__(owner, balance) # set owner and balance
[Link] = rate # extra: interest rate

def add_interest(self): # new method


interest = [Link] * [Link]
[Link] += interest
print(f'Interest added: Rs {interest:.2f}')

class CurrentAccount(BankAccount):
def __init__(self, owner, balance=0, overdraft=500):
super().__init__(owner, balance)
[Link] = overdraft

def withdraw(self, amount): # OVERRIDES parent withdraw


limit = [Link] + [Link]
if amount > limit:

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 6


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

print('Overdraft limit exceeded')


else:
[Link] -= amount
print(f'Withdrew {amount}. Balance: {[Link]}')

# Using the hierarchy


savings = SavingsAccount('Arun', 10000)
current = CurrentAccount('Priya', 500, overdraft=1000)

[Link](2000)
savings.add_interest() # 4% of 12000 = 480
[Link]()

[Link](900) # allowed — uses overdraft


[Link]()

print(isinstance(savings, BankAccount)) # True


print(isinstance(current, SavingsAccount)) # False

# Output:
# Deposited 2000. Balance: 12000
# Interest added: Rs 480.00
# SavingsAccount — Arun: Rs 12480
# Withdrew 900. Balance: -400
# CurrentAccount — Priya: Rs -400
# True
# False

8. Common mistakes

Mistake 1 — Forgetting super().__init__() in the child


class Dog(Animal):
def __init__(self, name, age, breed):
[Link] = breed # name and age are NEVER SET

Fix: call super().__init__(name, age) as the FIRST line.

Mistake 2 — Passing self to super().__init__()


Wrong: super().__init__(self, name, age) <- TypeError, extra argument
Right: super().__init__(name, age) <- self is passed automatically
super() already knows which object to use. Never pass self to it.

Mistake 3 — Overriding without calling super() when you need parent behaviour
If you override a method and also need the parent's logic, call super().method().
Without it, the parent's logic is completely replaced — sometimes that's right,
sometimes you lose important setup. Think before you override.

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 7


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

Mistake 4 — Using type(obj) == Dog instead of isinstance()


type(dog) == Dog is True but type(dog) == Animal is False.
isinstance(dog, Animal) correctly returns True because of inheritance.
Always use isinstance() — it respects the inheritance chain.

9. Practice exercises
All four exercises build real class hierarchies. Exercise 4 is the most complete — a full OOP
application.

Exercise 1 — Shape hierarchy


Create a parent Shape class with colour and a describe() method. Create Circle (adds radius, overrides
area() and perimeter()) and Rectangle (adds width and height, overrides area() and perimeter()). Use
[Link] for circles.

Exercise 2 — Employee hierarchy


Create an Employee parent class with name, id, and salary. Create Manager (adds team_size,
overrides describe() to include team info) and Developer (adds language, overrides describe()). Both
call super().describe() and extend it.

Exercise 3 — Vehicle hierarchy


Create a Vehicle parent with make, model, year, and a start() method. Create ElectricVehicle (adds
battery_range, overrides start() to say 'silent start') and PetrolVehicle (adds fuel_type, overrides start()
with engine noise). Use isinstance() to count EVs in a list.

Exercise 4 — Animal shelter


Build an animal shelter. Animal is the parent (name, age, adopted=False). Dog and Cat inherit from it.
Dog adds breed and can_fetch. Cat adds indoor_only. Add an adopt() method to Animal. Write a
shelter function that prints all unadopted animals, grouped by type using isinstance().

10. Quick reference card

# === basic inheritance ===


class Parent:
def __init__(self, x):
self.x = x
def method(self):
return self.x

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 8


Python Mastery — Phase 3: Object-Oriented Programming Inheritance

class Child(Parent): # inherit from Parent


def extra(self): # new method
return self.x * 2

# === child with own __init__ ===


class Child(Parent):
def __init__(self, x, y):
super().__init__(x) # ALWAYS call this first
self.y = y # then add child attributes

# === method overriding ===


class Child(Parent):
def method(self): # replaces parent's method
return self.x + 100

# === extend parent method ===


class Child(Parent):
def method(self):
base = super().method() # get parent's result
return base + ' extra' # add to it

# === isinstance and issubclass ===


isinstance(obj, Class) # True if obj is Class or child
issubclass(Child, Parent) # True if Child inherits Parent

# === polymorphism pattern ===


objects = [Dog('Rex'), Cat('Bella'), Fish('Nemo')]
for o in objects:
print([Link]()) # each calls its own version

What comes next?


You have completed Lesson 12 of Phase 3. Two lessons remain before the capstone:

• Lesson 13 — Special methods (dunder methods): __str__, __len__, __add__, __eq__ —


making your objects respond to print(), len(), + and == like built-in types
• Lesson 14 — Modules, packages, and list comprehensions
• Lesson 15 — Phase 3 capstone: a full OOP bank account system

YouTube tip
Record yourself building the BankAccount hierarchy — parent first, then both children.
Show what happens when you forget super().__init__() — the AttributeError is the content.
Then show the polymorphism loop: one line of code, three different outputs.
Title idea: 'Python inheritance explained by building a real bank — 10 minutes.'

Inheritance means never having to write the same code twice. Build the parent right, and everything
else follows.

Beginner's Python Notes | Phase 3 of 5 — Lesson 12 | Page 9

You might also like