🎯 Lab Objectives
What You'll Learn Today
- Understand Object-Oriented Programming (OOP) concepts
- Create classes and objects in Python
- Implement constructors and methods
- Master inheritance and method overriding
- Learn operator overloading for custom behavior
- Build real-world applications using OOP
📚 Understanding Classes and Objects
🔍 What is a Class?
A class is a blueprint or template for creating objects. It defines:
- Attributes: Properties/characteristics of objects
- Methods: Behaviors/actions that objects can perform
- Constructor: Special method to initialize objects
🏗️ What is an Object?
An object is an instance of a class. It has:
- State: Current values of attributes
- Behavior: Ability to perform methods
- Identity: Unique memory address
Class vs Object Relationship
Class: Car (Blueprint)
├── Attributes: color, brand, model, year
├── Methods: start(), stop(), accelerate()
└── Constructor: __init__()
Objects (Instances):
├── car1: Red, Toyota, Camry, 2022
├── car2: Blue, Honda, Civic, 2021
└── car3: Black, Tesla, Model 3, 2023
├── Attributes: color, brand, model, year
├── Methods: start(), stop(), accelerate()
└── Constructor: __init__()
Objects (Instances):
├── car1: Red, Toyota, Camry, 2022
├── car2: Blue, Honda, Civic, 2021
└── car3: Black, Tesla, Model 3, 2023
📝 Task 1: Basic Student Class
🎯 Problem Statement
Create a Student class with:
- Attributes: name, sap_id, marks (physics, chemistry, maths)
- Create 3 objects with user input
- Display details of all students
💻 Solution
class Student:
def __init__(self, name, sap_id, physics, chemistry, maths):
self.name = name
self.sap_id = sap_id
self.marks = {
'physics': physics,
'chemistry': chemistry,
'maths': maths
}
def display(self):
print(f"Name: {self.name}")
print(f"SAP ID: {self.sap_id}")
print("Marks:")
for subject, mark in self.marks.items():
print(f" {subject}: {mark}")
# Create 3 student objects
students = []
for i in range(3):
print(f"\n--- Enter Student {i+1} Details ---")
name = input("Enter name: ")
sap_id = input("Enter SAP ID: ")
physics = float(input("Enter Physics marks: "))
chemistry = float(input("Enter Chemistry marks: "))
maths = float(input("Enter Maths marks: "))
student = Student(name, sap_id, physics, chemistry, maths)
students.append(student)
# Display all student details
print("\n=== All Student Details ===")
for i, student in enumerate(students, 1):
print(f"\n--- Student {i} ---")
student.display()
SAMPLE OUTPUT:
--- Enter Student 1 Details ---Enter name: Alice
Enter SAP ID: 50001234
Enter Physics marks: 85
Enter Chemistry marks: 78
Enter Maths marks: 92
--- Enter Student 2 Details ---
Enter name: Bob
Enter SAP ID: 50001235
Enter Physics marks: 76
Enter Chemistry marks: 88
Enter Maths marks: 81
--- Enter Student 3 Details ---
Enter name: Charlie
Enter SAP ID: 50001236
Enter Physics marks: 90
Enter Chemistry marks: 85
Enter Maths marks: 87
=== All Student Details ===
--- Student 1 ---
Name: Alice
SAP ID: 50001234
Marks:
physics: 85
chemistry: 78
maths: 92
📝 Task 2: Enhanced Student Class with Methods
🎯 Problem Statement
Enhance the Student class with:
- Constructor to initialize n students
- display() method to show student details
- find_marks_percentage() method for each student
- display_result() method (Pass if each subject >40%, else Fail)
- Function to find class average
💻 Solution
class StudentEnhanced:
def __init__(self, name, sap_id, physics, chemistry, maths):
self.name = name
self.sap_id = sap_id
self.marks = {
'physics': physics,
'chemistry': chemistry,
'maths': maths
}
def display(self):
print(f"Name: {self.name}")
print(f"SAP ID: {self.sap_id}")
print("Marks:")
for subject, mark in self.marks.items():
print(f" {subject}: {mark}")
def find_marks_percentage(self):
# Assuming each subject is out of 100
total_marks = sum(self.marks.values())
percentage = (total_marks / 300) * 100
return percentage
def display_result(self):
percentage = self.find_marks_percentage()
print(f"Percentage: {percentage:.2f}%")
# Check if each subject > 40%
passed_all = all(mark > 40 for mark in self.marks.values())
if passed_all:
print("Result: PASS 🎉")
else:
print("Result: FAIL ❌")
# Show failed subjects
failed_subjects = [subject for subject, mark in self.marks.items() if mark <= 40]
print(f"Failed subjects: {', '.join(failed_subjects)}")
def class_average(students):
# Calculate average percentage of entire class
if not students:
return 0
total_percentage = sum(student.find_marks_percentage() for student in students)
average = total_percentage / len(students)
return average
# Example usage
students = []
for i in range(3):
print(f"\n--- Enter Student {i+1} Details ---")
name = input("Enter name: ")
sap_id = input("Enter SAP ID: ")
physics = float(input("Enter Physics marks: "))
chemistry = float(input("Enter Chemistry marks: "))
maths = float(input("Enter Maths marks: "))
student = StudentEnhanced(name, sap_id, physics, chemistry, maths)
students.append(student)
# Display individual results
for i, student in enumerate(students, 1):
print(f"\n--- Student {i} ---")
student.display()
student.display_result()
# Calculate and display class average
avg = class_average(students)
print(f"\n=== Class Average: {avg:.2f}% ===")
🧬 Task 3: Types of Inheritance
🔍 What is Inheritance?
Inheritance is a mechanism where a new class derives attributes and methods from an existing class.
- Parent Class (Base Class): Class being inherited from
- Child Class (Derived Class): Class that inherits
- Benefits: Code reusability, hierarchical organization
Types of Inheritance
1. Single Inheritance:
class Animal → class Dog
2. Multiple Inheritance:
class Father + class Mother → class Child
3. Multilevel Inheritance:
class Grandparent → class Parent → class Child
4. Hierarchical Inheritance:
class Parent → class Child1 + class Child2 + class Child3
5. Hybrid Inheritance:
Combination of multiple types
class Animal → class Dog
2. Multiple Inheritance:
class Father + class Mother → class Child
3. Multilevel Inheritance:
class Grandparent → class Parent → class Child
4. Hierarchical Inheritance:
class Parent → class Child1 + class Child2 + class Child3
5. Hybrid Inheritance:
Combination of multiple types
💻 Implementation Examples
# 1. Single Inheritance
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal):
def speak(self):
print("Dog barks: Woof!")
# 2. Multiple Inheritance
class Father:
def skills(self):
print("Father: Technical skills")
class Mother:
def skills(self):
print("Mother: Creative skills")
class Child(Father, Mother):
def skills(self):
print("Child: Both technical and creative skills")
# 3. Multilevel Inheritance
class Grandparent:
def property(self):
print("Grandparent: Wisdom")
class Parent(Grandparent):
def property(self):
print("Parent: Experience")
class Child(Parent):
def property(self):
print("Child: Energy")
# Test inheritance
print("=== Single Inheritance ===")
dog = Dog()
dog.speak()
print("\n=== Multiple Inheritance ===")
child = Child()
child.skills()
print("\n=== Multilevel Inheritance ===")
child = Child()
child.property()
🔄 Task 4: Method Overriding
🔍 What is Method Overriding?
Method Overriding occurs when a child class provides a specific implementation of a method that is already defined in its parent class.
- Child class method replaces parent class method
- Same method name and parameters
- Different implementation in child class
- Enables polymorphism - same interface, different behavior
💻 Implementation Example
class Shape:
def area(self):
print("Calculating area of generic shape")
return 0
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
# Overriding parent's area method
print("Calculating area of rectangle")
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
# Overriding parent's area method
print("Calculating area of circle")
return 3.14159 * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
# Overriding parent's area method
print("Calculating area of triangle")
return 0.5 * self.base * self.height
# Test method overriding
shapes = [
Rectangle(5, 4),
Circle(3),
Triangle(6, 8)
]
print("=== Method Overriding Examples ===")
for i, shape in enumerate(shapes, 1):
print(f"\nShape {i}:")
area = shape.area()
print(f"Area: {area:.2f}")
➕ Task 5: Operator Overloading
🔍 What is Operator Overloading?
Operator Overloading allows you to define how operators behave with your custom objects.
- Redefine standard operators (+, -, *, /, etc.)
- Make objects work with built-in operators
- Implement using magic methods (dunder methods)
- Creates intuitive object behavior
Common Operator Overloading Methods
Arithmetic Operators:
__add__ : + operator
__sub__ : - operator
__mul__ : * operator
__truediv__ : / operator
Comparison Operators:
__eq__ : == operator
__lt__ : < operator
__gt__ : > operator
String Representation:
__str__ : str() function
__repr__ : repr() function
__add__ : + operator
__sub__ : - operator
__mul__ : * operator
__truediv__ : / operator
Comparison Operators:
__eq__ : == operator
__lt__ : < operator
__gt__ : > operator
String Representation:
__str__ : str() function
__repr__ : repr() function
💻 Point Class with + Operator Overloading
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
# Overload + operator
if isinstance(other, Point):
new_x = self.x + other.x
new_y = self.y + other.y
return Point(new_x, new_y)
else:
raise TypeError("Can only add Point to Point")
def __str__(self):
# String representation
return f"Point(x={self.x}, y={self.y})"
def __repr__(self):
# Official string representation
return self.__str__()
# Create example points from problem
p1 = Point(10, 20)
p2 = Point(12, 15)
# Add points using overloaded + operator
p3 = p1 + p2
print(f"P1: {p1}")
print(f"P2: {p2}")
print(f"P3 = P1 + P2: {p3}")
# Test with different operations
print("\n=== Additional Examples ===")
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
# Overload * operator for scalar multiplication
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(3, 4)
v2 = Vector(1, 2)
# Vector addition
v3 = v1 + v2
print(f"Vector addition: {v1} + {v2} = {v3}")
# Scalar multiplication
v4 = v1 * 2
print(f"Scalar multiplication: {v1} * 2 = {v4}")