0% found this document useful (0 votes)
4 views25 pages

3 - Inheritance Python

d

Uploaded by

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

3 - Inheritance Python

d

Uploaded by

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

Module 3: Inheritance

Parent Classes, Child Classes & Code Reuse — Python


Edition

Object-Oriented Programming Fundamentals · Healthcare Domain ·


Beginner Level

OOP FUNDAMENTALS PYTHON HEALTHCARE DOMAIN


The Problem: Code Duplication
Without Inheritance
Imagine building a hospital management
system. A Doctor class and a Nurse class
would both need to repeat the same
attributes and methods — over and over
again.

name, age, and emp_id defined twice


display_info() method copied into
every class

Adding a phone field means editing


every single class
More classes = more duplication =
more bugs

Code duplication is the enemy of


maintainability. One change
should never require updates in
ten places.
The Solution: Inheritance
Inheritance lets a child class automatically receive all the attributes and
methods of a parent class. The child only adds what is new or different.

Define Once Reuse Everywhere


Common attributes like name, Every child class automatically
age, and emp_id live in the inherits all parent attributes and
parent class only. methods without rewriting them.

Extend Freely
Each child adds only what makes it unique — a specialization for
Doctor, a ward for Nurse.

In Python, you declare inheritance by putting the parent class name inside
parentheses: class Doctor(HospitalStaff):
Complete Inheritance Example
HospitalStaff → Doctor & Nurse

class HospitalStaff:
def __init__(self, name, age, emp_id):
[Link] = name
[Link] = age
self.emp_id = emp_id

def display_info(self):
print(f"Name: {[Link]} | Age: {[Link]} | ID: {self.emp_id}")

class Doctor(HospitalStaff): # Inherits from HospitalStaff


def __init__(self, name, age, emp_id, specialization):
super().__init__(name, age, emp_id) # Call parent constructor
[Link] = specialization

def prescribe(self):
print(f"Dr. {[Link]} prescribed medication.")

def display(self):
self.display_info() # Reuse parent method
print(f"Specialization: {[Link]}")

class Nurse(HospitalStaff):
def __init__(self, name, age, emp_id, ward):
super().__init__(name, age, emp_id)
[Link] = ward

def assist_surgery(self):
print(f"{[Link]} is assisting in surgery.")

def display(self):
self.display_info()
print(f"Ward: {[Link]}")

Key Syntax: super().__init__(...) calls the parent's __init__. Always call it in the child's __init__ to ensure parent attributes are
properly initialized. Forgetting super() means the child won't have the parent's attributes.
Running the Example
Creating Objects & Calling Methods Output

d1 = Doctor("Sharma", 45, 1001, "Cardiology") --- Doctor ---


n1 = Nurse("Priya", 30, 2001, "ICU") Name: Sharma | Age: 45 | ID: 1001
Specialization: Cardiology
print("--- Doctor ---") Dr. Sharma prescribed medication.
[Link]()
[Link]() --- Nurse ---
print("\n--- Nurse ---") Name: Priya | Age: 30 | ID: 2001
[Link]() Ward: ICU
n1.assist_surgery() Priya is assisting in surgery.

Inherited from Parent Added by Child


display_info() is defined once in HospitalStaff and reused prescribe() belongs only to Doctor. assist_surgery() belongs
by both Doctor and Nurse without any duplication. only to Nurse. Each child extends the parent uniquely.
Types of Inheritance in Python
Python supports all major forms of inheritance. Understanding each type helps you design clean, scalable class hierarchies.

Python's Method Resolution Order (MRO) handles conflicts in multiple and hybrid inheritance using the C3 linearization algorithm.
Check it with ClassName.__mro__.
Single Inheritance
The Simplest Form — One Child, One Parent

Structure: A → B
One child class inherits from exactly one
parent class. This is the most common
and straightforward form of inheritance.

class Doctor(HospitalStaff):
pass

Even with just pass, the Doctor class


immediately has access to all of
HospitalStaff's attributes and methods.

Single inheritance is the safest


and most readable form. Start
here before exploring more
complex patterns.
Multilevel Inheritance
A Chain: Person → HospitalStaff → Surgeon

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

class HospitalStaff(Person):
def __init__(self, name, age, emp_id):
super().__init__(name, age)
self.emp_id = emp_id

class Surgeon(HospitalStaff):
def __init__(self, name, age, emp_id, specialty):
super().__init__(name, age, emp_id)
[Link] = specialty

def operate(self):
print(f"Dr. {[Link]} ({[Link]}) performing surgery.")

Surgeon
Adds specialty and operate()
method

