Unit -3 Object-Oriented Programming in Python
Introduction
Definition
Object-Oriented Programming (OOP) is a programming paradigm that uses objects
and classes to structure code efficiently. It enables modularity, reusability, and scalability by
grouping related data and behaviour together.
Key Features of OOP
• Encapsulation: Bundling of data and methods that operate on the data.
• Inheritance: Allowing a class to inherit methods and attributes from another class.
• Polymorphism: The ability to use the same interface for different underlying data
types.
• Abstraction: Hiding implementation details and showing only the necessary
features.
1. Classes and Objects
- Class Definition
Definition
A class is a blueprint for creating objects. It defines attributes and methods that describe
the object.
Syntax
class ClassName:
def __init__(self, attr1, attr2):
self.attr1 = attr1
self.attr2 = attr2
Example Program
class Car:
def __init__(self, brand, model):
[Link] = brand
[Link] = model
def display(self):
print(f"Car: {[Link]}, Model: {[Link]}")
car1 = Car("Toyota", "Camry")
[Link]()
Output:
Car: Toyota, Model: Camry
Object Definition:
Definition
An object is an instance of a class that holds real values.
Syntax
object_name = ClassName(arguments)
Example Program
p1 = Car("Honda", "Civic")
[Link]()
2. Class Methods and Self Argument
Definition
A class method takes the class itself as the first argument using cls, while instance methods
use self.
Syntax
class ClassName:
@classmethod
def method_name(cls):
pass
Example Program
class Example:
class_var = "Hello"
@classmethod
def class_method(cls):
print("Class Variable:", cls.class_var)
Example.class_method()
Output:
Class Variable: Hello
3. __init__() and __del__() Methods
__init__() Method
Definition
The __init__() method is the constructor method that gets called automatically when an
object is instantiated.
Syntax
class ClassName:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
Example Program
class Person:
def __init__(self, name, age):
[Link] = name
[Link] = age
def show(self):
print(f"Name: {[Link]}, Age: {[Link]}")
p = Person("John", 30)
[Link]()
Output:
Name: John, Age: 30
__del__() Method
Definition
The __del__() method is the destructor method that gets called automatically when an
object is deleted.
Syntax
class ClassName:
def __del__(self):
print("Object destroyed")
Example :
class Example:
def __del__(self):
print("Destructor called, object deleted")
obj = Example()
del obj
Output:
Destructor called, object deleted
4. Class and Object Variables
Definition
Class variables are shared among all objects, while instance variables are unique to each
object.
Syntax
class ClassName:
class_var = "Shared"
def __init__(self, instance_var):
self.instance_var = instance_var
Example Program
class Example:
class_var = "Shared Variable"
def __init__(self, value):
self.instance_var = value
e1 = Example("Unique 1")
e2 = Example("Unique 2")
print(e1.instance_var, e2.instance_var)
print(Example.class_var)
Output:
Unique 1 Unique 2
Shared Variable
5. Other Special Methods
Definition
Special methods are predefined methods like __init__, __del__, __str__, etc.
Syntax
class ClassName:
def __init__(self):
pass
Example Program
class Example:
def __str__(self):
return "Example Object"
obj = Example()
print(obj)
Output:
Example Object
6. Private Methods
Definition
A private method is a method that cannot be accessed directly outside the class. It is
prefixed with double underscores __.
Syntax
class ClassName:
def __private_method(self):
print("This is a private method")
Example Program
class Example:
def __private_method(self):
print("This is a private method")
def public_method(self):
self.__private_method()
obj = Example()
obj.public_method() # Allowed
# obj.__private_method() # This will cause an error
Output:
This is a private method
7. Calling a Method from Another Class
Definition
Methods from another class can be accessed using composition or inheritance.
Syntax
class ClassA:
def method_a(self):
print("Method from ClassA")
class ClassB:
def call_method(self):
obj = ClassA()
obj.method_a()
Example Program
class First:
def display(self):
print("Method of First class")
class Second:
def show(self):
obj = First()
[Link]()
s = Second()
[Link]()
Output:
Method of First class
8. Built-in Functions
Definition
Built-in functions in Python can be used with classes and objects to perform various
operations like checking attributes, setting values, and retrieving properties.
Common Built-in Functions
• getattr(obj, attr): Returns the value of the specified attribute.
• setattr(obj, attr, value): Sets a specified attribute's value.
• hasattr(obj, attr): Checks if an object has a particular attribute.
• delattr(obj, attr): Deletes a specified attribute.
• isinstance(obj, class): Checks if an object is an instance of a class.
• issubclass(class1, class2): Checks if a class is a subclass of another class.
Example Program
class Car:
def __init__(self, brand, model):
[Link] = brand
[Link] = model
car1 = Car("Toyota", "Camry")
# Using built-in functions
print(getattr(car1, "brand")) # Output: Toyota
setattr(car1, "model", "Corolla")
print([Link]) # Output: Corolla
print(hasattr(car1, "brand")) # Output: True
delattr(car1, "brand")
print(hasattr(car1, "brand")) # Output: False
Explanation
• getattr(car1, "brand") retrieves the value of brand.
• setattr(car1, "model", "Corolla") modifies the model.
• hasattr(car1, "brand") checks if brand exists.
• delattr(car1, "brand") removes the brand attribute.
9. Class Attributes
Definition
Class attributes are shared across all instances of a class. They are declared inside the
class but outside the __init__() method.
Syntax
class ClassName:
class_variable = "Shared"
Example Program
class Example:
class_attr = "Common Value"
def __init__(self, value):
self.instance_attr = value
obj1 = Example("Unique 1")
obj2 = Example("Unique 2")
print(obj1.instance_attr, obj2.instance_attr) # Unique instance attributes
print(Example.class_attr) # Shared class attribute
Output :
Unique 1 Unique 2
Common Value
Explanation :
• class_attr is shared by all instances.
• instance_attr is unique to each object.
10. Garbage Collection
Garbage collection is a memory management technique used in programming
languages to automatically reclaim memory that is no longer accessible or in use by the
application.
It helps prevent memory leaks, optimize memory usage, and ensure efficient
memory allocation for the program.
Example
import gc
class Test:
def __del__(self):
print("Object deleted")
obj = Test()
del obj
print("Garbage Collector:", [Link]())
Output:
Object deleted
Garbage Collector: 0
11. Class and Static Methods
Class Methods
Definition
A class method is bound to the class rather than the instance. It is defined using
@classmethod and takes cls as its first parameter.
Syntax
class ClassName:
@classmethod
def method_name(cls):
pass
Example Program
class Example:
class_var = "Shared Value"
@classmethod
def class_method(cls):
print("Class Variable:", cls.class_var)
Example.class_method()
Output :
Class Variable: Shared Value
Explanation :
• @classmethod allows the method to access and modify class variables.
• cls.class_var is used to access the class variable.
Static Methods
Definition
A static method is independent of class or instance variables. It is defined using
@staticmethod.
Syntax
class ClassName:
@staticmethod
def method_name():
pass
Example Program
class MathOperations:
@staticmethod
def add(a, b):
return a + b
print([Link](5, 3))
Output
8
Explanation
• @staticmethod defines a method that does not require self or cls.
• The add method performs an operation without modifying class attributes.
[Link] in Python
Definition
Inheritance is a mechanism that allows one class (child class) to acquire the properties and
behaviour of another class (parent class). It promotes code reusability and hierarchical
classification. This allows the child class to inherit and extend the functionalities of the
parent class.
Types of Inheritance
1. Single Inheritance
2. Multiple Inheritance
3. Multilevel Inheritance
4. Hierarchical Inheritance
5. Hybrid Inheritance
6. Abstract Classes and Interfaces
1. Single Inheritance
Definition
A single child class inherits from a single parent class. This is the simplest form of
inheritance, allowing the child class to reuse the parent class's methods and attributes.
Syntax
class Parent:
def parent_method(self):
print("This is the parent class")
class Child(Parent):
def child_method(self):
print("This is the child class")
Example
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def bark(self):
print("Dog barks")
d = Dog()
[Link]()
[Link]()
Output
Animal speaks
Dog barks
Explanation
In this example, the Dog class inherits from the Animal class. The Dog class can access the
speak() method from Animal, demonstrating code reusability.
2. Multiple Inheritance
Definition
A child class inherits from multiple parent classes, meaning it can access methods and
attributes from more than one parent.
Syntax
class Parent1:
pass
class Parent2:
pass
class Child(Parent1, Parent2):
pass
Example
class Father:
def skill1(self):
print("Father: Coding")
class Mother:
def skill2(self):
print("Mother: Designing")
class Child(Father, Mother):
def skill3(self):
print("Child: Gaming")
c = Child()
c.skill1()
c.skill2()
c.skill3()
Output
Father: Coding
Mother: Designing
Child: Gaming
Explanation
The Child class inherits methods from both Father and Mother, demonstrating multiple
inheritance where a class can have multiple parents.
3. Multilevel Inheritance
Definition
A child class inherits from another child class, forming a chain of inheritance. This allows for
a hierarchical structure.
Syntax
class Grandparent:
pass
class Parent(Grandparent):
pass
class Child(Parent):
pass
Example
class Animal:
def breathe(self):
print("Breathing...")
class Mammal(Animal):
def feed_milk(self):
print("Feeding milk...")
class Human(Mammal):
def talk(self):
print("Talking...")
h = Human()
[Link]()
h.feed_milk()
[Link]()
Output
Breathing...
Feeding milk...
Talking...
Explanation
Here, the Human class inherits from Mammal, which in turn inherits from Animal. This forms
a multilevel inheritance chain.
4. Hierarchical Inheritance
Definition
Multiple child classes inherit from a single parent class, meaning they share common
attributes and behaviors from the parent.
Syntax
class Parent:
pass
class Child1(Parent):
pass
class Child2(Parent):
pass
Example
class Vehicle:
def move(self):
print("Vehicle is moving")
class Car(Vehicle):
def car_speed(self):
print("Car speed: 100km/hr")
class Bike(Vehicle):
def bike_speed(self):
print("Bike speed: 80km/hr")
c = Car()
b = Bike()
[Link]()
c.car_speed()
[Link]()
b.bike_speed()
Output
Vehicle is moving
Car speed: 100km/hr
Vehicle is moving
Bike speed: 80km/hr
Explanation
Here, Car and Bike inherit from Vehicle, allowing them to share the move() method while
having their own specific methods.
5. Hybrid Inheritance
Definition
A combination of more than one type of inheritance, such as multiple and hierarchical
inheritance together.
Syntax
class Parent:
pass
class Child1(Parent):
pass
class Child2(Parent, Child1):
pass
Example
class A:
def method_a(self):
print("Method A")
class B(A):
def method_b(self):
print("Method B")
class C(A):
def method_c(self):
print("Method C")
class D(B, C):
def method_d(self):
print("Method D")
d = D()
d.method_a()
d.method_b()
d.method_c()
d.method_d()
Output
Method A
Method B
Method C
Method D
Explanation
Here, D inherits from both B and C, while B and C inherit from A. This forms a hybrid
inheritance structure, combining multiple and hierarchical inheritance.
6. Abstract Classes and Interfaces
Abstract Classes
Definition
An abstract class is a class that cannot be instantiated and contains at least one abstract
method. Abstract methods are defined but do not contain implementation. It is used to
enforce that subclasses implement specific methods.
Syntax
from abc import ABC, abstractmethod
class AbstractClass(ABC):
@abstractmethod
def abstract_method(self):
pass
Example
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def make_sound(self):
pass
class Dog(Animal):
def make_sound(self):
print("Bark")
d = Dog()
d.make_sound()
Output
Bark
Explanation
The Animal class has an abstract method make_sound(), which is implemented by Dog.
Interfaces
Definition
An interface in Python is implemented using abstract classes where all methods are
abstract. It ensures that derived classes implement all methods defined in the interface.
Example
from abc import ABC, abstractmethod
class IShape(ABC):
@abstractmethod
def area(self):
pass
class Circle(IShape):
def area(self):
print("Area of Circle")
c = Circle()
[Link]()
Output
Area of Circle
Explanation
The IShape interface enforces that Circle implements the area() method.
Metaclass in Python
Definition
A metaclass in Python is a class that defines the behavior and structure of other classes. In
other words, a metaclass is responsible for creating classes, just like classes create objects.
It controls how classes behave by modifying their attributes, methods, or even their creation
process.
By default, Python uses the built-in type metaclass to create classes, but we can define
custom metaclasses to modify class behavior dynamically.
Why Use Metaclasses?
• To control class creation before instances are created.
• To enforce coding standards (e.g., ensuring all class names start with a capital
letter).
• To modify attributes or methods dynamically.
• To implement singleton patterns (ensuring only one instance of a class exists).
Metaclass Syntax
class Meta(type): # Inheriting from 'type' to define a metaclass
def __new__(cls, name, bases, dct):
print(f"Creating class: {name}")
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta): # Using the custom metaclass
pass
Explanation:
• Meta is a metaclass that inherits from type.
• The __new__ method is overridden to print a message when a class is created.
• MyClass is created using Meta as its metaclass.
Example Program
class MetaLogger(type):
def __new__(cls, name, bases, dct):
print(f"Creating class: {name}")
dct['log'] = lambda self: print(f"Logging from {self.__class__.__name__}")
return super().__new__(cls, name, bases, dct)
class User(metaclass=MetaLogger):
def __init__(self, username):
[Link] = username
u = User("Alice")
[Link]()
Output
Creating class: User
Logging from User
Explanation
• MetaLogger is a custom metaclass that modifies class behavior before it is created.
• The __new__ method prints a message when the class is being created.
• It dynamically adds a log method to the User class.
• When we create an instance u = User("Alice"), we can call [Link](), even though log()
was never explicitly defined in User.
Operator Overloading
Definition
Operator overloading allows us to define how built-in operators behave when used with
objects of a class. Python provides special methods (dunder methods) that we can override
to customize the behavior of operators like +, -, *, etc.
Example
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __str__(self):
return f"({self.x}, {self.y})"
p1 = Point(2, 3)
p2 = Point(4, 5)
p3 = p1 + p2
print(p3)
Output
(6, 8)
Explanation
Here, the __add__() method allows us to use the + operator to add two Point objects,
resulting in a new Point object.
Overriding __getitem__(), __setitem__(), and __call__() Methods
__getitem__() Method
Definition
This method allows indexing access to objects of a class.
Example
class CustomList:
def __init__(self, data):
[Link] = data
def __getitem__(self, index):
return [Link][index]
cl = CustomList([10, 20, 30, 40])
print(cl[2])
Output
30
Explanation
The __getitem__() method allows us to use index-based access just like a list.
__setitem__() Method
Definition
This method allows modifying object data using index notation.
Example
class CustomList:
def __init__(self, data):
[Link] = data
def __setitem__(self, index, value):
[Link][index] = value
cl = CustomList([10, 20, 30, 40])
cl[1] = 99
print([Link])
Output
[10, 99, 30, 40]
Explanation
The __setitem__() method allows setting a value at a specific index using bracket notation.
__call__() Method
Definition
This method makes an object callable like a function.
Example
class Greeting:
def __call__(self, name):
print(f"Hello, {name}!")
say_hello = Greeting()
say_hello("Alice")
Output
Hello, Alice!
Explanation
The __call__() method allows an instance of Greeting to be called like a function.