0% found this document useful (0 votes)
0 views

Advanced Python1 (Autosaved)-2

Uploaded by

netmirror36
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views

Advanced Python1 (Autosaved)-2

Uploaded by

netmirror36
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 177

ADVANCED PYTHON-3.7.

4(OOP’s Part-1)
What is Class:
In Python every thing is an object. To create objects we required some Model or Plan or Blue
Print, which is nothing but class.
We can write a class to represent properties(attributes) and actions(behavior) of Object.
Properties can be represented by variables.
Action can be represented by Methods.
Hence class contains both variables and methods.

How to define a Class?


We can define a class by using class keyword.

Syntax:

Class Classname:
’’’ documentation string ’’’
Variables: instance variables, static and local variables
Methods: instance methods, static methods, class methods

Documentation string represents description of the class. Within the class doc string is
always optional. We can get doc string by using the fallowing 2 ways.

1. print(classname. __doc__)
2. help(classname)

Example:

class Student:
'''This is student class with required data'''
print(Student.__doc__)
help(Student)

Within the Python class we can represent data by using variables.


There are three types of variables are allowed.
1) Instance Variables(Object Level Variable)
2) Static Variables(Class Level Variables)
3) Local Variables(Method Level Variables)

Within the python class, we can represent operations by using methods. The following are
Various types of allowed methods
1. Instance Methods
2. Class Methods
3. Static Methods

Example for Class:

class Student:
'''developed by naresh for python demo'''
def __init__(self):
self.name='naresh'
self.age=28
self.marks=80

def talk(self):
print("Hello I am:",self.name)
print("My Age is:",self.age)
print("My marks are:",self.marks)

What is Object:
Physical existence of a class is nothing but object. We can create any number of objects
For a class.

Syntax to create an object:


referencevariable = classname()

Example:
s=Student()

What is Reference Variable?


The variable which can be used to refer object is called reference variable.By using reference
variable, we can access properties and methods of object.

Program: Write a Python program to create a Student class and Creates an object to it.
Call the method talk() to display student details.

class Student:

'''developed by naresh for python demo'''


def __init__(self,name,rollno,marks):
self.name=name
self.rollno=rollno
self.marks=marks
def talk(self):
print("Hello I am:",self.name)
print("My Rollno is:",self.rollno)
print("My marks are:",self.marks)
s1=Student("Naresh",101,80)
s1.talk()

Output:
Hello I am: Naresh
My Rollno is: 101
My marks are: 80

Self Variable:

Self is the default variable which is always pointing to current object(like this keyword
In java)
By using self we can access instance variables and instance methods of object.

Note:
1) Self should be first parameter inside constructor
def__init__(self):
2) Self should be first parameter inside instance methods
def talk(self):

Constructor Concept:
Constructor is a special method in python.
The name of constructor should be __init__(self)
Constructor will be executed automatically at the time of object creation.
The main purpose of constructor is to be declare and initialize instance variables.
Per object constructor will be executed only once.
Constructor can take atleast one argument(atleast self)
Constructor is optional and if we are not providing any constructor then python will
Provide default constructor.

Example:

def__init__(self,name,rollno,marks):
self.name=name
self.rollno=rollno
self.marks=marks
Program to demonstrate Constructor will execute only once per Object :

class Test:

def __init__(self):
print("Constructor execution....")
def m1(self):
print("Method execution...")

t1=Test()
t2=Test()
t3=Test()
t1.m1()

Output:
Constructor execution....
Constructor execution....
Constructor execution....
Method execution...

Program:

class Student:

'''This is student class with required data'''


def __init__(self,x,y,z):
self.name=x
self.rollno=y
self.marks=z

def display(self):
print("Student Name:{}\nRoll Name:{}\nMarks:{}".format(self.name,
self.rollno,self.marks))

s1=Student("Naresh",101,80)
s1.display()
s2=Student("Sunny",102,100)
s2.display()

Output:

Student Name:Naresh
Roll Name:101
Marks:80
Student Name:Sunny
Roll Name:102
Marks:100

Differences between Methods and Constructors


Method Constructor
1.Name of Method can be any name 1.Constructor name should be always __init__
2.Method will be executed if we call that 2. Constructor will be executed automatically at
Method. The time of object creation
3.per object, method can be called any number 3.Per Object, Constructor will be executed only
of times. once
4.Inside method we can write business logic 4. Inside Constructor we have to declare and
Initialize instance variables.

Types Of Variables:
Inside Python class 3 types of Variables are allowed.

1. Instance Variables(Object Level Variables)


2. Static Variables (Class Level Variables)
3. Local Variables(Method Level Variables)

Just basic idea of instance /static and local variables:

Class Student:
colgname=’Nice Soft’ //static
def __init__(self,x,y):
count=0
self.name=x //instance variable
self.rollno=y
def display(self):
x=10 //local variable
print(“Method Execution…”)
print(“Hello My self is:”,self.name)
print(“Myroll no is:”,self,rollno)
s1=Student(‘naresh’,100)
s2=Student(‘navya’,200)
s3=Student(‘siva’,300)

1) Instance Variables:
 If the value of a variable is varied from object to object, then such type of variables are
called instance variables.
 For every object a separate copy of instance variable will be created.

Where we can declare Instance Variables:


1. Inside Constructor by using self variable
2. Inside Instance Method by using self variable
3. Outside of the class by using object reference variable.

1) Inside Constructor by using self Variable:


We can declare instance variables inside a constructor by using self keyword. Once we create
object, automatically these variables will be added to the object.

class Employee:

def __init__(self):
self.eno=100
self.ename='Naresh'
self.esal=10000

e=Employee()
print(e.__dict__)

Output:
{'eno': 100, 'ename': 'Naresh', 'esal': 10000}

2) Inside Instance Method by using Self Variable


We can also declare instance variables inside instance method by using self variable. If Any
instance variable declared inside instance method, that instance variable will be added once
we call that method.

class Test:

def __init__(self):
self.a=10
self.b=20

def m1(self):
self.c=30
t=Test()
t.m1()
print(t.__dict__)
Output:
{'a': 10, 'b': 20, 'c': 30}

3) Outside of the Class by using Object Reference Variable:


We can also add instance variable outside of a class to a particular object.

class Test:
def __init__(self):
self.a=10
self.b=20

def m1(self):
self.c=30
t=Test()
t.m1()
t.d=40
print(t.__dict__)

Output:
{'a': 10, 'b': 20, 'c': 30, 'd': 40}

How to Access Instance Variables:


We can access instance variables with in the class by using self variable and outside of the
Class by using object reference.

class Test:

def __init__(self):
self.a=10
self.b=20

def display(self):
print(self.a)
print(self.b)
t=Test()
t.display()
print(t.a,t.b)

Output:
10
20
10 20

How to delete Instance Variable from the Object:


1) Within a class we can delete instance variables as follows
del self.variableName
2) From outside of class we can delete instance variables as follows
del objectreference.variableName

class Test:

def __init__(self):
self.a=10
self.b=20
self.c=30
self.d=40

def m1(self):
del self.d
t=Test()
print(t.__dict__)
t.m1()
print(t.__dict__)
del t.c
print(t.__dict__)
Output:
{'a': 10, 'b': 20, 'c': 30, 'd': 40}
{'a': 10, 'b': 20, 'c': 30}
{'a': 10, 'b': 20}

Note: The instance variables which are deleted from one object, will not be deleted from
Other objects.

class Test:

def __init__(self):
self.a=10
self.b=20
self.c=30
self.d=40

t1=Test()
t2=Test()
del t1.a
print(t1.__dict__)
print(t2.__dict__)

Output:
{'b': 20, 'c': 30, 'd': 40}
{'a': 10, 'b': 20, 'c': 30, 'd': 40}

If we change the values of instance variables of one object then those changes won’t be reflected
to the remaining objects, because for every object we are separate copy of instance variables are
available.

class Test:
def __init__(self):
self.a=10
self.b=20
t1=Test()
t1.a=888
t1.b=999
t2=Test()
print('t1:',t1.a,t1.b)
print('t2:',t2.a,t2.b)

Output:
t1: 888 999
t2: 10 20
2) Static Variables:
If the value of a variable is not varied from object to object, such type of variables we
have to declare with in the class directly but outside of methods. Such types of variables
are called Static variables.

For total class only one copy of static variable will be created and shared by all objects of
the class.

We can access static variables either by class name or by object reference .But
recommended to use class name.

Instance Variables vs Static Variables:

Note: In the case of Instance variables for every object a separate copy will be created,
but in the case of Static Variables for total class only one copy will be created and shared
by every object of the class.

class Test:
x=10
def __init__(self):
self.y=20
t1=Test()
t2=Test()
print('t1:',t1.x,t1.y)
print('t2:',t2.x,t2.y)
Test.x=888
t1.y=999
print('t1:',t1.x,t1.y)
print('t2:',t2.x,t2.y)

Output:
t1: 10 20
t2: 10 20
t1: 888 999
t2: 888 20

Various Places to declare Static Variables:


In general we can declare within the class directly but from out side of any method
Inside constructor by using class name
Inside Instance method by using class name
Inside class method by using either class name or cls variable.
Inside static method by using class name

class Test:
x=10
def __init__(self):
Test.b=20
def m1(self):
Test.c=30
@classmethod
def m2(cls):
cls.d1=40
Test.d2=400
@staticmethod
def m3():
Test.e=50
print(Test.__dict__)
t=Test()
print(Test.__dict__)
t.m1()
print(Test.__dict__)
Test.m2()
print(Test.__dict__)
Test.m3()
print(Test.__dict__)
Test.f=60
print(Test.__dict__)

How to access Static Variables:


Inside constructor: by using either self or classname
Inside instance method: by using either self or classname
Inside class method: by using either cls variable or classname
Inside static method: by using classname
From outside of class: by using either object reference or classname

class Test:
a=10
def __init__(self):
print(self.a)
print(Test.a)
def m1(self):
print(self.a)
print(Test.a)
@classmethod
def m2(cls):
print(cls.a)
print(Test.a)
@staticmethod
def m3():
print(Test.a)
t=Test()
print(Test.a)
print(t.a)
t.m1()
t.m2()
t.m3()

Where we can modify the Value of Static Variable:


Anywhere either with in the class or outside of class we can modify by using classname.
But inside class method, by using cls variable.
class Test:
a=777
@classmethod
def m1(cls):
cls.a=888
@staticmethod
def m2():
Test.a=999
print(Test.a)
Test.m1()
print(Test.a)
Test.m2()
print(Test.a)

Output:
777
888
999
If we change the Value of Static Variable by using either self OR Object
Reference Variable :
If we change the value of static variable by using either self or object reference variable,
then the value of static variable won’t be changed, just a new instance variable with that
name will be added to that particular object.

class Test:
a=10
def m1(self):
self.a=888
t1=Test()
t1.m1()
print(Test.a)
print(t1.a)

Output:
10
888

class Test:
x=10
def __init__(self):
self.y=20
t1=Test()
t2=Test()
print('t1:',t1.x,t1.y)
print('t2:',t2.x,t2.y)
t1.x=888
t1.y=999
print('t1:',t1.x,t1.y)
print('t2:',t2.x,t2.y)

Output:
t1: 10 20
t2: 10 20
t1: 888 999
t2: 10 20

class Test:
a=10
def __init__(self):
self.b=20
t1=Test()
t2=Test()
Test.a=888
t1.b=999
print(t1.a,t1.b)
print(t2.a,t2.b)

Output:
888 999
888 20

class Test:
a=10
def __init__(self):
self.b=20
def m1(self):
self.a=888
self.b=999
t1=Test()
t2=Test()
t1.m1()
print(t1.a,t1.b)
print(t2.a,t2.b)

Output:
888 999
10 20

class Test:
a=10
def __init__(self):
self.b=20
@classmethod
def m1(cls):
cls.a=888
cls.b=999
t1=Test()
t2=Test()
t1.m1()
print(t1.a,t1.b)
print(t2.a,t2.b)
print(Test.a,Test.b)

Output:
888 20
888 20
888 999

How to Delete Static Variables of a Class:


1) We can delete static variable from anywhere by using the fallowing syntax
del classname . variablename
2) But inside classmethod we can also use cls variable
del cls . variablename

class Test:
a=10
@classmethod
def m1(cls):
del cls.a
Test.m1()
print(Test.__dict__)

Example:
class Test:
a=10
def __init__(self):
Test.b=20
del Test.a
def m1(self):
Test.c=30
del Test.b
@classmethod
def m2(cls):
cls.d=40
del Test.c
@staticmethod
def m3():
Test.e=50
del Test.d
print(Test.__dict__)
t=Test()
print(Test.__dict__)
t.m1()
print(Test.__dict__)
Test.m2()
print(Test.__dict__)
Test.m3()
print(Test.__dict__)
Test.f=60
print(Test.__dict__)
del Test.e
print(Test.__dict__)

*****Note:
By using object reference variable/self we can read static variable, but we cannot modify
or delete.
If we are trying to modify, then a new instance variable will be added to that particular
object.
t1.a=70
if we are trying to delete then we will get error.
Example:
class Test:
a=10
t1=Test()
del t1.a

Attribute Error: a

We can modify or delete static variables only by using classname or cls variable.

import sys
class Customer:
'''Customer class with bank operatios...'''
bankname='NICEBANK'
def __init__(self,name,balance=0.0):
self.name=name
self.balance=balance
def deposit(self,amt):
self.balance=self.balance+amt
print('Balance after deposit:',self.balance)
def withdraw(self,amt):
if amt>self.balance:
print('Insufficient Funds..cannot perform this operation')
sys.exit()
self.balance=self.balance-amt
print('balance after withdraw:',self.balance)

print('Welcome to',Customer.bankname)
name=input('Enter Your Name:')
c=Customer(name)
while True:
print('d-Deposit\nw-Withdraw\ne-exit')
option=input('Choose your Option:')
if option=='d' or option=='D':
amt=float(input('Enter amount:'))
c.deposit(amt)
elif option=='w' or option=='W':
amt=float(input('Enter amount:'))
c.withdraw(amt)
elif option=='e' or option=='E':
print('Thanks for Banking')
sys.exit()
else:
print('Invalid option...plz choose valid option')

Output:

Welcome to NICEBANK
Enter Your Name:hhh
d-Deposit
w-Withdraw
e-exit
Choose your Option:d
Enter amount:10000
Balance after deposit: 10000.0
d-Deposit
w-Withdraw
e-exit
Choose your Option:d
Enter amount:20000
Balance after deposit: 30000.0
d-Deposit
w-Withdraw
e-exit
Choose your Option:w
Enter amount:2000
balance after withdraw: 28000.0
d-Deposit
w-Withdraw
e-exit
Choose your Option:r
Invalid option...plz choose valid option
d-Deposit
w-Withdraw
e-exit
Choose your Option:e
Thanks for Banking

3)Local Variables:
Sometimes to meet temporary requirement of programmer, we can declare variables
Inside a method directly,such type of variables are called local variable or temporary
variables.
Local variables will be created at the time of method execution and destroyed once
method completes.
Local variables of a method cannot be accessed from outside of method.

class Test:
def m1(self):
a=1000
print(a)
def m2(self):
b=2000
print(b)
t=Test()
t.m1()
t.m2()

Output:
1000
2000

class Test:
def m1(self):
a=1000
print(a)
def m2(self):
b=2000
#print(a) Name Error:name 'a' is not defined
print(b)
t=Test()
t.m1()
t.m2()

Output:
1000
2000

Types of Methods:
Inside Python class 3 types of methods are allowed
1. Instance Method
2. Class Method
3. Static Method

1. Instance Methods:
 Inside method implementation if we are using instance variables then such type of
methods are called instance methods.
 Inside instance method declaration, we have to pass self variable. def m1(self):
 By using self variable inside method we can able to access instance variable.
 Within the class we can call instance method by using self variable and from outside
of the class we can call by using object reference.

class Student:
def __init__(self,name,marks):
self.name=name
self.marks=marks
def display(self):
print('Hi',self.name)
print('Your marks are:',self.marks)
def grade(self):
if self.marks>=60:
print('You got First Grade')
elif self.marks>=50:
print('You got Second Grade')
elif self.marks>=35:
print('You got Third Grade')
else:
print('You are Failed')
n=int(input('Enter no of Students'))
for i in range(n):
name=input('Enter Name:')
marks=int(input('Enter Marks'))
s=Student(name,marks)
s.display()
s.grade()
print()

Output:

Enter no of Students:2
Enter Name:naresh
Enter Marks90
Hi naresh
Your marks are: 90
You got First Grade

Enter Name:sunny
Enter Marks12
Hi sunny
Your marks are: 12
You are Failed

Setter and Getter Methods:


We can set and get the values of instance variables by using getter and setter methods.

Setter Method:
Set methods can be used to set values to the instance variables. setter methods also
known as mutator methods.

Syntax:
def setVariable(self,variable):
self.variable=variable

Example:
def setName(self,name):
self.name=name

Getter Method:
Getter methods can be used to get values of the instance variables. Getter methods also
knows as accessor methods.

Syntax:
def getVariable(self):
return self.variable

Example:
def getName(self):
return self.name

Example:
class Student:
def setName(self,name):
self.name=name
def getName(self):
return self.name
def setMarks(self,marks):
self.marks=marks
def getMarks(self):
return self.marks
n=int(input('Enter number of students:'))
for i in range(n):
s=Student()
name=input('Enter Name:')
s.setName(name)
marks=int(input('Enter Marks'))
s.setMarks(marks)

print('Hi',s.getName())
print('You Marks are:',s.getMarks())
print()

Output:
Enter number of students:2
Enter Name:naresh
Enter Marks100
Hi naresh
You Marks are: 100

Enter Name:suneetha
Enter Marks80
Hi suneetha
You Marks are: 80

Class Methods:
Inside method implementation if we are using only class variables(static variables),then
such type of methods we should declare as class methods.
We can declare class method explicitly by using @classmethod decorator.
For class method we should provide cls variable at the time of declaration
We can call class method by using classname or object reference variable.

class Animal:
LEgs=4
@classmethod
def walk(cls,name):
print('{}walks with{}LEgs....'.format(name,cls.LEgs))
Animal.walk('Dog')
Animal.walk('Cat')

Output:
Dogwalks with4LEgs....
Catwalks with4LEgs....

Program to track the number of Objects created for a Class:

class Test:
count=0
def __init__(self):
Test.count=Test.count+1
@classmethod
def noOfObjects(cls):
print('The no of Objects created for test class:',cls.count)
t1=Test()
t2=Test()
Test.noOfObjects()
t3=Test()
t4=Test()
t5=Test()
Test.noOfObjects()

Output:
The no of Objects created for test class: 2
The no of Objects created for test class: 5

Static Methods:
In general these methods are general utility methods.
Inside these methods we won’t use any instance or class variables
Here we won’t provide self or cls arguments at the time of declaration
We can declare static method explicitly by using @staticmethod decorator
We can access static methods by using class name or object reference

class NareshMath:
@staticmethod
def add(x,y):
print('The Sum=',x+y)
@staticmethod
def product(x,y):
print('The Product=',x*y)

@staticmethod
def average(x,y):
print('The Average=',(x+y)/2)
NareshMath.add(10,20)
NareshMath.product(10,20)
NareshMath.average(10,20)

Output:
The Sum= 30
The Product= 200
The Average= 15.0

Note:
In general we can use only instance and static methods. Inside static method we can
access class level variables by using class name.
Class methods are most rarely used methods in python.

Passing Members of One Class to Another Class:


We can access members of One class inside another class.

class Employee:
def __init__(self,eno,ename,esal):
self.eno=eno
self.ename=ename
self.esal=esal
def display(self):
print('Employee Number:',self.eno)
print('Employee Name:',self.ename)
print('Employee salary:',self.esal)
class Test:
def modify(emp):
emp.sal=emp.esal+10000
emp.display()
e=Employee(100,'naresh',10000)
Test.modify(e)
Output:
Employee Number: 100
Employee Name: naresh
Employee salary: 10000

In the above application, Employee class members are available to Test class.

Inner classes
Sometimes we can declare a class inside another class, such type of classes are called
inner classes.
Without existing one type of object if there is no chance of existing another type of object,
then we should go for inner classes.

Example: Without existing Car object there is no chance of existing Engine object.Hence
Engine class should be part of Car class.

Class Car:
…….
Class Engine:
…….

Example: Without existing university object there is no chance of existing Department


object.

Class University:
…….
Class Department:
…….

Example: Without exiting Human there is no chance of existing Head. Hence Head should
be part of Human.

Class Human:
Class Head:

Note: Without existing outer class object there is no chance of existing inner class object.
Hence inner class object is always associated with outer class object.

Demo Program-1:
class Outer:
def __init__(self):
print("outer class object creation")
class Inner:
def __init__(self):
print("Inner class object creation")
def m1(self):
print("Inner class method")
o=Outer()
i=o.Inner()
i.m1()

Output:
outer class object creation
Inner class object creation
Inner class method

Note: The Following are various possible syntaxes for calling inner class method

1) o=Outer()
i=o.Inner()
i.m1()
2) i=Outer().Inner()
i.m1()
3)Outer().Inner().m1()

Demo Program-2:

class Person:
def __init__(self):
self.name='naresh'
self.db=self.Dob()
def display(self):
print('Name:',self.name)
class Dob:
def __init__(self):
self.dd=28
self.mm=8
self.yy=1990
def display(self):
print('Dob={}/{}/{}'.format(self.dd,self.mm,self.yy))

p=Person()
p.display()
x=p.db
x.display()

Output:
Name : Naresh
Dob : 28/08/1990

Demo Program-3:
Inside a class we can declare any number of inner classes.

class Human:
def __init__(self):
self.name='Sunny'
self.head=self.Head()
self.brain=self.Brain()
def display(self):
print('Hello..',self.name)

class Head:
def talk(self):
print('Talking...')
class Brain:
def think(Self):
print('Thinking..')
h=Human()
h.display()
h.head.talk()
h.brain.think()

Output:
Hello….Sunny
Talking…
Thinking….

Garbage Collection
In Old Languages like C++, Programmer is responsible for both creation and destruction of
objects, Usually programmer taking very much care while creating object, but neglecting
destruction of useless objects. Because of his neglectance, total memory can be filled with
useless objects which creates memory problems and total application will be down with
Out of memory error.

But in Python, We have some assistant which is always running in the background to
Destroy useless objects, Because this assistance the chance of failing Python program
with memory problems is very less. This assistant is nothing but Grabage Collector.

Hence the main objective of garbage Collector is to destroy useless objects.

If an object does not have any reference variable then that object eligible for Garbage
Collection.

How to enable and disable Garbage Collector in our Program:

By default Garbage collector is enabled, but we can disable based on our requirement .In
this context we can the following functions of gc module.

1) gc.isenabled() Returns True if GC enabled


2) gc.disable() To disable GC explicitly
3) gc.enable() To enable GC explicitly

import gc
print(gc.isenabled())
gc.disable()
print(gc.isenabled())
gc.enable()
print(gc.isenabled())
Output:
True
False
True
Destructors:
 Destructors is a special method and the name should be __del__
 Just before destroying an object Garbage Collector always calls destructor to perform
clean up activities(Resource deallocation activities like close database connection
etc).
 Once Destructor execution completed then Garbage Collector automatically destroys
that object.
Note: The job of destructor is not to destroy object and it is just to perform clean up
activities.

import time
class Test:
def __init__(self):
print("Object Intialization")
def __del__(self):
print("Fulfilling last wish and performing clean up activities..")
t1=Test()
t1=None
time.sleep(5)
print("End of application")

Output:
Object Intialization
Fulfilling last wish and performing clean up activities..
End of application

Note: If the object does not contain any reference variable then only it is eligible for GC. ie
if the reference count is zero then only object eligible for GC.

import time
class Test:
def __init__(self):
print("Constructor execution...")
def __del__(self):
print("destructors execution..")