HospitalStaff
Inherits Person; adds
emp_id
Person
Holds name and age
attributes

Each level in the chain calls super().__init__() to pass attributes up the chain. Surgeon inherits from HospitalStaff, which inherits from
Person — giving Surgeon all three levels of attributes.
Hierarchical Inheritance
Multiple Children, One Shared Parent

Structure: One Parent → Many Children


Multiple child classes all inherit from the same single parent.
Each child gets the parent's attributes and adds its own unique
behavior.

class Doctor(HospitalStaff): pass


class Nurse(HospitalStaff): pass
class Technician(HospitalStaff): pass

All three classes — Doctor, Nurse, and Technician — share the


same HospitalStaff foundation: name, age, emp_id, and
display_info().

This is the most common pattern in real-world


systems. A single base class defines shared behavior
for an entire family of related classes.
Multiple Inheritance
Python Supports Inheriting from Two or More Parents

class Researcher:
def publish_paper(self):
print("Paper published.")

class Clinician:
def treat_patient(self):
print("Patient treated.")

class MedicalProfessor(Researcher, Clinician): # Two parents!


def teach(self):
print("Teaching medical students.")

mp = MedicalProfessor()
mp.publish_paper() # From Researcher
mp.treat_patient() # From Clinician
[Link]() # Own method

From Researcher From Clinician Own Method


publish_paper() — inherited directly treat_patient() — inherited directly teach() — defined in MedicalProfessor
itself

MRO: Python uses the C3 linearization algorithm to resolve method conflicts. Check the order with
MedicalProfessor.__mro__ or [Link]().
Inheritance Types — Summary
Type Structure Python Support

Single A→B ✅ Yes


Multilevel A→B→C ✅ Yes
Hierarchical A → B, A → C ✅ Yes
Multiple A, B → C ✅ Yes (MRO handles conflicts)
Hybrid Mix of above ✅ Yes (MRO handles diamond)
Python is one of the few languages that fully supports multiple inheritance. The Method Resolution Order (MRO) ensures
predictable behavior even in complex diamond inheritance scenarios.
Accessing Parent Members
with super()
Python's super() function returns a proxy object that lets you call the
parent's methods — without hardcoding the parent class name.

Overriding and Extending Why Use super()?


Avoids hardcoding the parent
class HospitalStaff: class name
def display_info(self):
Works correctly with multiple
print("Staff info")
inheritance and MRO
Most critical use:
class Doctor(HospitalStaff):
def display_info(self): # super().__init__() in constructors

Overrides parent Lets you extend parent


