UNIT 3 Notes of PYTHON

Download as pdf or txt
Download as pdf or txt
You are on page 1of 34

UNIT 3:

What is OOPs in Python?

OOPs stands for object oriented programming.

This is a feature/concept which is generally provided by most of the


languages.
This concept is helps to make real-world applications using python.
OOPs helps in making a code so smaller and writing the resuable code.
OOPs is a programming concept that uses some other technical terms to work
and these technical terms are necessary to understand before one starts
using oops concepts. Technical terms are like–
 class
 object
 method
 inheritance
 polymorphism
 encapsulation
 data-abstraction

We will try to cover everything in detail with easy explanations.

Class

Class is called as the blueprint for the object. If you want to create a class then
you need to use class keyword then write the name of the class and finally give
a colon(:).

Syntax:
class ClassName:

statemen-1
statemen-2

statemen-3

statement-n

A class contains class attributes, class constructor, class methods, etc.


For example, Parrot is an object of class bird that can
have attributes like name, age, color, etc.

Object

Objects are the instantiation of classes and also the way to use classes.

These are those entities that have attributes and behaviors which are defined
inside the class.

In real-word, object examples are desktop, mobile, ac, freeze, etc.

When we create a class, then we only describe the blueprint for objects but
memory is allocated when we create objects of classes.

Syntax
class ClassName:

pass

obj = ClassName()

Here, ClassName is the name of the class, and obj is the object of the class.
Example
class Employee:

# class attribute

company = "copyassignment.com"

# constructor

def __init__(self, name, age, salary):

# instance attributes

self.name = name

self.age = age

self.salary = salary

# creating objects

emp1 = Employee("John", 34, 50000)

emp2 = Employee("Harry", 30, 60000)

# accessing class attributes using __class__ method

# syntax is-- instance.__class__.attribute

print(f"{emp1.name} and {emp2.name} work for {emp1.__class__.company}")

# accessing instance attributes

# syntax is-- instance.instance_attribute

print(f"{emp1.name}'s age is {emp1.age} and salary is {emp1.salary}")

print(f"{emp2.name}'s age is {emp2.age} and salary is {emp2.salary}")


Output
John and Harry work for copyassignment.com

John's age is 34 and salary is 50000

Harry's age is 30 and salary is 60000


Explanation

Class Attribute
We create a class with name “Employee“. Variables that we create in a class
are called class attributes and here, the company is a class attribute.
Constructor
Then, we have created the constructor. A constructor is a special method in a
class that the python always calls when we create or instantiate an object.
Python uses “__init__()” to create a constructor.
The self parameter
The __init__() method can take parameters but the first parameter should
always be the “self” parameter which refers to the current instance of the
class.

You can use any name instead of self but it should be the first parameter
always.
Instance Attribute
Variables that we create inside a constructor are called instance attributes.
These attributes are different for different instances. Like here name, age,
and salary are different for both emp1 and emp2 instances.
Methods
Methods are the functions that are defined inside the body of a class and
associated with an object. They are used to define the behaviors of an object.
Example
class Employee:

# class attribute

company = "copyassignment.com"

# constructor

def __init__(self, name, age, salary):

# instance attributes

self.name = name

self.age = age

self.salary = salary

# class method
def myMethod1(self):

print(f"Hi {self.name}!")

def myMethod2(self, city):

print(f"{self.name}, do you lives in {city}?")

# creating objects

emp1 = Employee("John", 34, 50000)

emp2 = Employee("Harry", 30, 60000)

# calling methods

emp1.myMethod1()

emp1.myMethod2("London")

Output
Hi John!

John, do you lives in London?

Here, we have created two methods mymethod1 and mymethod2, we can


use self parameter with them.

1. Inheritance (IMP)

Inheritance is one of the most important and powerful features of object-


oriented programming. Inheritance refers to the property in which a class
can inherit properties of another class that is the derived class can access all
the properties, functions, and data members of the base class from which it has
been inherited. To compare the feature with real-time, children get
characteristics and behaviors inherited from their parents. Inheritance in Python
is provided for the same purpose as explained.
Advantages of Inheritance:

 Reusability of code – since one can inherit from the base class, the efficiency of