t1=Test()
t2=t1
t3=t2
del t1
time.sleep(5)
print("Object not yet destroyed after deleting t1")
del t2
time.sleep(5)
print("object not yet destroyed even after deleting t2")
print("I am trying to delete last reference variable..")
del t3

Output:
Constructor execution...
Object not yet destroyed after deleting t1
object not yet destroyed even after deleting t2
I am trying to delete last reference variable..
destructors execution..

Example:
import time
class Test:
def __init__(self):
print("Constructor Execution")
def __del__(self):
print("Destructor Execution")

list=[Test(),Test(),Test()]
del list
time.sleep(5)
print("End of application")

Output:
Constructor Execution
Constructor Execution
Constructor Execution
Destructor Execution
Destructor Execution
Destructor Execution
End of application

How to find the Number of References of an Object:


sys module contains getrefcount() function for this purpose.
sys.getrefcount(objectreference)
import sys
class Test:
pass
t1=Test()
t2=t1
t3=t1
t4=t1
print(sys.getrefcount(t1))

Note: For Every object, Python internally maintains one default reference variable self.

OOP’s Part-2
Agenda:

Inheritance
Has –A- Relationship
IS-A-Relationship
IS-A vs HAS-A Relationship
Composition vs Aggregation

Types of Inheritance
Single Inheritance
Multi Level Inheritance
Hierarchical Inheritance
Multiple Inheritance
Hybrid Inheritance
Cyclic Inheritance
Method Resolution Order(MRO)
Super () Method

Using Members of One Class inside Another Class:


We can use members of one class inside another class by using the following ways

1. By Composition (Has-A-Relationship)
2.By Inheritance (Is-A-Relationaship)

1) By Composition (Has-A-Relationship):
 By using Class Name or by creating object we can access members of one class
inside another class is nothing but composition (Has- A- Relationship).
 The main advantage of Has-A-Relationship is code Reusability.
Demo Program-1:

class Engine:
a=10
def __init__(self):
self.b=20
def m1(self):
print("Engine Specific Functionality")
class Car:
def __init__(self):
self.engine=Engine()
def m2(self):
print('Car using Engine Class Functionality')
print(self.engine.a)
print(self.engine.b)
self.engine.m1()
c=Car()
c.m2()

Output:
Car using Engine Class Functionality
10
20
Engine Specific Functionality

Demo Program-2:

class Car:
def __init__(self,name,model,color):
self.name=name
self.model=model
self.color=color
def getinfo(self):
print("Car Name:{}, Model:{} and Color:{}" .format(self.name,self.model,self.color))
class Employee:
def __init__(self,ename,eno,car):
self.ename=ename
self.eno=eno
self.car=car
def empinfo(self):
print("Employee Name:",self.ename)
print("Employee Number:",self.eno)
print("Employee Car Info:")
self.
car.getinfo()
c=Car("Innova","2.5V","Grey")
e=Employee('Naresh',10000,c)
e.empinfo()

Output:
Employee Name: Naresh
Employee Number: 10000
Employee Car Info:
Car Name:Innova, Model:2.5V and Color:Grey

In the above program Employee class Has-A-Car reference and hence Employee class
can access all members of Car class.

Demo Program-3:

class X:
a=10
def __init__(self):
self.b=20
def m1(self):
print("m1 method of X class")
class Y:
c=30
def __init__(self):
self.d=40
def m2(self):
print("m2 method of Y class")
def m3(self):
x1=X()
print(x1.a)
print(x1.b)
x1.m1()
print(Y.c)
print(self.d)
self.m2()
print("m3 method of Y class")
y1=Y()
y1.m3()

Output:
10
20
m1 method of X class
30
40
m2 method of Y class
m3 method of Y class

2) By Inheritance (IS-A Relationaship):


What ever Variables, methods and constructors available in the parent class by default
available to the child classes and we are not required to rewrite. Hence the main
advantage of Inheritance is Code Reusability and we can extend existing functionality with
some more extra functionality.

Syntax: class child class(parent class)

class P:
a=10
def __init__(self):
self.b=10
def m1(self):
print("Parent Instant method")
@classmethod
def m2(cls):
print("parent class method")
@staticmethod
def m3():
print("Parent static method")

class C(P):
pass

c=C()
print(c.a)
print(c.b)
c.m1()
c.m2()
c.m3()

Output:
10
10
Parent Instant method
parent class method
Parent static method

class P:
a=10 methods
class C(P):
5 methods

In the above example parent class contains 10 methods and these methods automatically
available to the child class and we are not required to rewrite those methods(Code
Reusability)
Hence child class contains 15 methods.

Note: What ever members present in Parent class are by default available to the child
class through inheritance.

class P:
def m1(self):
print("Parent class method")
class C(P):
def m2(self):
print("Child class Method")
c=C()
c.m1()
c.m2()

Output:
Parent class method
Child class Method

What Ever methods present in parent class are automatically available to the child class
and hence on the child class reference we can call both parent class methods and child
class methods.
Similarly variables also
class P:
a=10
def __init__(self):
self.b=20
class C(P):
c=30
def __init__(self):
super(). __init__() #===>Line-1
self.d=30
c1=C()
print(c1.a,c1.b,c1.c,c1.d)

Output:
10 20 30 30

If we comment Line-1 then variable b is not available to the child class.

Demo Program for Inheritance:

class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def eatndrink(self):
print("Eat biryani and DrinkThumsup")
class Employee(Person):
def __init__(self,name,age,eno,esal):
super(). __init__(name,age)
self.eno=eno
self.esal=esal

def work(self):
print("Coding Python is very easy just like drinking chilled thumsup")
def empinfo(self):
print("Employee name:",self.name)
print("Employee Age:",self.age)
print("Employee Number",self.eno)
print("Employee Salary",self.esal)
e=Employee('Naresh',28,100,10000)
e.eatndrink()
e.work()
e.empinfo()

Output:
Eat biryani and DrinkThumsup
Coding Python is very easy just like drinking chilled thumsup
Employee name: Naresh
Employee Age: 28
Employee Number 100
Employee Salary 10000

IS-A vs HAS-A Relationship:


If we want to extend existing functionality with some more extra functionality then we
should go for IS-A Relationaship
If we don’t want to extend and just we have to use existing functionality then we should go
for HAS-A Relationship.
Eg: Employee class extends Person class Functionality But Employee class just uses Car
functionality but not extending

class Car:
def
__init__(self,name,model,color):
self.name=name
self.model=model
self.color=color
def getinfo(self):
print("Car Name:{}, Model:{} and Color:{}" .format(self.name,self.model,self.color))
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def eatndrink(self):
print("Eat Biryani and Drink Beer")

class Employee(Person):
def __init__(self,name,age,eno,esal,car):
super().__init__(name,age)
self.eno=eno
self.esal=esal
self.car=car
def work(self):
print("Coding python is very easy just like drinking chilled Beer")
def empinfo(self):
print("Employee Name:",self.name)
print("Employee Age:",self.age)
print("Employee Number:",self.eno)
print("Employee Salary:",self.esal)
print("Employee Car Info:")
self.car.getinfo()

c=Car("Innova","2.5V","Grey")
e=Employee('Naresh',28,100,10000,c)
e.eatndrink()
e.work()
e.empinfo()

Output:
Eat Biryani and Drink Beer
Coding python is very easy just like drinking chilled Beer
Employee Name: Naresh
Employee Age: 28
Employee Number: 100
Employee Salary: 10000
Employee Car Info:
Car Name:Innova, Model:2.5V and Color:Grey

In the above example Employee class extends Person class functionality but just uses Car
class Functionality.

Composition vs Aggregation:
Composition:
Without Existing Container object if there is no chance of existing contained object then
the container and contained objects are strongly associated and that strong association is
nothing but Composition.

Eg:
University Contains several departments and without existing university object there is no
chance of existing Department Object .Hence University and Department Objects are
strongly associated and this strong association is nothing but composition.

Aggregation:
Without existing container object if there is a chance of existing contained object then the
container and contained objects are weakly associated and that weak association is
nothing but Aggregation.
Eg: Department contains several Professors. Without Existing Department still there may
be a chance of existing professor. Hence Department and Professor Object are weakly
associated, which is nothing but Aggregation.
Coding Example:

class Student:
collegeName="NICESOFT"
def __init__(self,name):
self.name=name
print(Student.collegeName)
s=Student("Naresh")
print(s.name)

Output:
NICESOFT
Naresh

In the above example without existing student object there is no chance of existing his
name. Hence Student Object and his name are strongly associated which is nothing but
Composition.
But without existing Student object there may be a chance of existing college Name.
Hence Student object and college Name are weakly associated which is nothing but
Aggregation.

Conclusion:
The relation between object and Instant Variables is always Composition where as the
relation between object and static variables is Aggregation.

Note: Whenever we are creating child class object then child class constructor will be
executed. If the child class does not contain constructor then parent class constructor
will be executed, but parent object won’t be created.

class P:
def __init__(self):
print(id(self))
class C(P):
pass
c=C()
print(id(c))
Output:
44459984
44459984

class Person:
def __init__(self,name,age):
self.name=name
self.age=age
class Student(Person):
def __init__(self,name,age,rollno,marks):
super(). __init__(name,age)
self.rollno=rollno
self.marks=marks
def __str__(self):
return 'Name={}\nAge={}\nRollno={}\nMarks={}'.format(self.name,self.age,self.rollno,self.marks)
s1=Student('Naresh',28,101,90)
print(s1)
Output:
Name=Naresh
Age=28
Rollno=101
Marks=90

Note: In the above example whenever we are creating child class object both parent
and child class constructors got executed to perform initialization of child object.

Types Of Inheritance:

1) Single Inheritance:
The concept of inheriting the properties from one class to another class is known as
single inheritance.

class P:
def m1(self):
print("Parent Method")
class C(P):
def m2(self):
print("Child Method")
c=C()
c.m1()
c.m2()

Output:
Parent Method
Child Method

2) Multi Level Inheritance:


The concept of Inheriting the properties from multiple classes to single class with the
concept of one after another is known as multilevel inheritance.

class P:
def m1(self):
print("Parent Method")
class C(P):
def m2(self):
print("Child Method")
class CC(C):
def m3(self):
print("Sub Child Method")
c=CC()
c.m1()
c.m2()
c.m3()

Output:
Parent Method
Child Method
Sub Child Method

3) Hierarchical Inheritance:
The concept of Inheriting the properties from one class into multiple classes which are
present at same level is known as Hierarchical Inheritance.

class P:
def m1(self):
print("Parent Method")
class C1(P):
def m2(self):
print("Child1 Method")
class C2(P):
def m3(self):
print("Child2 Method")
c1=C1()
c1.m1()
c1.m2()
c2=C2()
c2.m1()
c2.m3()

Output:
Parent Method
Child1 Method
Parent Method
Child2 Method

4) Multiple Inheritance:
The Concept of inheriting the properties from multiple classes into a single class at a
time, is known as multiple inheritance.

class P1:
def m1(self):
print("Parent1 Method")
class P2:
def m2(self):
print("Parent2 Method")
class C(P1,P2):
def m3(self):
print("Child2 Method")
c1=C()
c1.m1()
c1.m2()
c1.m3()

Output:
Parent1 Method
Parent2 Method
Child2 Method
If the same method is inherited from both present classes, then Python will always
consider the order of Parent classes in the declaration of the child class.

Class C(P1,P2): P1 method will be considered


Class C(P2,P1): P2 method will be considered

class P1:
def m1(self):
print("Parent1 Method")
class P2:
def m1(self):
print("Parent2 Method")
class C(P1,P2):
def m2(self):
print("Child Method")
c1=C()
c1.m1()
c1.m2()

Output:
Parent1 Method
Child Method
5) Hybrid Inheritance:
Combination of single, Multi level,multiple and Hierarchical inheritance is known as
Hybrid Inheritance.
6) Cyclic Inheritance:
The concepts of inheriting properties from one class o another class in cyclic way,is
called Cyclic inheritance. Python won’t support for Cyclic Inheritance of course it is
really not required.

Eg-1 class A(A): pass


Name Error: name ‘A’ is not defined

Eg:-2
class A(B):
Pass
class B(A):
pass
name error: name ‘B’ is not defined.
Method Resolution Order (MRO):
In Hybrid Inheritance the method resolution order is decided based on MRO
ALGORITHM.
This algorithm is also known as C3 algorithm.
Samuele Pedroni proposed this algorithm.
It follows DLR (Depth First Left to Right) i.e Child will get more priority than Parent.
Left Parent will get more priority than Right Parent.
MRO(X)=X+Merge(MRO(P1),MRO(P2),….ParentList)

Head Element vs Tail Terminology:

AssumeC1,C2,C3,….ARE classes
In the list: C1C2C3C4C5……
C1 is considered as Head Element and remaining is considered as Tail.

How to Find Merge:

Take the head of First List


If the head is not in the tail part of any other list, then add this head to the result and
remove it from the lists in the merge.
If the head is present in the tail part of any other list, then consider the head element
of the next list and continue the same process.
Note:We can find MRO of any class by using mro() function
Print(ClassName.mro())

Demo Program-1 for Method Resolution Order:


mro(A) = A, object
mro(B) = B, A, object
mro(C) = C, A, object
mro(D) = D, B, C, A, object

test.py:

class A:pass
class B(A):pass
class C(A):pass
class D(B,C):pass
print(A.mro())
print(B.mro())
print(C.mro())
print(D.mro())

Output:
[<class '__main__.A'>, <class 'object'>]
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
[<class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class
'__main__.A'>, <class 'object'>]

Demo Program-2 for Method Resolution Order:


Mro(A)=A,object
Mro(B)=B,object
Mro(C)= C,object
Mro(X)=X,A,B,object
Mro(Y)=Y,B,C,object
Mro(P)=P,X,A,Y,B,C,object

Finding mro(P) by using C3 Algorithm:


Formula: MRO(X)= X+Merge (MRO(P1),MRO(P2),…….ParentList)
mro(p)= P+Merge(mro(X),mro(Y),mro(C),XYC)
=P+Merge(XABO,YBCO,CO,XYC)
=P+X+Merge(XABO,YBCO,CO,XYC)
=P+X+A+Merge(XABO,YBCO,CO,XYC)
=P+X+A+Y+Merge(XABO,YBCO,CO,XYC)
=P+X+A+Y+B+Merge(XABO,YBCO,CO,XYC)
=P+X+A+Y+B+C+O
Test.py

class A: pass
class B: pass
class C: pass
class X(A,B): pass
class Y(B,C): pass
class P(X,Y,C): pass

print(A.mro())#AO
print(X.mro())#XABO
print(Y.mro())#YBCO
print(P.mro())#PXAYBCO

Output:
[<class '__main__.A'>, <class 'object'>]
[<class '__main__.X'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
[<class '__main__.Y'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]
[<class '__main__.P'>, <class '__main__.X'>, <class '__main__.A'>, <class
'__main__.Y'>, <class '__main__.B'>, <class '__main__.C'>, <class 'object'>]

Test.py:

class A:
def m1(self):
print('A class method')
class B:
def m1(self):
print('B class method')
class C:
def m1(self):
print('C class method')
class X(A,B):
def m1(self):
print('X class method')
class Y(B,C):
def m1(self):
print('Y class method')
class P(X,Y,C):
def m1(self):
print('P class method')
p=P()
p.m1()
Output:
P class method

In the above example P class m1() method will be considered. If P class does not
contain m1() method then as per MRO, X class method will be considered. If X class
does not contain then A class method will be considered and this process will be
continued.

The method resolution in the following order: PXAYBCO

Demo Program-3 for Method Resolution Order:

mro(o) = object
mro(D)=D,object
mro(E)=E,object
mro(F)=F,object
mro(B)=B,D,E,object
mro(C)=C,D,F,object
mro(A)=A+Merge(mro(B),mro(C),BC)
A+Merge(BDEO,CDFO,BC)
A+B+Merge(DEO,CDFO,C)
A+B+C+Merge(DEO,DFO)
A+B+C+D+Merge(EO,FO)
A+B+C+D+E+Merge(O,FO)
A+B+C+D+E+F+Merge(O,O)
A+B+C+D+E+F+O

Test.py:
class D:pass
class E:pass
class F:pass
class B(D,E):pass
class C(D,F):pass
class A(B,C):pass
print(D.mro())
print(B.mro())
print(C.mro())
print(A.mro())

Output:
[<class '__main__.D'>, <class 'object'>]
[<class '__main__.B'>, <class '__main__.D'>, <class '__main__.E'>, <class 'object'>]
[<class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <class 'object'>]
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class
'__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <class 'object'>]

super() Method:
super () is a built – in method which is useful to call the super class constructor,
variables and methods from the child class.The main Purpose is code reusability.

Demo Program-1 for super():

class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def display(self):
print('Name:',self.name)
print('Age:',self.age)

class Student(Person):
def __init__(self,name,age,rollno,marks):
super(). __init__(name,age)
self.rollno=rollno
self.marks=marks
def display(self):
super().display()
print('Roll No:',self.rollno)
print('Marks:',self.marks)

s1=Student('Durga',22,101,90)
s1.display()

Output:
Name: Durga
Age: 22
Roll No: 101
Marks: 90

In the above program we are using super() method to call parent class constructor and
display() method.

Demo Program-2 for super():


class P:
a=10
def __init__(self):
self.b=10
def m1(Self):
print('Parent Instance Method')
@classmethod
def m2(cls):
print('parent class method')
@staticmethod
def m3():
print('parent static method')

class C(P):
a=888
def __init__(self):
self.b=999
super().__init__()
print(super().a)
super().m1()
super().m2()
super().m3()
c=C()

Output:
10
Parent Instance Method
parent class method
parent static method

In the above example we are using super() to call various members of parent class.

How to call Method of a Particular Super Class:


We can use the fallowing approaches

1. super (D,self).m1()
It will call m1() method of super class of D.
2. A.m1(self)
It will call A class m1() method

class A:
def m1(Self):
print('A class Method')
class B(A):
def m1(self):
print('B class Method')
class C(B):
def m1(self):
print('C class Method')
class D(C):
def m1(self):
print('D class Method')
class E(D):
def m1(self):
A.m1(self)
e=E()
e.m1()
Output:
A class Method

Various Important Points about super():

Case:1 From child class we are not allowed to access parent class instance variables
by using super(),Compulsory we should use self only.
But we can access parent class static variables by using super().

class P:
a=10
def __init__(self):
self.b=20
class C(P):
def m1(self):
print(super().a)#valid
print(self.b)#valid
print(super().b)#invalid
c=C()
c.m1()

Output:
10
20
AttributeError: ‘Super’ object has no attribute ‘b’.

Case:2 From child class constructor and instance method, we can access parent class
instance method, static method and class method by using super()

class P:
def __init__(self):
print('Parent Constructor')
def m1(self):
print('Parent Instance Method')
@classmethod
def m2(cls):
print('Parent class Method')
@staticmethod
def m3():
print('Parent Static Method')
class C(P):
def __init__(self):
super().__init__()
super().m1()
super().m2()
super().m3()

def m1(self):
super().__init__()
super().m1()
super().m2()
super().m3()
c=C()
c.m1()

Output:
Parent Constructor
Parent Instance Method
Parent class Method
Parent Static Method
Parent Constructor
Parent Instance Method
Parent class Method
Parent Static Method

Case3: From child class, class method we cannot access parent class instance
methods and constructor by using super() directly(but indirectly possible). But we can
access parent class static and class methods.

class P:
def __init__(self):
print('parent constructor')
def m1(self):
print('Parent Instance Method')
@classmethod
def m2(cls):
print('Parent class method')
@staticmethod
def m3():
print('Parent static method')
class C(P):
@classmethod
def m1(cls):
#super().__init__()-->invalid
#super().m1()-->invalid
super().m2()
super().m3()

C.m1()

Output:
Parent class method
Parent static method

From Class Method of Child Class, How to call Parent class instance
methods and Constructors:

class A:
def __init__(self):
print('Parent constructor')
def m1(self):
print('Parent Instance Method')
class B(A):
@classmethod
def m2(cls):
super(B,cls).__init__(cls)
super(B,cls).m1(cls)

B.m2()

Output:
Parent Constructor
Parent instance Method

Case-4: In child class static method we are not allowed to use super() generally (But
in special way we can use)
class P:
def __init__(self):
print('Parent Constructor')
def m1(self):
print('Parent instance method')
@classmethod
def m2(cls):
print('Parent class Method')
@staticmethod
def m3():
print('Parent static method')
class C(P):
@staticmethod
def m1():
super().m1()#-->invalid
super().m2()#-->invalid
super().m3()#-->invalid

C.m1()

Output:
Runtime Error: super():no arguments

How to Call Parent Class Static Method From Child Class Static
Method By using super():

class A:

@staticmethod
def m1():
print('Parent static method')

class B(A):
@staticmethod
def m2():
super(B,B).m1()

B.m2()

Output:
Parent Static Method

OOP’s Part-3
POLYMORPHISM:
Poly means many. Morphs means forms.
Polymorphism means ‘Many Forms’.
Eg1: Yourself is best example of polymorphism. In front of Your parents You will have one type
of behavior and with friends another type of behavior. Same person but different behaviors at
different places , which is nothing but polymorphism.
Eg2: + operator acts as concatenation and arithmetic addition.
Eg3: * operator acts as multiplication and repetition operator
Eg4: The same method with different implementations in Parent class and child classes.
(overriding)
Related to Polymorphism he fallowing 4 topics are important
1. Duck Typing Philosophy of Python
2. Overloading
1.Operater Overloading
2.Method Overloading
3.Constructor Overloading
3.Overriding
1.Method Overriding
2.Constructor Overloading
1) Duck Typing Philosophy of Python:
In Python we cannot specify the type explicitly. Based on provided value at runtime the type
will be considered automatically. Hence Python is considered as Dynamically Typed Programing
Language.

def f1 (obj):

obj.talk()
what is the type of object? We cannot decide at the Beginning. At Runtime we can pass any
Type. Then how we can decide the Type?

At runtime if ‘it walks like a duck and talks like a duck, It must be duck’. Python follows this
principle. This is called Duck Typing Philosophy of Python.

class Duck:
def talk(self):
print('Quack...Quack...')

class Dog:
def talk(Self):
print('Bow..Bow..')
class Cat:
def talk(self):
print('Meow Meow')
class Goat:
def talk(self):
print('Myaah Myaah')
def f1(obj):
obj.talk()
I=[Duck(),Cat(),Dog(),Goat()]
for obj in I:
f1(obj)

Output:
Quack...Quack...
Meow Meow
Bow..Bow..
Myaah Myaah

The problem in this approach is if obj does not contain talk() method then we will get
AttributeError.

class Duck:
def talk(self):
print('Quack...Quack...')
class Dog:
def bark(Self):
print('Bow..Bow..')
def f1(obj):
obj.talk()

d=Duck()
f1(d)
d=Dog()
f1(d)
Output:
Quack...Quack...
Traceback (most recent call last):
File "C:/Users/Nice Computers/AppData/Local/Programs/Python/Python37-32/test.py", line
14, in <module>
f1(d)
File "C:/Users/Nice Computers/AppData/Local/Programs/Python/Python37-32/test.py", line 9,
in f1
obj.talk()
AttributeError: 'Dog' object has no attribute 'talk'

But we can solve this problem by using hasattr() function


Hasattr(obj,’attributename’) attributename can be Method Name OR Variable name

Demo Program with hasattr() Function:

class Duck:
def talk(self):
print('Quack..Quack..')

class Human:
def talk(self):
print('Hello Hi')

class Dog:
def bark(self):
print('Bow..Bow..')
def f1(obj):
if hasattr(obj,'talk'):
obj.talk()
elif hasattr(obj,'bark'):
obj.bark()

d=Duck()
f1(d)
h=Human()
f1(h)
d=Dog()
f1(d)

Output:
Quack..Quack..
Hello Hi
Bow..Bow..

2. Overloading
We can use same operator or methods for different purposes.
Eg1: + operator can be used for Arithmetic addition and string concatenation
Print(10+20)#30
Print(‘nice’+’soft’)#nicesoft