super().display_info() # behavior rather than replace it
Call parent version first
print("Plus doctor-specific
Tip: super() also works in
info")
__init__ to call the parent
constructor:
super().__init__(name,
age). This is the most
common and important
use for beginners.
isinstance() and issubclass()
Checking Object Relationships at Runtime

Code Example What Each Function Does

d1 = Doctor("Sharma", 45, 1001, "Cardiology") isinstance(obj, issubclass(Child,


Class) Parent)
print(isinstance(d1, Doctor)) # True
Returns True if obj is an Returns True if Child is a
print(isinstance(d1, HospitalStaff)) # True (parent!)
instance of Class or any subclass of Parent.
print(issubclass(Doctor, HospitalStaff)) # True
of its subclasses. Works Checks class
up the entire inheritance relationships, not object
chain. instances.
Key Insight: isinstance(d1, HospitalStaff) returns True
even though d1 is a Doctor object. A child object IS
an instance of its parent class too.
Constructor Chaining in Inheritance
How super().__init__() Flows Through the Chain

class Person:
def __init__(self, name):
[Link] = name
print(f"1. Person: {[Link]}")

class HospitalStaff(Person):
def __init__(self, name, emp_id):
super().__init__(name)
self.emp_id = emp_id
print(f"2. Staff: ID {self.emp_id}")

class Doctor(HospitalStaff):
def __init__(self, name, emp_id, spec):
super().__init__(name, emp_id)
[Link] = spec
print(f"3. Doctor: {[Link]}")

d = Doctor("Sharma", 1001, "Cardiology")

Output — Execution Order


Warning — #1 Inheritance Mistake: If you forget
super().__init__() in the child, the parent's attributes
1. Person: Sharma
(name, emp_id) will NOT exist on the object. You'll
2. Staff: ID 1001
get an AttributeError at runtime.
3. Doctor: Cardiology

Notice the order: Grandparent first, then Parent, then Child.


Each super().__init__() call triggers the next level up before
continuing.
Constructor Chaining — Visual Flow

Doctor.__init_ HospitalStaff. Person.__init_


_ __init__ _

Each constructor in the chain does its own work and then delegates upward via super(). The chain unwinds from the top (Person)
back down to the bottom (Doctor), setting attributes at each level.

01 02

Doctor.__init__ called HospitalStaff.__init__ called


Receives name, emp_id, spec. Calls super().__init__(name, Receives name, emp_id. Calls super().__init__(name) before
emp_id) before setting [Link]. setting self.emp_id.

03 04

Person.__init__ called Chain unwinds


Receives name. Sets [Link]. No more super() calls — chain Execution returns to HospitalStaff (sets emp_id), then to Doctor
complete. (sets spec). Object is fully initialized.
Exercise 1: Hospital Staff
Hierarchy
Hands-On Practice — HospitalStaff → Doctor & Nurse

Problem: Create HospitalStaff (name, emp_id), Doctor (specialization), and


Nurse (ward). Each has a display() method. Demo with 2 doctors and 1
nurse.
Exercise 1 — Complete Solution
class HospitalStaff:
def __init__(self, name, emp_id):
[Link] = name; self.emp_id = emp_id
def display_info(self):
print(f"Name: {[Link]} | ID: {self.emp_id}")

class Doctor(HospitalStaff):
def __init__(self, name, emp_id, spec):
super().__init__(name, emp_id); [Link] = spec
def display(self):
self.display_info()
print(f"Specialization: {[Link]}")

class Nurse(HospitalStaff):
def __init__(self, name, emp_id, ward):
super().__init__(name, emp_id); [Link] = ward
def display(self):
self.display_info()
print(f"Ward: {[Link]}")

d1 = Doctor("Sharma", 1001, "Cardiology")


d2 = Doctor("Patel", 1002, "Neurology")
n1 = Nurse("Priya", 2001, "ICU")

Expected Output What to Notice

display_info() is defined once in HospitalStaff and reused by


=== Doctors === both children
Name: Sharma | ID: 1001
Each child calls super().__init__() to initialize shared
Specialization: Cardiology
attributes

Name: Patel | ID: 1002 Doctor and Nurse each add only their unique attribute
Specialization: Neurology Both children override display() to show their specific field

=== Nurses ===


This is hierarchical inheritance in action — one
Name: Priya | ID: 2001
parent, two children, zero code duplication for shared
Ward: ICU
behavior.
Exercise 2: Multilevel — Person → Employee →
Manager
Three-Level Constructor Chaining

Problem: Build a three-level inheritance chain with constructor chaining. Show output at each level as objects are created.

class Person:
def __init__(self, name, age):
[Link] = name; [Link] = age
print(f"Person created: {[Link]}")

class Employee(Person):
def __init__(self, name, age, emp_id, salary):
super().__init__(name, age)
self.emp_id = emp_id; [Link] = salary
print(f"Employee created: ID {self.emp_id}")

class Manager(Employee):
def __init__(self, name, age, emp_id, salary, dept, team_size):
super().__init__(name, age, emp_id, salary)
[Link] = dept; self.team_size = team_size
print(f"Manager created: {[Link]}")

def display(self):
print(f"Name: {[Link]} | Age: {[Link]}")
print(f"ID: {self.emp_id} | Salary: {[Link]}")
print(f"Dept: {[Link]} | Team: {self.team_size}")

Creating the Object Output

print("--- Creating Manager ---") --- Creating Manager ---


m = Manager("Sharma", 50, 1001, 150000, "Cardiology", Person created: Sharma
12) Employee created: ID 1001
print("\n--- Details ---") Manager created: Cardiology
[Link]()
--- Details ---
Name: Sharma | Age: 50
ID: 1001 | Salary: 150000
Dept: Cardiology | Team: 12

Notice the print statements fire from the top of the chain downward — Person first, then Employee, then Manager. This
confirms the order in which super().__init__() calls execute.
Exercise 3: Vehicle Fleet
Mixed Practice — Ambulance & SupplyTruck

Problem: Build a Vehicle base class (brand, year). Create Ambulance (hospital, siren_on) and SupplyTruck (cargo) as children.
Implement activate_siren() and load_cargo(kg).

class Vehicle:
def __init__(self, brand, year):
[Link] = brand; [Link] = year
def show_vehicle(self):
print(f"{[Link]} ({[Link]})")

class Ambulance(Vehicle):
def __init__(self, brand, year, hospital):
super().__init__(brand, year)
[Link] = hospital; self.siren_on = False
def activate_siren(self):
self.siren_on = True
print(f"{[Link]} siren ACTIVATED for {[Link]}")
def display(self):
self.show_vehicle()
print(f"Hospital: {[Link]} | Siren: {'ON' if self.siren_on else 'OFF'}")

class SupplyTruck(Vehicle):
def __init__(self, brand, year):
super().__init__(brand, year); [Link] = 0
def load_cargo(self, kg):
[Link] += kg
print(f"{[Link]} loaded {kg} kg (Total: {[Link]} kg)")
def display(self):
self.show_vehicle()
print(f"Cargo: {[Link]} kg")
Exercise 3 — Running the Fleet
Demo Code

a1 = Ambulance("Tata Winger", 2023,


"City General")
a1.activate_siren()
t1 = SupplyTruck("Mahindra Bolero",
2022)
t1.load_cargo(250); t1.load_cargo(150)

print("\n--- Fleet Status ---")


[Link](); print(); [Link]()

Expected Output

Tata Winger siren ACTIVATED for City


General
Mahindra Bolero loaded 250 kg
(Total: 250 kg)
Mahindra Bolero loaded 150 kg
(Total: 400 kg) Key Observations: siren_on starts as False and is toggled by
activate_siren(). Cargo accumulates across multiple load_cargo() calls.
--- Fleet Status --- Both children reuse show_vehicle() from Vehicle.
Tata Winger (2023)
Hospital: City General | Siren: ON

Mahindra Bolero (2022)


Cargo: 400 kg
Common Mistakes & How to
Avoid Them
❌ Forgetting super().__init__()
The #1 inheritance mistake. Without it, the parent's attributes are never
set. Any access to [Link] or self.emp_id will raise an AttributeError
at runtime.

❌ Wrong Argument Order in super()


The arguments passed to super().__init__() must match the parent's
__init__ signature exactly. Passing them in the wrong order silently
assigns wrong values.

❌ Hardcoding the Parent Class Name


Writing HospitalStaff.__init__(self, name) instead of
super().__init__(name) breaks multiple inheritance and MRO. Always
use super().

❌ Calling super() After Setting Child Attributes


Always call super().__init__() first in the child constructor. Setting child
attributes before the parent is initialized can cause subtle bugs.
Quick Reference — Syntax at a Glance
Core Inheritance Syntax All Inheritance Patterns

class Parent: # Single


def __init__(self, x): class B(A): pass
self.x = x
# Multilevel
class Child(Parent): # Inherits from Parent class C(B): pass # C inherits B inherits A
def __init__(self, x, y):
super().__init__(x) # Call parent constructor # Hierarchical
self.y = y class B(A): pass
class C(A): pass
def show(self):
super().show() # Call parent method # Multiple
class C(A, B): pass # MRO resolves conflicts

Checking Relationships

You can always verify the MRO with


isinstance(obj, Parent) # True for child objects too
print([Link]()) to see exactly which class
issubclass(Child, Parent) # True
Python will look in first when resolving a method call.
ClassName.__mro__ # View method resolution order
Key Concepts Summary
Concept Remember This

Inheritance class Child(Parent): — child gets all parent members automatically

super() Calls parent methods/constructor; always use in __init__

Constructor order Grandparent → Parent → Child (via super() chain)

Single class B(A): — one parent, simplest form

Multilevel A → B → C — chain of super() calls at each level

Multiple class C(A, B): — Python supports; MRO resolves conflicts

isinstance() isinstance(obj, Parent) returns True for child objects too

#1 Mistake Forgetting super().__init__() — parent attrs won't exist


Inheritance vs. No Inheritance
The Before and After of Good OOP Design

The DRY Principle


Don't Repeat Yourself. Inheritance is one of the most powerful
tools for achieving DRY code in object-oriented programming.

Single source of truth One change, everywhere Fewer bugs, easier testing
Shared attributes and methods live updated Less duplicated code means
in exactly one place — the parent Add a phone field to HospitalStaff fewer places for bugs to hide and
class. and every child class gets it fewer tests to write.
instantly.
Module 3 — Wrap Up
What You've Learned: Inheritance in Python

Inheritance Basics Four Types


Child classes inherit all parent attributes and methods. Use Single, Multilevel, Hierarchical, and Multiple inheritance —
class Child(Parent): syntax. Only define what's new or Python supports all of them. MRO handles conflicts in
different in the child. multiple and hybrid cases.

super() Mastery Runtime Checks


Always call super().__init__() first in child constructors. Use isinstance() and issubclass() let you inspect class
super().method() to extend — not replace — parent relationships at runtime. Child objects are instances of their
behavior. parent classes too.

Next Steps: Practice the three exercises until constructor chaining feels natural. Then explore Module 4: Polymorphism
— where inherited methods take on different forms depending on the object calling them.

You might also like