the code increases and the size of the code also decreases instead of rewriting
the code.
 It forms a chain process i.e. if a child class is inherited from the base class, and if
a new class is inherited from the child class, then all the properties of the base
class will also be present in the new class.
Syntax:
Class base_class:

Body of base_class

Class child_class (base_class):

Body of child_class

Example
class Parent:

def __init__(self , fname, fage):

self.firstname = fname

self.age = fage

def view(self):

print(self.firstname , self.age)

class Child(Parent):

def __init__(self , fname , fage):

Parent.__init__(self, fname, fage)

self.lastname = "Machine Learning"

def view(self):

print(self.firstname ," came ", self.age , " years ago. Today, python is
the base for" , self.lastname)

object = Child("Python" , '28')


object.view()

Output
Python came 28 years ago. Today, python is the base for Machine Learning

Types of inheritance:

 Single inheritance
 Multiple inheritance
 Multilevel inheritance
 Hierarchical inheritance
 Hybrid inheritance

Single inheritance

In single inheritance, only one child class can be inherited from the base class.
Not more than one class can be used for inheritance.

Syntax:
Class base_class:
Body of base_class

Class child_class (base_class):

Body of child_class

Example
class Employee:
company = "Google"

def showDetails(self):
print("This is an employee")

class Programmer(Employee):
language = "Python"
# company = "Youtube"

def getLanguage(self):
print(f"The language is {self.language}")

# def showDetails(self):
# print("This is an programmer")

e = Employee()
e.showDetails()
p = Programmer()
p.showDetails()
print(p.company)

Output
This is an employee

This is an employee

Google

Multiple inheritance

In multiple inheritance, a child class can be inherited from more than one base
class. Unlike single inheritance, there is no restriction on the number of base
classes for inheriting the properties.
Syntax:
Class Base1():

Body of base1

Class of Base2():

Body of base2

Class Child (Base1,Base2):

Body of child

Example
class Freelancer:
company = "Fiverr"
level = 0

def upgradeLevel(self):
self.level = self.level + 1
print(self.level)

class Employee:
company = "Visa"
eCode = 120

class Programmer(Freelancer, Employee):


name = "Rohit"

p = Programmer()
p.upgradeLevel()
print(p.company)

Output
1

Fiverr

Multilevel inheritance

The multilevel inheritance is like a chain process. In this type, a class is


derived from a base class and it becomes a base class for another class that
is another new class is derived from this derived class.

Syntax:
Class Base:

Body of base class


Class Derived1 (Base):

Body of derived1 class

Class Derived2 (Derived1):

Body of derived2 class


Example
class Person:
country = "India"
def takeBreath(self):
print("I am breathing...")

class Employee(Person):
company = "Honda"

def getSalary(self):
print(f"Salary is {self.salary}")

def takeBreath(self):
print("I am an Employee so I am luckily breathing..")

class Programmer(Employee):
company = "Fiverr"

def getSalary(self):
print(f"No salary to programmers")

def takeBreath(self):
print("I am a Progarmmer so I am breathing++..")

p = Person()
p.takeBreath()
# print(p.company) # throws an error

e = Employee()
e.takeBreath()
print(e.company)

pr = Programmer()
pr.takeBreath()
print(pr.company)
print(pr.country)

OUTPUT:

I am breathing...
I am an Employee so I am luckily breathing..

Honda

I am a Progarmmer so I am breathing++..

Fiverr

India

Hierarchical inheritance

In hierarchical inheritance from a single base class, we can inherit multiple


derived classes. There is no restriction on the number of derived classes.
Syntax:
Class Base:

Body of base class

Class Derived1 (Base) :

Body of derived1 class

Class Derived2 (Base) :

Body of derived2 class

Example
Python program to demonstrate

# Hierarchical inheritance

# Base class

class Parent:

def func1(self):

print("This function is in parent class.")

# Derived class1

class Child1(Parent):

def func2(self):

print("This function is in child 1.")

# Derivied class2

class Child2(Parent):

def func3(self):
print("This function is in child 2.")

# Driver's code

object1 = Child1()

object2 = Child2()

object1.func1()

object1.func2()

object2.func1()

object2.func3()

Output:
This function is in parent class.
This function is in child 1.
This function is in parent class.
This function is in child 2.

Hybrid inheritance

The hybrid inheritance is a combination of other types of inheritance. Mostly it


is a combination of multilevel and multiple inheritance. This type of inheritance
is not much used.

Inheritance consisting of multiple types of inheritance is called hybrid


inheritance.
Example:
 Python3

# Python program to demonstrate

# hybrid inheritance

class School:

def func1(self):

print("This function is in school.")

class Student1(School):
def func2(self):

print("This function is in student 1. ")

class Student2(School):

def func3(self):

print("This function is in student 2.")

class Student3(Student1, School):

def func4(self):

print("This function is in student 3.")

# Driver's code

object = Student3()

object.func1()

object.func2()

Output:
This function is in school.
This function is in student 1.
2.Constructors(IMP)
Constructors are generally used for instantiating an object. The task of
constructors is to initialize(assign values) to the data members of the class
when an object of the class is created. In Python the __init__() method is
called the constructor and is always called when an object is created.
Syntax of constructor declaration :
def __init__(self):
# body of the constructor
Types of constructors :
 default constructor: The default constructor is a simple constructor
which doesn’t accept any arguments. Its definition has only one argument
which is a reference to the instance being constructed.
 parameterized constructor: constructor with parameters is known as
parameterized constructor. The parameterized constructor takes its first
argument as a reference to the instance being constructed known as self
and the rest of the arguments are provided by the programmer.
Example of default constructor :

 Python3

class GeekforGeeks:

# default constructor

def __init__(self):

self.geek = "GeekforGeeks"

# a method for printing data members

def print_Geek(self):

print(self.geek)
# creating object of the class

obj = GeekforGeeks()

# calling the instance method using the object obj

obj.print_Geek()

Output :
GeekforGeeks

Example of the parameterized constructor :


 Python3

class Addition:

first = 0

second = 0

answer = 0

# parameterized constructor

def __init__(self, f, s):

self.first = f

self.second = s

def display(self):
print("First number = " + str(self.first))

print("Second number = " + str(self.second))

print("Addition of two numbers = " + str(self.answer))

def calculate(self):

self.answer = self.first + self.second

# creating object of the class

# this will invoke parameterized constructor

obj = Addition(1000, 2000)

# perform Addition

obj.calculate()

# display result

obj.display()

Output :
First number = 1000
Second number = 2000
Addition of two numbers = 3000

3.Polymorphism in Python(IMP)
The word polymorphism means having many forms. In programming,
polymorphism means the same function name (but different signatures)
being used for different types. The key difference is the data types and
number of arguments used in function.
Example of inbuilt polymorphic functions:
 Python3

# Python program to demonstrate in-built poly-

# morphic functions

# len() being used for a string

print(len("geeks"))

# len() being used for a list

print(len([10, 20, 30]))

Output:
5
3

Implementing Polymorphism with a Function

 Python3

class India():

def capital(self):

print("New Delhi is the capital of India.")


def language(self):

print("Hindi is the most widely spoken language of India.")

def type(self):

print("India is a developing country.")

class USA():

def capital(self):

print("Washington, D.C. is the capital of USA.")

def language(self):

print("English is the primary language of USA.")

def type(self):

print("USA is a developed country.")

def func(obj):

obj.capital()

obj.language()

obj.type()
obj_ind = India()

obj_usa = USA()

func(obj_ind)

func(obj_usa)

Output:
New Delhi is the capital of India.
Hindi is the most widely spoken language of India.
India is a developing country.
Washington, D.C. is the capital of USA.
English is the primary language of USA.
USA is a developed country.

4.Abstraction in Python(IMP)
Abstraction in python is defined as a process of handling complexity by hiding
unnecessary information from the user. This is one of the core concepts of object-oriented
programming (OOP) languages. That enables the user to implement even more complex
logic on top of the provided abstraction without understanding or even thinking about all the
hidden background/back-end complexity.

Importance:

Abstraction provides a programmer to hide all the irrelevant data/process of an


application in order to reduce complexity and increase the efficiency of the program.
Now, we can start learning how we can achieve abstraction using the Python
program.

Achieving Abstraction in Python:

In Python, abstraction can be achieved by having/using abstract classes and


methods in our programs.
An abstract class can be useful when we are designing large functions. An abstract class is
also helpful to provide the standard interface for different implementations of components.
Python provides the abc module to use the abstraction in the Python program.

Syntax

1. from abc import ABC


2. class ClassName(ABC):

We import the ABC class from the abc module.

We use the @abstractmethod decorator to define an abstract method or if we don't provide


the definition to the method, it automatically becomes the abstract method.

Example -

1. # Python program demonstrate


2. # abstract base class work
3. from abc import ABC, abstractmethod
4. class Car(ABC):
5. def mileage(self):
6. pass
7.
8. class Tesla(Car):
9. def mileage(self):
10. print("The mileage is 30kmph")
11. class Suzuki(Car):
12. def mileage(self):
13. print("The mileage is 25kmph ")
14. class Duster(Car):
15. def mileage(self):
16. print("The mileage is 24kmph ")
17.
18. class Renault(Car):
19. def mileage(self):
20. print("The mileage is 27kmph ")
21.
22. # Driver code
23. t= Tesla ()
24. t.mileage()
25.
26. r = Renault()
27. r.mileage()
28.
29. s = Suzuki()
30. s.mileage()
31. d = Duster()
32. d.mileage()

Output:

The mileage is 30kmph


The mileage is 27kmph
The mileage is 25kmph
The mileage is 24kmph

Explanation -

In the above code, we have imported the abc module to create the abstract base
class. We created the Car class that inherited the ABC class and defined an abstract
method named mileage(). We have then inherited the base class from the three
different subclasses and implemented the abstract method differently. We created
the objects to call the abstract method.

5.Operator Overloading in Python(IMP)


Operator Overloading means giving extended meaning beyond their
predefined operational meaning. For example operator + is used to add two
integers as well as join two strings and merge two lists. It is achievable
because ‘+’ operator is overloaded by int class and str class. You might have
noticed that the same built-in operator or function shows different behavior
for objects of different classes, this is called Operator Overloading.

# Python program to show use of

# + operator for different purposes.


print(1 + 2)

# concatenate two strings

print("Geeks"+"For")

# Product two numbers

print(3 * 4)

# Repeat the String

print("Geeks"*4)

Output
3
GeeksFor
12
GeeksGeeksGeeksGeeks

Overloading binary + operator in Python:


When we use an operator on user-defined data types then automatically a
special function or magic function associated with that operator is invoked.
Changing the behavior of operator is as simple as changing the behavior of a
method or function. You define methods in your class and operators work
according to that behavior defined in methods. When we use + operator, the
magic method __add__ is automatically invoked in which the operation for +
operator is defined. Thereby changing this magic method’s code, we can
give extra meaning to the + operator.
How Does the Operator Overloading Actually work?
Whenever you change the behavior of the existing operator through
operator overloading, you have to redefine the special function that is
invoked automatically when the operator is used with the objects.
For Example:
Code 1:
 Python3

# Python Program illustrate how

# to overload an binary + operator

# And how it actually works

class A:

def __init__(self, a):

self.a = a

# adding two objects

def __add__(self, o):

return self.a + o.a

ob1 = A(1)

ob2 = A(2)

ob3 = A("Geeks")

ob4 = A("For")

print(ob1 + ob2)
print(ob3 + ob4)

# Actual working when Binary Operator is used.

print(A.__add__(ob1 , ob2))

print(A.__add__(ob3,ob4))

#And can also be Understand as :

print(ob1.__add__(ob2))

print(ob3.__add__(ob4))

Output
3
GeeksFor
3
GeeksFor
3
GeeksFor

Here, We defined the special function “__add__( )” and when the


objects ob1 and ob2 are coded as “ob1 + ob2“, the special function is
automatically called as ob1.__add__(ob2) which simply means that ob1
calls the __add__( ) function with ob2 as an Argument and It actually
means A .__add__(ob1, ob2). Hence, when the Binary operator is
overloaded, the object before the operator calls the respective function with
object after operator as parameter.

6.Python Exception Handling(IMP)

Error in Python can be of two types i.e. Syntax errors and Exceptions. Errors
are the problems in a program due to which the program will stop the
execution. On the other hand, exceptions are raised when some internal
events occur which changes the normal flow of the program.

Exceptions: Exceptions are raised when the program is syntactically


correct, but the code resulted in an error. This error does not stop the
execution of the program, however, it changes the normal flow of the
program.

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.
try:
i = int(input("Enter a number: "))
c = 1/i
except Exception as e:
print(e)
else:
print("We were successful")

OUTPUT:

Enter a number: 0

division by zero

Catching Specific Exception


A try statement can have more than one except clause, to specify handlers
for different exceptions. Please note that at most one handler will be
executed. For example, we can add IndexError in the above code. The
general syntax for adding specific exceptions are –
try:
# statement(s)
except IndexError:
# statement(s)
except ValueError:
# statement(s)
try:
a = int(input("Enter a number: "))
c = 1/a
print(c)

except ValueError as e:
print("Please Enter a valid value")

except ZeroDivisionError as e:
print("Make sure you are not dividing by 0")
OUTPUT:
Enter a number: 0
Make sure you are not dividing by 0
Thanks for using this code!

Finally Keyword in Python


Python provides a keyword finally, which is always executed after the try and
except blocks. The final block always executes after normal termination of try
block or after try block terminates due to some exception.
Syntax:
try:
# Some Code....

except:
# optional block
# Handling of exception (if required)

else:
# execute if no exception

finally:
# Some code .....(always executed)
try:
i = int(input("Enter a number: "))
c = 1/i
except Exception as e:
print(e)
exit()
finally:
print("We are done")

print("Thanks for using the program")

OUTPUT:

Enter a number: 0
division by zero

We are done

7.Multithreading in Python(IMP)

A thread is an entity within a process that can be scheduled for execution.


Also, it is the smallest unit of processing that can be performed in an OS
(Operating System). In simple words, a thread is a sequence of such
instructions within a program that can be executed independently of
other code.

Multi-threading: Multiple threads can exist within one process where:


 Each thread contains its own register set and local variables (stored in
stack).
 All threads of a process share global variables (stored in heap) and
the program code.

Consider the diagram below to understand how multiple threads exist in memory:

Multithreading is defined as the ability of a processor to execute multiple threads


concurrently.
In a simple, single-core CPU, it is achieved using frequent switching between threads.
This is termed as context switching. In context switching, the state of a thread is
saved and state of another thread is loaded whenever any interrupt (due to I/O or
manually set) takes place. Context switching takes place so frequently that all the
threads appear to be running parallelly (this is termed as multitasking).

Consider the diagram below in which a process contains two active threads:
Multi-threading in Python
In Python, the threading module provides a very simple and intuitive API for
spawning multiple threads in a program. Let us consider a simple example using a
threading module:
 Python3

# Python program to illustrate the concept

# of threading

# importing the threading module

import threading
def print_cube(num):

# function to print cube of given num

print("Cube: {}" .format(num * num * num))

def print_square(num):

# function to print square of given num

print("Square: {}" .format(num * num))

if __name__ =="__main__":

# creating thread

t1 = threading.Thread(target=print_square, args=(10,))

t2 = threading.Thread(target=print_cube, args=(10,))

# starting thread 1

t1.start()

# starting thread 2

t2.start()

# wait until thread 1 is completely executed


t1.join()

# wait until thread 2 is completely executed

t2.join()

# both threads completely executed

print("Done!")

Square: 100
Cube: 1000
Done!
Let us try to understand the above code:
 To import the threading module, we do:
import threading
 To create a new thread, we create an object of Thread class. It takes following
arguments:
 target: the function to be executed by thread
 args: the arguments to be passed to the target function
 To start a thread, we use start method of Thread class.
t1.start()
t2.start()
 Once the threads start, the current program (you can think of it like a main thread)
also keeps on executing. In order to stop execution of current program until a
thread is complete, we use join method.
t1.join()
t2.join()
 As a result, the current program will first wait for the completion of t1 and then t2.
Once, they are finished, the remaining statements of current program are executed.
Consider the diagram below for a better understanding of how above program works:
Consider the python program given below in which we print thread name and
corresponding process for each task:
The diagram given below clears the above concept:

You might also like