OOP Notes
OOP Notes
Programming Using
Python
1
Index
oriented programming
3. What are Classes and Objects?
4. Object-Oriented Programming methodologies:
• Inheritance
• Polymorphism
• Encapsulation
• Abstraction
2
1. Introduction to Object Oriented
Programming in Python
3
2. Difference between Object Oriented and
Procedural Oriented Programming
Procedural-Oriented
Object-Oriented Programming (OOP)
Programming
(Pop)
It is a bottom-up approach It is a top-down approach
Object can move freely within member Data can move freely from function to
functions function within programs
•Example:
class class1(): // class 1 is the name of the class
5
Creating an Object and Class in python:
Example:
class employee():
def init (self,name,age,id,salary): //creating a
function self.name = name // self is an instance of a class
self.age = age
self.salary = salary
self.id = id
6
4. Object-Oriented
Programming
methodologies:
❑ Inheritance
❑ Polymorphism
❑ Encapsulation
❑ Abstraction
7
Inheritance:
• Ever heard of this dialogue from relatives “you look exactly
like your father/mother” the reason behind this is called
‘inheritance’.
• From the Programming aspect, It generally means
“inheriting or transfer of characteristics from parent to
child class without any modification”.
• The new class is called the derived/child class and the one
from which it is derived is called a parent/base class.
9
Single Inheritance:
Output: 22
Multilevel Inheritance:
Example:
print(emp1.age)
print(emp2.age)
Output: 22,23
Hierarchical Inheritance:
Example:
class employee():
def init (self, name, age, salary): //Hierarchical
Inheritance self.name = name
self.age = age
self.salary = salary
class childemployee1(employee):
def init
(self,name,age,salary):
self.name = name
self.age = age
self.salary = salary
class childemployee2(employee):
def init (self, name,
age, salary): self.name = name
self.age = age
self.salary = salary
emp1 = employee('harshit',22,1000)
emp2 = employee('arjun',23,2000)
Multiple Inheritance:
Example:
class childemployee(employee1,employee2):
def init (self, name, age, salary,id):
self.name = name
self.age = age
self.salary = salary
self.id = id
emp1 = employee1('harshit',22,1000)
emp2 = employee2('arjun',23,2000,1234)
Polymorphism:
• You all must have used GPS for navigating the route, Isn’t it
amazing how many different routes you come across for the
same destination depending on the traffic, from a
programming point of view this is called ‘polymorphism’.
• It is one such OOP methodology where one task can be
performed in several different ways.
• To put it in simple words, it is a property of an object which
allows it to take multiple forms.
Polymorphism is of two types:
❑ Compile-time Polymorphism
❑ Run-time Polymorphism
Compile-time Polymorphism:
A compile-time polymorphism also called as static
polymorphism which gets resolved during the compilation
time of the program. One common example is “method
overloading”
Example:
class employee1():
def
name(self):
print("Harshit is his name")
def salary(self):
print("3000 is his salary")
def age(self):
print("22 is his age")
class employee2():
def name(self):
print("Rahul is his name")
def salary(self):
print("4000 is his salary")
def age(self):
print("23 is his age")
def func(obj)://Method Overloading
obj.name()
obj.salary()
obj.age()
obj_emp1 = employee1()
obj_emp2 = employee2()
func(obj_emp1)
func(obj_emp2)
Output:
Harshit is his
name 3000 is his
salary 22 is his
age
Rahul is his name
23
4000 is his
Run-time Polymorphism:
A run-time Polymorphism is also, called as dynamic
polymorphism where it gets resolved into the run time. One
common example of Run-time polymorphism is “method
overriding”.
Example:
class employee():
def init
(self,name,age,id,salary):
self.name = name
self.age = age
self.salary = salary
self.id = id
def earn(self):
pass
class childemployee1(employee):
def earn(self): //Run-time polymorphism
print("no money")
class childemployee2(employee):
def earn(self):
print("has money")
c = childemployee1
c.earn(employee)
d=
childemployee2
d.earn(employee)
• A class method takes cls as the first parameter while a static method needs
no specific parameters.
• A class method can access or modify the class state while a static method
can’t access or modify it.
• In general, static methods know nothing about the class state. They are
utility-type methods that take some parameters and work upon those
parameters. On the other hand class methods must have class as a
parameter.
• We use @classmethod decorator in python to create a class method and
we use @staticmethod decorator to create a static method in python.
# Python program to demonstrate
# use of class method and static method.
from datetime import date
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
print(person1.age)
print(person2.age)
# Defining class
class Portal:
# Getter method
def name(self):
return self.__name
# Setter method
@name.setter
def name(self, val):
self.__name = val
# Deleter method
@name.deleter
def name(self):
del self.__name
# Creating object
p = Portal();
# Setting name
p.name = ‘Hi DR FURUSA'
# Prints name
print (p.name)
# Deletes name
del p.name
class Composite:
• It’s big confusing among most of the people that both the concepts are pointing to
Code Reusability then what is the difference b/w Inheritance and Composition and
when to use Inheritance and when to use Composition?
• Inheritance is used where a class wants to derive the nature of parent class and
then modify or extend the functionality of it.
• Inheritance will extend the functionality with extra features allows overriding of
methods, but in the case of Composition, we can only use that class we can not
modify or extend the functionality of it. It will not provide extra features.
• Thus, when one needs to use the class as it without any modification, the
composition is recommended and when one needs to change the behavior of the
method in another class, then inheritance is recommended.
Python’s Magic Methods Guide
• To get the list of magic functions in Python, open cmd or terminal,
type python3 to go to the Python console, and type:
• dir(int)
Python’s Magic Methods Guide
Initialization and Construction
• __init__ method
• The __init__ method for initialization is invoked without any call,
when an instance of a class is created, like constructors in certain
other programming languages such as C++, Java, C#, PHP, etc.
• These methods are the reason we can add two strings with the ‘+’
operator without any explicit typecasting.
Code
• # declare our own string class
• class String:
•
• # magic method to initiate object
• def __init__(self, string):
• self.string = string
•
• # Driver Code
• if __name__ == '__main__':
•
• # object creation
• string1 = String('Hello')
• # Driver Code
• if __name__ == '__main__':
•
• # object creation
• string1 = String('Hello')
• Adapter Method
• Bridge Method
• Composite Method
• Decorator Method
• Facade Method
• Proxy Method
• FlyWeight Method
Behavioral Design Pattern:
• Reusability: By using Inheritance, they helps in making the code reusable and
hence we can use them in multiple projects.
• Transparent: It improves the transparency of the code for all the developers who
are going to use it in future.
• Established Solution: We can blindly believe on the solution provided by Design
Patterns as they are well-proved and testified at critical stages.
• Established Communication: Design patterns make communication between
designers more efficient. Software professionals can immediately picture the high-
level design in their heads when they refer the name of the pattern used to solve a
particular issue when discussing system design.
• Efficient Development: Design patterns helps in the development of the highly
cohesive modules with minimal coupling.
Designing Classes for Data Handling
A python code using a class to read data from
a csv
• import pandas as pd
• class CSVReader:
• def __init__(self, file_path):
• self.file_path = file_path
• self.data = None
• def read_data(self):
• self.data = pd.read_csv(self.file_path)
• # Usage:
• file_path = "C:/Users/HONZ/Desktop/Desktop/IBM/honz.csv"
• reader = CSVReader(file_path)
• reader.read_data()
• reader.display_data(10) # Display first 10 rows
import pandas as pd
class CSVReader:
def __init__(self, file_path):
self.file_path = file_path
self.data = None
def read_data(self):
self.data = pd.read_csv(self.file_path)
# Usage:
file_path = "your_file_path_here.csv"
reader = CSVReader(file_path)
reader.read_data()
reader.display_data(10) # Display first 10 rows
SOLID Principle in Programming
• High-level modules/classes should not depend on low-level modules/classes. Both should depend upon
abstractions.
• Abstractions should not depend upon details. Details should depend upon abstractions.
• The above lines simply state that if a high module or class will be dependent more on low-level modules or
class then your code would have tight coupling and if you will try to make a change in one class it can break
another class which is risky at the production level. So always try to make classes loosely coupled as much
as you can and you can achieve this through abstraction. The main motive of this principle is decoupling the
dependencies so if class A changes the class B doesn’t need to care or know about the changes.
• You can consider the real-life example of a TV remote battery. Your remote needs a battery but it’s not
dependent on the battery brand. You can use any XYZ brand that you want and it will work. So we can say
that the TV remote is loosely coupled with the brand name. Dependency Inversion makes your code more
reusable.
Error and Exception Handling in
OOP
Different types of exceptions in python:
• SyntaxError: This exception is raised when the interpreter encounters a syntax error in the code, such as a
misspelled keyword, a missing colon, or an unbalanced parenthesis.
• TypeError: This exception is raised when an operation or function is applied to an object of the wrong type,
such as adding a string to an integer.
• NameError: This exception is raised when a variable or function name is not found in the current scope.
• IndexError: This exception is raised when an index is out of range for a list, tuple, or other sequence types.
• KeyError: This exception is raised when a key is not found in a dictionary.
• ValueError: This exception is raised when a function or method is called with an invalid argument or input,
such as trying to convert a string to an integer when the string does not represent a valid integer.
• AttributeError: This exception is raised when an attribute or method is not found on an object, such as
trying to access a non-existent attribute of a class instance.
• IOError: This exception is raised when an I/O operation, such as reading or writing a file, fails due to an
input/output error.
• ZeroDivisionError: This exception is raised when an attempt is made to divide a number by zero.
• ImportError: This exception is raised when an import statement fails to find or load a module.
Difference between Syntax Error and
Exceptions
• Syntax Error: As the name suggests this error is caused by the wrong
syntax in the code. It leads to the termination of the program.
• # initialize the amount variable
• amount = 10000
•
• # check that You are eligible to
• # purchase Dsa Self Paced or not
• if(amount > 2999)
• print("You are eligible to purchase Dsa Self Paced")
Exceptions
• Exceptions are raised when the program is syntactically correct, but
the code results in an error. This error does not stop the execution of
the program, however, it changes the normal flow of the program.
• # initialize the amount variable
• marks = 10000
•
• # perform division with 0
• a = marks / 0
• print(a)
Try and Except Statement – Catching Exceptions
• Try and except statements are used to catch and handle exceptions in
Python.
• Statements that can raise exceptions are kept inside the try clause
and the statements that handle the exception are written inside
except clause.
Python program to handle simple runtime error
• #Python 3
•
• a = [1, 2, 3]
• try:
• print ("Second element = %d" %(a[1]))
•
• # Throws error since there are only 3 elements in array
• print ("Fourth element = %d" %(a[3]))
•
• except:
• print ("An error occurred")
• In the above example, the statements that can cause the error are
placed inside the try statement (second print statement in our case).
The second print statement tries to access the fourth element of the
list which is not there and this throws an exception. This exception is
then caught by the except statement.
Catching Specific Exception
def fun(a):
if a < 4:
try:
fun(3)
fun(5)
• In Python, you can also use the else clause on the try-except block
which must be present after all the except clauses. The code enters
the else block only if the try clause does not raise an exception.
• try:
• # Some Code....
• except:
• # optional block
• # Handling of exception (if required)
• else:
• # execute if no exception
• finally:
• # Some code .....(always executed)
Raising Exception
• try:
• raise NameError("Hi there") # Raise Error
• except NameError:
• print ("An exception")
• raise # To determine whether the exception was raised or not
Advantages of Exception Handling: