1.
Class and Object
• A class is like a blueprint or template which defines how something should be.
• It contains attributes (data) and methods (functions) that describe a real-world
entity.
• An object is a real instance of a class — it holds actual values and performs actions.
• For example, a Car class can have objects like BMW, Tesla that have different colors
and speeds.
class person:
def __init__(self, name, age):
self.name = name
self.age = age
p1 = person("John", 36)
print(p1.name)
print(p1.age)
John
36
#example - 2
class car:
def __init__(self,brand,color,speed):
self.brand = brand
self.color = color
self.speed = speed
def show(self):
return self.speed,self.brand,self.color
c1 = car('bmw','grey',300)
c1.brand
{"type":"string"}
2. Constructor (init())
• A constructor is a special function in Python which automatically runs when an
object is created.
• Its purpose is to initialize the object's variables (like setting a name or age when a
student is created).
• In Python, the constructor is always named init() and it's the first method that gets
triggered.
• It helps in automatically setting up the object with necessary data as soon as it's
made.
# Example 1
class Student:
def __init__(self, name, roll):
self.name = name
self.roll = roll
s1 = Student("Aman", 101)
print(s1.name, s1.roll)
Aman 101
# Example 2
class Book:
def __init__(self, title, author):
print("Constructor called")
self.title = title
self.author = author
b1 = Book("Python 101", "John")
print(b1.title, "-", b1.author)
Constructor called
Python 101 - John
3. Encapsulation
• Encapsulation means binding data and methods together so that access to data is
controlled.
• It hides the internal details of how something works and allows access only via
methods.
• We use _ for protected and __ (double underscore) for private variables in Python.
• For example, you cannot directly access your bank account balance — you need to
go through proper methods.
class Bank:
def __init__(self, name, balance):
self.name = name
if not isinstance(balance, int) or balance < 0:
raise ValueError("Initial balance must be a non-negative
integer")
self.__balance = balance
def get(self):
return self.__balance
def set(self, new_balance):
if not isinstance(new_balance, int):
raise TypeError("Balance must be an integer")
if new_balance < 0:
raise ValueError("Balance must be positive")
self.__balance = new_balance
person1 = Bank("Rohit", 10000)
person1.set(50000)
print(person1.get()) # Output: 50000
50000
person1.set('five')
----------------------------------------------------------------------
-----
TypeError Traceback (most recent call
last)
<ipython-input-31-1470266873> in <cell line: 0>()
----> 1 person1.set('five')
<ipython-input-25-3308413514> in set(self, new_balance)
11 def set(self, new_balance):
12 if not isinstance(new_balance, int):
---> 13 raise TypeError("Balance must be an integer")
14 if new_balance < 0:
15 raise ValueError("Balance must be positive")
TypeError: Balance must be an integer
print(person1.get())
50000
4. Inheritance
• Inheritance allows a new class (called child class) to use the properties and methods
of an existing class (called parent class).
• This avoids code duplication and makes it easy to reuse and extend functionality.
• Child classes can add new features or even modify (override) inherited ones.
• For example, a Dog class can inherit common behavior from Animal class and add its
own features like bark().
# Example 1 - Single Inheritance
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def bark(self):
print("Dog barks")
d = Dog()
d.speak()
d.bark()
Animal speaks
Dog barks
# Example 2 - Multilevel Inheritance
class Grandparent:
def house(self):
print("Grandparent's house")
class Parent(Grandparent):
def car(self):
print("Parent's car")
class Child(Parent):
def bike(self):
print("Child's bike")
c = Child()
c.house()
c.car()
c.bike()
Grandparent's house
Parent's car
Child's bike
5. Polymorphism
• Polymorphism means same function or method name behaving differently based on
the object that calls it.
• It makes your code flexible, reusable, and easier to manage, especially in large
applications.
• Python supports it via method overriding (same method, different class) and built-
in functions like len() working on both strings and lists.
• For example, speak() method can make a dog bark and a cat meow — same method,
different behavior.
# Example 1 - Built-in polymorphism
print(len("Rohit")) # 5
print(len([1, 2, 3])) # 3
5
3
# Example 2 - Method overriding
class Bird:
def sound(self):
print("Generic bird sound")
class Sparrow(Bird):
def sound(self):
print("Chirp Chirp")
s = Sparrow()
s.sound()
Chirp Chirp
# 6. Abstraction
• Abstraction means showing only essential features and hiding the internal
implementation from the user.
• It helps in focusing on what an object does instead of how it does it.
• In Python, abstraction is achieved using the ABC module where we define abstract
classes and methods.
• For example, when you drive a car, you press the accelerator — but you don’t need
to know how fuel is burned inside.
# Example 1
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
class Rectangle(Shape):
def area(self):
return 10 * 20
r = Rectangle()
print("Area:", r.area())
Area: 200
# Example 2
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Cat(Animal):
def make_sound(self):
print("Meow")
c = Cat()
c.make_sound()
Meow
7. Method Overloading and Overriding
• Method Overloading allows us to use the same method name with different number
of parameters. Python doesn’t support it directly but we can simulate using default
arguments.
• Method Overriding means redefining a parent class’s method in the child class to
provide specific behavior.
• Overloading is useful when you want one function to handle multiple types of
inputs.
• Overriding helps when you want your child class to behave differently from the
parent class for a specific method.
# Overloading using default arguments
class Calculator:
def add(self, a, b=0, c=0):
return a + b + c
calc = Calculator()
print(calc.add(5))
print(calc.add(5, 3))
print(calc.add(5, 3, 2))
5
8
10
# Overriding
class Parent:
def message(self):
print("Message from parent")
class Child(Parent):
def message(self):
print("Message from child")
c = Child()
c.message()
Message from child
8. Self Keyword
• self is a special keyword in Python which refers to the current object of the class.
• It is used inside methods to access the object’s own variables and functions.
• Every time you create an object and call its method, self helps Python understand
which object you're talking about.
• It is mandatory in instance methods as it allows each object to maintain its own
values.
class Bike:
def __init__(self, brand):
self.brand = brand
def show(self):
print("Brand:", self.brand)
b = Bike("Yamaha")
b.show()
Brand: Yamaha
9. Class Variable vs Instance Variable
• A class variable is shared by all instances (objects) of the class. Changing it affects all
objects.
• An instance variable is unique to each object — changing one doesn't affect others.
• Use class variables when the data is common to all objects, like company_name, and
instance variables for data like employee_name.
• This helps organize and separate global data from object-specific data.
class Employee:
company = "Google" # Class variable
def __init__(self, name):
self.name = name # Instance variable
e1 = Employee("Amit")
e2 = Employee("Rita")
print(e1.company)
print(e2.company)
print(e1.name)
print(e2.name)
Google
Google
Amit
Rita
Final Mini Project: Student Management
System using OOPs
This project uses:
Class/Object
Constructor
Encapsulation
Inheritance
Polymorphism
Abstraction
self
Class vs Instance Variable
from abc import ABC, abstractmethod
# Abstract class
class Person(ABC):
def __init__(self, name, age):
self._name = name
self._age = age
@abstractmethod
def display(self):
pass
# Student class using inheritance & encapsulation
class Student(Person):
school_name = "ABC Public School" # class variable
def __init__(self, name, age, student_id, marks):
super().__init__(name, age)
self.__student_id = student_id
self.marks = marks # instance variable
def display(self):
print(f"Student: {self._name}, Age: {self._age}, ID:
{self.__student_id}, Marks: {self.marks}")
# Teacher class using inheritance
class Teacher(Person):
def __init__(self, name, age, subject):
super().__init__(name, age)
self.subject = subject
def display(self):
print(f"Teacher: {self._name}, Age: {self._age}, Subject:
{self.subject}")
# Polymorphism in action
people = [
Student("Rohit", 20, "S001", 88),
Teacher("Mrs. Sharma", 35, "Mathematics")
]
for person in people:
person.display()
Student: Rohit, Age: 20, ID: S001, Marks: 88
Teacher: Mrs. Sharma, Age: 35, Subject: Mathematics