Advanced Python1 (Autosaved)-2
Advanced Python1 (Autosaved)-2
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.
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 operations by using methods. The following are
Various types of allowed methods
1. Instance Methods
2. Class Methods
3. Static Methods
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.
Example:
s=Student()
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:
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:
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
Types Of Variables:
Inside Python class 3 types of Variables are allowed.
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.
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}
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}
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}
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
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.
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
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__)
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()
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
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 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....
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.
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:
…….
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.
If an object does not have any reference variable then that object eligible for Garbage
Collection.
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.
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
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
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
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
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
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
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 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:-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)
AssumeC1,C2,C3,….ARE classes
In the list: C1C2C3C4C5……
C1 is considered as Head Element and remaining is considered as Tail.
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'>]
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.
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.
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.
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.
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
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'
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
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.
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)
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
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:
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
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
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.
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
abcabstract 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
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.
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.
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....')
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.
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...
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
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'
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)
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
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()
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
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
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'
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
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.
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
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.
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.
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
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.
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
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
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
closedReturns 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)
1From current position
2From 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
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
Diagram
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”)
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
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) aExcatly 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) ^xIt 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”)
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) CRITICAL50
Represents a very serious problem that needs high attention
2) ERROR40
Represents a serious error
3) WARNING30
Represents a warning message,some caution needed.It is alert to the programmer.
4) INFO20
Represents a message with some important information
5) DEBUG10
Represents a message with debugging information
6) NOTSET0
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.
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 HandlerconsoleHandler.setformatter(formatter)
6) Add Handler to loggerlogger.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:
LoggerDEBUG consoleINFOValid and INFO will be considered
LoggerINFO consoleDEBUGInvalid 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’)
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)