Eg:2
*Operator can be used for multiplication and string repetition purposes.
Print(10*20)#200
Print(‘Nice’*3)#nicenicenice

Eg:3
We can use deposit() method to deposit cash or cheque or dd
Deposit(cash)
Deposit(cheque)
Deposit(dd)
There are 3 types of overloading
1. Operator Overloading
2. Method Over loading
3. Constructor Overloading
1.Operator Over Loading:
We can use the same operator for multiple purposes, which is nothing but operator
overloading.
Python supports operator overloading.
Eg:1 + operator can be used for Arithmetic addition and string concatenation
Print(10+20)#30
Print(‘Nice’+’soft’)#nicesoft
Eg:2 *operator can be used for multiplication and string repetition purposes.
Print((10*20)#200
Print(‘nice’*3)#nicenicenice

Demo program to use + operator for our class objects:


class Book:
def __init__(self,pages):
self.pages=pages

b1=Book(100)
b2=Book(200)
print(b1+b2)
output:
Traceback (most recent call last):
File "C:/Users/Nice Computers/AppData/Local/Programs/Python/Python37-32/test.py", line 7,
in <module>
print(b1+b2)
TypeError: unsupported operand type(s) for +: 'Book' and 'Book'

Note:
We can overload + operator to work with book objects also. i.e. Python supports operator
overloading
For every operator Magic methods are available.To overload any operator we have to override
that method in our class
Internally + operator is implemented by using __add__() method.This method is called magic
method for + operator.We have to override this method in our class.

Demo Program to Overload + operator for Our Book Class Objects:


class Book:
def __init__(self,pages):
self.pages=pages
def __add__(self,other):
return self.pages+other.pages

b1=Book(100)
b2=Book(200)
print('The total Number of pages:',b1+b2)

Output:
The total Number of pages: 300
The fallowing is the list of operators and corresponding magic methods:
1) +  object.__add__(self,other)
2) -  object.__sub__(self,other)
3) *  object.__mul__(self,other)
4) /  object.__div__(self,other)
5) //  object.__floordiv__(self,other)
6) %  object.__mod__(self,other)
7) **  object.__pow__(self,other)
8) +=  object.__iadd__(self,other)
9) -=  object.__isub__(self,other)
10) *=  object.__imul__(self,other)
11) /=  object.__idiv__(self,other)
12) //=  object.__ifloordiv__(self,other)
13) %=  object.__imod__(self,other)
14) **=  object.__ipow__(self,other)
15) <  object.__it__(self,other)
16) <=  object.__Ie__(self,other)
17) >  object.__gt__(self,other)
18) >=  object.__ge__(self,other)
19) ==  object.__eq__(self,other)
20) !=  object.__ne__(self,other)

Overloading > and <= Operators for student Class Objects:


class Student:
def __init__(self,name,marks):
self.name=name
self.marks=marks
def __gt__(self,other):
return self.marks>other.marks
def __le__(self,other):
return self.marks<=other.marks

print("10>20=",10>20)
s1=Student("Durga",100)
s2=Student("Ravi",200)
print("s1<s2=",s1>s2)
print("s1<s2=",s1<s2)
print("s1<=s2=",s1<=s2)
print("s1>=s2=",s1>=s2)

output:

10>20= False
s1<s2= False
s1<s2= True
s1<=s2= True
s1>=s2= False

Program to Overload Multiplication Operator to work on Employee Object:


class Employee:
def __init__(self,name,salary):
self.name=name
self.salary=salary
def __mul__(self,other):
return self.salary*other.days
class TimeSheet:
def __init__(self,name,days):
self.name=name
self.days=days

e=Employee('Durga',500)
t=TimeSheet('Durga',25)
print('This Month Salary:',e*t)

Output:
This Month Salary: 12500
2.Method Overloading:
If 2 methods having same name but different type of arguments then those methods are said to
be overloaded methods.
Eg: m1(int a)
m1(double d)
But in python Method Overloading is not possible.
If we are trying to declare multiple methods with same name and different number of
arguments then Python will always consider only last method.

Demo Program:
class Test:
def m1(self):
print('no-arg method')
def m1(self,a):
print('one-arg method')
def m1(self,a,b):
print('two-arg method')
t=Test()
#t.m1()
#t.m1(10)
t.m1(10,20)

Output: two-arg method


In the above program python will consider only last method.

How we can handle Overloaded Method Requirements in Python:


Most of the times, If method with variable number of arguments required then we can handle
with default arguments or with variable number of argument methods.

Demo programs with Default arguments:


class Test:
def sum(self,a=None,b=None,c=None):
if a!=None and b!=None and c!=None:
print('The sum of 3 Numbers:',a+b+c)
elif a!=None and b!=None:
print('The sum of 2 Numbers:',a+b)
else:
print('Please provide 2 or 3 arguments')
t=Test()
t.sum(10,20)
t.sum(10,20,30)
t.sum(10)

Output:
The sum of 2 Numbers: 30
The sum of 3 Numbers: 60
Please provide 2 or 3 arguments
Demo Program with Variable number of arguments:
class Test:
def sum(self,*a):
total=0
for x in a:
total=total+x
print('The sum:',total)
t=Test()
t.sum(10,20)
t.sum(10,20,30)
t.sum(10)
t.sum()

Output:
The sum: 30
The sum: 60
The sum: 10
The sum: 0

3. Constructor OverLoading:
Constructor Overloading is not possible in Python.
If we define multiple constructors then the last constructor will be considered.
class Test:
def __init__(self):
print('No-Arg Constructor')
def __init__(self,a):
print('One Arg constructor')
def __init__(self,a,b):
print('two-Arg constructor')
#t1=Test()
#t1=Test(10)
t1=Test(10,20

Output:
two-Arg constructor
In the above program only Two-Arg Constructor is available.
But based on our requirement we can declare constructor with default arguments and
variable number of arguments.
Constructor with Default Arguments:
class Test:
def __init__(self,a=None,b=None,c=None):
print('Constructor with 0|1|2|3 number of arguments')

t1=Test()
t2=Test(10)
t3=Test(10,20)
t4=Test(10,20,30)

Output:
Constructor with 0|1|2|3 number of arguments
Constructor with 0|1|2|3 number of arguments
Constructor with 0|1|2|3 number of arguments
Constructor with 0|1|2|3 number of arguments

Constructor with Variable Number of Arguments:


class Test:
def __init__(self,*a):
print('Constructor with variable number of arguments')

t1=Test()
t2=Test(10)
t3=Test(10,20)
t4=Test(10,20,30)
t5=Test(10,20,30,40,50,60)

Output:
Constructor with variable number of arguments
Constructor with variable number of arguments
Constructor with variable number of arguments
Constructor with variable number of arguments
Constructor with variable number of arguments

3 Overriding:
Method Overriding
What ever members available in the parent class are by default available to the child class
through inheritance. If the child class not satisfied with parent class implementation then
child class is allowed to redefine that method in the child class based on its requirement.
This concept is called as overriding.
Over riding concept applicable for both methods and constructors.
Demo Program for Method Overriding:

class P:
def property(self):
print('Gold+Land+Cash+Power')
def marry(self):
print('Appalamma')
class C(P):
def marry(self):
print('Katrina Kaif')

c=C()
c.property()
c.marry()

Output:
Gold+Land+Cash+Power
Katrina Kaif

From Overriding method of child class, We can call parent class method also by using super()
method.

class p:
def property(self):
print('Gold+land+cash+power')
def marry(self):
print('Appalama')
class C(p):
def marry(self):
super().marry()
print('kartina kaif')
c=C()
c.property()
c.marry()
Output:
Gold+Land+Cash+Power
Appalamma
Katrina kaif

Demo Program For Constructor Overriding:


class P:
def __init__(self):
print('parent Constructor')
class C(P):
def __init__(self):
print('child Constructor')
c=C()

Output:
'child Constructor'
In the above example, If child class does not contain constructor then parent class
constructor will be executed.

From child class constructor we can call parent class constructor by using super() method.

Demo program to call Parent Class constructor by using super():


class Person:
def __init__(self,name,age):
self.name=name
self.age=age

class Employee(Person):
def __init__(self,name,age,eno,esal):
super().__init__(name,age)
self.eno=eno
self.esal=esal

def display(self):
print('Employee Name:',self.name)
print('Employee Age:',self.age)
print('Employee Number:',self.eno)
print('Employee Salary:',self.esal)
e1=Employee('Naresh',48,872425,26000)
e1.display()
e2=Employee('Sunny',39,872426,36000)
e2.display()
Output:
Employee Name: Naresh
Employee Age: 48
Employee Number: 872425
Employee Salary: 26000
Employee Name: Sunny
Employee Age: 39
Employee Number: 872426
Employee Salary: 36000

OOP’S Part-4
Agenda :
 Abstract Method
 Abstract class
 Interface
 Public, Private and protected Members
 __str__() Method
 Difference between str() and repr() functions
 Small Banking Application
Abstract Method:
Sometimes we don’t know about implementation, still we can declare a method.Such types of
methods are called abstract methods. i.e abstract method has only declaration but not
implementation.
In python we can declare abstract method by using @abstractmethod decorator as fallows.

@abstractmethod
def m1(self):pass
@abstractmethod decorator present in abc module. Hence compulsory we should import abc module ,
otherwise we will get error
abcabstract base class module

class Test:
@abstractmethod
def m1(self):
pass
output:
NameError: name 'abstractmethod' is not defined

Eg:
from abc import*
class Test:
@abstractmethod
def m1(self):
pass

Eg:
from abc import*
class Fruit:
@abstractmethod
def taste(self):
pass
Child classes are responsible to provide implementation for parent class abstract method

Abstract class:
Some times implementation of a class is not complete, such type of partially implementation
Classes are called abstract classes . Every abstract class in python should be derived from ABC class
which is present in abc module .

Case-1:
from abc import*
class Test:
pass
t=Test()

In the above code we can create object for Test class b’z it is concrete class and it does not conatin
any abstract method.

Case-2:
from abc import*
class Test(ABC):
pass

t=Test()

In the above code we can create object, even it is derived from ABC class ,b’z it does not contain any
abstract method.

Class-3:
from abc import*
class Test(ABC):
@abstractmethod
def m1(self):
pass
t=Test()
Output:
Type Error: cant instantiate abstract class Test with abstract methods m1

Case-4:
from abc import*
class Test:
@abstractmethod
def m1(self):
pass
t=Test()

We can create object even class contains abstract method b’z we are not extending ABC class.
Case-5:
from abc import*
class Test:
@abstractmethod
def m1(self):
print('Hello')
pass
t=Test()
t.m1()

Output: Hello

Conclusion: If a class contains at least one abstract method and if we are extending ABC class then
instantiation is not possible.
“abstract class with abstract method instantiation is not possible”
Parent class abstract methods should be implemented in the child classes. Otherwise we cannot
instantiate child class. If we are not creating child class object then we won’t get any error.

Case-1:
from abc import*
class Vehicle(ABC):
@abstractmethod
def noofwheels(self):
pass
class Bus(Vehicle):pass

Note:It is valid because we are not creating Child Class object.

Case-2:
from abc import*
class Vehicle(ABC):
@abstractmethod
def noofwheels(self):
pass
class Bus(Vehicle):pass
b=Bus()

Output:
TypeError: Can't instantiate abstract class Bus with abstract methods noofwheels

Note: If we are extending abstract class and does not override its abstract method then child class is
also abstract and instantiation is not possible.

from abc import*


class Vehicle(ABC):
@abstractmethod
def noofwheels(self):
pass
class Bus(Vehicle):
def noofwheels(self):
return 7

class Auto(Vehicle):
def noofwheels(self):
return 3

b=Bus()
print(b.noofwheels())#7

a=Auto()
print(a.noofwheels())#3

Output:
7
3
Note: Abstract class can contain both abstract and non-abstract methods also.

Interfaces in Python:
In general if an abstract class contains only abstract methods such type of abstract class is considered
as interface.

from abc import *


class DBInterface(ABC):
@abstractmethod
def connect(self):pass
@abstractmethod
def disconnect(self):pass

class Oracle(DBInterface):
def connect(self):
print('Connecting to Oracle Database...')
def disconnect(self):
print('Disconnecting to Oracle Database...')

class Sqlbase(DBInterface):
def connect(self):
print('Connecting to sql database...')
def disconnect(self):
print('Disconnecting to Sql Database....')

dbname=input('Enter Database Name:')


classname=globals()[dbname]
x=classname()
x.connect()
x.disconnect()

Output:
Enter Database Name:Oracle
Connecting to Oracle Database...
Disconnecting to Oracle Database...
Enter Database Name:Sqlbase
Connecting to sql database...
Disconnecting to Sql Database....

Note: The inbuilt function globals()[str] converts the string ‘str’ into a class name and returns the
class name.

Demo program-2: Reading class name from the file

Config.txt
EPSON

Test.py
from abc import *
class Printer(ABC):
@abstractmethod
def printit(self,text):pass

@abstractmethod
def disconnect(self):pass

class EPSON(Printer):
def printit(self,text):
print('Printing from EPSON Printer...')
print(text)
def disconnect(self):
print('Printing completed on Epson Printer...')

class HP(Printer):
def prinit(self,text):
print('printing from HP Printer...')
print(text)
def disconnect(self):
print('Printing completed from HP Printer..')
with open('config.txt','r') as f:
pname=f.readline()

classname=globals()[pname]
x=classname()
x.printit('This data has no print...')
x.disconnect()

Output:
Printing from EPSON Printer...
This data has no print...
Printing completed on Epson Printer...

Concreate class vs Abstract Class vs Interface:


If we don’t know anything about implementation just we have requirement specification then we
should go for interface.
If we are talking about implementation but not completely then we should go for abstract
class(partially implemented class)
If we are talking about implementation completely and ready to provide service then we should go
for concrete class.

from abc import*


class CollegeAutomation(ABC):
@abstractmethod
def m1(self):pass
@abstractmethod
def m2(self):pass
@abstractmethod
def m3(self):pass
class AbsCls(CollegeAutomation):
def m1(self):
print('m1 method implementation')
def m2(self):
print('m2 method implementation')

class ConcreteCls(AbsCls):
def m3(self):
print('m3 method implementation')
c=ConcreteCls()
c.m1()
c.m2()
c.m3()

Output:
m1 method implementation
m2 method implementation
m3 method implementation

Public, Protected and Private Attributes:


By default every attribute is public. We can access from anywhere either within the class or from
outside of the class.
Eg: name= ‘navya’
Protected attributes can be accessed within the class anywhere but from outside of the class only in
child classes. We can specify an attribute as protected by prefixing with _ symbol
Syntax: _variablename=value
Eg: _name=’naresh’
But is just convention and in really does not exists protected attributes.
Private attributes can be accessed only with in the class. i.e from outside of the class we connot
access. We can declare a variable as private explicitly by prefixing with 2 underscore symbols.

Syntax: __variablename=value
Eg: __name=’naresh’

class Test:
x=10
_y=20
__z=30
def m1(self):
print(Test.x)
print(Test._y)
print(Test.__z)
t=Test()
t.m1()
print(Test.x)
print(Test._y)
print(Test.__z)

Output:
10
20
30
10
20
Traceback (most recent call last):
File "C:/Users/Nice Computers/Desktop/test.py", line 13, in <module>
print(Test.__z)
AttributeError: type object 'Test' has no attribute '__z'

How to Access Private Variables fromOutside of the class:


We cannot access private variables directly from outside of the class. But we can access indirectly as
fallows…… objectreference. _classname__variablename

class Test:
def __init__(self):
self.__x=10
t=Test()
print(t._Test__x) #10

__str__ () method:
Whenever we are printing any object reference internally __str__() method will be called which is
returns string in the following format
<__main__.classname object at 0x022144B0>
To return meaningful string representation we have to override __str__() method

class Student:
def __init__(self,name,rollno):
self.name=name
self.rollno=rollno
def __str__(self):
return 'This is Student with Name:{} and Rollno:{}'.format(self.name,self.rollno)
s1=Student('Naresh',101)
s2=Student('Ravi',102)
print(s1)
print(s2)

Output with overriding str():


This is Student with Name:Naresh and Rollno:101
This is Student with Name:Ravi and Rollno:102
Output without Overriding str():
<__main__.Student object at 0x022144B0>
<__main__.Student object at 0x022144D0>

Difference between str() and repr()


(or)
Difference between __str__() and __repr__()
 Str() internally calls __str__() function and hence functionality of both is same.
 Similarly,repr() internally calss __repr__() function and hence functionality of both is same.
 Str() returns a string containing a nicely printable representation object.
 The main purpose of str() is for readability, It may not possible to convert result string to original
object.

import datetime
today=datetime.datetime.now()
s=str(today) #converting datetime object to str
print(s)
d=eval(s) #converting str object to datetime

Output:
2019-08-30 18:04:58.521169
Traceback (most recent call last):
File "C:/Users/Nice Computers/AppData/Local/Programs/Python/Python37-32/test.py", line 5, in
<module>
d=eval(s) #converting str object to datetime
File "<string>", line 1
2019-08-30 18:04:58.521169
^
SyntaxError: invalid token

But repr() returns a string containing a printable representation of object.


The main goal of repr() is unambigouous. We can convert result string to original object by using eval()
function,which may not possible in str() function.

import datetime
today=datetime.datetime.now()
s=repr(today) #converting datetime object to str
print(s)
d=eval(s) #converting str object to datetime
print(d)

Output:
datetime.datetime(2019, 8, 30, 18, 8, 53, 57670)
2019-08-30 18:08:53.057670
Note: It is recommended to use repr() instead of str()

Mini Project: Banking Application


class Account:
def __init__(self,name,balance,min_balance):
self.name=name
self.balance=balance
self.min_balance=min_balance

def deposit(self,amount):
self.balance+=amount
def withdraw(self,amount):
if self.balance-amount>=self.min_balance:
self.balance-=amount
else:
print("Sorry,Insufficient Funds")
def printStatement(self):
print("Account Balance:",self.balance)
class Current(Account):
def __init__(self,name,balance):
super().__init__(name,balance,min_balance=-1000)
def __str__(self):
return "{}'s Current account with balance:{}".format(self.name,self.balance)
class Savings(Account):
def __init__(self,name,balance):
super().__init__(name,balance,min_balance=0)
def __str__(self):
return "{}'s Savings Account with Balance:{}".format(self.name,self.balance)

c=Savings("Naresh",10000)
print(c)
c.deposit(5000)
c.printStatement()
c.withdraw(16000)
c.withdraw(15000)
print(c)
c2=Current("Ratnam",20000)
c2.deposit(6000)
print(c2)
c2.withdraw(27000)
print(c2)
Output:
Naresh's Savings Account with Balance:10000
Account Balance: 15000
Sorry,Insufficient Funds
Naresh's Savings Account with Balance:0
Ratnam's Current account with balance:26000
Ratnam's Current account with balance:-1000

EXCEPTION HANDLING
In any programming language there are 2 types of errors are possible.
1. Syntax Errors
2. Runtime Errors

1.Syntax Errors:
The errors which occur because of invalid syntax are called syntax errors.
Eg:1
x=10
if x==10
print("Hello")
SyntaxError: Invalid syntax

Eg:2
Print “Hello”
SyntaxError: Missing parentheses in call to ‘print’

Note : Programmer is responsible to correct these syntax errors. Once all syntax errors are corrected
then only program execution will be started.

2.Runtime Errors:
 Also Known as exceptions.
 While executing the program if something goes wrong because of end user input or programming
logic or memory problems etc then we will get runtime errors.
Eg :
1) print(10/0) Zero Division Errors: division by zero
2) print(10/”ten”) Type Error: Un supported operand type(s) for/:’int’ and ‘str’
3) x=int(input(“Enter Number”))
print(x)
c:\Python_classes>py test.py
Enter number: ten
ValueError: invalid literal for int() with base 10:’ten’
4) f=open(‘xyz.txt’)
print(f.read())
FileNotFoundError:
Note: Exception Handling concept applicable for Runtime Errors but not for syntax errors.

What is Exception?
An unwanted and unexpected event that disturbs normal flow of program is called exception.
Eg:
 ZeroDivisionError
 TypeError
 ValueError
 FileNotFoundError
 EOFError
 SleepingError
 TypePuncturedError
It is highly recommended to handle exceptions. The main objective of exception handling is GRACEFUL
TERMINATION OF THE PROGRAM(i.e we should not block our resources and we should not miss
anything)

Exception handling does not mean repairing exception. We have to define alternative way to continue
rest of the program normally.

Eg: For example our program requirement is reading data from remote file locating at London. At
runtime if London file is not available then the program should not be terminated abnormally, We have
to provide local file to continue rest of the program normally. This way of defining alternative is nothing
but exception handling.

try:
Read Data from Remote File locating at London.
Except FileNotFoundError:
Use local file and continue rest of the program normally

Q. What is an Exception
Q. What is the purpose of Exception Handling?
Q. What is the meaning of Exception Handling?
P1:This week end iam planning to goto my native place by bus.
P2:This week end iam planning to goto my native place by bus. If bus is not available then I will try for
train .If train is not available then I will try for flight. Still it is not available then I will go for cab.
Default Exception Handling in Python:
Every exception in python is an object. For every exception type the corresponding classes are available.
Whenever an exception occurs PVM will create the corresponding exception object and will check for
handling code. If Handling code is not available then Python interpreter terminates the program
abnormally and prints corresponding exception information to the console.
The rest of the program won’t be executed.

print("Hello")
print(10/0)
print("Hi")

Output:
Hello
Traceback (most recent call last):
File "C:/Users/Nice Computers/AppData/Local/Programs/Python/Python37-32/test.py", line 2, in
<module>
print(10/0)
ZeroDivisionError: division by zero

PYTHON’S EXCEPTION HIERARCHY

 Every Exception in Python is a class.


 All exception classes are child classes of Base Exception. i.e every exception class extends Base
Exception either directly or indirectly. Hence Base Exception acts as root for Python Exception
Hierarchy.
 Most of the times being a programmer we have to concentrate Exception and its child class.

Customized Exception Handling by using try-except:


It is highly recommended to handle exceptions.
The code which may raise exception is called risky code and we have to take risky code inside try block.
The corresponding handling code we have to take inside except block.

try:
Risky code
Except XXX:
Handling code/Alternative Code
Without try-except:
print(“stmt-1”)
print(10/0)
print(“stmt-3”)
Output:
Stmt-1
ZeroDivisionError: division by zero
Abnormal termination/Non –Graceful Termination.

With try-except:
Print(“stmt-1”)
try:
Print(10/0)
Except ZeroDivisionError:
Print(10/2)
Print(“stmt-3”)

Output:
Stmt-1
5.0
Stmt-3
Normal Termination/Graceful Termination
Control Flow in try-except:
try
stmt-1
stmt-2
stmt-3
except XXX
stmt-4
stmt-5
Case-1: If there is no exception
1,2,3,5 and Normal Termination
Case-2:If an exception raised at stmt-2 and corresponding except block matched 1,4,5 Normal
Termination
Case-3: If an exception rose at stmt-2 and corresponding except block not matched 1,Abnormal
Termination.
Case-4: If an exception rose at stmt-4 or at stmt-5 then it is always abnormal termination.

Conclusions:
With in the try block if anywhere exception raised then rest of the try block won’t be
Executed even though we handled that exception. Hence we have to take only risky code
inside try block and length of the try block should be as less as possible.
In addition to try block, there may be a chance of raising exceptions inside except and finally
blocks also.
If any statement which is not part of try block raises an exception then it is always abnormal
termination.
How to Print Exception Information:
try:
print(10/0)
except ZeroDivisionError as msg:
print("exception raised and its description is:",msg)
Output: exception raised and its description is: division by zero
Try with Multiple except Blocks:
The way of handling exception is varied from exception to exception. Hence for every exception type a
separate except block we have to provide. i.e. try with multiple except blocks is possible and
recommended to use.
Eg:
try:
------
------
------
Except ZeroDivisionError:
Perform alternate arithmetic operations
Except FileNotFoundError:
Use local file instead of remote file

