Unit 2
Unit 2
The re.search() method takes a regular expression pattern and a string and searches for
that pattern within the string. If the search is successful, search() returns a match object
or None otherwise.
Example
import re
txt = input("Enter String:")
x = re.search("^B *", txt)
if x:
print("String starts with B")
else:
print("String does not start with B")
Example 2
import re
txt = input("Enter String:")
x = re.search("gar$", txt)
if x:
print("String ends with gar")
else:
print("String does not end with gar")
Example 3
import re
txt = input(“Enter String:”)
x = re.search("^B.*gar$", txt)
if x:
print("String starts with B and ends with gar")
else:
Metacharacters are characters with a special meaning. The meta characters supported
by python are discussed below.
Python regex also supports fullmatch() and match() functions that return a Match object
if they find a match. The fullmatch() function matches the whole string with a pattern
while the match() function only finds a match at the beginning of the string.
Example
import re
s = 'Test'
pattern = 'Test'
# fullmatch
m = re.fullmatch(pattern, s)
print(m)
# search
m = re.match(pattern, s)
print(m)
In the above example fullmatch() return None but match(0 function returns match
object.
Example
A special sequence is a \ followed by one of the characters in the list below, and has a
special meaning.
\d Returns a match where the string contains digits (numbers from 0-9)
\D Returns a match where the string DOES NOT contain digits
\s Returns a match where the string contains a white space character
\S Returns a match where the string DOES NOT contain a white space
character
\w Returns a match where the string contains any word characters (characters
from a to Z, digits from 0-9, and the underscore _ character)
\W Returns a match where the string DOES NOT contain any word characters
Enumerate
The enumerate function in Python converts a data collection object into an enumerate
object. Enumerate returns an object that contains a counter for each value within an
object. The enumerate object can be used directly for loops or converted into a list of
tuples using the list() method.
Syntax:
enumerate (iterable, start=0)
Parameters:
Iterable: any object that supports iteration
Start: the index value from which the counter is to be started, by default it is 0
Example
# enumerate function
l1 = ["eat", "sleep", "repeat"]
s1 = "geek"
# creating enumerate objects
obj1 = enumerate(l1)
obj2 = enumerate(s1,1)
print (obj1)
print (obj1)
for k,v in list(obj1):
print(k,v)
for k,v in list(obj2):
Exceptions
Exceptions are runtime errors that terminates our program abnormally. The try...except
block is used to handle exceptions in Python. Here's the syntax of try...except block:
try:
except:
Here, we have placed the code that might generate an exception inside the try block.
Every try block is followed by an except block. When an exception occurs, it is caught by
the except block. The except block cannot be used without the try block. Multiple except
block can be placed after a try block.
Example
#Exception Handling
print("Enter Two Numbers:")
x=int(input())
y=int(input())
try:
z=int(x/y)
print("Quotient=",z)
except ZeroDivisionError:
print("Division By Zero Error!!!!!!")
Example2
l=[3,4,2,1,5]
try:
print("List Elements:")
for i in range(5):
print(l[i])
print("Squared List Elements:")
for i in range(6):
print(l[i]*l[i])
except IndexError:
In Python, the ‘finally’ keyword is used in the context of exception handling, specifically
with try-except blocks. The ‘finally’ block contains code that will always be executed,
regardless of whether an exception occurs or not within the “try” block. Normally,
cleaning codes (e.g. closing files, closing database connections etc.) are placed in finally
block.
Example
def divide(a,b):
c=[]
try:
for i in range(0,6):
c.append(a[i]//b)
return c
except ZeroDivisionError as e:
print("Exception!!!!")
print(e)
except IndexError as e:
print("Exception!!!!")
print(e)
except Exception as e:
print("Exception!!!!")
print(e)
finally:
print("Finally Block")
#Driver Code
print("Enter N:")
n=int(input())
x=[]
print("Enter List Elements:")
for i in range(n):
x.append(int(input()))
y=int(input("Enter b:"))
c=divide(x,y)
print(c)
We can also unzip or unpack a list using the zip function. For argument unpacking we should send
packed argument with asterisk symbol in the zip function.
Example
#Zip
list1=['a','b','c']
list2=[1,2,3]
list3=list(zip(list1,list2))
print("Zipped List:",list3)
l1,l2=zip(*list3)
print("First List:",l1)
print("Second List:",l2)
File Handling
Reading/ Writing Text Files
File handling is a mechanism for creating a file, writing data, and reading data from it.
Python is enriched with packages for handling different file types. To read a text file in
Python, you follow these steps:
First, open a text file for reading by using the open() function.
Second, read text from the text file using the file read(), readline(), or readlines()
method of the file object.
Third, close the file using the file close() method.
Open() function
The open() function has many parameters but we will be focusing on the first two:
Open(filename, mode). The filename parameter specifies the path to the text file. If the
program and file are in the same folder, we need to specify only the filename of the file.
Otherwise, we need to include the path to the file as well as the filename. The mode is an
optional parameter. It’s a string that specifies the mode in which you want to open the
file. The following table shows available modes for opening a text file:
The file object provides us with three methods for reading text from a text file:
read(size): read some contents of a file based on the optional size and return the
contents as a string. If you omit the size, the read() method reads from where it left
off till the end of the file. If the end of a file has been reached, the read() method
returns an empty string.
readline(): read a single line from a text file and return the line as a string. If the
end of a file has been reached, the readline() returns an empty string.
readlines(): read all the lines of the text file into a list of strings. This method is
useful if you have a small file and you want to manipulate the whole text of that
file.
close() method
The file that we open will remain open until we close it using the close () method. It’s
important to close the file that is no longer in use for the following reasons:
First, when we open a file in your script, the file system usually locks it down so
no other programs or scripts can use it until we close it.
Second, our file system has a limited number of file descriptors that we can create
before it runs out of them. Although this number might be high, it’s possible to
open a lot of files and deplete our file system resources.
Third, leaving many files open may lead to race conditions which occur when
multiple processes attempt to modify one file at the same time and can cause all
kinds of unexpected behaviors.
Example 1
f = open('/content/drive/My Drive/Data/test.txt', 'r')
s=f.read()
print(s)
f.close()
Example 2
f = open('/content/drive/My Drive/Data/test.txt', 'r')
s=f.read(8)
Example 3
f = open('/content/drive/My Drive/Data/test.txt', 'r')
s=f.readline()
while (s):
print(s)
s=f.readline()
f.close()
Example 4
f = open('/content/drive/My Drive/Data/test.txt', 'a')
f.write("Data Science")
f.close()
f = open('/content/drive/My Drive/Data/test.txt', 'r')
s=f.read()
print(s)
f.close()
CSV stands for comma-separated values. A CSV file is a delimited text file that uses a
comma to separate values. A CSV file consists of one or more lines. Each line is a data
record. And each data record consists of one or more values separated by commas. In
addition, all the lines of a CSV file have the same number of values. Typically, we use a
CSV file to store tabular data in plain text. The CSV file format is quite popular and
supported by many software applications such as Microsoft Excel and Google
Spreadsheet.
To read a CSV file in Python, you follow these steps: First, import the csv module:
import csv
Second, open the CSV file using the built-in open() function in the read mode:
f = open('path/to/csv_file')
If the CSV contains UTF8 characters, you need to specify the encoding like this:
f = open('path/to/csv_file', encoding='UTF8')
csv_reader = csv.reader(f)
The csv_reader is an iterable object of lines from the CSV file. Therefore, you can iterate
over the lines of the CSV file using a for loop:
print(line)
Example 1
import csv
f = open('/content/drive/My Drive/Data/emp.csv')
csv_reader = csv.reader(f)
for rec in csv_reader:
print(rec)
f.close()
Example 2
import csv
f = open('/content/drive/My Drive/Data/emp.csv')
csv_reader = csv.reader(f)
next(csv_reader)#skips header
for rec in csv_reader:
print(rec[0:3]) #dsiplays only Eid, Ename, and Salary
f.close()
Constructors
A constructor is a unique function that gets called automatically when an object is created
of a class. The main purpose of a constructor is to initialize or assign values to the data
members of that class. It cannot return any value other than none.
In Python, the method the __init__() simulates the constructor of the class. This method
is called when the class is instantiated. It accepts the self-keyword as a first argument
which allows accessing the attributes or method of the class. We can pass any number of
arguments at the time of creating the class object, depending upon the __init__()
definition. It is mostly used to initialize the class attributes. Every class must have a
constructor, even if it simply relies on the default constructor.
Two types of constructors can be defined in python: Non-parameterized (default) constructor
and parameterized constructor.
Default constructor: The default constructor is a simple constructor which doesn’t
accept any arguments. Its definition has only one argument which is a reference
to the instance being constructed.
Parameterized constructor: constructor with parameters is known as
parameterized constructor. The parameterized constructor takes its first argument
as a reference to the instance being constructed known as self and the rest of the
arguments are provided by the programmer.
Example
class Employee:
def __init__(self,id,n,s): #Parameterized Constructor
self.eid=id
self.ename=n
self.salary=s
def display(self):#method
print("Eid:",self.eid)
print("Ename:",self.ename)
print("Salary:",self.salary)
Access Modifiers
Python access modifiers are used to modify the default scope of a variable. There are
three types of access modifiers in Python and they are: Public, Private, and Protected.
Access modifiers play an important role to protect the data from unauthorized access.
Public: All the members in the Python class are public by default. Any member
declared as public can be accessed from outside the class through an object. We
can also modify their value from outside of the class.
Private: A double underscore “__” makes the variable private as well as secure
and the members of the class which is declared private are accessible only within
the class. It is not possible to access them outside the class because it will throw an
error.
Protected: Class properties and methods with protected access modifier can be
accessed within the class and from the class that inherits the protected class. In
python, protected members and methods are declared using single underscore(‘_’)
as prefix before their names.
Example
class AccessTest:
def __init__(self,a,b,c):
self.a=a
self.__b=b
self._c=c
def display(self):
print("From Display:")
print("a=",self.a)
print("b=",self.__b)
print("c=",self._c)
x=AccessTest(2,6,9)
print("a=",x.a)
#print("b=",x.b) #Error
print("c=",x._c) #No Error
x.display()
class Account:
minbal=1000 #class variable
def __init__(self,accno,name,balance):
self.accno=accno #instance variable
self.name=name #instance variable
self.balance=balance #instance variable
def display(self):
print("Account Number:",self.accno)
print("Name:",self.name)
print("Balance:",self.balance)
a=Account(2001,"Ram",50000)
b=Account(2002,"Rina",60000)
print("######Account1 Data######")
print("Minimum Balance:",Account.minbal)
a.display()
print("######Account2 Data######")
print("Minimum Balance:",b.minbal)
def display(self):
print("Account Number:",self.accno)
print("Name:",self.name)
print("Balance:",self.balance)
a=Account(2001,"Ram",50000)
b=Account(2002,"Rina",60000)
print("######Account1 Data######")
a.dispminbal()
a.display()
print("######Account2 Data######")
b.dispminbal()
b.display()
a.deposit(10000)
print("######Account1 Data######")
a.dispminbal()
a.display()
b.withdraw(20000)
print("######Account2 Data######")
b.dispminbal()
b.display()
b.withdraw(50000)
print("######Account2 Data######")
b.dispminbal()
b.display()
Method Overloading
Method overloading is essentially a feature of object oriented languages, in which we can
have two or more methods functions that have the same name but the parameters that
they take as input values are different. Like other languages do, python does not support
Example
def sum(a,b):
return a+b
def sum(a,b,c):
return a+b+c
#Driver Code
#s=sum(4,5)#Error
#print("Sum=",s)
s=sum(4,5,8)
print("Sum=",s)
In addition, methods in Python can be called with zero, one, or more parameters. This
process of calling the same method in different ways is called method overloading.
Example
class Student:
def show(self,fn=None,ln=None):
if(fn is not None and ln is not None):
print(f"Hello {fn} {ln}")
elif(fn is not None):
print("Hello ",fn)
else:
print("Hello")
#Driver Code
s=Student()
Inheritance
Inheritance is the process by which one class takes on the attributes and methods of
another. Newly formed classes are called child classes, and the classes that child classes
are derived from are called parent classes. Child class inherits all members from parent
class and can also have its own members (variables and methods). The main advantage
of in heritance is that it makes code reusable and saves lots of time and money during
software development. Different types of inheritance are listed below:
Single inheritance
Multiple inheritance
Example
#Single Inheritance
class Employee:
def _init_(self):
self.eid=-1
self.ename=""
self.salary=-1
def getData(self):
print("Enter ID, Name, and Salary:")
self.eid=int(input())
self.ename=input()
self.salary=float(input())
def display(self):
print("Eid:",self.eid)
print("Ename:",self.ename)
print("Salary:",self.salary)
class Typist(Employee):
def _init_(self):
self.ts=0
def getData(self):
super(Typist,self).getData()
print("Enpter Typing Speed");
self.ts=int(input())
def display(self):
super(Typist,self).display()
print("Typing Speed:",self.ts)
t=Typist()
t.getData()
print("*****Typist Details*****")
t.display()
#Multiple Inheritance
class Instructor:
def __init__(self):
self.iid=None
self.iname=None
self.post=None
def getData(self):
self.iid=input("Enter I-id:")
self.iname=input("Enter I-Name:")
self.post=input("Enter Post:")
Method Overriding
Method overriding is an ability of any object-oriented programming language that allows
a subclass or child class to provide a specific implementation of a method that is already
provided by one of its super-classes or parent classes. When a method in a subclass has
the same name and same signature as a method in its super-class, then the method in the
subclass is said to override the method in the super-class.
The version of a method that is executed will be determined by the object that is used to
invoke it. If an object of a parent class is used to invoke the method, then the version in
the parent class will be executed, but if an object of the subclass is used to invoke the
method, then the version in the child class will be executed.
#Method Overriding
class Parent:
def show(self):
print("Inside Parent")
class Child(Parent):
def show(self):#Method Overriden
print("Inside Child")
#Driver Code
x=Parent()
y=Child()
Parent class methods can also be called within the overridden methods. This can
generally be achieved by two ways.
Using Classname: Parent’s class methods can be called by using the Parent
classname.method inside the overridden method.
Using Super(): Python super() function provides us the facility to refer to the
parent class explicitly. It is basically useful where we have to call superclass
functions. It returns the proxy object that allows us to refer parent class by ‘super’.
#Method Overriding:
class Parent:
def show(self):
print("Inside Parent")
class Child(Parent):
def show(self):#Method Overriden
Parent.show(self)#show metod of Parent is invoked
print("Inside Child")
#Driver Code
x=Child()
x.show() #show metod of Child is invoked
#Driver Code
x=Child()
x.show() #show metod of Child is invoked
Because of the method resolution order (__mro__) in Python, the ambiguity of the
diamond problem in Python becomes irrelevant. The method resolution order in Python
is the order in which a method is searched for in the class hierarchy, in case of inheritance.
We can view this order by accessing the __mro__ attribute on the classes. When we inherit
from multiple classes, and if their method name conflicts, then the first-class name takes
precedence. This is the reason why, class B is before class C in the order of __mro__.
#Diamond Problem
class A:
def show(self):
print("From A")
class B(A):
def show(self):
print("From B")
class C(A):
def show(self):
print("From C")
class D(B,C):
pass
#Driver Code
#print(D.__mro__)
x=D()
x.show()
Abstract Class
Abstract classes are classes that contain one or more abstract methods. An abstract
method is a method that is declared, but contains no implementation. Abstract classes
cannot be instantiated, and require subclasses to provide implementations for the abstract
methods. Typically, we use an abstract class to create a blueprint for other classes. It
allows us to create a set of methods that must be created within any child classes built