If try with multiple except blocks available then based on raised exception the corresponding except
block will be executed.

Problem:
try:
x=int(input("Enter First Number:"))
y=int(input("Enter Second Number:"))
print(x/y)
except ZeroDivisionError:
print("Can't divide with zero")
except ValueError:
print("please provide int value only")

o/p:1
Enter First Number:10
Enter Second Number:2
5.0

o/p:2
Enter First Number:10
Enter Second Number:0
Can’t divide with zero

o/p:3
Enter First Number:10
Enter Second Number:ten
Please provide int value only.

If try with multiple except blocks available then the order of these except blocks is important. Python
interpreter will always consider from top to bottom until matched except block identified.

try:
x=int(input("Enter First Number:"))
y=int(input("Enter Second Number:"))
print(x/y)
except ArithmeticError:
print("ArithmeticError")
except ZeroDivisionError:
print("ZeroDivisionError")

o/p:
Enter First Number:10
Enter Second Number:0
ArithmeticError

Single except Block that can handle Multiple Exceptions:


We can write a single except block that can handle multiple different types of exceptions.

except(Exception1,Exception2,Exception3,…): OR
except(Exception1,Exception2,Exception3,…) as msg:

Parentheses are mandatory and this group of exceptions internally considered as tuple.
Problem:
try:
x=int(input("Enter First Number:"))
y=int(input("Enter Second Number:"))
print(x/y)
except(ZeroDivisionError,ValueError) as msg:
print("Plz Provide valid numbers only and problems is:",msg)
O/p-1:
Enter First Number:10
Enter Second Number:0
Plz Provide valid numbers only and problems is: division by zero
O/p-2:
Enter First Number:10
Enter Second Number:ten
Plz Provide valid numbers only and problems is: invalid literal for int() with base 10: 'ten'

Default exception Block:


We can use default except block to handle any type of exceptions.
In default except block generally we can print normal error messages.
Syntax:
except:
statements

try:
x=int(input("Enter First Number:"))
y=int(input("Enter Second Number:"))
print(x/y)
except ZeroDivisionError:
print("Zero Division Error:Can not divide with zero")
except:
print("Default Except:plz provide valid input only")
O/p:
Enter First Number:10
Enter Second Number:0
Zero Division Error:Can not divide with zero
O/p:
Enter First Number:10
Enter Second Number:ten
Default Except:plz provide valid input only
***Note: if try with multiple except blocks available then default except block should be last,
otherwise we will get Syntax Error.

try:
print(10/0)
except:
print("Default Except")
except ZeroDivisionError:
print("ZeroDivisionError")
Syntax Error: default ‘except:’ must be last

Note: The following are various possible combinations of except blocks


1) except ZeroDivisionError:
2) except ZeroDivisionError as msg:
3)except (ZeroDivisionError,ValueError):
4)except (ZeroDivisionError,ValueError) as msg:
5)except :

finally Block:
 It is not recommended to maintain clean up code(Resource Deallocating Code or
 Resource Releasing code) inside try block because there is no guarantee for the execution of every
statement inside try block always.
 It is not recommended to maintain clean up code inside except block, because if there is no
exception then except block won’t be executed.
 Hence we required some place to maintain clean up code which should be executed always
irrespective of whether exception raised or not raised and whether exception handled or not
handled. Such type of best place is nothing but finally block.
 Hence the main purpose of finally block is to maintain clean up code.

try:
Risky Code
except:
Handling Code
finally:
Cleanup code

The specialty of finally block is it will be executed always whether exception raised or not raised and
whether exception handled or not handled.

Case -1: if there is no Exception


try:
print("try")
except:
print("Except")
finally:
print("finally")

O/p:
Try
Finally
Case -2: if there is an Exception raised but handled
try:
print("try")
print(10/0)
except ZeroDivisionError:
print("Except")
finally:
print("finally")

O/p:
try
except
finally

Case -3: if there is an exception raised but not handled


try:
print("try")
print(10/0)
except NameError:
print("Except")
finally:
print("finally")

O/p:
Try
finally
ZeroDivisionError: division by zero(Abnormal Termination)

***Note: There is only one situation where finally block won’t be executed ie whenever we are using
Os._exit(0) function.

Whenever we are using os._exit(0) function then Python Virtual Machine itself will be shutdown. In this
particular case finally won’t be executed.

import os
try:
print("try")
os._exit(0)
except NameError:
print("Except")
finally:
print("finally")
o/p:try

Note:
Os._exit(0)
Where 0 represents status code and it indicates normal termination.there are multiple status codes are
possible.

Control Flow in try-except-finally:


try:
stmt-1
stmt-2
stmt-3
except:
stmt-4
finally:
stmt-5
stmt-6

Case-1: if there is no exception. 1,2,3,5,6 Normal Termination

Case-2: If an exception raised at stmt-2 and corresponding except block matched 1,4,5,6, Normal
Termination.
Case-3: If an exception raised at stmt-2 and corresponding except block not matched 1,5 ,6Abnormal
Termination.

Case-4: If an exception raised at stmt-4 then it is always Abnormal Termination but before that finally
block will be executed.

Case-5: If an exception raised at stmt-5 or at stmt-6 then It will always Abnormal Termination.

Nested try-except-finally Blocks:


We can take try-except-finally blocks inside try or except or finally blocks. i.e nesting of try-except-finally
is possible.

try:
----------
---------
---------
---------
try:
----------
----------
----------
Except:
----------
----------
----------
Except:
----------
----------
----------

Generally Risky code we have to take inside outer try block and too much risky code we have to take
inside inner try block. Inside inner try block if an exception raised then inner except block is responsible
to handle. If it is unable to handle then outer except block is responsible to handle.

try:
print("outer try block")
try:
print("Inner try block")
print(10/0)
except ZeroDivisionError:
print("Inner Except Block")
finally:
print("Inner Finally Block")
except:
print("Outer except block")
finally:
print("Outer finally Block")

Output:
outer try block
Inner try block
Inner Except Block
Inner Finally Block
Outer finally Block

Control Flow in nested try-except-finally:


try:
stme-1
stme-2
stme-3
try:
stmt-4
stmt-5
stmt-6
except X:
stmt-7
finally:
stmt-8
stmt-9
except Y:
stmt-10
finally:
stmt-11
stmt-12

Case-1: If there is no exception. 1,2,3,4,5,6,8,9,11,12 Normal Termination


Case-2: If an exception raised at stmt-2 and the corresponding except block matched 1,10,11,12
Normal Termination
Case-3: If an exception raised at stmt-2 and the corresponding except block not matched 1,11
Abnormal Termination
Case-4: If an exception raised at stmt-5 and inner except block matched 1,2,3,4,7,8,9,11,12 Normal
Termination
Case-5: If an exception raised at stmt-5 and inner except block not matched but outer except
block is matched 1,2,3,4,8,10,11,12, Normal Termination.
Case-6: If an exception raised at stmt-5 and inner and outer except block not matched .
1,2,3,4,8,11, Abnormal Termination.
Case-7: If an exception raised at stmt-7 and the corresponding except block matched 1,2,3,
….8,10,11,12, Normal Termination.
Case-8: If an exception raised at stmt-7 and the corresponding except block not matched 1,2,3,
….8,11,Abnormal Termination.

Case-9: If an exception raised at stmt-8 and the corresponding except block matched 1,2,3,
…,10,11,12, Normal Termination.
Case-10: If an exception raised at stmt-8 and the corresponding except block not matched 1,2,3,
…,,11,Abnormal Termination.
Case-11: If an exception raised at stmt-9 and the corresponding except block matched 1,2,3,
…,8,10,11,12, Normal Termination.
Case-12: If an exception raised at stmt-9 and the corresponding except block not matched 1,2,3,
…,8,11, AbNormal Termination.
Case-13: If an exception raised at stmt-10 and It is always abnormal Termination but before
abnormal termination finally block (stmt-11) will be executed.
Case-14: If an exception raised at stmt-11 or stmt-12 and It is always abnormal Termination.

Note:If the control entered into try block then compulsory finally block will be executed.if the
control not entered into try block then finally block won’t be executed.

else Block with try-except-finally:


We Can use else block with try-except-finally blocks.
Else block will be executed if and only if there are no exeptions inside try block.

try:
Risky Code
except:
will be executed if exception inside try
else:
will be executed if there is no exception inside try
finally:
will be executed whether exception raised or not raised and handled or not handled.

Eg:
try:
print(“try”)
print(10/0)
except:
print(“except”)
else:
print(“else”)
finally:
print(“finally”)

If we comment line-1 then else block will be executed b’z there is no exception inside try. In this
Case the output is:
try
else
finally
If we are not commenting line-1 then else block won’t be executed b’z there is exception inside try.
In this Case the output is:
Try
Except
finally

Various Possible Combinations of try-except-else-finally:


1. Whenever we are writing try block, compulsory we should write except or finally block. i.e
without except or finally block we cannot write try block.
2. Whenever we are writing except block, compulsory we should write try block . i.e except
without try always invalid.
3. Whenever we are writing finally block, compulsory we should write try block. i.e i.e finally
without try always invalid.
4. We can multiple except blocks for the same try , but we cannot write multiple finally blocks for
the same try
5. Whenever we are trying else block compulsory except block should be there. i.e without except
we cannot write else block.
6. In try-except-else-finally order is important.
7. We can define try-except-else-finally inside try, except, else and finally blocks. i.e nesting of try-
except-else-finally is always possible.

1
try:
print("try")
x
2
except:
print("hello")
x
3
else:
print("hello")
x
4 finally:
print("try") x
try:
print("try")
5
except:
print("except")
try:
print("try")
6
finally:
print("finally")
try:
print("try")
except:
7 print("except")
else:
print("else")

try:
8
else:
print("try") x
print("else")
try:
print("try")
else:
9 print("else") x
finally:
print("finally")

try:
print("try")
except XXX:
10 print("except-1")
except YYY:
print("except-2")

11 try:
print("try") x
except:
print("except-1")
else:
print("else")
else:
print("else")

try:
print("try")
except:
print("except-1")
12 finally: X
print("finally")
finally:
print("finally")

try:
print("try")
13
print(“Hello”)
except:
x
print("except")

try:
print("try")
except:
14 print("except") x
print(“Hello”)
except:
print(“except”)
try:
print("try")
except:
15 print("except") x
print(“Hello”)
finally:
print(“finally”)
16 try:
print("try") x
except:
print("except")
print(“Hello”)
else:
print(“else”)
try:
print("try")
except:
print("except")
17
try:
print(“try”)
except:
print(“except”)
try:
print("try")
except:
print("except")
18
try:
print(“try”)
finally:
print(“finally”)
try:
print("try")
except:
print("except")
19
if 10>20:
print(“if”)
finally:
print(“finally”)
try:
print("try")
try:
print("try")
except:
20
print(" inner except")
finally:
print("inner finally")
except:
print(“except”)
try:
print("try")
except:
print(“except”)
21 try:
print("try")
except:
print(" inner except")
finally:
print("inner finally")

try:
print("try")
except:
print(“except”)
finally:
22 try:
print("inner try")
except:
print(" inner except")
finally:
print("inner finally")

try:
print("try")
except:
print(“except”)
23 try: x
print("try")
else:
print(“else”)

try:
print("try")
try:
24 print(“inner try”) x
except:
print(“except”)

25 try:
print("try") x
else:
print(“else”)
except:
print(“except")
finally:
print(“finally”)

Types Of Exceptions:
In Python there are 2 types of exceptions are possible.
1) Predefined Exceptions
2) User defined Exceptions
1. Predefined Exceptions:
 Also Known as inbuilt exceptions.
 The exceptions which are raised automatically by python virtual machine whenever a particular
event occurs are called pre defined exceptions.

Eg-1: Whenever we trying to perform Division by zero, automatically Python will raise
ZeroDivisionError.
print(10/0)
Eg-2: Whenever we trying to convert input value to int type and if input value is not int value then
Python will raise Value Error automatically.
x=int(“ten”) -> ValueError
2. User defined Exceptions:
 Also Known as Customized Exceptions or programmatic Exceptions .
 Some times we have to define and raise exceptions explicitly to indicate that something goes wrong,
such type of exceptions are called User defined Exceptions or Customized Exceptions.
 Programmer is responsible to define these exceptions and Python not having any idea about these.
Hence we have to raise explicitly based on our requirement by using “raise” keyboard.
Eg:
InsufficientFundsException
InvalidInputException
TooYoungException
TooOldException
How to define and raise Customized Exceptions:
Every exception in Python is a class that extends Exception class either directly or indirectly.

Syntax:
class classname(predefined exception class name):
def __init__(self,arg):
self.msg=arg
Eg:
class TooYoungException(Exception):
def__init__(self,arg):
self.msg=arg
TooYoungException is our class name which is the child class of Exception

We can raise exception by using raise keyword as fallows raise TooYoungException(“message”)

Program:
class TooYoungException(Exception):
def __init__(self,arg):
self.msg=arg
class TooOldException(Exception):
def __init__(self,arg):
self.msg=arg

age=int(input("Enter age:"))
if age<18:
raise TooYoungException("plz wait some more time you will get best match soon..!!!")
elif age>60:
raise TooOldException("Your age already crossed marriage age...no chance of getting marriage")
else:
print("You will get match details soon by email!!!!")

output:
Enter age:17
__main__.TooYoungException: plz wait some more time you will get best match soon..!!!

Enter age:67
__main__.TooOldException: Your age already crossed marriage age...no chance of getting marriage

Enter age:22
You will get match details soon by email!!!!

Note: raise keyboard is best suitable for customized exceptions but not for pre defined exceptions.

FILE HANDLING
As the part of programming requirement , we have to store our data permanently for future purpose.
For this requirement we should go for files.
Files are very common permanent storage areas to store our data.
Types of files:
There are two types of files
1) Text files:
Usually we can use text files to store character data
Eg: abc.txt
2) Binary Files:
Usually we can use binary files to store binary data like images , video files,audio files etc….
Opening a file:
Before performing any operation (like read or write) on the file,firsh we have to open that file.For this
we should use phython’s in built function open()
But at the time of open , we have to specify mode, which represents the purpose of opening file.
F=open (filename,mode)
The allowed modes in python are
1) r open an existing file for read operation.The file pointer is positioned at the beginning of the
file.If the specified file does not exist then we will get file Not found error.This is default mode.
2) w open an existing file for write operation.If the filial ready contains some data then it will be
overridden. If the specified file is not already available then this mode will create that file.
3) a open an existing file for opened operation.It won’t overridde exsting data. If the specified file
is not already available then this mode will create a new file.
4) r+ To read and write data into the file.The previous data in the file will not be deleted.The file
pointer is placed at the beginning of the file.
5) w To write and read data. It will override existing data.
6) a+ To append and read data from the file.It wont override existing data.
7) x To open a file in exclusive creation mode for write operation.If the file already exists then we
will get file ExistsError.
Note:All the above modes are applicable for text files. If the above modes suffixed with ‘b’ then
represents for binary files.
Eg: rb,wb,r+b,w+b,a+b,xb
F=open(‘’abc.txt”,”w”)
We are opening abc.txt file for writing data.
Closing a File:
After completing our operations on the file, it is highly recommended to close the file. For this we
have to use close() function.
f.close()
Various properties of file obeject:
Once we opened a file and we got file object, we can get various details related to that file by using
it’s properties.
name Name of opened file
mode Mode in which the file is opened
closedReturns Boolean value indicates that whether file is closed or not
readable()Returns Boolean value indicates that whether file is readable or not
writable() Returns Boolean value indicates that whether file is writable or not.
1) f=open(“abc.txt”,’w’)
2) print (“file Name:”,f.name)
3) print (“file Mode:”,f.mode)
4) print (“Is file Readable:”,f.readable())
5) print (“Is file writable:”,f.writable())
6) print (“ Is file closed:”,f.closed)
7) f.close()
8) print(“Is file closed:”,f.closed)
Output
D:\python- classes>py test.py
File name: abc.txt
File mode: w
Is file readable: False
Is file writable:True
Is file closed: false
Is file closed: True
Writing Data to Text File:
We can write character data to the text files by using the following 2 methods
1) write(str)
2) writelines(list of lines)

1) f=open(“abcd.txt”,’w’)
2) f=write(“Durga\n”)
3) f=write(“Software\n”)
4) f=write(“Solutions\n”)
5) Print(“Data written to the file successfully”)
6) F:close()
Abcd.txt:
Durga
Software
Solutions
Note:In the above program,data present in the file will be overridden every time if we run the
program. Instead of overriding if we append operation then we should open the file as follows.
F:open(“abcd.txt”,a”)
Eg2:
1) F=open(“abcd.txt”,’w’)
2) List=[“sunny\n”,”bunny\n”,”vinny\n”,”chinny”]
3) F.writelines(list)
4) Print(“List of lines written to the file successfully”)
5) F.close()
abcd.txt:
sunny
bunny
vinny
chinny
Note:While writing data by using write() methods,compulsory we have to provide line separator(\
n),otherwise total data should be written to a single line.
Reading Chatacter Data from Text File:
we can read character data from text file by using the following read methods.
Read() To read total data from the file
Read(n) To read ‘n’ characters from the file
Readlines() To read only one line
Readlines() To read all lines into a list
Eg1: To read total data from the file
1) F=open(“abc.txt”,’r’)
2) Data=f.read()
3) Print(data)
4) F.close()
Output
Sunny
Bunny
Chinny
Vinny
Eg2: To read only first 10 characters:
1) F:open(“abc.txt”,’r’)
2) Data=f.read(10)
3) Print(data)
4) F:close()
Output:
Sunny
bunn
Eg3: To read data line by line:
1) F:open(“abc.txt”,’r’)
2) Line1=f.readline()
3) Print(line1,end=”)
4) Line2=f.readline()
5) Print(line2,end=”)
6) Line3=f.readline()
7) Print(line3,end=”)
8) F.close()
Output
Sunny
Bunny
Chinny
Eg4: To read all lines into list:
1) F=open(“abc.txt”,’r’)
2) Lines=f.readlines()
3) For line in lines:
4) Print()
5) F:close()
Output
Sunny
Bunny
Chinny
Vinny
Eg5:
1) F=open(“abc.txt”,’r’)
2) Print(f.read(3))
3) Print(f.readline())
4) Print(f.read(4))
5) Print(“Remaining data”)
6) Print(f.read())
Output
Sun
ny

bunn
Remaining data
Y
Chinny
Vinny
The with statement:
The with statement can be used while opening a file. We can use this to group file operation
statements within a block.
The advantage of with statements is it will take care closing of file, after completing all operations
automatically even in the case of exceptions also,and we are not required to close explicity.
1) With open (“abc.txt”,”w”) as f:
2) F.write(“Durga\n”)
3) F.write(“swoftware\n”)
4) F.write(“solutions\n”)
5) Print(“is file closed:”,f.closed)
6) Print(“is file closed:”,f.closed)
Output
Is file closed: false
Is file closed: true
The seek() and tell() Methods:
Tell():
We can use tell() method to return current position of the cursor(file pointer) from beginning of
the file.[ can you plese tell current cursor position]
The position(index) of first character in files is zero just like string index.
1) F=open(“abc.txt”,”r”)
2) Print(f.tell())
3) Print(f.read(2))
4) Print(f.tell())
5) Print(f.read(3))
6) Print(f.tell())
Abc.txt:
Sunny
Bunny
Chinny
Vinny
Output:
0
su
2
nny
5
Seek():
We can use seek() method to move cursor (file pointer) to specified location.
[Can you please seek the cursor to a particular location]
f.seek(offset,fromwhere)  offset represents the number of position
The allowed values for 2nd Attribute (from where) are
0 From beginning of file (Default value)
1From current position
2From end of the file
Note:Python 2 supports all 3 values but python 3 supports only zero.
1) Data=”All students are STUPIDS”
2) F=open(“abc.txt”,”w”)
3) F.write(data)
4) With open(“abc.txt”,”r+”) as f:
5) Text=f.read()
6) Print(text)
7) Print(“The current cursor position:”,f.tell())
8) F.seek(17)
9) Print(“The current cursor position:”,f.tell())
10) F.write(“GEMS!!!”)
11) F.seek(0)
12) Text=f.read()
13) Print(“Data After Modification:”)
14) Print(text)
output
All students are STUPIDS
The current cursor position:24
The current cursor position:17
Data After Modification:
All students are GEMS!!!
How to check a particular file exists OR not?
We can use os library to get information about files in our computer.
Os module has path sub module,which contains isfile() function to check whether a particular file
exists or not?
Os.path.isfile(fname)
Q) Write a program to check whether the given file exists OR not. If it is available then print its
content?
1) import so,sys
2) fname=input(“Enter File Name:”)
3) if os.path.isfile(fname)
4) print(“file exists:”,fname)
5) f=open(fname,”r”)
6) else:
7) print(“file does not exist:”,fname)
8) sys.exit(0)
9) print(“The content of file is:”)
10) data=f.read()
11) print(data)
output
D:\Python-classes>py test.py
Enter File Name:durga.txt
File does not exist: durga.txt
D:\Python-classes>py test.py
Enter File Name:abc.txt
File exists:abc.txt
The content of file is:
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
Note:
Sys.exit(0)To exit system without executing rest of the program.
Argument represents status code.0 means normal termination and it is the default value.
Q) Program to print the number of lines,word and characters present in the
given file?
1) import os,sys
2) fname=input(“Enter File Name:”)
3) if os.path.isfile(fname):
4) print(“file exits:”,fname)
5) f=open(fname,”r”)
6) else:
7) print(“File does not exists:”,fname)
8) sys.exit(0)
9) Icount=wcount=ccount=0
10) for line in f:
11) Icount= Icount+1
12) ccount= ccount+len(line)
13) words=line.split()
14) wcount=wcount+len(words)
15) print(“The number of lines:”,Icount)
16) print(“The number of words:”,Wcount)
17) print(“The number of characters:”,ccount)
output
D:\python-classes>py test.py
Enter file name: durga.txt
File does not exist: durga.txt

D:\python- classes>py test.py


Enter file name: abc.txt
File exists:abc.txt
The number of lines:6
The number of words:24
The number of character:149
Abc.txt
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
All students are GEMS!!!
Handling Binary Data:
It is very common requirement to read or write binary data like images,video files, audio files etc.
Q) Prigram to read images file and write to a new images file?
1) f1=open(“rossum.jpg”,”rb”)
2) f2=open(“newpic.jpg”,”wb”)
3) bytes=f1.read()
4) f2.write(bytes)
5) print(“New images is available with the name:newpic.jpg”)
Handling CSV Files:
CSVComma separated values
As the part of programming,it is very comma requirement to write and read data wrt csv file.
Python provides csv module to handle csv files.
Writing Data to CSV File:
1) Import csv
2) With open(“emp.csv”,”w”,newline=”)as f:
3) W=csv.writer(f) # returns csv writer object
4) W=writerow([“ENO”,”ENAME”,”ESAL”,”EADDR”])
5) N=int(input(“Enter Number of Employees:”))
6) For I in range(n):
7) Eno=input(“Enter Employee No:”)
8) Ename=input(“Enter Employee Name:”)
9) Esal=input(“Enter Employee salary:”)
10) Eaddr=input(“Enter Employee Address:”)
11) W.writeow([eno,ename,esal,eaddr])
12) Print(“Total Employee data written to csv file successfully”)
Note: Observe the difference with newline attribute and with out
With open(“emp.csv”,”w”,newline=”) as f:
With open(“emp.csv”,”w”) as f:
Note: If we are not using new line attribute then in the csv file blank lines will be included between
data. To prevent these balnk lines, newline attribute is required in python-3,but in python-2 just we
can specify mode as ‘wb’ and we are not required to use new line attribute.
Reading Data from CSV File:
1) Import csv
2) F=open(“emp.csv”,’r’)
3) R=csv.reader(f) # returns csv reader object
4) Data=list(r)
5) #print(data)
6) For line in data:
7) For word in line:
8) Print(word,”\t”,end=”)
9) Print()
output
D:\pyhton-classes>py test.py

ENO ENAME ESAL EADDER


100 Durga 1000 Hyd
200 sachin 2000 Mumbai
300 Dhoni 3000 Ranchi
Zipping and Unzipping Files:
It is very common requirement to zip and un zip files.
The main advantages are:
1) To improve memory utilization
2) We can reduce transport time
3) We can improve performance.
To perform zip and unzip operations, python contains one in-built module zip file.
This module contains a class:zipfile
To create zip file:
We have to create zip file class object with name of the zip file, mode and constant ZIP-
DEFLATED.The constant represents we are creating zip file.
F= ZipFile(“files.ZIP”,”W”,”ZIP-DEFLATED”)
Once we create zipfile object,we can add files by using write() method.
f.write(filename)
1) from zipfile import*
2) f=zipfile(“files.zip”,’w’,ZIP-DEFLATED)
3) f. write(“file1.txt”)
4) f. write(“file2.txt”)
5) f. write(“file3.txt”)
6) f.close()
7) print(“files.zip file created successfully”)
To perform unzip operation:
We have to create zipfile object as follows
F=ZIPFile(“files.zip”,”r”,ZIP-STORED)
ZIP-STORED represents unzip operations.This is default value and hence we are not required to
specify.
Once we created zip file object for unzip operations,we can get all file names present in that zip
file by using namelist() method.
Names=f.namelist()
1) From zipfile import*
2) F=zipfile(“files.zip”,’r’,ZIP-STORED)
3) Names=f.namelist()
4) For name in names:
5) Print(“File name:”,names)
6) Print(“The content of this file is:”)
7) F1=open(name,’r’)
8) Print(f1.read())
9) Print()
Working with Directories:
It is very common requirement to perform operations for directories like
1) To know current working directory
2) To create a new directory
3) To remove an existing directory
4) To rename a directory
5) To list contents of the directory
etc....
To perform these operations,python provides inbuilt module os,which contains several functions
to perform directory related operations.
Q1) To know current working Directory
Imports os
Cwd=os.getcwd()
Print(“current working Directory:”,cwd)
Q2) To create a sub Directory in the current working Directory
Imports os
os.mkdir(“mysub”)
Print(“mysub directory created in cwd”)
Q3) To create a sub Directory in mysub Directory
Cwd
|-mysub
|-mysub2
Import os
Os.mkdir(“mysub/mysub2”)
Print(“mysub2 created inside mysub”)
Note:Assume mysub already present in cwd.
Q4) To create Multiple Directories like sub1 in that sub2 in that sub3
Import os
Os.makedirs(“sub1/sub2/sub3”)
Print(“sub1 and in that sub2 and in that sub3 directories created”)
Q5) To Remove a Directory
Import os
Os.rmdir(“mysub/mysub2”)
Print(“mysub2 directory deleted”)
Q6) To Remove Multiple Directories in the path
Import os
Os.removedirs(“sub1/sub2/sub3”)
Print(“All 3 directories sub1,sub2,and sub3 removed”)
Q7) To Rename a Directory
Import os
Os.rename(“mysub”,”newdir”)
Print(“my sub directory renamed to newdir”)
Q8) To know contents of Directory
Os module provides listdir() to list out the contents of the specified directory.It won’t display
the contents of sub directory.
1) Imports os
2) Print(os.listdir(“.”))
The above program disply contents of current working directory but not contents of sub
directories.
If we want the contents of a directory including sub directories then we should go for walk()
function.
Q9) To know contents of Directory including sub Directories
 We have to use walk()function
 [can you please walk in the directory so that we can aware all contents of that
directory]
 Os.walk(path,topdown=True,onerror=None,followlinks=False)
 It returns an Iterator object whose contents can be displayed by using for loop
 PathDirectory path.cwd means.
 Topdown==TrueTravel from top to bottom
 Onerror=noneOn error detected which function has to execute.
 Followlinks=True To visit directories pointed by symbolic links
Eg: To display all contents of current working directory including sub directories:
1) Import os
2) For dirpath,dirnames,filenames in os.walk(‘.’):
3) Print(“current Directory path:”,dirpath)
4) Print(“Directories:”,dirnames)
5) Print(“files:”,filenames)
6) Print()
Note:To display contents of particular directory,we have to provide that directory name as
argument to walk() function.
Os.walk(“directoryname”)

Q) What is the difference between listdir() and walk() function?


In the case of listdir(),we will get contents of specified directory but not sub dorectory
contents.But in the case of walk() function we will get contents of specified directory and its
sub directories also.
Running Other programs from python program:
Os Module contains system() function to run programs and commands.It is exactly same as
system() function in C language.
Os.system(“command string”)
Eg:
Import os
Os.system(“dir*.py”)
Os.system(“py abc.py”)
How to get Information about a file:
We can get statistics of a file like size,last accessed time,last modified time etc by using stat()
function of os module.
Starts=os.stat(“abc.txt”)
The statistics of a file includes the following parameters:
1) St-modeprotection Bits
2) St-inoInode number
3) St-devdevice
4) St-nlinknumber of hard links
5) St-uidUser id of Owner
6) St-gidGroup id of owner
7) St-sizesize of file in bytes
8) St-atimeTime of most recent Access
9) St-mtime Time of most recent Modification
10) St-ctime Time of most recent Meta Data change
Note:st-atime,st-mtime and st-ctime returns the time as number of milli seconds since jan 1 st
1970,12:00 AM.By using datetime module from timestamp() function,we can get exact date
and time.
Q) To print all statistics of file abc.txt
1) import os
2) starts=os.stat(“abc.txt”)
3) print(stats)
Q) To print specified properties
1) import os
2) from datetime import*
3) stats=os.stat(“abc.txt”)
4) print(“File size in Bytes:”,stats.st-size)
5) print(“File last Accessed Time:”,datetime.fromtimestamp(stats.st-atime))
6) print(“File last Modified Time:”,datetime.fromtimestamp(stats.st-mtime))
Pickling and Unpickling of Objects:
Sometimes we have to write total state of object to the file and we have to read total object
from the file.
The process of writing state of object to the file is called pickling and the process of reading
state of an object from the file is called unpickling.
We can implement pickling and unpickling by using pickle module of python.
Pickle module contains dump() function to perform pickling.pickle.dump(object,file)
Pickle module contains load() function to perform unpickling obj=pickle.load(file)
Writing and Reading State of object by using pickle Module:
1) Import pickle
2) Class Employee:
3) Def—init—(self,eno,ename,esal,eaddr):
4) Self.eno=eno;
5) Self.ename=ename;
6) Self.esal=esal;
7) Self.eaddr=eaddr=eaddr;
8) Def display(self):
9) Print(self.eno,”\t”,self.ename,”\t”,self.esal,”\t”,self.eaddr)
10) With open(“emp.dat”,”wb”) as f:
11) e=Empoyee(100,”durga”,1000,”hyd”)
12) Pickle.dump(e,f)
13) Print(“pickling of Employee object completed…”)
14)
15) With open(“emp.dat”,”rb”) as f:
16) Obj=pickle.load(f)
17) Print(“printing Employee Information after unpickling”)
18) Obj.display()
Writing Multiple Employee Object to the file:
Emp.py:
1) Class Employee:
2) Def—init—(self,eno,ename,esal,eaddr):
3) Self.eno=eno”
4) Self.ename=ename;
5) Self.esal=esal;
6) Self.eaddr=eaddr;
7) Def display(self);
8)
9) Print(self.eno,”\t”,self.ename,”\t”,self.esal,”\t”,self.eaddr)
Pick.py:
1) Import emp,pickle
2) F=open(“emp.dat”,”wb”)
3) n=int(input(“enter the number of Employee:”))
4) for I in range(n):
5) eno=int(input(“Enter Employee Number:”))
6) ename=input(“Enter Employee Name:”)
7) esal=float(input(“Enter Employee salary:”))
8) eaddr=input(“Enter Employee Address:”)
9) e=emp.Employee(eno,ename,esal,eaddr)
10) pickle.dump(e,f)
11) print(“Employee objects pickled successfully”)
unpick.py:
1) import emp,pickle
2) f=open(“emp.dat”,”rb”)
3) print(“Employee details:”)
4) while True:
5) try:
6) Obj=pickle.load(f)
7) Obj.display()
8) Except EOFError:
9) Print(“All employee completed”)
10) Break
11) F.close()

MULTI THREADING
Multi Tasking:
Executing several tasks simultaneously is the concept of multitasking.
There are 2 types of multi Tasking
1) Process based multi Tasking
2) Thread based Multi Tasking
1) Process based multi Tasking:
Executing several tasks simmmultaneously where each task is a separate independent
process is called process based multi tasking.
Eg: While typing python program in the editor we can listen mp3 audio songs from the
same system. At the same time we can download a file from the internet.All these tasks
are executing simultaneously and independent of each other.Hence it is process based
multi tasking.
This type of multi tasking is best suitable at operating system level.
2) Thread based multitasking:
Executing several tasks simultaneously where each task is a separate independent part of
the same program, is called thread based multi tasking,and each independent part is called
a thread.
This type of multi tasking is best suitable at programmatic level.
Note:Whether it is process based or thread based, the main advantage of multi tasking is
to improve performance of the system by reducing response time.
The main important application areas of multi threading are:
1) To implement multimedia graphics
2) To develop animations
3) To develop video games
4) To develop web and application server
Etc…
Note:Where ever a group of independent jobs are available, then it is highly
recommended to execute simultaneously instead of executing one by one.For such type of
cases we should go for multi Threading.
Python provide one inbuilt module”threading” to provide support for developing
threads.Hence developing multi threaded programs is very easy in python.
Every python program by default contains one thread which is nothing but mainThread.
Q) Program to print Name of current executing Thread
1) import threading
2) print(“current Executing Thread:”,threading.current-thread().getName())
Note:threading module contains function current—thread() which returns the current
executing Thread object.On this object if we call getName() method we will get current
executing thread name.
Thread ways of creating Thread in python:
We can create a thread in python by using 3 ways
1) Creating a Thread without using any class
2) Creating a Thread by extending Thread class
3) Creating a Thread without extending Thread class
1) Creating a Thread without using any class
1) From threading import*
2) Def display():
3) For I in range(1,11):
4) Print(“child thread”)
5) t=Thread(target=display) # creating Thread object
6) t.start() # starting of thread
7) for I in range(1,11)
8) print(“Main thread”)
If multiple threads present in our program, then we cannot expect execution order and
hence we cannot except exact output for the multi threaded program.B’z of this we cannot
provide exact output for the above program. It is varied from machine to machine and run
to run.
Note:Thread is a pre defined class present in threading module which can be used to
create our own Threads.
2) Creating a Thread by extending Thread class
We have to create child class for Thread class.In that child class we have to override run()
method with our required job.Whenever we cal start() method then automatically run()
method will be executed and perform our job.
1) From threading import*
2) Class my Thread(Thread):
3) Def run(self):
4) For I in range(10):
5) Print(“child Thread-1”)
6) t=my Thread()
7) t.start()
8) for I in range(10):
9) print(“main Thread-1”)
3) Creating a Thread without extending Thread class
1) From threading import*
2) Class Test:
3) Def display(self):
4) For I in range(10):
5) Print(“child Thread-2”)
6) Obj=Test()
7) t=Thread(target=obj.display)
8) t.start()
9) for I in range(10):
10) print(“Main Thread-2”)
Without Multi Threading
1) from threading import*
2) import time
3) def doubles (numbers):
4) for n in numbers:
5) time.sleep(1)
6) print(“Double:”,2*n)
7) def squares(numbers):
8) for n in numbers:
9) time.sleep(1)
10) print(“square:”,n*n)
11) numbers=[1,2,3,4,5,6]
12) begintime=time.time()
13) doubles(numbers)
14) squares(numbers)
15) print(“The total time Tken:”,time.time()-begintime)
With multi Threading
1) from threading import*
2) import time
3) def doubles(numbers):
4) for n in numbers:
5) time.sleep(1)
6) print(“Double:”,2*n)
7) def squares(numbers):
8) for n in number:
9) time.sleep(1)
10) print(“squares:”,n*n)
11)
12) Numbers=[1,2,3,4,5,6]
13) Begintime=time.time()
14) t1=Thread(target=double,args=(numbers,))
15) t2=Thread(target=squares,args=(numbers,))
16) t1.start()
17) t2.start()
18) t1.join()
19) t2.join()
20) print(“The total time taken:”time.time()-begintime)
may be default name generated by python or customized name provided by programmer.
Settings and Getting Name of a Thread:
Every thread in python has name.It
We can get and set name of thread by using the following Thread class methods.
t.getname()Returns Name of Thread
t.setName(newName)To set our own name
note:Every Thread has implicit variable”name”to represents name of Thread.
1) From threading import*
2) Print(current-thread().getname())
3) Current-thread().setname(“pawan kalian”)
4) Print(current-thread().getname())
5) Print(current-thread().name)
Thread Identification number(ident):
For every thread internally a unique identification number is available.We can access this id
by using implicit variable “ident”
1) From threading import*
2) Def test():
3) Print(“child Thread”)
4) t=Thread(target=test)
5) t.start()
6) print(“Main Thread Identification number:”,current-thread().ident)
7) print(“child Thread Identification number:”,t.ident)
active—count():
This function returns the number of active threads currently running.
1) From threading import*
2) Import time
3) Def display():
4) Print(current—thread().getname(),”…started”)
5) Time.sleep(3)
6) Print(current—thread().getname(),”…ended”)
7) Print(“The number of active Thread:”,active—count())
8) t1=Thread(target=display,name=”ChildThread1”)
9) t2=Thread(target=display,name=”ChildThread2”)
10) t3=Thread(target=display,name=”ChildThread3”)
11) t1.start()
12) t2.start()
13) t3.start()
14) print(“The number of active Threads:”,active—count())
15) time.sleep(5)
16) print(“The number of active Threads:”,active—count())
enumerate() Functin:
This function returns a list of all active threads currently running.
1) From threading import*
2) Import time
3) Def display():
4) Print(current—thread().getname(),”…started”)
5) Time.sleep(3)
6) Print(current—thread().getname(),”…ended”)
7) t1=Thread(target=display,name=”childThread1”)
8) t2=Thread(target=display,name=”childThread2”)
9) t3=Thread(target=display,name=”childThread3”)
10) t1.start()
11) t2.start()
12) t3.start()
13) I=enumerate()
14) For t in I:
15) Print(“Thread name:”,t.name)
16) Time.sleep(5)
17) I=enumerate()
18) For t in I:
19) Print(“Thread name:”,t.name)
Is Alive() Method:
isAlive() method checks whether a thread is still executing or not.
1) From threading import*
2) Import time
3) Def display():
4) Print(current—thread().getname(),”…started”)
5) Time.sleep(3)
6) Print(current—thread().getname(),”…ended”)
7) t1=Thread(target=display,name=”child Thread1”)
8) t2=Thread(target=display,name=”child Thread2”)
9) t1.start()
10) t2.start()
11)
12) Print(t1.name,”is Alive:”,t1.isAlive())
13) Print(t1.name,”is Alive:”,t1.isAlive())
14) Time.sleep(5)
15) Print(t1.name,”is Alive:”,t1.isAlive())
16) Print(t2.name,”is Alive:”,t2.isAlive())
Join() Method:
If a thread wants to wait until completing some other thread then we should go for join()
Method.
1) From threading import*
2) Import time
3) Def display():
4) For I in range(10):
5) Print(“seethe Thread”)
6) Time.sleep(2)
7)
8) t=Thread(target=diplay)
9) t.start()
10) t.join()# This line executed by main Thread
11) for I in range(10):
12) print(“rama Thread”)
In the above example main Thread waited until completing child thread.In this case
Output is:
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Seetha Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Rama Thread
Note:We can call join() method with time period also.
t.join(seconds)
In this case thread will wait only specified amount of time.
1) From threading import*
2) Import time
3) Def display():
4) For I in range(10):
5) Print(“seethe Thread”)
6) Time.sleep(2)
7)
8) t=Thread(target=display)
9) t=start()
10) t=join(5)# This line executed by main Thread
11) for I in range(10):
12) print(“Rama Thread”)
In this case main thread waited only 5 seconds.
Daemon Threads:
The threads which are running in the background are called Daemon Threads.
The main objective of Daemon Thread is to provide support for Non Daemon threads(like
main thread)
Eg: Garbage Collector
Whenever Main Thread runs with low memory,immediately PVM runs Garbage collector to
destroy useless objects and to provide free memory,so that main thread can continue its
execution without having any memory problems.
We can check whether thread is Daemon or not by using t.isDaemon() method of Thread
class or by using daemon property.
1) From threading import*
2) Print(current—thread().isDaemon()) #false
3) Print(current—thread().daemon) # false
We can change Daemon nature by using setDaemon() method of Thread class.
t.setDaemon(True)
But we can use this method before starting of Thread.i.e once thread started,we cannot
change its Daemon nature,otherwise we will get
RuntimeException:cannot set daemon status of active thread.
1) From threading import*
2) Print(current—thread().isDaemon())
3) Current—thread().setDaemon(True)
RuntimeError: cannot set daemon status of active thread
Default Nature:
By default main thread is always non-daemon.But for the remaining threads Daemon
nature will be inherited from parent to child.i.e if the parent Thread is Daemon then child
thread is also Daemon and if the parent thread is non Daemon then childThread is also Non
Daemon.
1) From threading import*
2) Def job():
3) Print(“child Thread”)
4) t=Thread(target=job)
5) print(t.isDaemon()) #false
6) t=setDaemon(True)
7) print(t.isDaemon()) #True
Note: Main Thread is always Non-Daemon and we cannot change its Daemon nature b’z it
is already started at the beginning only.
Whenever the last Non-Daemon Thread terminates automatically all Daemon Thread will
be terminated.
1) From threading import*
2) Import time
3) Def job():
4) For I in range(10):
5) Print(“Lazy Thread”)
6) time.sleep(2)
7)
8) t=Thread(target=job)
9) #t.setDaemon(True)====> Line-1
10) t.start()
11) time.sleep(5)
12) print(“End of main Thread”)
In the above program if we comment Line-1 then both main Thread and child Thread are
Non Daemon and hence both will be executed until their completion.
In this case output is:
Lazy Thread
Lazy Thread
Lazy Thread
End of main Thread
Lazy Thread
Lazy Thread
Lazy Thread
Lazy Thread
Lazy Thread
Lazy Thread
Lazy Thread
If we are not commenting Line-1 then Main Thread is Non-Deamon and child Thread is
Deamon.Hence whenever main Thread terminates automatically child thread will be
terminated.In this case output is
Lazy Thread
Lazy Thread
Lazy Thread
End of main Thread

Synchronization:
If multiple threads are executing simultaneously then there may be chance of data
inconsistency problems.
1) From threading import*
2) Import time
3) def wish(name):
4) for I in range(10):
5) print(“Good Evening:”,end=”)
6) time.sleep(2)
7) print(name)
8) t1=Thread(target=wish,args=(“Dhoni”,))
9) t2=Thread(target=wish,args=(“yuvraj”,))
10) t1.start()
11) t2.start()
….
We are getting irregular output b’z both theads are executing simultaneously wish()
function.
To overcome this problem we should go for synchronization.
In synchronization the threads will be executed one by one so that we can overcome data
inconsistency problems.
Synchronization means at a time only one Thread
The main application areas of synchronization are
1) Online Reservation system
2) Funds Transfer from joint accounts
3) Etc
In python, we can implement synchronization by using the following
1) Lock
2) Rock
3) Semaphore

Synchronization By using lock concept:


Lock are the most fundamental synchronization mechanism provided by threading module.
We can create lock object as follows I=Lock()
The lock object can be hold by only one thread at a time.If any other thread required the
same lock then it will wait until thread releases lock.(similar to common wash rooms,public
telephone booth etc)
A Thread can acquire the lock by using acquire() Method I.acquire()
A Thread can release the lock by using release() Method I.release()
Note:To call release() method compulsory thread should be owner of that lock.i.e thread
should has the lock already,otherwise we will get Runtime exception saying
RuntimeError: release unlocked lock.
1) From threading import*
2) I=lock()
3) #I.acquire()1
4) I.release()
If we are commenting line-1 then we will get RuntimeError: release unlocked lock
1) From threading import*
2) Import time
3) I=lock()
4) Def wish(name):
5) I.acquire()
6) For I in range (10):
7) Print(“Good Evening:”,end=”)
8) Time.sleep(2)
9) Print(name)
10) I.release()
11)
12) t1=Thread(target=wish,args=(“Dhoni”,))
13) t2=Thread(target=wish,args=(“yuvraj”,))
14) t3=Thread(target=wish,args=(“kohli”,))
15) t1.start()
16) t2.start()
17) t3.start()
In the above program at a time only one thread is allowed to execute wish() method and
hence we will get regular output.
Problem with simple lock:
The standard lock object does not care which thread is currently holding that lock.If the
lock is held and any thread attempts to acquire lock,thenit will be blocked, even the same
thread is already holding that lock.
1) From threading import*
2) I=lock()
3) Print(“Main Thread trying to acquire lock”)
4) I.acquire()
5) Print(“Main Thread trying to acquire lock again”)
6) I.acquire()
Note:To kill the blocking thread from windows command prompt we have to use
ctrl+break.Here ctrl+c won’t work.
If the Thread calls recursive functions or nested access to resourses,then the thread
may trying to acquire the same lock again and again,which may our thread.
Hence Traditional Locking Mechanism Won’t Work for executing recursive functions
To over come this problems,we should go for Rlock(Reentrant lock).Reentrant means
the thread can acquire the same lock again and again.If the lock is held by other
threads then only the thread will be blocked.
Reentrant facility is available only for owner thread but not for other threads.
1) From threading import*
2) I=Rlock()
3) Print(“Main Thread trying to acquire lock”)
4) I.acquire()
5) Print(“Main Thread trying to acquire lock again”)
6) I.acquire()
In this case main Thread won’t be locked b’z thread can acquire the lock any number of
times.
This Rlock keeps track of recursion level and hence for every acquire() call compulsory
release() call should be available. i.e the number of acquire() calls and release() calls
should be matched then only lock will be released.
Eg:
I=Rlock()
I.acquire()
I.acquire()
I.release()
I.release()
After 2 release() calls only the lock will be released.
Note:
1) Only owner thread can acquire the lock multiple times
2) The number of acquire() calls and release() calls should be matched.

Demo program for synchronization by using Rlock:


1) From threading import*
2) Import time
3) I=Rlock()
4) Def factorial(n):
5) I.acquire()
6) If n==0:
7) Result=1
8) Else:
9) Result=n*factorial(n-1)
10) I.release()
11) Return result
12)
13) Def results(n):
14) Print(“The factorial of”,n,”is:”,factorial(n))
15)
16) t1=Thread(target=results,args=(5,))
17) t2=Thread(target=results,args=(9,))
18) t1=start()
19) t2=start()
Output:
The factorial of 5 is:120
The factorial of 9 is:362880
In the above program instead of Rlock if we use normal lock then the thread will be
blocked.
Difference between Lock and Rlock
Lock Rlock
1) Lock object can be acquired by 1) RLock object can be acquired by
only one thread at a time.Even owner only one thread at a time,but owner
thread also cannot acquire multiple times. thread can acquiresame lock object
multiple times.
2) Not suitable to execute recursive 2) Best suitable to execute recursive
functions and nested access calls. functions and nested access calls.
3) In this case lock object will takes 4) In this case Rlock object will takes
care only locked or unlocked and it never care whether locked or unlocked and
takes care about owner thread and owner thread information, recursiion
recursion level. level.

Synchronization by using semaphore:


 In the case of lock and Rlock, at a time only one thread is allowed to execute.
 Sometimes our requirement is at a time a particular number of thread are
allowed to access(like at a time 10 members are allowed to access database
server,4 members are allowed to access network connection etc).T o handle
this requirement we cannot use lock and Rlock conecpts and we should go for
semaphore concept.
 Semaphore can be used to limit the access to the shared resourses with limited
capacity.
 Semaphore is advanced synchronization Mechanism.
 We can create semaphore object as follow s=Semaphore(counter)
 Here counter represents the maximum number of thread are allowed to access
simultaneously . The default value of counter is 1.
 Whenever thread executes acquire() method,then the counter value will be
decremented by 1 and if thread executes release() method then the counter
value will be incremented by 1.
 i.e for every acquire() call counter value will be decremented and for every
release() call counter value will be incremented.
Case-1: s=Semaphore()
In this case counter value is 1 and at a time only ane thread is allowed to access. It
is exactly same as lock concept.
Case-2: s=Semaphore(3)
In this case Semaphore object can be accessed by 3 thread at a time.The remaing
threads have to wait until releasing the semaphore.
1) From threading import*
2) Import time
3) s=Semaphore(2)
4) def wish(name):
5) s.acquire()
6) for I in range(10):
7) print(“Good Evening:”,end=”)
8) time.sleep(2)
9) print(name)
10) s.release()
11)
12) t1=Thread(target=wish,args=(“Dhoni”,))
13) t2=Thread(target=wish,args=(“yuvraj”,))
14) t3=Thread(target=wish,args=(“kohli”,))
15) t4=Thread(target=wish,args=(“Rohit”,))
16) t5=Thread(target=wish,args=(“Pandya”,))
17) t1.start()
18) t2.start()
19) t3.start()
20) t4.start()
21) t5.start()
In the above program at a time 2 therads are allowed to access semaphore and
hence 2 threads are allowed to execute wish() function.
Bounded semaphore:

Normal semaphore is an unlimited semaphore which allows us to call release()


method any number of times to increment counter.The number of release() calls
can exceed the number of acquire calls also.
1) From threading import*
2) s=Semaphore(2)
3) s.acquire()
4) s.acquire()
5) s.release()
6) s.release()
7) s.release()
8) s.release()
9) print(“End”)
It is valid because in normal semaphore we can call released() any number of times.
Bounedsemaphore is exactly same as semaphore except that the number of
release() calls should not exceed the number of acquire() calls,otherwise we will
get.
ValueError: Semaphore released too many times
1) from threading import*
2) s=Boundedsemaphore(2)
3) s.acquire()
4) s.acquire()
5) s.release()
6) s.release()
7) s.release()
8) s.release()
9) print(“End”)
ValueError: Semaphore released too many times
It is invalid b’z the number of release() calls should not exceed the number of
acquire() calls in Boundedsemaphore.
Note:To prevent simple programming mistakes,it is recommended to use
Boundedsemaphore over normal semaphore.
Difference between Lock and Semaphore:
At a time lock object can be acquired by only one thread, but semaphore object can
be acquired by fixed number of thread specified by counter value.
Conclusion:
The main advantages of synchronization is we can overcome data overcome data
inconsistency problems.But the main disadvantages of synchronization is it
increases waiting time of threads and creates performance problems. Hence if
there is no specific requirement then it is not recommended to use
synchronization.
Inter Thread Communication:
Some time as the part of programming requirement,threads are required to
communicate with each other.This concept is nothing but interthread
communication.
Eg: After producing items producer thread has to communicate with consumer
thread to notify about new item.Then consumer thread can consume that new
item.
In python,we can implement interthread communication by using the following
ways
1) Event
2) Condition
3) Queue
Etc
Inter Thread Communication by using Event Object:
Event object is the simplest communication mechanism between the threads.One thread signals an
event and other thread wait for it.
We can create Event object as follows….
Event =threading.event()
Event manages an internal flag that can set() or clear()
Thread can wait until event set.
Methods of Event class:
1) Set() internal flag value will become True and it represents GREEN signal for all waiting
threads.
2) Clear()internal flag value will become False and it represents RED signal for all waiting
threads.
3) isSet() This method can be used whether the event is set or not
4) wait() | wait(seconds) Thread can wait until event is set
Pseudo Code:
Event= threading.Event()
# consumer thread has to wait until event is set
Event.wait()
# producer thread can set or clear event
Event.set()
Event.clear()
Demo program-1:
1) from threading import*
2) import time
3) def producer():
4) time.sleep(5)
5) print(“producer thread producing items:”)
6) print(“producer thread got notification by setting event”)
7) event.set()
8) def consumer():
9) print(“consumer thread is waiting for updation”)
10) event.wait()
11) print(“consumer thread got notification and consuming items”)
12)
13) event=Event()
14) t1=Thread(target=producer)
15) t2=Thread(target=consumer)
16) t1.start()
17) t2.start()
Demo Program-2:
1) from threading import*
2) import time
3) def trafficpolice():
4) while true:
5) time.sleep(10)
6) print(“Traffic police giving GREEN signal”)
7) event.set
8) time.sleep(20)
9) print(“Traffic police Giving RED signal”)
10) event.clear()
11) def driver():
12) num=0
13) while True:
14) print(“Drivers waiting for GREEN signal”)
15) event.wait()
16) print(“Traffic signal is GREEN…Vehicles can move”)
17) while event.isSet():
18) num=num+1
19) print(“Vehicle no:”,num,”crossing the signal”)
20) time.sleep(2)
21) print(“Traffic signal is RED…Drivers have to wait”)
22) event=Event()
23) t1=Thread(target=trafficpolice)
24) t2=Thread(target=driver)
25) t1.start()
26) t2.start()
In the above program driver thread has to wait until Trafficpolice thrfead sets event.i.e until giving
GREEN signal.Once Traffic police thread sets event(giving GREEN signal),vehicles can cross the
signal.Once traffic police thread clears event(giving RED signal) then the driver thread has to wait.
Inter Thread communication by using condition object:
Condition is the more advanced version of event object for interthread communication.A
condition represents some kind of state change in the application like producing item or
consuming item.Thread can wait for that condition and threads to wait until notified by another
thread.
Condition is always associated with a lock (Reentrantlock).
A condition has acquire() and release() methods that call the corresponding methods of the
associated lock.
We can create condition object as follow condition=threading.condition()
Methods of condition:
1) acquire()To acquire Condition object before producing or consuming items i.e thread
acquiring internal lock.
2) Release()To release condition object after producing or consuming items.i.e thread release
internal lock.
3) Wait()|wait(time)To wait until getting notification or time expired.
4) Notify()To give notification for one waiting thread.
5) notifyAll()To give notification for all waiting threads.
Case study:
The producing thread needs to acquire the condition before producing item to the resourses and
notifing the consumers.
#producer thread
…generate item..
Condition.acquire()
…add item to the resource…
Condition.notify()#signal that a new item is available(notifyAll())
Condition.release()
The consumer must acquire the condition and then it can consume items from the resource
#consumer thread
Condition.acquire()
Condition.wait()
Consume item
Condition.release()
Demo program-1:
1) from threading import*
2) def consume(c):
3) c.acquire()
4) print(“consumer waiting for updation”)
5) c.wait()
6) print(“consumer got notification & consuming the item”)
7) c.release()
8)
9) Def produce(c):
10) C.acquire()
11) Print(“producer producing items”)
12) Print(“producer giving Notification”)
13) C.notify()
14) C.release()
15)
16) C=condition()
17) t1=Thread(target=consume,args=(c,))
18) t2=Thread(target=produce,args=(c,))
19) t1.start()
20) t2.start()
Demo program-2:
1) from threading import*
2) import time
3) import random
4) items=[]
5) def produce(c):
6) while True:
7) c.acquire()
8) item=random.randint(1,100)
9) print(“producer producing item:”,item)
10) items.append(item)
11) print(“producer giving notification”)
12) c.notify()
13) c.release()
14) time.sleep(5)
15)
16) Def consume(c):
17) While True:
18) C.acquire()
19) Print(“consumer waiting for updation”)
20) C.wait()
21) Print(“consumer consumed the item”,items.pop())
22) C.release()
23) Time.sleep(5)
24)
25) C=condition()
26) t1=Thread(target=consume,args=(c,))
27) t2=Thread(target=produce,args=(c,))
28) t1.start()
29) t2.start()
In the above program consumer thread expecting updation and hence it is responsible to call
wait() method on condition object.
Producer thread performing updation and hence it is responsible to call notify() or notifyAll()on
condition object.
Inter Thread Communication by Using Queue:
Queues concept is the most enhanced mechanism for interthread communication and to share
data between threads.
Queue internally has condition and that condition has lock.Hence whenever we are using queue
we are not required to worry about synchronization.
If we want to use queue first we should import queue module import queue
We can create Queue object as follows q=queue.Queue()
Important methods of Queue:
1) put():put an item into the queue.
2) Get():Remove and return an item from the queue.
Producer thread uses put() method to insert data in the queue.Internally this method has logic to
acquire the lock before inserting data into queue.After inserting data lock will be released
automatically.
Put() method also checks whether the queue is full or not and if queue is full then the producer
thread will entered in to waiting state by calling wait() method internally.
Consumer Thread uses get() method to remove and get data from the queue. Internally this
method has logic to acquire the lockbefor removing data from the queue.Once removal
completed then the lock will be released automatically.
If the queue is empty then consumer thread will entered into waiting state by calling wait()
method internally.Once queue updated with data then the thread will be notified automatically.
Note:The Queue module takes care of locking for us which is a great Advantages.
1) From threading import*
2) Import time
3) Import random
4) Import queue
5) Def produce(q):
6) While True:
7) Item=random.randint(1,100)
8) Print(“producer producing item:”,item)
9) Q.put(item)
10) Print(“producer giving Notification”)
11) Time.sleep(5)
12) Def consume(q):
13) While True:
14) Print(“consumer wating for updation”)
15) Print(“consumer consumed the item:”,q.get())
16) Time.sleep(5)
17)
18) Q=queue.Queue()
19) t1=Thread(target=consume,args=(q,))
20) t2=Thread(target=produce,args=(q,))
21) t1.start()
22) t2.start()
Types of Queues:
Python supports 3 Types of Queue.
1) FIFO Queue:
q=queue.Queue()
This is Default Behaviour.In which order we put items in the queue, in the same order the items
will come out(FIFO-First In First out).
1) Import queue
2) q=queue.Queue()
3) q.put(10)
4) q.put(5)
5) q.put(20)
6) q.put(15)
7) while not q.empty():
8) print(q.get(),end=’ ‘)
2) LIFO Queue:
The removal will be happened in the reverse order of insertion (Last In First Out)
1) Import queue
2) q=queue.LifoQueue()
3) q.put(10)
4) q.put(5)
5) q.put(20)
6) q.put(15)
7) while not q.empty():
8) print(q.get(),end=’ ‘)
3) Priority Queue:
The elements will be inserted based on some priority order.
1) Import queue
2) q=queue.priorityQueue()
3) q.put(10)
4) q.put(5)
5) q.put(20)
6) q.put(15)
7) while not q.empty():
8) print(q.get(),end=’ ‘)
Eg 2:If the data is non-numeric,then we have to provide our data in the from of tuple.
(x,y)
X is priority
Y is our element
1) import queue
2) q=queue.priorityQueue()
3) q.put((1,”AAA”))
4) q.put((3,”CCC”))
5) q.put((2,”BBB”))
6) q.put((4,”DDD”))
7) while not q.empty():
8) print(q.get()[1],end=’ ‘)
Good programming practices with usage of Locks:
Case-1:
It is highly recommended to write code of releasing locks inside finally block.The advantages is
lock will be released always whether exception raised or not raised and whether handled or not
handled.
I=threading.Lock()
I.acquire()
try:
perform required safe operations
finally:
I.release()
Demo program:
1) from threading import*
2) import time
3) I=lock()
4) Def wish(name):
5) I.acquire()
6) try:
7) for I in range(10):
8) Print(“Good Evening:”,end=”)
9) Time.sleep(2)
10) Print(name)
11) Finally:
12) I.release()
13)
14) t1=Thread(target=wish,args=(“Dhoni”,))
15) t2=Thread(target=wish,args=(“yuvraj”,))
16) t3=Thread(target=wish,args=(“kohli”,))
17) t1.start()
18) t2.start()
19) t3.start()
Case-2:
It is highly recommended to acquire lock by using with statement.The main advantages of with
statement is the lock will be released automatically once control reaches end of with block and we
are not required to release explicity.
This is exactly same as usage of with statement for files.
Example for file:
With open(‘demo.txt’,’w’)as f:
f.write(“Hello…”)
Example for Lock:
Lock=threading.Lock()
With lock:
Perform required safe operations
Lock will be released automatically
Demo program:
1) From threading import*
2) Import time
3) lock=lock()
4) def wish(name):
5) with lock:
6) for I in range(10):
7) print(“Good Evening:”,end=”)
8) time.sleep(2)
9) print(name)
10) t1=Thread(target=wish,args=(“Dhoni”,))
11) t2=Thread(target=wish,args=(“yuvraj”,))
12) t3=Thread(target=wish,args=(“kohli”,))
13) t1.start()
14) t2.start()
15) t3.start()
Q) What is the Advantages of using with statement to acquire a lock in Threading?
Lock will be released automatically once control reaches end of with block and we are not
required to release explicity.
Note:We can use with statement in multithreading for the following cases:
1) Lock
2) Rlock
3) Semaphore
4) Condition

Python data base


programming
Storage Areas
As the part of our Application, we required to store our Data like customers information,Billing
Information ,calls information etc.
To store this Data, we required storage Areas. There are 2 types of storage Areas.
1) Temporary storage Areas
2) Permanent storage Areas
1) Temporary storage Areas:
These are the memory Areas where Data will be stored temporarily.
Eg:python objects like List,Tuple,Dictionary.
Once python program completes its executin then these objects will be destroyed automatically
and data will be lost.
2) Permanent storage Areas:
Also know as persistent storage Areas.Here we can store data permanently.
Eg:File systems,Databases,Data ware houses,Big Data technologies etc
File systems:
Also systems can be provided by local operating system.File systems are best suitable to store
very Amount of Information.
Limitations:
1) We cannot store huge Amount of Information.
2) There is no Query Language support and hence operations will become very complex.
3) There is no security for data.
4) There is no Mechanism to prevent duplicate Dtata.Hence there may be a chance of data
Inconsistency problems.
To overcome the above problems of file systems,we should go for Databases.
Databases:
1) We can store Huge Amount of information in the database.
2) Query language support is available for every Database and hence we can perform Database
operations very easily.
3) To access Data present in the Database,compulsory username and pwd must be
required.Hence Data is secured.
4) Inside Database Data will be stored in the form of tables.While developing database table
schemas,Database Admin follow various Normalization Techniques and can implement
various constraints like Unique key constrains,primary key constraints etc which prevent Data
Duplication.Hence there is no chance of Data Inconsistency problems.
Limitations of Databases:
1) Database cannot hold very Huge Amount of Information like Terabytes of Data.
2) Database can provide support only for structed Data(Tarbular Data OR Relational Data)and
cannot provide support for semi structed Data(like XML Files) and Unstructured Data(like videl
files,Audio files,Images etc)
To overcome these problems we should go for more Advanced storage Areas like BBig Data
Technologies,Data warehouses etc.
Python Database programming:
1) Sometimes as the part of programming requirement we have to connect to the database
and we have to perform several operations like creating tables,inserting data,updating
data,deleting data,selecting data etc.
2) We can use SQl language to talk to the database and we can use python to send those SQL
commands to the database.
3) Python provides inbuilt support for several database like Oracle, Mysql, Sqlserver, Gadfly,
Sqlite,etc
4) python has separate module for each database
Eg:cx—Oracle module for communicating with Microsoft aql server
Standard steps for python database programming:
1) Import database specific module
Eg:import cx—Oracle
2) Establish connection betweew python program and database.
We can create this connection object by using connect() function of the module.
Con = cx—Oracle.connect(database information)
Eg:con = cx—Oracle.connect(‘scott/tiger@localhost’)
3) To execute our sql queries and to hold result some special object is required,which is
nothing but cursor object.We can create cursor object by using cursor() method.
Cursor =con.cursor()
4) Execute SQL Queries By using cursor object.For this we can use the following methods
 Execute(sqlquery) To execute a single SQL Query
 Executescript(sqlqueries)To execute a string of SQL Queries separated by semi-
colon’;’
 Execute many()To exeute a parameterized Query.
Eg:cursor.execute(“select*from employees”)
5) Commit OR Rollback changes based on our requirement in the case of DML Queries
(insert|update|delete)
Commit()saves the changes to the database
Rollback()rolls all temporary changes back
6) Fetch the result from the cursor object in the case of select queries
Fetchone()To fetch only one row
Fetchall()To fetch all rows and it returns a list of rows
Fetchmany(n)To fetch first n rows
Eg 1:data = cursor.fetchone()
Print(data)
Eg 1:data = cursor.fetchall()
For row in data:
Print(row)
7) Close the Resourses
After complecting our operations it is highly recommended to close the resourses in the
reverse order of their opening by using close() methods.
Cursor.close()
Con.close()
Note:The following is the list of all important methods which can be used fo python
database programming.
 Connect()
 Cursor()
 Execute()
 Executescript()
 Executemany()
 Commit()
 Rollback()
 Fetchone()
 Fetchall()
 Fetchmany(n)
 Fetch
 Close()
These methods won’t be changed from database to database and same for all database.
Working with Oracle Database:
From python program if we want to communicate with any database,some translator must be
required to translate python calls into database specific calls and database specific calls into python
calls.This translator is nothing but Driver/connector.

Diagram

For oracle database the name of driver needed is cx—oracle.


cx—oracle is a python extension module that enables access to oracle database.It can be used for
both python2 and python3.It can work with any version of oracle database like 9,10,11 and 12.
Installing cx—Oracle:
How to Test Installation:
From python console execute the following command:
>>> help(“module”)
In the output we can see cx—oracle
….
-multiprocessing crypt ntpath timeit
-opcode csv ntural2path tkinter
-operator csvr numbers token
-osx—support csvw opcode tokenize
-overlapped ctypes operator trace
-pickle curses optparse traceback
-pydecimal custexcept os tracemalloc
-pyio cx—Oracle parser try
-random data pathlib tty
-sha1 datetime pdb turtle
-sha256 dbm pick turtledemo
-sha3 decimal pickle types
-sha512 demo pickletools typing
-signal difflib pip unicodedata
-sitebuiltins dis pipes unittest
-socket distutils pkg—resourses unpick
-sqlite3 doctest pkgutil update
-sre dummy-threading platform urllib
-ssl durgamath plistlib uu
-stat easy-install polymorph uuid
…..
App 1)Program to connect with oracle Database and print its version
1) import cx—oracle
2) con=cx—oracle.connect(‘scott/tiger@localhost’)
3) print(con.version)
4) con.close()
Output
D:\python—classes>py db1.py
11.2.0.2.0
App 2) Write a program to create Employees Table in the oracle Database
Employees(eno,ename,esal,eaddr)
1) import cx—oracle
2) try:
3) con=cx—oracle.connect(‘scott/tiger@localhost’)
4) cursor=con.cursor()
5) cursor.execute(“createtablesemployees(enonumber,enamevarchar2(10),esalnumber(10,2
),eadder varcher2(10))”
6) print(“Table created succefully”)
7) except cx-Oracle.DatabaseError as e:
8) if con:
9) con.rollback()
10) print(“There is a problem with sql” ,e)
11) finnaly:
12) if cursor:
13) cursor.close()
14) if con:
15) con.close()
App 3) Write a program to Drop Employees Table from oracle Database?
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cursor.execute(“drop table employees”)
6) Print(“Table dropped successfully”)
7) Except cx-oracle.Database Error as e:
8) If con:
9) Con.rollback()
10) Print(“There is a problem with sql”,e)
11) Finally:
12) If cursor:
13) Cursor.close()
14) If con:
15) Con.close()
App 3) Write a program to insert a single row in the employees table
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cursor.execute(“insert into employees values(100,’Durga’,1000,’Hyd’)”)
6) Con.commit()
7) Print(“record Inserted successfully”)
8) Except cx-oracle.Database Error as e:
9) If con:
10) Con.rollback()
11) Print(“There is a problem with sql”,e)
12) Finally:
13) If cursor:
14) Cursor.close()
15) If con:
16) Con.close()
App 4) Write a program to insert Multiple Rows in the Employees Table
by using executemany() Method
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Sql=”insert into employees values(:eno,:ename,:esal,:eaddr)”
6) Records=[(200,’sunny’,2000,’mumbai’),
7) (300,’chinny’,3000,’Hyd’),
8) (400,’chinny’,4000,’Hyd’)]
9) Cursor.executemany(sql,records)
10) Con.commit()
11) Print (“Records Instead Successfully”)
12) Except cx-oracle.DatabaseError as e:
13) If con:
14) Con.rollback()
15) Print(“There is a problem with sql”,e)
16) Finally:
17) If cursor:
18) Cursor.close()
19) If con:
20) Con.close()
App 5) Write a program to insert Multiple Rows in the Employees Table with
Dynamic input from the keyboard?
1) Import cx-Oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) While True:
6) Eno=int(input(“Enter Employee Number:”))
7) Ename=input(“Enter Employee Name:”)
8) Esal=float(input(“Enter Employee Salary:”))
9) eaddr=(input(“Enter Employee Address:”))
10) Sql=”insert into employees values(%d,’%s’,%f,’%s’)”
11) Cursor.execute(sql%(eno,ename,esal,eaddr))
12) Print(“Record Inserted Successfully”)
13) Option=inpt(“Do you want to insert one more record[yes|no]:”)
14) If option==”no”:
15) Con.commit()
16) Break
17) Except cx-oracle.DatabaseError as e:
18) If con:
19) Con.rollback()
20) Print(“There is a problem with sql”,e)
21) Finally:
22) If cursor:
23) Cursor.close()
24) If con:
25) Con.close()
App 6) Write a program to update Employee salaries with Increment for the
certain Range with Dynamic Input
Eg:Increment all employee salaries by 500 whose salary<5000
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Increment=float(input(“Enter Increment salary:”))
6) Salrange=float(input(“Enter salary Range:”))
7) Sql=”update employees set esal=esal+%f where esal>%f”
8) Cursor.execute(sql%(Increment,salrange))
9) Print(“Records updated successfully”)
10) Con.commit()
11) Except cx-oracle.DatabaseError as e:
12) If con:
13) Con.rollback()
14) Print(“There is a problem with sql:”,e)
15) Finally:
16) If cursor:
17) Cursor.close()
18) If con:
19) Con.close()
App 7) Write a program to delete Employees whose salary Greater provided
salary as Dynamic Input?
Eg: delete all employees whose salary>5000
1) Importcx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cutoffsalary=float(input(“Enter cutoff salary:”))
6) Sql=”delete from employees where esal>%f”
7) Cursor.execute(sql%(cutoffsalary))
8) Print(“Records Deleted successfully”)
9) Con.commit()
10) Except cx-oracle.DatabaseError as e:
11) If con:
12) Con.rollback()
13) Print(“There is a problem with sql:”,e)
14) Finally:
15) If cursor:
16) Cursor.close()
17) If con:
18) Con.close()
App 8) Write a program to select Employee info by using fetchone() method?
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cursor.execute(“select*from employees”)
6) Row=cursor.fetchone()
7) While row is not none:
8) Print(row)
9) Row=cursor.fetchone()
10) Except cx-oracle.DatabaseError as e:
11) If con:
12) Con.rollback()
13) Print(“There is a problem with sql:”,e)
14) Finally:
15) If cursor:
16) Cursor.close()
17) If con:
18) Con.close()
App 9) Write a program to select all Employees info by using fetchall()
method?
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cursor.execute(“select*from employees”)
6) Data=cursor.fetchall()
7) For row in data:
8) Print(“Employee Number:”,row[0])
9) Print(“Employee Name:”,row[1])
10) Print(“Employee salary:”,row[2])
11) Print(“Employee Address:”,row[3])
12) Print()
13) Print()
14) Except cx-oracle.DatabaseError as e:
15) If con:
16) Con.rollback()
17) Print(“There is a problem with sql:”,e)
18) Finally:
19) If cursor:
20) Cursor.close()
21) If con:
22) Con.close()
App 10) Write a program to select employees info by using fetchmany()
method and the required number of Rows will be provided as Dynamic
Input?
1) Import cx-oracle
2) Try:
3) Con=cx-oracle.connect(‘scott/tiger@localhost’)
4) Cursor=con.cursor()
5) Cursor.execute(“select*from employees”)
6) n=int(input(“Enter the number of required rows:”))
7) data=cursor.fetchmany(n)
8) for row in data:
9) print(row)
10) Except cx-oracle.DatabaseError as e:
11) If con:
12) Con.rollback()
13) Print(“There is a problem with sql:”,e)
14) Finally:
15) If cursor:
16) Cursor.close()
17) If con:
18) Con.close()
Working with MySQL Database:
Current version:5.7.19
Vendor:SUN micro systems/oracle corporation
Open source and Freeware
Default port:
Default user:root
Note: In MYSQL, everything w have to work with our own database,which are also known as Logical
Databases.
The following are 4 Default Databases available in MYSQL.
 Information-scheme
 Mysql
 Performance-scheme
 Test
In the above diagram only one physical databases is available and 4 logical databases are
available.
Commonly used commands in MYSQL:
1) To know Available Databases
Mysql>show databases;
2) To create our own logical Databases
Mysql>create database durgadb;
3) To drop our own Databases
Mysql>drop database durgadb;
4) To use a particular logical Databases
Mysql>use durgadb; OR mysql>connect durgadb;
5) To create a table
Create table employees(eno int(5) primary key,ename varchar(10),esal double(10,2),eaddr
varchar(10));
6) To insert data
Insert into employees values(100,’Durga’,1000,’hyd’);
Insert into employees values(200,’Ravi’,2000,’Mumbai’);
In MySQL instead of single quotes we can use double quotes also.
Drive/connector Information:
From python program if we want to communicates with Mysql database,compulsory some
translator is required to convert python specific calls into mysql database specific calls and
mysql database specific calls into python specific calls.This translator is nothing but Driver or
connector.
We have to download connector separately from mysql database.
https://dev.mysql.com/downloads/connector/python/2.1.html
How to check Installation:
From python console we have to use help(“modules”)
In the list of modules,compulsory mysql should be there.
Note: In the case of python3.4 we have to set PATH and PYTHONPATH explicity

PATH=C:\python34
PYTHONPATH=C:\python34\Lib\site-packages
Q) Write a program to create Table,Insert Data and display Data by
using MYSQL Database
1) import mysql.connector
2) try:
3)con=mysql.connectro.connect(host=’localhost’,database=’durgadb’,user=’root’,password
=’root’)
4) cursor=con.cursor()
5) cursor.execute(“create table employees(eno int(5) primary key,ename varchar(10),esal
double(10,2),eaddr varchar(10))”)
6) print(“Table created…”)
7)
8) sql=”insert into employees(eno,ename,esal,eaddr)VALUES(%S, %S, %S, %S)”
9) records=[(100,’sachin’,1000,’Mumbai’),
10) (200,’Dhoni’,2000,’Ranchi’),
11) (300,’kohli’,3000,’Delhi’),
12) cursor.executemany(sql,records)
13) con.commit()
14) print(“Records Inserted Successfully…”)
15) cursor.execute(“select * from employees”)
16) data=cursor.fetchall()
17) for row in data:
18) print(“Employee Number:”,row[0])
19) print(“Employee Number:”,row[0])
20) print(“Employee Number:”,row[0])
21) print(“Employee Number:”,row[0])
22) print()
23) print()
24) Except mysql.connector.DatabaseError as e:
25) If con:
26) Con.rollback()
27) Print(“There is a problem with sql:”,e)
28) Finally:
29) If cursor:
30) Cursor.close()
31) If con:
32) Con.close()
Q) Write a program to copy Data present in Employees Table of MYSQL
Database into oracle Database
1) import mysql.connector
2) import cx-oracle
3) try:
4)con=mysql.connectro.connect(host=’localhost’,database=’durgadb’,user=’root’,password
=’root’)
5) cursor=con.cursor()
6) cursor.execute(“select * from employees”)
7) data=cursor.fetchall()
8) list=[]
9) for row in data:
10) t=(row[0],row[1],row[2],row[3])
11) list.append(t)
12) except mysql.connector.DatabaseError as e:
13) If con:
14) Con.rollback()
15) Print(“There is a problem with sql:”,e)
16) Finally:
17) If cursor:
18) Cursor.close()
19) If con:
20) Con.close()
21)
22) try:
23) con=cx-oracle.connect(‘scott/tiger@localhost’)
24) cursor=con.cursor()
25) sql=”insert into employees values(:eno,:ename,:esal,:eaddr)”
26) cursor.executemany(sql,list)
27) con.commit()
28) print(“Records copied from MYSQL Database to oracle Database successfully”)

29) Except mysql.connector.DatabaseError as e:


30) If con:
31) Con.rollback()
32) Print(“There is a problem with sql:”,e)
33) Finally:
34) If cursor:
35) Cursor.close()
36) If con:
37) Con.close()
https://dev.mysql.com/downloads/connector/python/2.1.html
1) Create table employees(eno int(5) primary key,ename varchar(10),esal double(10,2),eaddr
varchar(10));
2) Insert into employees values(100,’Durga’,1000,’Hyd’);
3) Insert into employees values(200,’Ravi’,2000,’Mumbai’);
4) Insert into employees values(300,’Shiva’,3000,’Hyd’);

REGULAR EXPRESSIONS
& WEB SCRAPING
 If we want to represent a group of strings according to a particular format/pattern then
we should go for Regular Expressions.
 i.e Regular Expressions is a declarative mechanism to represent a group of strings
according to particular format/pattern.
 Eg 1: We can write a regular expression to represent all mobile numbers
 Eg 2: We can write a regular expression to represent all mail ids.
The main important application areas of Regular Expressions are
1) To develop validation frameworks/validation logic
2) To develop pattern matching applications(ctrl-f in windows,grep in UNIX etc)
3) To develop Translators like compilers,interpreters etc
4) To develop digital circuits
5) To develop communication protocols like TCP/IP,UDP etc.
 We can develop Regular Expression Based applications by using python module:re
 This module contains several inbuilt functions to use Regular Expressions very easily
in our applications.
1) Compile()
Returns module contains compile()Function to compile a pattern into Regexobject.
Pattern=re.compile(“ab”)
2) Finditer():
Return an Iterator object which yields match object for every match
Matcher=pattern.finditer(“abaababa”)
On match object we can call the following methods.
1) Start()Returns start index of the match
2) end()Returns end+1 index of the match
3) Start()Returns the matched string

1) Import re count=0
2) Pattern=re.compile(“ab”)
3) Matcher=pattern.finditer(“abaababa”)
4) For match in matcher:
5) Count+1
6) Print(match.start(),”…”,match.end(),”…”,match.group())
7) Print(“The number of occurrences:”,count)
Note: We can pass pattern directly as argument to finditer() function.
1) Import re
2) Count=0
3) Matcher=re.finditer(“ab”,”abaababa”)
4) For match in matcher:
5) Count+1
6) Print(match.start(),”…”,match.end(),”…”,match.group())
7) Print(“The number of occurrences:”,count)
Character classes:
We can use character classes to search angroup of character
1) [abc]Either a OR b OR c
2) [^abc]Except a and b and c
3) [a-z]Any Lower case alphabet symbol
4) [A-Z]Any upper case alphabet symbol
5) [a-zA-Z]Any alphabet symbol
6) [0-9]Any digit from 0 to 9
7) [a-zA-Z0-9]Any alphanumeric character
8) [^a-zA-Z0-9]Except alphanumeric character(special character)
1) Import re
2) Matcher=re.finditer(“x”,”a7b@k9z”)
3) For match in matcher:
4) Print(match.start(),”……”,match.group())
x=[abc] x=[^abc] x=[a-z] x=[0-9] x=[a-zA-Z0-9] x=[^a-zA-Z0-9]
0……a 1……7 0……a 1…….7 0…….a 3……..@
2……b 3……@ 2……b 5…….9 1…….7
4…….k 4…….k 2…….b
5……9 6…….z 4…….k
6……z 5…….9
6…....z

Pre defined character classes:


1) \sSpace character
2) \SAny character except Space character
3) \dAny digit from 0 to 9
4) \DAny character except digit
5) \wAny word character [a-zA-Z0-9]
6) \WAny character except word character(special character)
7) .Any character including special characters

1) Import re
2) Matcher=re.finditer(“x”,”a7b k@9z”)
3) For match in matcher:
4) Print(match.start(),”……..”,match.group())
X=\s: x=\S: x=\d: x=\D: x=\w: x=\W: x=.
3…… 0……a 1……7 0……a 0…….a 3…… 0…..a
1……7 6……9 2……b 1…….7 5…….@ 1…..7
2……b 3…… 2…….b 2……b
4……k 4……k 4…….k 3……
5……@ 5……@ 6…….9 4……k
6……9 7…….z 7…....z 5…@
7……z 6……9
7……z
Qunatifiers:
We can use quantifier to specify the number of occurrences to match.
1) aExcatly one ‘a’
2) a+Atleast one ‘a’
3) a*Any number of a’s including zero number
4) a?-->Atmost one ‘a’ ie either zero number or one number
5) a{m}Exactly m number of a’s
6) a{m,n}Minimum m number of a’s and Maximum n number of a’s.

1) import re
2) for match in matcher:
3) print(match.start(),”………”,match.group())
x=a: x=a+: x=a*: x=a?: x=a{3}: x=a{2,4}:
0….a 0…..a o……a 0…..a 5…..aaa 2……aa
2….a 2……aa 1….. 1….. 5……aaa
3….a 5…….aaa 2….aa 2…..a
5….a 4….. 3……a
6….a 5……aaa 4……
7….a 8…... 5……a
9…… 6……a
7…..a
8…..
9…..

Note:
1) ^xIt will check whether target string starts with x OR not.
2) x$It will check whether target string starts with x OR not.
Important Functions of Remodule:
1) match()
2) fullmatch()
3) search()
4) findall()
5) finditer()
6) sub()
7) subn()
8) split()
9) compile()
1) match():
 We can use match function to check the given pattern at beginning of target string.
 If the match is available then we will get match, otherwise we wil get none.
1) Import re
2) S=input(“Enter patternto check:”)
3) M=re.match(s,”abcabdefg”)
4) If m!=None:
5) Print(“Match is available at the beginning of the string”)
6) Print(“start index:”,m.start(),”and End Index:”,m.end())
7) Else:
8) Print(“Match is not available at the beginning of the string”)
2) fullmatch():
 We can use fullmatch() function to match a pattern to all of target string.i.e
complete string should be matched according to given pattern.
 If complete string matched then this function returns match object otherwise it
returns none.
1) Import re
2) S=input(“Enter pattern to check:”)
3) M=re.fullmatch(s,”abababa”)
4) If m!=None:
5) Print(“Full string matched”)
6) Else:
7) Print(“Full string not matched”)
3) search():
 We can use search() function to search the given pattern in the target string.
 If the match is available then it returns the match object with represents first
occurrence of the match.
 If the match is not available then it returns none
1) Import re
2) S=input(“Enter pattern to check:”)
3) M=re.search(s,”abaaaba”)
4) If m!=None:
5) Print(“match is available”)
6) Print(“First occuuence of match with start index:”,m.start(),”and end index:”,m. end())
7) Else:
8) Print(“match is not available”)
4) search():
 To find all occurrence of the match.
 This function returns a list object which contains all occurrences.
1) Import re
2) I=re.findall(“[0-9]”.”a7b9c5kz”)
3) Print(I)
5) finditer():
 Returns the iterator yielding a match object for each match.
 On each match object we can call start(),end() and group() functions.
1) Import re
2) Itr=re.finditer(“[a-z]”,” a7b9c5k8z”)
3) For m in itr:
4) Print(m.start(),”….”,m.end(),”……”,m.group())
6) sub():
 sub means substitution or replacement.
 Re.sub(regex,replacement,tergetstring)
 In the target string every matched pattern will be replaced with provided
replacement.
1) Import re
2) S=re.sub(“[a-z]”,”#”,”a7b9c5k8z”)
3) Print(s)
7) subn():
 It is exactly same as sub except it can also returns the number of replacement.
 This function returns a tuple wher first element is result string and second element
is number of replacements.
(resultstring,number of replacement)
1) Import re
2) t=re.subn([a-z]”,”#”,”a7b9c5k8z”)
3) print(t)
4) print(“The Result string:”,t[0])
5) print(“The number of replacement:”,t[1])
8) split():
 If we want to split the given target string according to a particular pattern then we
should go for split() function.
 This function returns list of all tokens.
1) Import re
2) I=re.split(“,”,”sunny,bunny,chinny,vinny,pinny”)
3) Print(I)
4) For t in I:
5) Print(t)
Output:
D:\python-classes>py test.py
[‘sunny’,’bunny’,’chinny’,’vinny’,’pinny’]
Sunny
Bunny
Chinny
Vinny
Pinny
1) Import re
2) I=re.split(“\.”,”www.durgasoft.com”)
3) For t in I:
4) Print(t)
Output:
D:\python-classes>py test.py
www
durgasoft
com
9) ^ symbol:
 We can use ^ symbol to check whether the given target string starts with our
provided pattern or not.
 Eg:res=re.search(“^learn”,s)
 If the target string starts with learn then it will returnmatch object,otherwise
returns None.
Test.py
1) Import re
2) S=”Learning python is very Easy”
3) Res=re.search(“^Learn”,s)
4) If res!=None:
5) Print(“Target string starts with Learn”)
6) Else:
7) Print(“Target string not starts with learn”)
Output:Target string starts with learn
10) $ symbol:
 We can use $ symbol to check whether the given target string ends with our
provided pattern or not.
 Eg:res=re.search(“Easy$”,s)
 If the target string ends with Easy then it will return match object,otherwise
returns None.
Test.py
1) Import re
2) S=”Learning python is very Easy”
3) Res=re.search(“Easy$”,s)
4) If res!=None:
5) Print(“Target string ends with Easy”)
6) Else:
7) Print(“Target string not ends with Easy”)
Output:Target string ends with easy
Note:If we want to ignore case then we have to pass 3rd argument re.IGNORECASE for search() function.
Eg:res=re.search(“easy$”,s,re.IGNORECASE)
Test.py
1) Import re
2) S=”Learning python is very Easy”
3) Res=re.search(“Easy$”,s,re.IGNORECASE)
4) If res!=None:
5) Print(“Target string ends with Easyby ignoring case”)
6) Else:
7) Print(“Target string not ends with Easy by ignoring case”)
Output:Target string ends with easy by ignoring case
App 1) Write a Regular Expression to represent all Yava Language
Identifiers
Rules:
1) The allowed characters are a-z,A-Z,0-9,#
2) The first character should be a lower case alphabet symbol from a to k
3) The second character should be a digit divisible by 3
4) The length of identifier should be atleast 2.
[a-k][0369][a-zA-Z0-9#]*
App 2) Write a python program to check whettther the given string
is Yava Language Identifiers OR not?
1) Import re
2) S=input(“Enter Identifier:”)
3) m=re.fullmatch(“[a-k][0369][a-zA-Z0-9#]*”,s)
4) If m!=None:
5) Print(s,“is valid Yava Identifier”)
6) Else:
7) Print(s,“is invalid Yava Identifier”)

App 3) Write a Regular Expression to represent all 10 Digit Mobile


Numbers
Rules:
1) Every number should contains exactly 10 Digits
2) The 1st Digit should be 7 OR 8 OR 9
[7-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]
OR
[7-9][0-9]{9}
OR
[7-9]\D{9}

App 4) Write a Python program to check whether the given number


is valid mobile number OR not?
8) Import re
9) n=input(“Enter number:”)
10) m=re.fullmatch(“[7-9]\D{9}”,n)
11) If m!=None:
12) Print(“valid mobile number”)
13) Else:
14) Print(“invalid mobile number”)
App 5) Write a Python program to extract all mobile numbers
present in input.txt where number are mixed with normal Text
Data
1) Import re
2) F1=open(“input.txt”,”r”)
3) F2=open(“output.txt”,”w”)
4) For line in f1:
5) List=re.findall(“[7-9]\d{9}”,line)
6) For n in list:
7) F2.write(n+”\n”)
8) Print(“Extracted all mobile numbers into output.txt”)
9) F1.close()
10) F2.close()
Web scraping by using Regular Expressions
The process of collecting information from web pages is called web scraping.In web
scraping to match our required patterns like mail ids,mobile numbers we can use regular
expressions.
1) Import re,urllib
2) Import urllib.request
3) Sites=”google rediff”.split()
4) Print(sites)
5) For s in sites:
6) Print(“searching….”,s)
7) U=urllib.request.urlopen(http://+s+.com”)
8) Text=u.read()
9) Title=re.findall(“<title>.*</title>”,str(text),re.I)
10) Print(title[10])
Program to get all phone number of redbus.in by using web
scraping and Regular Expressions
1) Import re,urllib
2) Import urllib.request
3) U=urllib.request.urlopen(http://”www.redbus.in/info/contactus”)
4) Text=u.read()
5) Numbers=re.findall(“[0-9]{7}[0-9-]+”,str(text),re.I)
6) For n in numbers:
7) Print(n)
Program a python program to check whether the given mail id is
valid gmail id OR not?
1) Import re
2) s=input(“Enter mail id:”)
3) m=re.fullmatch(“\w[a-zA-Z0-9_.]*@gmail[.]com”,s)
4) If m!=None:
5) Print(“valid mail id”);
6) Else:
7) Print(“invalid mail id”)
Write a python program to check whether the given car
Registration number is valid Telangana number OR not?
1) Import re
2) s=input(“Enter Vehicle Registration number:”)
3) m=re.fullmatch(“TS[012][0-9][A-Z{2}\d{4}”,s)
4) If m!=None:
5) Print(“valid Vehicle Registration number:”)
6) Else:
7) Print(“invalid Vehicle Registration number:”)
python program to check whether the given mobile number is valid
OR not(10 Digit OR 11 Digit OR 12 Digit)
8) Import re
9) s=input(“Enter mobile number:”)
10) m=re.fullmatch(“(0|91)?[7-9][0-9]{9}”,s)
11) If m!=None:
12) Print(“valid mobile number:”)
13) Else:
14) Print(“invalid mobile number:”)
Summary Table and some more Examples.
DECORATOR FUNCTIONS
Decorator is a function which can take a function as argument and extend its functionality and returns
modified function with extended functionality.

The main objective of decorator functions is we can extend the functionality of existing functions
without modifies that function.

1) Def wish(name):
2) Print(“Hello”,name,”Good morning”)
This function can always print same output for any name
Hello Durga Good Morning
Hello Ravi Good Morning
Hello Sunny Good Morning
But we want to modify this function to provide different message if name is sunny.
We can do this without touching wish() function by using decorator.
1) Def decor(func):
2) Def inner(name):
3) If name==”sunny”:
4) Print(“Hello sunny Bad Morning”)
5) Else:
6) Func(name)
7) Return inner
8)
9) @decor
10) Def wish(name):
11) Print(“Hello”,name,”Good Morning”)
12)
13) Wish(“Durga”)
14) Wish(“Ravi”)
15) Wish(“Sunny”)
Hello Sunny Bad Morning
In the above program whenever we call wish() function automatically décor function will be executed.
How to call same Function with Decorator and without Decorator:
We should not use @decor
1) Def decor(func):
2) Def inner(name):
3) If name==”sunny”:
4) Print(“Hello sunny Bad Morning”)
5) Else:
6) Func(name)
7) Return inner
8)
9) Def wish(name):
10) Print(“Hello”,name,”Good Morning”)
11)
12) Decorfunction=decor(wish)
13)
14) Wish(“Durga”)#decorator wont be executed
15) Wish(“Sunny”)#decorator wont be executed
16) Decorfunction(“Durga”) #decorator will be executed
17) Decorfunction(“Sunny”) #decorator will be executed
Without Decorator we will get Error.In this case outut is:
10.0
Traceback(most recent call last:
File “test.py”, line 16, in <module>
Print(division(20,0))
File “test.py”, line 13, in division
Return a/b
ZeroDivisionError: division by zero
With Decorator we won’t get any Error.In this case outut is:
We are dividing 20 with 2
10.0
We are dividing 20 with 0
Oops…..cannot divide
None
1) Def marriagedecor(func):
2) Def inner():
3) Print(‘Hair decoration…..’)
4) Print(‘Face decoration with platinum package’)
5) Print(‘Fair and Lovely etc…’)
6) Func()
7) Return inner
8)
9) Def getready():
10) Print(‘Ready for the marriage’)
11)
12) Decorated_getready=marriagedecor(getready)
13)
14) Decorated_getready()
Decorated chaining
We can define multiple decorators for the same function and all these decorators will form
Decorator chaining.
We can define multiple decorators for the same function and all these decorators will form
Decorator chaining.
Eg:
@decor 1
@decor
Def num():
For num() function we are applying 2 decorator functions.First inner decorator will work and then
outer decorator.
1) Def decor 1(func):
2) Def inner():
3) X=func()
4) Returnx*x
5) Return inner
6)
7) Def decor(func):
8) Def inner():
9) X=func()
10) Return 2*x
11) Return inner
12)
13) @decor 1
14) @decor
15) Def num():
16) Return 10
17)
18) Print(num())

GENERATOR FUNCTIONS
Generator is a function which is responsible to generate a sequence of values.
We can write generator functions just like ordinary functions,but it uses yield keyword to return
values.
1) Def mygen():
2) Yield ’A’
3) Yield ’B’
4) Yield ’C’
5)
6) G=mygen()
7) Print(type(g))
8)
9) Print(next(g))
10) Print(next(g))
11) Print(next(g))
12) Print(next(g))
Eg 3: To generate first n numbers
1) Def firstn(num):
2) n=1
3) while n<=num:
4) yield n
5) n=n+1
6)
7) Values=firstn(5)
8) For x in values:
9) Print(x)
Eg 4 :To generate Fibonacci Numbers…
The next is the sum of previous 2 numbers
Eg:0,1,1,2,3,5,8,13,21……
1) Def fib():
2) a,b=0,1
3) while True:
4) yield a
5) a,b=b,a+b
6) for f in fib():
7) if f>100:
8) break
9) print(f)
Advantages of Generator Functions:
1) When compared with class Level Iterators,Generators are very easy to use.
2) Improve Memory Utilization and performance.
3) Generators are best suitable for reading Data from large number of large files.
4) Generators work great for web scraping and crawling.
Generators vs Normal Collections wrt Performance:
1) Import random
2) Import time
3)
4) Names=[‘Sunny’,’Bunny’,Chinny’,’Vinny’]
5) Subjects=[‘python’,’java’,’Blockchain’]
6)
7) Def people_list(num_people):
8) Result=[]
9) For I in range(num_people):
10) Person={
11) ‘id’:I,
12) ‘name’:random.choice(names),
13) ‘subject’:random.choice(subjects)
14) }
15) Result.append(person)
16) Return results
17)
18) Def people_generator(num_people):
19) For I in range(num_people):
20) Person={
21) ‘id’:I,
22) ‘name’:random.choice(names),
23) ‘major’:random.choice(subjects)
24) }
25) Yield person
26)
27) “”’t1=time.clock()
28) People=people_list(10000000)
29) t2=time.clock()”’
30)
31) t1=time.clock()
32) people=people_generator(10000000)
33) t2=time.clock()
34)
35)Print(‘Took{}’.format(t2-t1))
Note: In the above program observe the difference wrt execution time by using list and generators
Generators vs Normal collections wrt Memory Utilization:
Normal collection:
I=[x*x for x in range (10000000000000000)]
Print(I[0])
We will get memoryError in this case because all these values are required to store in the memory.
Generators:
g=(x*x for x in range(10000000000000000))
print(next(g))
output:0
We won’t get any memoryError because the values won’t be stored at the beginning.

ASSERTIONS
Debugging python program by using assert keyword:
 The process of identifying and fixing the bug is called debugging.
 Very common way of debugging is to use print() statement.But the problem with the print()
statement is after fixing the bug,compulsory we have to delete the extra added print()
statements,otherwise these will be executed at runtime which creates performance problems
and disturbs console output.
 To overcome this problem we should go for assert statement.The main advantages of assert
statement over print() statement is after fixing bug we are not required to delete assert
statements.Based on our requirement we can enable or disable assert statements.
 Hence the main purpose of assertions is to perform debugging.Usully we can perform debugging
either in development or in test environments but not in production environments but not for
production environment.
Types of assert Statements:
There are 2 types of assert statements
1) Simple version
2) Augmented version
1) Simple version:
Assert conditional_expression
2) Augmented version:
 Assert conditional_expression,message
 Conditional_expression will be evaluated and if it is true then the program will be continued.
 If it is false then the program will be terminated by raising AssertionError.
 By seeing AssertionError,programmer can analyze the code and can fix the problem.
1) def squarelt(x):
2) return**x
3) assert squarelt(2)==4,”The square of 2 should be 4”
4) assert squarelt(3)==9,”The square of 3 should be 9”
5) assert squarelt(4)==16,”The square of 4 should be 16”
6) print(squarelt(2))
7) print(squarelt(3))
8) print(squarelt(4))
9)
10) D:\Python_classes>py test.py
11) Traceback(most recent call last):
12) File “test.py”,line 4,in<module>
13) Assert squarelt(3)==9,”The square of 3 should be 9”
14) Assert ionError:The squre of 3 should be 9
15)
16) Def squarelt(x):
17) Return x*x
18) Assert squarelt (2)==4,”The square of 2 should be 4”
19) Assert squarelt (3)==9,”The square of 3 should be 9”
20) Assert squarelt (4)==16,”The square of 4 should be 16”
21) Print(squarelt(2))
22) Print(squarelt(3))
23) Print(squarelt(2))
Exception Handling vs Assertions:
Assertions concept can be used to alert programmer to resolve development time errors.
Exception Handling can be used to handle runtime error.

PYTHON LOGGING
It is highly recommended to store complete application flow and exception information to a
file.This process is called logging.
The main advantages of logging are:
1) We can use log files while performing debugging
2) We can provide statistics like number of requests per day etc
To implement logging,python provides inbuilt module logging.
Logging Levels:
Depending on type of information,logging data is divided according to the following 6
Levels in python
1) CRITICAL50
Represents a very serious problem that needs high attention
2) ERROR40
Represents a serious error
3) WARNING30
Represents a warning message,some caution needed.It is alert to the programmer.
4) INFO20
Represents a message with some important information
5) DEBUG10
Represents a message with debugging information
6) NOTSET0
Represents that level is not set
By default while executing python program only WARNING and higher level message will be
displayed.
How to implement Logging:
To perform logging,first we required to create a file to store messages and we have to
specify which level message required to store.

We can do this by using basicconfig() function of logging module.


Logging.basicconfig(file name=’log.txt’,level=logging.WARNING)
The above line will create a file log.txt and we can store either WARNING level or higher
level messages to that file.
After creating log file,we can write message to that file by using the following methods
 Logging.debug(message)
 Logging.info(message)
 Logging.warning(message)
 Logging.error(message)
 Logging.critical(message)
Q) Write a python program to create a log file and write WARNING
and Higher level messages?
1) Import logging
2) Logging.basicconfig(filename=’log.’txt’,level=logging.WARNING)
3) Print(‘logging Demo’)
4) Logging.debug(Debug informtion’)
5) Logging.info(‘info information’)
6) Logging.warning(‘warning informtion’)
7) Logging.error(‘error information’)
8) Logging.critical(‘critical information’)
Log.txt:
WARNING:root:warning information
ERROR:root:error information
CRITICAL:root:critical information
Note: In the above program only WARNING and higher level messages will be written to
the log file.If we set level as DEBUG then all messages will be written to the log file.
Test.py
1) Import logging
2) Logging.basicconfig(filename=’log.txt’,level=logging.DEBUG)
3) Print(‘logging Demo’)
4) Logging.debug(Debug informtion’)
5) Logging.info(‘info information’)
6) Logging.warning(‘warning informtion’)
7) Logging.error(‘error information’)
8) Logging.critical(‘critical information’)
Log.txt
DEBUG:root:Debug information
INFO:root:info information
WARNING:root:warning information
ERROR:root:error information
CRITICAL:root:critical information
How to configure log file in over writing mode:
In the above program by default data will be appended to the log file.i.e append is the
default mode.instead of appending if we want to over write data then we have to use
file mode property.
Logging.basicconfig(filename=’log786.txt’,level=logging.WARNING)
Meant for appending
Logging.basicconfig(filename=’log786.txt’,level=logging.WARNING,filemode=’a’)
Explicitly we are specifying appending.
Logging.basicconfig(filename=’log786.txt’,level=logging.WARNING,filemode=’w’)
Meant for over writing of previous data.
Note:
Logging.basicconfig(filename=’log786.txt’,level=logging.DEBUG)
If we are not specifying level then the default level is WARNING(30)
If we are not specifying file name then the message will be printed to the console.
Test.py
1) Import logging
2) Logging.basicconfig()
3) Print(‘logging Demo’)
4) Logging.debug(Debug informtion’)
5) Logging.info(‘info information’)
6) Logging.warning(‘warning informtion’)
7) Logging.error(‘error information’)
8) Logging.critical(‘critical information’)
D:\durgaclasses>py test.py
Logging Demo
WARNING:root:warning information
ERROR:root:error information
CRITICAL:root:critical information
How to format log Messages:
By using format keyword argument,we can format messages.
1) To display only level name: Logging.basicconfig(format=’%(levelnames)s’)
Output:
Warning
Error
Critical
2) To display levelname and message:
Logging.basicconfig(format=’%(levelname)s:%(message)s’)
Output:
WARNING:warning information
ERROR:error information
CRITICAL:critical information
How to add Timestamp in the log messages:
Logging.basicconfig(format=’%(asctime)s:%(levelname)s:%(message)s’)
How to change Date and Time Format:
We have to use special keyword argument:datefmt
Logging.basicconfig(format=’%(asctime)s:%(levelname)s:%(message)s’,
Datefmt=’%d/%m/%y %I:%m:%s%p’)
Datefmt=’%d/%m/%y %I:%m:%s%p’Case is important
Note:
%Imeans 12 Hours time scale
%Hmeans 24 Hours time scale
Eg: Logging.basicconfig(format=’%(asctime)s:%(levelname)s:%(message)s’,
Datefmt=’%d/%m/%y %H:%m:%s’)
How to write python program Exceptions to the log file:
By using the following function we can write exception information to the log file.
Logging.exception(msg)
Q) Python program to write Exception information to the log file
1) import logging
2) logging.basicconfig(filename=’mylog.txt’,level=logging.INFO,format=’%(asctime)s:
%(levelname)s:%(message)s’:datefmt=’%d/%m/%y %I:%M:%S %P’)
3) Logging.info(‘A new Request came’)
4) Try:
5) X=int(input(‘Enter First Number:’))
6) Y=int(input(‘Enter Second Number:’))
7) Print(‘The Result:’,x/y)
8)
9) Except ZeroDivisionError as msg:
10) Print(‘cannot divide with zero’)
11) Logging.exception(msg)
12)
13) Except valueError as msg:
14) Print(‘please provide int values only’)
15) Logging.exception(msg)
16)
17) Logging.info(Request processing Completed’)

D:\durgaclasses>py test.py
Enter First Number:10
Enter second number:2
The Result:5.0

D:\durgaclasses>py test.py
Enter First Number:20
Enter second number:2
The Result:10.0

D:\durgaclasses>py test.py
Enter First Number:10
Enter second number:0
Cannot divide with zero

D:\durgaclasses>py test.py
Enter First Number:ten
Please provide int values only

Mylog.txt
15/06/2018 12:30:51 PM:INFO:A new Request came
15/06/2018 12:30:53 PM:INFO:Request processing completed
15/06/2018 12:30:55 PM:INFO:A new Request came
15/06/2018 12:31:00 PM:INFO:Request processing completed
15/06/2018 12:31:02 PM:INFO:A new Request came
15/06/2018 12:31:05 PM:ERROR:division by zero
Traceback(most recent call last):
File”test.py”, line 7,in<module>
Print(‘The Result:’,x/y)
ZeroDivisionError: division by zero
15/06/2018 12:31:05 PM:INFO:Request processing completed
15/06/2018 12:31:06 PM:INFO:A new Request came
15/06/2018 12:31:10 PM:ERROR:invalid literal for int() with base 10:’ten’
Traceback(most recent call last):
File ”test.py”, line 5,in<module>
X=int(input(‘Enter First Number:’))
ValueError:invalid literal for int() with base 10: ‘ten’
15/06/2018 12:31:10 PM:INFO:Request processing completed
Problems with Root Logger:
If we are not defining our own logger,then bydefault root logger will be considered.Once we
perform basic configuration to root logger then the configurations are fixed and we cannot change.
Demo Application:
Student.py:
1) Import logging
2) Logging.basicconfig(filename=’student.log’,level=logging.INFO)
3) Logging.info(‘info message from student module’)
test.py:
1) Import logging
2) Import student
3) Logging.basicconfig(filename=’test.log’,level=logging.DEBUG)
4) Logging.debug(‘debug message from test module’)
Student.log:
INFO:root:info message from student module
In the above application the configurations performed in test module won’t be reflected,because
root logger is already configured in student module.
Need of our own customized logger:
The problems with root logger are:
1) Once we set basic configuration then that configuration is final and we cannot change.
2) It will always work for only one handler at a time,either console or file,but not both
simultaneously.
3) It is not possible to configure logger with different configurations at different levels.
4) We cannot specify multiple log files for multiple modules/classes/methods.
To overcome these problems we should go for our customized loggers
Advanced logging module features: logger:
Logger is more advanced than basic logging.
It is highly recommended to use and it provides several extra features.
Steps for Advanced logging:
1) Creation of Logger object and set log level.
Logger=logging.getlogger(‘demologger’)
Logger.setlevel(logging.INFO)
2) Creation of Handler object and set log level
3) There are several types of Handlers like streamHandler,FileHandler etc.
consoleHandler=logging.streamHandler()
consoleHandler.setlevel(logging.INFO)
Note: If we use streamHandler then log messages will be printed to console.
4) Creation of formatter object.
Formatter =logging.formatter(‘%(asctime)s-%(name)s- %(levelname)s: %(message)ss’,
Datefmt=’%d/%m/%y%I:%M:%S %P’)
5) Add formatter to HandlerconsoleHandler.setformatter(formatter)
6) Add Handler to loggerlogger.addHandler(consoleHandler)
7) Write message by using logger object and the following methods
Logger.debug(‘debug message’)
Logger.info(‘info message’)
Logger.warn(‘warn message’)
Logger.error(‘error message’)
Logger.critical(‘critical message’)
Note: Bydefault logger will set to WARNING level.But we can set our own level based on our
requirement.
Logger=logging.getlogger(‘demologger’)
Logger.setlevel(logging.INFO)
Logger log level by default available to console and file handlers.If we are not satisfied with logger
level,then we can set log level explicitly at console level and file levels.
consoleHandler=logging.streamHandler()
consoleHandler.setlevel(logging.WARNING)

fileHandler=logging.fileHandler(‘abc.log’,mode=’a’)
fileHandler.setlevel(logging.ERROR)
Note: console and file log levels should be supported by logger.i.e logger log level should be
lower than console than console and file levels.Otherwise only logger log level will be
considered.
Eg:
LoggerDEBUG consoleINFOValid and INFO will be considered
LoggerINFO consoleDEBUGInvalid and only INFO will be considered to the console.
Demo program for console Handler:
1) Import logging
2) Class loggerDemoconsole:
3)
4) Def testlog(self):
5) Logger=logging.getlogger(‘demologger’)
6) Logger.setlevel(logging.INFO)
7)
8) consoleHandler=logging.streamHandler()
9) consoleHandler.setlevel(logging.INFO)
10)
11) Formatter=logging.formatter(‘%(asctime)s-%(name)s-%(levelname)s: %(message)s’,
12) Datefmt=’%m/%d/%y%I:%M:%S %P’)
13)
14) consoleHandler.setFormatter(formatter)
15) logger.addHandler(consoleHandler)
16) logger.debug(‘debug message’)
17) logger.info(‘info message’)
18) logger.warn(‘warn message’)
19) logger.error(‘error message’)
20) logger.critical(‘critical message’)
21)
22) Demo=loggerDemoconsole()
23) Demo.testlog()
D:\durgaclasses>py loggingdemo3.py
06/18/2018 12:14:15 PM – demologger – INFO:info message
06/18/2018 12:14:15 PM – demologger – WARNING:warn message
06/18/2018 12:14:15 PM – demologger – ERROR:error message
06/18/2018 12:14:15 PM – demologger – CRITICAL:critical message
Note: If we want to use class name as logger name ten we have to create logger object as
follows logger=logging.getlogger(loggerDemoconsole.__name__)
In this case output is:
06/18/2018 12:21:00 PM – loggerdemoconsole – INFO:info message
06/18/2018 12:21:00 PM – loggerdemoconsole – WARNING:warn message
06/18/2018 12:21:00 PM – loggerdemoconsole – ERROR:error message
06/18/2018 12:21:00 PM – loggerdemoconsole – CRITICAL:critical message
Demo program for file Handler:
1) Import logging
2) Class loggerDemoconsole:
3)
4) Def testlog(self):
5) Logger=logging.getlogger(‘demologger’)
6) Logger.setlevel(logging.INFO)
7)
8) fileHandler=logging.fileHandler(‘abc.log’,mode=’a’)
9) fileHandler.setlevel(logging.INFO)
10)
11) Formatter=logging.formatter(‘%(asctime)s-%(name)s-%(levelname)s: %(message)s’,
12) Datefmt=’%m/%d/%y%I:%M:%S %P’)
13)
14) fileHandler.setFormatter(formatter)
15) logger.addHandler(fileHandler)
16)
17) logger.debug(‘debug message’)
18) logger.info(‘info message’)
19) logger.warn(‘warn message’)
20) logger.error(‘error message’)
21) logger.critical(‘critical message’)
22)
23) Demo=loggerDemoconsole()
24) Demo.testlog()
abc.log:
07/05/2018 08:58:04 AM – demologger – INFO:info message
07/05/2018 08:58:04 AM – demologger – WARNING:warn message
07/05/2018 08:58:04 AM – demologger – ERROR:error message
07/05/2018 08:58:04 AM – demologger – CRITICAL:critical message
Logger with configuration file:
In the above program,everything we hard coded in the python script.It is not a good
programming practice.We will configure all the required things inside a configuration file and we
can use this file directly in our program.
Logging.config.fileconfig(‘logging.conf’)
Logger=logging.getlogger(loggerDemoconf._name_)
Note: The extension of the file need not be conf.We canuse any extension like txt or durga etc.
Logging.conf
[logger]
Keys=root,loggerDemoconf

[handlers]
Keys=fileHandler

[formatters]
Keys=simpleformatter

[logger_root]
Level=DEBUG
Handlers=fileHandler

[logger_LoggreDemoconf]
Level=DEBUG
Handlers=fileHandlers
Qualname=demologger

[handler_fileHandler]
Class=fileHandler
Level=DEBUG
Formatter=simpleformatter
Args=(‘test.log’,’w’)

[formatter_simpleformatter]
Format=%(asctime)s-%(name)s-%(levelname)s-%message)s
Datefmt=%m/%d/%y %I:%M:%S %P
test.py
1) Import logging
2) Import logging.config
3) Class loggerDemoconf():
4) Def testlog(self):
5) Logging.config.fileconfig(‘logging.conf’)
6) Logger.logging.getlogger(loggerDemoconf._name_)
7)
8) logger.debug(‘debug message’)
9) logger.info(‘info message’)
10) logger.warn(‘warn message’)
11) logger.error(‘error message’)
12) logger.critical(‘critical message’)
13)
14) Demo=loggerDemoconf()
15) Demo.testlog()
test.log
06/18/2018 12:40:05 PM – loggerdemoconf – DEBUG-debug messsge
06/18/2018 12:40:05 PM – loggerdemoconf – INFO-info message
06/18/2018 12:40:05 PM – loggerdemoconf – WARNING-warn message
06/18/2018 12:40:05 PM – loggerdemoconf – ERROR-error message
06/18/2018 12:40:05 PM – loggerdemoconf – CRITICAL-critical message
Case-1: To set log level as INFO

[handler_fileHandler]
Class=fileHandler
Level=INFO
Formatter=simpleformatter
Args=(‘test.log’,’w’)
Case-2: To set Append mode

[handler_fileHandler]
Class=fileHandler
Level=INFO
Formatter=simpleformatter
Args=(‘test.log’,’a’)

Creation of custom Logger:


Customlogger.py
1) Import logging
2) Import inspect
3) Def getcustomlogger(level):
4) # Get name of class/method form where this method called
5) Loggername=inspect.stack()[1][3]
6) Logger=logging.getlogger(loggername)
7) Logger.setlevel(level)
8)
9) fileHandler=logging.fileHandler(‘abc.log’,mode=’a’)
10) fileHandler.setlevel(level)
11)
12) Formatter=logging.fileHandler(‘%(asctime)s-%(name)s-%(levelname)s: %
(message)s’,datefmt=’%m/%d/%y %I:%M:%S %P’)
13) fileHandler.setformatter(formatter)
14) logger.addHandler(fileHandler)
15)
16) Return logger
test.py
1) Import logging
2) From customlogger import get custom logger
3) Class loggingDemo:
4) Def m1(self):
5) Logger=getcustomlogger(logging.DEBUG)
6) logger.debug(‘m1:debug message’)
7) logger.info(‘m1:info message’)
8) logger.warn(‘m1:warn message’)
9) logger.error(‘m1:error message’)
10) logger.critical(‘m1:critical message’)
11) Def m2(self):
12) Logger=getcustomlogger(logging.WARNING)
13) logger.debug(‘m2:debug message’)
14) logger.info(‘m2:info message’)
15) logger.warn(‘m2:warn message’)
16) logger.error(‘m2:error message’)
17) logger.critical(‘m2:critical message’)
18) Def m3(self):
19) Logger=getcustomlogger(logging.ERROR)
20) logger.debug(‘m3:debug message’)
21) logger.info(‘m3:info message’)
22) logger.warn(‘m3:warn message’)
23) logger.error(‘m3:error message’)
24) logger.critical(‘m3:critical message’)
25)
26) I=loggingDemo()
27) Print(‘custom Logger Demo’)
28) I.m1()
29) I.m2()
30) I.m3()
abc.log:
06/19/2018 12:17:19 PM-m1-DEBUG:m1:debug message
06/19/2018 12:17:19 PM-m1-INFO:m1:debug message
06/19/2018 12:17:19 PM-m1-WARNING:m1:debug message
06/19/2018 12:17:19 PM-m1-ERROR:m1:debug message
06/19/2018 12:17:19 PM-m1-CRITICAL:m1:debug message
06/19/2018 12:17:19 PM-m1-WARNING:m2:debug message
06/19/2018 12:17:19 PM-m1-ERROR:m2:debug message
06/19/2018 12:17:19 PM-m1-CRITICAL:m2:debug message
06/19/2018 12:17:19 PM-m1-ERROR:m3:debug message
06/19/2018 12:17:19 PM-m1-CRITICAL:m3:debug message
How to create separate log file based on caller:
1) Import logging
2) Import inspect
3) Def getcustomlogger(level):
4) Loggername=inspect.stack()[1][3]
5) Logger=logging.getlogger(loggername)
6) Logger.setlevel(level)
7)
8) fileHandler=logging.fileHandler(‘{}.log’.format(loggername),mode=’a’)
9) fileHandler.setlevel(level)
10)
11) Formatter=logging.fileHandler(‘%(asctime)s-%(name)s-%(levelname)s: %
(message)s’,datefmt=’%m/%d/%y %I:%M:%S %P’)
12) fileHandler.setformatter(formatter)
13) logger.addHandler(fileHandler)
14)
15) Return logger
test.py:
#same as previous

1) Import logging
2) From customlogger import get custom logger
3) Class loggingDemo:
4) Def m1(self):
5) Logger=getcustomlogger(logging.DEBUG)
6) logger.debug(‘m1:debug message’)
7) logger.info(‘m1:info message’)
8) logger.warn(‘m1:warn message’)
9) logger.error(‘m1:error message’)
10) logger.critical(‘m1:critical message’)
11) Def m2(self):
12) Logger=getcustomlogger(logging.WARNING)
13) logger.debug(‘m2:debug message’)
14) logger.info(‘m2:info message’)
15) logger.warn(‘m2:warn message’)
16) logger.error(‘m2:error message’)
17) logger.critical(‘m2:critical message’)
18) Def m3(self):
19) Logger=getcustomlogger(logging.ERROR)
20) logger.debug(‘m3:debug message’)
21) logger.info(‘m3:info message’)
22) logger.warn(‘m3:warn message’)
23) logger.error(‘m3:error message’)
24) logger.critical(‘m3:critical message’)
25)
26) I=loggingDemo()
27) Print(‘ Logging Demo with separate log file’)
28) I.m1()
29) I.m2()
30) I.m3()
M1.log
06/19/2018 12:26:04 PM -m1- DEBUG:m1:debug message
06/19/2018 12:26:04 PM -m1- INFO:m1:info message
06/19/2018 12:26:04 PM -m1- WARNING:m1:warn message
06/19/2018 12:26:04 PM -m1- ERROR:m1:error message
06/19/2018 12:26:04 PM -m1- CRITICAL:m1:critical message
M2.log
06/19/2018 12:26:04 PM –m2- WARNING:m2:warn message
06/19/2018 12:26:04 PM –m2- ERROR:m2:error message
06/19/2018 12:26:04 PM –m2- CRITICAL:m2:critical message
M3.log
06/19/2018 12:26:04 PM –m3- ERROR:m3:error message
06/19/2018 12:26:04 PM –m3- CRITICAL:m3:critical message
Advantages of customized logger:
1) We can reuse same customlogger code where ever logger required.
2) For every caller we can able to create a separate log file
3) For different handlers we can set different log levels.
Another Example for custom Handler:
Customlogger.py:
1) Import logging
2) Import inspect
3) Def getcustomlogger(level):
4) Loggername=inspect.stack()[1][3]
5)
6) Logger=logging.getlogger(loggername)
7) Logger.setlevel(level)
8) fileHandler=logging.fileHandler(‘test.log’,mode=’a’)
9) fileHandler.setlevel(level)
10) Formatter=logging.fileHandler(‘%(asctime)s-%(name)s-%(levelname)s: %
(message)s’,datefmt=’%m/%d/%y %I:%M:%S %P’)
11) fileHandler.setformatter(formatter)
12) logger.addHandler(fileHandler)
13) Return logger
test.py
1) Import logging
2) From customlogger import get custom logger
3) Class test:
4) Def logtest(self):
5) Logger=getcustomlogger(logging.DEBUG)
6) logger.debug(‘debug message’)
7) logger.info(‘info message’)
8) logger.warn(‘warn message’)
9) logger.error(‘error message’)
10)logger.critical(‘critical message’)
11)t=Test()
12)t=logest()
student.py:
1) Import logging
2) From customlogger import get custom logger
3) Def studentfunction():
4) Logger=getcustomlogger(logging.ERROR)
5) logger.debug(‘debug message’)
6) logger.info(‘info message’)
7) logger.warning(‘warn message’)
8) logger.error(‘error message’)
9) logger.critical(‘critical message’)
10)studentfunction()
Note:We can disable a particular level of logging as follows:
Logging.disable(logging.CRITICAL)

You might also like