Python Notes
· Python
Programming language in February 1991.
· IDE
– Integrated Development Environment
·
Python is used by many of the best tech
companies. A few of those companies are:
1.
Instagram
2.
Facebook
3.
Google
4.
Reddit
5.
Spotify
6.
Quora
7.
Dropbox
8.
Netflix
·
There are two types of modules in python:
- Built-in Modules - These modules are ready to import and use and ships with the
python interpreter. There is no need to install such modules explicitly.
- External Modules - These modules are imported from a third party file or can be
installed using a package manager like pip or conda. Since this code is
written by someone else, we can install different versions of a same
module with time.
·
The pip command - It
can be used as a package manager pip to install a
python module. Lets install a module called pandas using the following command
Syntax-> pip install pandas
· Single-Line Comments: To write a comment just add a ‘#’ at the start of
the line.
· Multi-Line Comments: To write multi-line comments you can use ‘#’ at
each line or you can use the multiline string “”””””.
·
Escape Sequence Characters
print("This will \" execute")
output-> This will “ execute
·
More on Print statement
print(object(s), sep=separator, end=end, file=file,
flush=flush)
·
Other Parameters of Print Statement
1.
object(s):
Any object, and as many as you like. Will be converted to string before printed.
2.
sep='separator':
Specify how to separate the objects, if there is more than one. Default is ' '
3.
end='end':
Specify what to print at the end. Default is '\n' (line feed)
4.
file: An object with a
write method. Default is sys.stdout
Parameters
2 to 4 are optional.
·
What is a variable?
Variable
is like a container that holds data. Very similar to how
our containers in kitchen holds sugar, salt etc Creating a variable is like
creating a placeholder in memory and assigning it some value. In Python its as
easy as writing:
a = 1
b = True
c = "Harry"
d = None
·
What is a Data Type?
Data
type specifies the type of value a variable holds. This
is required in programming to do various operations without causing an error.
In python, we can print the type of any operator using type function.
a = 1
print(type(a))
b = "1"
print(type(b))
·
By default, python provides the
following built-in data types:
· Numeric data: int,
float, complex.
3.
complex: 6 + 2i
· Text data: str
str:
"Hello World!!!", "Python Programming"
·
Boolean data: Boolean
data consists of values True or False.
·
Sequenced data: list, tuple.
1.
list: A list is an
ordered collection of data with elements separated by a comma and enclosed
within square brackets. Lists are mutable and can be modified after creation.
Example:
list1 = [8, 2.3, [-4, 5], ["apple", "banana"]]
print(list1)
Output:
[8, 2.3, [-4, 5], ['apple', 'banana']]
2.
Tuple: A
tuple is an ordered collection of data with elements separated by a comma and
enclosed within parentheses. Tuples are immutable and can not be modified after
creation.
Example:
tuple1 = (("parrot", "sparrow"), ("Lion", "Tiger"))
print(tuple1)
Output:
(('parrot', 'sparrow'), ('Lion', 'Tiger'))
·
Mapped data: dic: A
dictionary is an unordered collection of data containing a key:value pair. The
key:value pairs are enclosed within curly brackets.
Example:
dict1 = {"name":"Sakshi", "age":20, "canVote":True}
print(dict1)
Output:
{'name': 'Sakshi', 'age': 20, 'canVote': True}
//Floor Division 15//7 -> convert float to integer.
·
Typecasting
in python
The
conversion of one data type into the other data type is known as type casting
in python or type conversion in python.
Python
supports a wide variety of functions or methods like: int(), float(), str(),
ord(), hex(), oct(), tuple(), set(), list(), dict(), etc. for the type casting
in python.
·
Two Types of Typecasting:
1. Explicit Conversion
(Explicit type casting in python)
2. Implicit Conversion
(Implicit type casting in python).
1. Explicit typecasting: The conversion of one data type into
another data type, done via developer or programmer's intervention or manually
as per the requirement, is known as explicit type conversion.
It can be achieved with the help of Python’s built-in type conversion
functions such as int(), float(), hex(), oct(), str(), etc.
Example of
explicit typecasting:
string
="15"
number
=7
string_number
=int(
string
)#throws an error if the string is not a valid integer
sum=number
+string_number
print("The Sum of both the numbers is: ",sum)
Output:
The Sum of both the numbers
is22
2. Implicit type casting: Data types in Python do not have the same
level i.e. ordering of data types is not the same in Python. Some of the data
types have higher-order, and some have lower order. While performing any
operations on variables with different data types in Python, one of the
variable's data types will be changed to the higher data type. According to the
level, one data type is converted into other by the Python interpreter itself
(automatically). This is called, implicit typecasting in python.
Python converts a smaller data type to a higher data type to
prevent data loss.
Example of
implicit type casting:
# Python automatically converts
# a to int
a
=7
print(type(a
))
# Python automatically converts b to float
b
=3.0
print(type(b
))
# Python automatically converts c to float as it is a float addition
c
=a
+b
print(c
)
print(type(c
))
Ouput:
<class'int'>
<class'float'>
10.0
<class'float'>
·
How to take Inputs:
variable=input()
variable=int(input())
variable=float(input())
a=input("Enter the name: ")
print(a)
trailing character(!).
rstrip() function is used to skip the trailing character.
Leading exclamation mark means this symbol “!” at starting.
Example:
var = "!!!Enter val!!!!"
print(var.rstrip("!"))
Output:
!!!Enter val
indentation –> one tab space.
Strings
Multiline
Strings: If our string has multiple lines, we can create
them like this.
a = """Lorem ipsum dolor sit
amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt
ut labore et dolore magna
aliqua."""
print(a)
Accessing
Characters of a String: In Python, string is like an array of
characters. We can access parts of string by using its index which starts from
0. Square brackets can be used to access elements of the string.
print(name[0])
print(name[1])
·
Looping through the string: We
can loop through strings using a for loop like this.
for character in name:
print(character)
Above
code prints all the characters in the string name one by one!
·
Length of a String: We can
find the length of a string using len() function.
fruit = "Mango"
len1 = len(fruit)
print("Mango is a",
len1, "letter
word.")
Output:
Mango is a 5 letter word
·
String as an array: A
string is essentially a sequence of characters also called an array. Thus we
can access the elements of this array.
Example:
pie
="ApplePie"
print(pie
[#Python automatically assume 0 here:5])
print(pie
[6])#returns character at specified index
Output:
Apple
i
Note: This method of specifying the start and end index to
specify a part of a string is called slicing.
·
Slicing
Example:
pie
="ApplePie"
print(pie
[:5])#Slicing from Start
print(pie
[5:])#Slicing till End
print(pie
[2:6])#Slicing in between
print(pie
[-8:])#Slicing using negative index
Output:
Apple
Pie
pleP
ApplePie
·
Loop through a String: Strings are arrays and
arrays are iterable. Thus we can loop through strings.
Example:
alphabets
="ABCD"
fori
inalphabets
:
print(
i
)
Output:
A
B
C
D
String methods
1.
upper() : The upper() method converts a string to upper
case.
Example:
str1
="AbcDEfghIJ"
print(str1
.upper
())
Output:
ABCDEFGHIJ
2.
lower(): The lower() method converts a string to lower
case.
Example:
str1
="AbcDEfghIJ"
print(str1
.lower
())
Output:
abcdefghij
3. strip() : The
strip() method removes any white spaces before and after the string.
Example:
str2
=" Silver Spoon "
print(str2
.strip()
)
#AND
print(str2
.strip
)
Output:
Silver Spoon
<built-in method strip of str object at 0x000001EB30A4BDB0>
4.
rstrip() : The rstrip() removes any trailing characters.
Example:
str3
="Hello !!!"
str4
="Hello !!! "
print(str3
.rstrip
("!"))
print(str3
.rstrip
("!"))
Output:
Hello
Hello !!!
5.
replace() : The replace() method replaces all occurences of
a string with another string.
Example:
str2
="Silver Spoon"
print(str2
.replace
("Sp","M"))
Output:
Silver Moon
6.
split() : The split() method splits the given string at
the specified instance and returns the separated strings as list items.
Example:
str2
="Silver Spoon"
print(str2
.split
(" "))#Splits the string at the whitespace " ".
Output:
['Silver','Spoon']
We can use various other string methods
to modify that strings.
7.
capitalize() : The capitalize() method turns only the
first character of the string to uppercase and the rest other characters of the
string are turned to lowercase. The string has no effect if the first character
is already uppercase.
Example:
str1
="hello"
capStr1
=str1
.capitalize
()
print(capStr1
)
str2
="hello WorlD"
capStr2
=str2
.capitalize
()
print(capStr2
)
Output:
Hello
Hello world
8.
center() :The center() method aligns the string to the
center as per the parameters given by the user.
Example:
str1
="Welcome to the Console!!!"
print(str1
.center
(50))
Output:
Welcome to the Console!!!
We
can also provide padding character. It will fill the rest of the fill
characters provided by the user.
Example:
str1
="Welcome to the Console!!!"
print(str1
.center
(50,"."))
Output:
............Welcome to the Console!!!
.............
9.
count() :The count() method returns the number of times
the given value has occurred within the given string.
Example:
str2
="Abracadabra"
countStr
=str2
.count
("a")
print(countStr
)
Output:
4
10.
endswith() : The endswith() method checks if the
string ends with a given value. If yes then return True, else return False.
Example :
str1
="Welcome to the Console !!!"
Output:
True
We
can even also check for a value in-between the string by providing start and
end index positions.
Example:
str1
="Welcome to the Console !!!"
print(str1
.endswith
("to",4,
10)) #negative value also allow.
Output:
True
11.
find() : The find() method searches for the first
occurrence of the given value and returns the index where it is present. If
given value is absent from the string then return -1.
Example:
str1
="He's name is Dan. He is an honest man."
print(str1
.find
("is"))
Output:
10
As
we can see, this method is somewhat similar to the index() method. The major
difference being that index() raises an exception if value is absent whereas
find() does not.
Example:
str1
="He's name is Dan. He is an honest man."
print(str1
.find
("Daniel"))
Output:
-1
12.
index() : The index() method searches for the first
occurrence of the given value and returns the index where it is present. If
given value is absent from the string then raise an exception.
Example:
str1
="He's name is Dan. Dan is an honest man."
print(str1
.index
("Dan"))
Output:
13
As
we can see, this method is somewhat similar to the find() method. The major
difference being that index() raises an exception if value is absent whereas
find() does not.
Example:
str1
="He's name is Dan. Dan is an honest man."
print(str1
.index
("Daniel"))
Output:
ValueError
:substring
notfound
13. isalnum() : The
isalnum() method returns True only if the entire string only consists of A-Z,
a-z, 0-9. If any other characters, space and punctuations are present, then it
returns False.
Example:
str1
="WelcomeToTheConsole546"
print(str1
.isalnum
())
Output:
True
14.
isalpha() : The isalnum() method returns True only if the
entire string only consists of A-Z, a-z. If any other characters or
punctuations or numbers(0-9) are present, then it returns False.
Example :
str1
="Welcome"
print(str1
.isalpha
())
Output:
True
15.
islower() : The islower() method returns True if all the
characters in the string are lower case, else it returns False.
Same
as in case of isupper
Example:
str1
="hello world"
print(str1
.islower
())
Output:
True
16.
isprintable() : The isprintable() method returns True if
all the values within the given string are printable, if not, then return
False.
Example :
str1
="We wish you a Merry Christmas"
print(str1
.isprintable
())
Output:
True
17.
isspace() : The isspace() method returns True only and only
if the string contains white spaces, else returns False.
Example:
str1
=" "
#using Spacebar
print(str1
.isspace
())
str2
=" "
#using Tab
print(str2
.isspace
())
Output:
True
True
18.
istitle() : The istitile() returns True only if the first
letter of each word of the string is capitalized, else it returns False.
Example:
str1
="World Health Organization"
print(str1
.istitle
())
str2
="world Health Organization"
print(str2
.istitle
())
Output:
True
False
19.
startswith() : The startswith() method checks if the
string starts with a given value. If yes then return True, else return False.
Example :
str1
="Python is a Interpreted Language"
print(str1
.startswith
("Python"))
Output:
True
20. swapcase() :The
swapcase() method changes the character casing of the string. Upper case are
converted to lower case and lower case to upper case.
Example:
str1
="Python is a Interpreted Language"
print(str1
.swapcase
())
Output:
pYTHON IS A iNTERPRETED lANGUAGE
21.
title() : The
title() method capitalizes frist letter of the word within the string.
Example:
str1
="He's name is Dan. Dan is an honest man."
print(str1
.title
())
Output:
He'S Name Is Dan
.Dan Is An Honest Man
.
if-else Statements
·
if
·
if-else
·
if-elif -else
·
nested if-elif -else
applePrice = 210
budget = 200
if (applePrice <= budget):
print("Alexa,
add 1 kg Apples to the cart.")
else:
print("Alexa,
do not add Apples to the cart.")
·
Output:
Alexa, do not add
Apples to the cart.
v Excercise 2: To greet your teacher as according to time
like:
Ø 5:00 – 12:00 -> Good Morning
Ø 12:00 – 5:00 -> Good Afternoon
Ø 5:00 – 8:00 -> Good Evening
Ø 8:00 – 5:00 -> Good Night
import time
timestamp = time.strftime('%H:%M:%S')
print(timestamp)
timestamp = time.strftime('%H')
print(timestamp)
timestamp = time.strftime('%M')
print(timestamp)
timestamp = time.strftime('%S')
print(timestamp)
# https://docs.python.org/3/library/time.html#time.strftime
-> Read More
ü Match Case Statements: To
implement switch-case like characteristics very similar to if-else
functionality, we use a match case in python. If you are coming from a C, C++
or Java like language, you must have heard of switch-case statements.
A
match statement will compare a given variable’s value to different shapes, also
referred to as the pattern. The main idea is to keep on comparing the variable
with all the present patterns until it fits into one.
The
match case consists of three main entities :
1. The match keyword
2. One or more case clauses
3. Expression for each case
The
case clause consists of a pattern to be matched to the variable, a condition to
be evaluated if the pattern matches, and a set of statements to be executed if
the pattern matches.
ü
Syntax:
matchvariable_name
:
case
‘pattern1’
://
statement1
case
‘pattern2’
://
statement2
…
case
‘pattern n’
://
statement n
Example:
x
=4
# x is the variable to match
matchx
:
# if x is 0
case
0:
print("x is zero")
# case with if-condition
case
4
if
x
%2
==
0:
print("x % 2 == 0 and case is 4")
# Empty case with if-condition
case
_
ifx
<10:
print("x is < 10")
# default case(will only be matched if the above cases were not matched)
# so it is basically just an else:
case
_:
print(
x
)
Output:
x
%2
==
0
and
case
is
4
Introduction to Loops
1. The for
Loop: for loops can iterate over a sequence of iterable objects in
python. Iterating over a sequence is nothing but iterating over strings, lists,
tuples, sets and dictionaries.
Example:
iterating over a string:
name
='Abhishek'
fori
inname
:
print(
i
,end
=",")
print(i
,end
="")
print(i
,end
=" ")
print(i
)
Output:
A
,b
,h
,i
,s
,h
,e
,k
,
Abhi
shek
A b h i s h e k
A
B
H
I
S
H
E
k
Example:
iterating over a list:
colors
=["Red",
"Green",
"Blue",
"Yellow"]
forcol
incolors
:
print(
col
)
#and
for word in col
Print(word)
Output:
Red
R
E
d
Green
#->Like this
Blue
Yellow
Similarly,
we can use loops for lists, sets and dictionaries.
23.
range():
What
if we do not want to iterate over a sequence?
What if we want to use for loop for a specific
number of times?
Here,
we can use the range() function.
Example:
fork
inrange(5):
print(
k
)
Output:
0
1
2
3
4
Here, we can see that the loop starts from 0 by default and
increments at each iteration. But we can also loop over a specific range.
Example:
fork
inrange(4,9):
print(
k
)
Output:
4
5
6
7
8
Note:
range does not support float values.
Quick
Quiz: Explore about third parameter of range (ie range(x, y, z))
Ans: range(start, stop, step)
Step: It is the difference between start and stop arguments.
Break & Continue Statement
Example:
fori
inrange(1,10,1):
print(
i
,end
=" ")
if(
i
==5):
break
else:
print("Mississippi")
print("Thank you")
output:
1 Mississippi
2 Mississippi
3 Mississippi
4 Mississippi
5Thank you
Example:
for i in [2,3,4,6,8,0]:
if (i%2!=0):
continue
print(i,
end=“,”)
output
2,4,6,8,0
ü
Python
Functions: A function is a block of code that performs a
specific task whenever it is called. In bigger programs, where we have large
amounts of code, it is advisable to create or use existing functions that make
the program flow organized and neat.
There
are two types of functions:
1. Built-in functions
2. User-defined functions
1.
Built-in functions: These functions are defined
and pre-coded in python. Some examples of built-in functions are as follows:
min(),
max(), len(), sum(), type(), range(), dict(), list(), tuple(), set(), print(),
etc.
2.
User-defined functions: We can create functions to
perform specific tasks as per our needs. Such functions are called user-defined
functions.
Syntax:
deffunction_name(
parameters
):
pass #use for we will write a code later
# Code and Statements
1. Create a function using
the “def” keyword, followed by a function name, followed by parenthesis (()),
and a colon(:).
2. Any parameters and
arguments should be placed within the parentheses.
3. Rules to naming function
are similar to that of naming variables.
4. Any statements and other
code within the function should be indented.
ü Calling a function: We call a function by giving the function
name, followed by parameters (if any) in the parenthesis.
Example:
defname(
fname
,lname
):
print("Hello,",
fname
,lname
)
name
("Sam","Wilson")
Output:
Hello
,Sam Wilson
ü Function Arguments and Return Statement
There
are four types of arguments that we can provide in a function:
- Default Arguments
- Keyword Arguments
- Variable length Arguments
- Required Arguments
ü
Default
arguments: We can
provide a default value while creating a function. This way the function
assumes a default value even if a value is not provided in the function call
for that argument.
Example:
defname(
fname
,mname
="Jhon",
lname
="Whatson"):
print("Hello,",
fname
,mname
,lname
)
name
("Amy")
Output:
Hello
,Amy Jhon Whatson
ü Keyword arguments: We can provide arguments with “key = value” Syntax, this way the interpreter recognizes the
arguments by the parameter name. Hence, the order in which the arguments are passed
does not matter.
Example:
defname(
fname
,mname
,lname
):
print("Hello,",
fname
,mname
,lname
)
name
(mname
="Peter",
lname
="Wesker",
fname
="Jade")
Output:
Hello
,Jade Peter Wesker
ü Required arguments: In case we don’t pass the arguments with
a “key = value” syntax, then it is necessary to pass the
arguments in the correct positional order and the number of arguments passed
should match with actual function definition.
Example 1: when number of arguments passed does not match
to the actual function definition.
defname(
fname
,mname
,lname
):
print("Hello,",
fname
,mname
,lname
)
name
("Peter","Quill")
Output:
name
("Peter","Quill")
\
TypeError
:name
()missing
1required positional argument
:'lname'
Example 2:
when number of arguments passed matches to the actual function definition.
defname(
fname
,mname
,lname
):
print("Hello,",
fname
,mname
,lname
)
name
("Peter","Ego",
"Quill")
Output:
Hello
,Peter Ego Quill
ü
Variable-length
arguments: Sometimes we
may need to pass more arguments than those defined in the actual function. This
can be done using variable-length arguments.
1.
Arbitrary
Arguments.
2.
Keyword
Arbitrary Arguments.
1.
Arbitrary Arguments: While creating a function, pass a “*” before the parameter
name while defining the function. The function accesses the arguments by
processing them in the form of tuple.
Example:
defname(*
name
):
print("Hello,",
name
[0],name
[1],name
[2])
name
("James","Buchanan",
"Barnes")
Output:
Hello
,James Buchanan Barnes
ü
Keyword Arbitrary Arguments: While creating a function, pass a * before the parameter
name while defining the function. The function accesses the arguments by
processing them in the form of dictionary.
Example:
defname(**
name
):
print("Hello,",
name
["fname"],name
["mname"],name
["lname"])
name
(mname
="Buchanan",
lname
="Barnes",
fname
="James")
Output:
Hello
,James Buchanan Barnes
ü Return
Statement: The return statement is used to return the value
of the expression back to the calling function.
Example:
defname(
fname
,mname
,lname
):
return
"Hello, "
+
fname
+" "
+
mname
+" "
+
lname
print(name
("James","Buchanan",
"Barnes"))
Output:
Hello
,James Buchanan Barnes
Python
Lists
·
Lists are ordered collection of data items.
·
They store multiple items in a single variable.
·
List items are separated by commas and enclosed within square
brackets [ ].
·
Lists are changeable/mutable meaning we can alter them after
creation.
Example 1:
lst1
=[1,2,2,3,5,4,6]
lst2
=["Red",
"Green",
"Blue"]
print(lst1
)
print(lst2
)
Output:
[1,2,
2,
3,
5,
4,
6]
['Red','Green',
'Blue']
Example 2:
details
=["Abhijeet",
18,
"FYBScIT",
9.8]
print(details
)
Output:
['Abhijeet',18,
'FYBScIT',
9.8]
As
we can see, a single list can contain items of different data types.
List Methods
1. list.sort(): This method sorts
the list in ascending order. The original list is updated
Example 1:
colors
=["violet",
"indigo",
"blue",
"green"]
colors
.sort
()
print(colors
)
num
=[4,2,5,3,6,1,2,1,2,8,9,7]
num
.sort
()
print(num
Output:
['blue','green',
'indigo',
'violet']
[1,1,
2,
2,
2,
3,
4,
5,
6,
7,
8,
9]
ü
What if you want
to print the list in descending order?
ü
We must give “reverse=True” as a parameter in the sort
method.
ü
The reverse parameter is set to False by default.
Example:
colors
=["violet",
"indigo",
"blue",
"green"]
colors
.sort
(reverse
=True)
print(colors
)
num
=[4,2,5,3,6,1,2,1,2,8,9,7]
num
.sort
(reverse
=True)
print(num
)
Output:
['violet','indigo',
'green',
'blue']
[9,8,
7,
6,
5,
4,
3,
2,
2,
2,
1,
1]
Note: Do not mistake the
reverse parameter with the reverse method.
2. reverse(): This method
reverses the order of the list.
Example:
colors
=["violet",
"indigo",
"blue",
"green"]
colors
.reverse
()
print(colors
)
num
=[4,2,5,3,6,1,2,1,2,8,9,7]
num
.reverse
()
print(num
)
Output:
['green','blue',
'indigo',
'violet']
[7,9,
8,
2,
1,
2,
1,
6,
3,
5,
2,
4]
3. index(): This method
returns the index of the first occurrence of the list item.
Example:
colors
=["violet",
"green",
"indigo",
"blue",
"green"]
print(colors
.index
("green"))
num
=[4,2,5,3,6,1,2,1,3,2,8,9,7]
print(num
.index
(3))
Output:
1
3
4. count(): Returns the count
of the number of items with the given value.
Example:
colors
=["violet",
"green",
"indigo",
"blue",
"green"]
print(colors
.count
("green"))
Output:
2
5. copy(): Returns copy of
the list. This can be done to perform operations on the list without modifying
the original list.
Example:
colors
=["violet",
"green",
"indigo",
"blue"]
newlist
=colors
.copy
()
print(colors
)
print(newlist
)
Output:
['violet','green',
'indigo',
'blue']
['violet','green',
'indigo',
'blue']
6. append(): This method
appends items to the end of the existing list.
Example:
colors
=["violet",
"indigo",
"blue"]
colors
.append
("green")
print(colors
)
Output:
['violet','indigo',
'blue',
'green']
7. insert(): This method inserts an item at the given index. User has to
specify index and the item to be inserted within the insert() method.
Example:
colors
=["violet",
"indigo",
"blue"]
# [0] [1] [2]
colors
.insert
(1,"green")
#inserts item at index 1
# updated list: colors = ["violet", "green", "indigo", "blue"]
# indexs [0] [1] [2] [3]
print(colors
)
Output:
['violet','green',
'indigo',
'blue']
8. extend(): This method adds an entire list or any
other collection datatype (set, tuple, dictionary) to the existing list.
Example 1:
#add a list to a list
colors
=["violet",
"indigo",
"blue"]
rainbow
=["green",
"yellow",
"orange",
"red"]
colors
.extend
(rainbow
)
print(colors
)
Output:
['violet','indigo',
'blue',
'green',
'yellow',
'orange',
'red']
Concatenating
two lists: You can simply concatenate two lists to join two lists.
Example:
colors
=["violet",
"indigo",
"blue",
"green"]
colors2
=["yellow",
"orange",
"red"]
print(colors
+colors2
)
Output:
['violet','indigo',
'blue',
'green',
'yellow',
'orange',
'red']
Python Tuples & Tuple Indexes
Tuples
are ordered collection of data items. They store multiple items in a single
variable. Tuple items are separated by commas and enclosed within round
brackets/parenthesis “()”. Tuples are unchangeable/immutable meaning we can not alter them after creation.
Example 1:
tuple1
=(1,2,2,3,5,4,6)
tuple2
=("Red",
"Green",
"Blue")
tuple3
=(1) #python interpiter confuse in this case means this is tuple or int
tuple4
=(1,)
print(tuple1
)
print(tuple2
)
print(type(tuple3
))
print(type(tuple4
) )
Output:
(1,2,
2,
3,
5,
4,
6)
('Red','Green',
'Blue')
<class 'int'>
<class 'tuple'>
Example 2:
details
=("Abhijeet",
18,
"FYBScIT",
9.8)
print(details
)
Output:
('Abhijeet',18,
'FYBScIT',
9.8)
Tuple Methods
1. Tuple Indexes: Each
element in a tuple has its own unique index. This index can be used to access
any particular element from the tuple. In tuple, index starts from zero.
Example:
country
=("Spain",
"Italy",
"India",)
# [0] [1] [2]
1. Accessing tuple items:
I. Positive
Indexing: As we have
seen that tuple items have index, as such we can access items using these
indexes.
Example:
country
=("Spain",
"Italy",
"India",)
# [0] [1] [2]
print(country
[0])
print(country
[1])
print(country
[2])
Output:
Spain
Italy
India
II. Negative
Indexing: Similar to
positive indexing, negative indexing is also used to access items, but from the
end of the tuple. The last item has index [-1], second last item has index [-2],
third last item has index [-3], and so on.
Example:
country
=("Spain",
"Italy",
"India",
"England",
"Germany")
# [0] [1] [2] [3] [4]
print(country
[-1])# Similar to print(country[len(country) - 1])
print(country
[-3])
print(country
[-4])
Output:
Germany
India
Italy
III.
Check for item: We can check if a given item is present in the
tuple. This is done using the “in
”
keyword.
Example 1:
country
=("Spain",
"Italy",
"India",
"England",
"Germany")
if"Germany"
in
country
:
print("Germany is present.")
else:
print("Germany is absent.")
Output:
Germany
ispresent
.
Example 2:
country
=("Spain",
"Italy",
"India",
"England",
"Germany")
if"Russia"
in
country
:
print("Russia is present.")
else:
print("Russia is absent.")
Output:
Russia
isabsent
.
IV. Range of
Index: You can print a
range of tuple items by specifying where do you want to start, where do you
want to end and if you want to skip elements in between the range.
Syntax:
Tuple
[start
:end
:jumpIndex
]
Note: jump
Index is optional. We will see this in given examples.
Example: Printing elements within a particular
range:
animals
=("cat",
"dog",
"bat",
"mouse",
"pig",
"horse",
"donkey",
"goat",
"cow")
print(animals
[3:7])#using positive indexes
print(animals
[-7:-2])#using negative indexes
Output:
('mouse','pig',
'horse',
'donkey')
('bat','mouse',
'pig',
'horse',
'donkey')
Here,
we provide index of the element from where we want to start and the index of
the element till which we want to print the values.
Note: The element of the end index provided
will not be included.
Example: Printing all element from a given index
till the end
animals
=("cat",
"dog",
"bat",
"mouse",
"pig",
"horse",
"donkey",
"goat",
"cow")
print(animals
[4:])#using positive indexes
print(animals
[-4:])#using negative indexes
Output:
('pig','horse',
'donkey',
'goat',
'cow')
('horse','donkey',
'goat',
'cow')
When
no end index is provided, the interpreter prints all the values till the end.
Example: printing all elements from start to a
given index
animals
=("cat",
"dog",
"bat",
"mouse",
"pig",
"horse",
"donkey",
"goat",
"cow")
print(animals
[:6])#using positive indexes
print(animals
[:-3])#using negative indexes
Output:
('cat','dog',
'bat',
'mouse',
'pig',
'horse')
('cat','dog',
'bat',
'mouse',
'pig',
'horse')
When
no start index is provided, the interpreter prints all the values from start up
to the end index provided.
Example: Print alternate values.
animals
=("cat",
"dog",
"bat",
"mouse",
"pig",
"horse",
"donkey",
"goat",
"cow")
print(animals
[::2])#using positive indexes
print(animals
[-8:-1:2])#using negative indexes
Output:
('cat','bat',
'pig',
'donkey',
'cow')
('dog','mouse',
'horse',
'goat')
Here,
we have not provided start and end index, which means all the values will be
considered. But as we have provided a jump index of 2 only alternate values
will be printed.
Example: printing every 3rd consecutive withing
given range.
animals
=("cat",
"dog",
"bat",
"mouse",
"pig",
"horse",
"donkey",
"goat",
"cow")
print(animals
[1:8:3])
Output:
('dog','pig',
'goat')
Here,
jump index is 3. Hence it prints every 3rd element within given index.
Manipulating
Tuples & Tuple Methods
Manipulating
Tuples: Tuples are immutable, hence if you want to add, remove or
change tuple elements, then first you must convert the tuple to a list. Then
perform operation on that list and convert it back to tuple.
Example:
countries
=("Spain",
"Italy",
"India",
"England",
"Germany")
temp
=list(
countries
)
temp
.append
("Russia")#add item
temp
.pop
(3)#remove item
temp
[2]=
"Finland"
#change item
countries
=tuple(
temp
)
print(countries
)
Output:
('Spain','Italy',
'Finland',
'Germany',
'Russia')
Thus,
we convert the tuple to a list, manipulate items of the list using list
methods, then convert list back to a tuple.
However,
we can directly concatenate two tuples without converting them to list.
Example:
countries
=("Pakistan",
"Afghanistan",
"Bangladesh",
"ShriLanka")
countries2
=("Vietnam",
"India",
"China")
southEastAsia
=countries
+countries2
print(southEastAsia
)
Output:
('Pakistan','Afghanistan',
'Bangladesh',
'ShriLanka',
'Vietnam',
'India',
'China')
Tuple methods
As
tuple is an immutable type of collection of elements it has limited built-in
methods. They are explained below
1. count() Method: The
count() method of Tuple returns the number of times the given element appears
in the tuple.
Syntax:
tuple.count
(element
)
Example:
Tuple1
=(0,
1,
2,
3,
2,
3,
1,
3,
2)
res
=Tuple1
.count
(3)
print('Count of 3 in Tuple1 is:',res
)
Output:
3
2. index()
method: The Index() method returns the first occurrence of the given
element from the tuple.
Syntax:
tuple.index
(element
,start
,end
)
Note: This method raises a ValueError if the
element is not found in the tuple.
Example:
Tuple
=(0,
1,
2,
3,
2,
3,
1,
3,
2)
res
=Tuple
.index
(3)
print('First occurrence of 3 is',res
)
Output
3
Exercise -
3 - kaun banega crorepati:
Create
a program capable of displaying questions to the user like KBC. Use List data
type to store the questions and their correct answers. Display the final amount
the person is taking home after playing the game.
Strings
Formatting
Starting of “f-string” in version python 3.6.
1.
String
formatting in python
String
formatting can be done in python using the format method.
txt
="For only {price:.2f} dollars!"
print(txt
.format(price
=49))
txt = "Hello {name}"
print(txt.format(name = "Sanskar")) #or (name, Sankar)
2. f-strings
in python: It is a new string formatting mechanism
introduced by the PEP 498. It is also known as Literal String Interpolation or
more commonly as F-strings (f character preceding the string literal). The
primary focus of this mechanism is to make the interpolation easier.
When
we prefix the string with the letter “f”, the string becomes the
f-string itself. The f-string can be formatted in much same as the ”str.format()”
method. The f-string offers a convenient way to embed Python expression inside
string literals for formatting.
Example:
val
='Geeks'
print(f"{val}for{val} is a portal for {val}.")
name
='Tushar'
age
=23
print(f"Hello, My name is {name} and I'm {age} years old.")
print(f"Hello, My name is {{name}} and I'm {{age}} years old.")
Output:
Hello
,My name
isTushar
andI'm
23years old
.
Hello
,My name
is{name}
andI'm
{age}years old
.
In
the above code, we have used the f-string to format the string. It evaluates at
runtime. We can put all valid Python expressions in them. We can use it in a
single statement as well.
Example:
print(f"{2 * 30})"
Output:
60
3.
Docstrings
in python: Python docstrings are the string literals that
appear right after the definition of a function, method, class, or module.
Example:
defsquare(
n
):
'''Takes in a number n, returns the square of n'''
print(
n
**2)
square
(5)
Here,
'''Takes in a number n, returns the square of n''' is a docstring
which will not appear in output
Output:
25
Here
is another example:
defadd(
num1
,num2
):
"""
Add up two integer numbers.
This function simply wraps the ``+`` operator, and does not
do anything interesting, except for illustrating what
the docstring of a very simple function looks like.
Parameters
----------
num1 : int
First number to add.
num2 : int
Second number to add.
Returns
-------
int
The sum of ``num1`` and ``num2``.
See Also
--------
subtract : Subtract one integer from another.
Examples
--------
>>> add(2, 2)
4
>>> add(25, 0)
25
>>> add(10, -10)
0
"""
return
num1
+num2
Python Comments vs Docstrings
Python Comments:
Comments are
descriptions that help programmers better understand the intent and functionality
of the program. They are completely ignored by the Python interpreter.
Python
docstrings: As mentioned
above, Python docstrings are strings used right after the definition of a
function, method, class, or module (like in Example 1). They are used to
document our code.
We
can access these docstrings using the “__doc__”
Python doc attribute: Whenever
string literals are present just after the definition of a function, module,
class or method, they are associated with the object as their doc attribute. We can
later use this attribute to retrieve this docstring.
Example:
defsquare(
n
):
'''Takes in a number n, returns the square of n'''
return
n
**2
print(square
.__doc__
)
Output:
Takes
ina number n
,returns the square of n
·
When you
write ”import this” than pyhton interpeater print “zen of Python”.
Recursion
in python
Recursion
is the process of defining something in terms of itself.
1. Python Recursive
Function: In Python, we know that a function can call other
functions. It is even possible for the function to call itself. These types of
construct are termed as recursive functions.
Example:
deffactorial(
num
):
if
(
num
==1
or
num
==0):
return
1
else:
return
(
num
*factorial
(num
-1))
# Driver Code
num
=7;
print("Number: ",num
)
print("Factorial: ",factorial
(num
))
Output:
number
:7
Factorial
:5040
Quick quiz:
Write a program to print Fibonacci
sequence.
Ans:
def fibo(n,a,b):
if n == 0:
return
else:
c = a + b
print(c)
a = b
b = c
fibo(n-1,a,b)
a = 0
b = 1
n = 11
print(a)
print(b)
fibo(n-2,a,b)
Python
Sets
Sets
are unordered collection of data items. They store multiple items in a single
variable. Set items are separated by commas and enclosed within curly brackets “{ }”. Sets are immutable, meaning you cannot
change items of the set once created. Sets do not contain duplicate items.
Example:
info
={"Carla",
19,
False,
5.9,
19}
print(info
)
Output:
{False,19,
5.9,
'Carla'}
Here
we see that the elements
of set occur in random order and hence
they cannot be accessed
using index numbers.
Also sets do not allow
duplicate values.
Quick Quiz: Try to create an empty set. Check using the type() function
whether the type of your variable is a set.
Ans: set1
= {}
Print(type(set1))
#but
Set2 = set{}
Print(type(set2))
Output:
<class 'dict'>
<class <’set’>
4. Accessing set items:
· Using a For loop: You can access items of set using a for
loop.
Example:
info
={"Carla",
19,
False,
5.9}
foritem
ininfo
:
print(
item
)
Output:
False
Carla
19
5.9
Joining
Sets & Set Methods
Sets
in python more or less work in the same way as sets in mathematics. We can
perform operations like union and intersection on the sets just like in
mathematics.
I.
union() and update(): The union() and update() methods prints all
items that are present in the two sets. The union() method returns a new set
whereas update() method adds item into the existing set from another set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities3
=cities
.union
(cities2
)
print(cities3
)
Output:
{'Tokyo','Madrid',
'Kabul',
'Seoul',
'Berlin',
'Delhi'}
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities
.update
(cities2
)
print(cities
)
Output:
{'Berlin','Madrid',
'Tokyo',
'Delhi',
'Kabul',
'Seoul'}
II.
intersection and intersection_update(): The intersection() and
intersection_update() methods prints only items that are similar to both the
sets. The intersection() method returns a new set whereas intersection_update()
method updates into the existing set from another set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities3
=cities
.intersection
(cities2
)
print(cities3
)
Output:
{'Madrid','Tokyo'}
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities
.intersection_update
(cities2
)
print(cities
)
Output:
{'Tokyo','Madrid'}
III.
symmetric_difference and symmetric_difference_update(): The
symmetric_difference() and symmetric_difference_update() methods prints only
items that are not similar to both the sets. The symmetric_difference() method
returns a new set whereas symmetric_difference_update() method updates into the
existing set from another set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities3
=cities
.symmetric_difference
(cities2
)
print(cities3
)
Output:
{'Seoul','Kabul',
'Berlin',
'Delhi'}
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
cities
.symmetric_difference_update
(cities2
)
print(cities
)
Output:
{'Kabul','Delhi',
'Berlin',
'Seoul'}
IV.
difference() and difference_update(): The difference() and
difference_update() methods prints only items that are only present in the
original set and not in both the sets. The difference() method returns a new
set whereas difference_update() method updates into the existing set from
another set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Seoul",
"Kabul",
"Delhi"}
cities3
=cities
.difference
(cities2
)
print(cities3
)
Output:
{'Tokyo','Madrid',
'Berlin'}
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Seoul",
"Kabul",
"Delhi"}
print(cities
.difference
(cities2
))
Output:
{'Tokyo','Berlin',
'Madrid'}
Set Methods
There
are several in-built methods used for the manipulation of set. They are
explained below.
1. isdisjoint(): The
isdisjoint() method checks if items of given set are present in another set.
This method returns False if items are present, else it returns True.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Tokyo",
"Seoul",
"Kabul",
"Madrid"}
print(cities
.isdisjoint
(cities2
))
Output:
False
2. issuperset(): The
issuperset() method checks if all the items of a particular set are present in
the original set. It returns True if all the items are present, else it returns
False.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Seoul",
"Kabul"}
print(cities
.issuperset
(cities2
))
cities3
={"Seoul",
"Madrid","Kabul"}
print(cities
.issuperset
(cities3
))
Output:
False
False
3. issubset(): The
issubset() method checks if all the items of the original set are present in
the particular set. It returns True if all the items are present, else it
returns False.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Delhi",
"Madrid"}
print(cities2
.issubset
(cities
))
Output:
True
4. add(): If
you want to add a single item to the set use the add() method.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities
.add
("Helsinki")
print(cities
)
Output:
{'Tokyo','Helsinki',
'Madrid',
'Berlin',
'Delhi'}
5. update(): If
you want to add more than one item, simply create another set or any other
iterable object(list, tuple, dictionary), and use the update() method to add it
into the existing set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Helsinki",
"Warsaw",
"Seoul"}
cities
.update
(cities2
)
print(cities
)
Output:
{'Seoul','Berlin',
'Delhi',
'Tokyo',
'Warsaw',
'Helsinki',
'Madrid'}
6. remove()/discard(): We
can use remove() and discard() methods to remove items form list.
The
main difference between remove and discard is that, if we try to delete an item
which is not present in set, then remove() raises an error, whereas discard()
does not raise any error.
Example :
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities2
={"Helsinki",
"Warsaw",
"Seoul"}
cities
.update
(cities2
)
print(cities
)
Output:
{'Delhi','Berlin',
'Madrid'}
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities
.remove
("Seoul")
print(cities
)
Output:
KeyError
:'Seoul'pop()
7.
pop(): This
method removes the last item of the set but the catch is that we don’t know
which item gets popped as sets are unordered. However, you can access the
popped item if you assign the pop() method to a variable.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
item
=cities
.pop
()
print(cities
)
print(item
)
Output:
{'Tokyo','Delhi',
'Berlin'}
Madrid
#-> This is the removed item
8. del(): del
is not a method, rather it is a keyword which deletes the set entirely.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
del cities
print(cities
)
Output:
NameError:
name 'cities' is not defined We get an error because our entire set has been
deleted and there is no variable called cities which contains a set.
What
if we don’t want to delete the entire set, we just want to delete all items
within that set?
9. clear(): This
method clears all items in the set and prints an empty set.
Example:
cities
={"Tokyo",
"Madrid",
"Berlin",
"Delhi"}
cities
.clear
()
print(cities
)
Output:
set()
10. Check if item exists: You
can also check if an item exists in the set or not.
Example:
info
={"Carla",
19,
False,
5.9}
if"Carla"
in
info
:
print("Carla is present.")
else:
print("Carla is absent.")
Output:
Carla
ispresent
.
Python
Dictionaries
Dictionaries
are ordered collection of data items. They store multiple items in a single
variable. Dictionary items are key-value pairs that are separated by commas and
enclosed within curly brackets { }.
Note: before python 3.7 version dictionaries are unordered.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
)
Output:
{'name':'Karan',
'age':
19,
'eligible':
True}
·
Accessing Dictionary items:
I. Accessing
single values: Values in
a dictionary can be accessed using keys. We can access dictionary values by
mentioning keys either in square brackets or by using get method.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
['name']) #it throughs an error
print(info
.get
('eligible')) #if in case value does not exists so I shows “none”
Output:
Karan
True
II. Accessing
multiple values: We can
print all the values in the dictionary using values() method.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
.values
())
Output:
dict_values
(['Karan',19,
True])
III. Accessing
keys: We can print all
the keys in the dictionary using keys() method.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
.keys
())
#and
for key in info.keys():
Print(f”{key} is {info[key]}”)
Output:
dict_keys
(['name','age',
'eligible'])
name is Karan
age is 19
eligible is True
IV. Accessing
key-value pairs: We can
print all the key-value pairs in the dictionary using items() method.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
.items
())
#and
for key,value in dic.items():
print(f"{key} is {value}")
Output:
dict_items
([('name','Karan'),
('age',
19),
('eligible',
True)])
name is Karan
age is 19
eligible is True
Dictionary
Methods
Dictionary
uses several built-in methods for manipulation. They are listed below.
1. update(): The
update() method updates the value of the key provided to it if the item already
exists in the dictionary, else it creates a new key-value pair.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
print(info
)
info
.update
({'age':20})
info
.update
({'DOB':2001})
print(info
)
Output:
{'name':'Karan',
'age':
19,
'eligible':
True}
{'name':'Karan',
'age':
20,
'eligible':
True,
'DOB':
2001}
·
Removing items from dictionary: There are a few
methods that we can use to remove items from dictionary.
2.
clear(): The
clear() method removes all the items from the list.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
info
.clear
()
print(info
)
Output:
{}
3.
pop(): The pop() method removes the key-value pair whose key is
passed as a parameter.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True}
info
.pop
('eligible')
print(info
)
Output:
{'name':'Karan',
'age':
19}
4.
popitem(): The
popitem() method removes the last key-value pair from the dictionary.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True,
'DOB':2003}
info
.popitem
()
print(info
)
Output:
{'name':'Karan',
'age':
19,
'eligible':
True}
5.
del: we can
also use the del keyword to remove a dictionary item.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True,
'DOB':2003}
delinfo
['age']
print(info
)
Output:
{'name':'Karan',
'eligible':
True,
'DOB':
2003}
Note: If key is not provided, then the del keyword will delete
the dictionary entirely.
Example:
info
={'name':'Karan',
'age':19,
'eligible':True,
'DOB':2003}
del info
print(info
)
Output:
NameError
:name
'info'is
not
defined
Python
- else in Loop
As
you have learned before, the else clause is used along with the if statement.
Python
allows the else keyword to be used with the for and while loops too. The else
block appears after the body of the loop. The statements in the else block will
be executed after all iterations are completed. The program exits the loop only
after the else block is executed.
Syntax:
forcounter
insequence
:
#Statements inside for loop block
else:
#Statements inside else block
Example:
forx
inrange(5):
("iteration no {} in for loop".format(
x
+1))
else:
("else block in loop")
("Out of loop")
Output:
iteration no
1in
for
loop
iteration no
2in
for
loop
iteration no
3in
for
loop
iteration no
4in
for
loop
iteration no
5in
for
loop
elseblock
inloop
Out of loop
Quick quiz: What is the output of this
program.
for i in range(5):
print(i)
if i==3:
break
else:
print("sorry i is not
available")
Output: 0
1
2
3
Exception
Handling
Exception
handling is the process of responding to unwanted or unexpected events when a
computer program runs. Exception handling deals with these events to avoid the
program or system crashing, and without this process, exceptions would disrupt
the normal operation of a program.
·
Exceptions in Python
Python has
many built-in exceptions that are raised when your program encounters an error
(something in the program goes wrong).
When these
exceptions occur, the Python interpreter stops the current process and passes
it to the calling process until it is handled. If not handled, the program will
crash.
·
Python try...except
try…..
except blocks are used in python to handle errors and exceptions. The code in
try block runs when there is no error. If the try block catches the error, then
the except block is executed.
Syntax:
try:
#statements which could generate
#exception
except:
#Soloution of generated exception
Example:
try:
num
=int(input("Enter an integer: "))
exceptValueError
:
print("Number entered is not an integer.")
#and
try:
num = int(input("Enter an integer: "))
a =[3,4]
print(a[num])
except ValueError:
print("Number entered is not an integer.")
except IndexError:
print("Index not found")
Output:
Enter an integer
:6.022
Number entered
isnot
an integer
.
Finally
Clause
The
finally code block is also a part of exception handling. When we handle
exception using the try and except block, we can include a finally block at the
end. The finally block is always executed, so it is generally used for doing
the concluding tasks like closing file resources or closing database connection
or may be ending the program execution with a delightful message.
Syntax:
try:
#statements which could generate
#exception
except:
#solution of generated exception
finally:
#block of code which is going to
#execute in any situation
The
finally block is executed irrespective of the outcome of try……except…..else
blocks
One of the important use cases of finally block is in a function which returns
a value.
Example:
try:
num
=int(input("Enter an integer: "))
exceptValueError
:
print("Number entered is not an integer.")
else:
print("Integer Accepted.")
finally:
print("This block is always executed.")
#and
def func():
try:
num = int(input("Enter an integer: "))
except ValueError:
print("Number entered is not an integer.")
return 1
else:
print("Integer Accepted.")
return 0
finally:
return "This block is always executed."
print(func())
Output
1:
Enter an integer
:19
Integer Accepted
.
This block
isalways executed
.
Output
2:
Enter an integer
:3.142
Number entered
isnot
an integer
.
This block
isalways executed
.
Raising
Custom errors
In
python, we can raise custom errors by using the raise
keyword.
salary
=int(input("Enter salary amount: "))
ifnot
2000
<
salary
<5000:
raise
ValueError
("Not a valid salary")
In
the previous tutorial, we learned about different built-in exceptions in Python
and why it is important to handle exceptions. However, sometimes we may need to
create our own custom exceptions that serve our purpose.
·
Defining Custom Exceptions
In
Python, we can define custom exceptions by creating a new class that is derived
from the built-in Exception class.
Here's the syntax to define custom
exceptions:
classCustomError(
Exception
):
# code ...
pass
try:
# code ...
exceptCustomError
:
# code...
This
is useful because sometimes we might want to do something when a particular
exception is raised. For example, sending an error report to the admin, calling
an api, etc.
If
... Else in One Line
There
is also a shorthand syntax for the if-else statement that can be used when the
condition being tested is simple and the code blocks to be executed are short.
Here's an example:
a
=2
b
=330
print("A")if
a
>b
elseprint("B")
You
can also have multiple else statements on the same line:
Example:
One
line if else statement, with 3 conditions:
a
=330
b
=330
print("A")if
a
>b
elseprint("=")
if
a
==b
elseprint("B"
Another
Example:
result
=value_if_true
ifcondition
elsevalue_if_false
This
syntax is equivalent to the following if-else statement:
ifcondition
:
result
=value_if_true
else:
result
=value_if_false
·
Conclusion: The shorthand syntax can be a convenient way to
write simple if-else statements, especially when you want to assign a value to
a variable based on a condition.
However, it's not suitable
for more complex situations where you need to execute multiple statements or
perform more complex logic. In those cases, it's best to use the full if-else
syntax.
· Enumerate function in python: The
enumerate function is a built-in function in Python that allows you to loop
over a sequence (such as a list, tuple, or string) and get the index and value
of each element in the sequence at the same time. Here's a basic example of how
it works:
# Loop over a list and print the index and value of each element
fruits
=['apple',
'banana',
'mango']
forindex
,fruit
inenumerate(
fruits
):
print(
index
,fruit
)
output:
0 apple
1 banana
2mango
As
you can see, the enumerate function returns a tuple containing the index and value of each element in the sequence.
You can use the for loop to unpack these tuples and assign them to variables,
as shown in the example above.
·
Changing the start index
By
default, the enumerate function starts the index at 0, but you can specify a
different starting index by passing it as an argument to the enumerate
function:
# Loop over a list and print the index (starting at 1) and value of each element
fruits
=['apple',
'banana',
'mango']
forindex
,fruit
inenumerate(
fruits
,start
=1):
print(
index
,fruit
)
output:
1 apple
2 banana
3mango
The
enumerate function is often used when you need to loop over a sequence and
perform some action with both the index and value of each element. For example,
you might use it to loop over a list of strings and print the index and value
of each string in a formatted way:
fruits
=['apple',
'banana',
'mango']
forindex
,fruit
inenumerate(
fruits
):
print(f'{index+1}: {fruit}')
output:
1: apple
2: banana
3:mango
In
addition to lists, you can use the enumerate function with any other sequence
type in Python, such as tuples and strings. Here's an example with a tuple:
# Loop over a tuple and print the index and value of each element
colors
=('red',
'green',
'blue')
forindex
,color
inenumerate(
colors
):
print(
index
,color
)
And here's an example with a string:
# Loop over a string and print the index and value of each character
s
='hello'
forindex
,c
inenumerate(
s
):
print(
index
,c
)
Virtual
Environment
A
virtual environment is a tool used to isolate specific Python environments on a
single machine, allowing you to work on multiple projects with different
dependencies and packages without conflicts. This can be especially useful when
working on projects that have conflicting package versions or packages that are
not compatible with each other.
To
create a virtual environment in Python, you can use the “venv module” that comes with Python. Here's an example of how to create a
virtual environment and activate it.
# Create a virtual environment
python
-m venv myenv
# Activate the virtual environment (Linux/macOS)
source myenv
/bin/activate
# Activate the virtual environment (Windows)
myenv\Scripts\activate
.bat
Once the virtual environment is activated, any packages that you
install using pip will be installed in the virtual environment, rather than in
the global Python environment. This allows you to have a separate set of
packages for each project, without affecting the packages installed in the
global environment.
·
To deactivate the virtual environment, you can use the deactivate
command:
# Deactivate the virtual environment
deactivate
·
The "requirements.txt" file
In
addition to creating and activating a virtual environment, it can be useful to
create a requirements.txt file that lists the packages and their versions that
your project depends on. This file can be used to easily install all the
required packages in a new environment.
·
To create a requirements.txt file, you can use the pip freeze
command, which outputs a list of installed packages and their versions. For
example:
# Output the list of installed packages and their versions to a file
pip freeze
>requirements
.txt
·
To install the packages listed in the requirements.txt file, you
can use the pip install command with the -r flag:
# Install the packages listed in the requirements.txt file
pip install
-r requirements
.txt
Using
a virtual environment and a requirements.txt file can help you manage the
dependencies for your Python projects and ensure that your projects are
portable and can be easily set up on a new machine.
How
importing in python works
Importing
in Python is the process of loading code from a Python module into the current
script. This allows you to use the functions and variables defined in the
module in your current script, as well as any additional modules that the
imported module may depend on.
To
import a module in Python, you use the import statement followed by the name of
the module. For example, to import the math module, which contains a variety of
mathematical functions, you would use the following statement:
importmath
Once
a module is imported, you can use any of the functions and variables defined in
the module by using the dot notation. For example, to use the sqrt function
from the math module, you would write:
import math
result
=math
.sqrt
(9)
print(result
)# Output: 3.0
·
from keyword
You
can also import specific functions or variables from a module using the from
keyword. For example, to import only the sqrt function from the math module,
you would write:
frommath
importsqrt
result
=sqrt
(9)
print(result
)# Output: 3.0
You
can also import multiple functions or variables at once by separating them with
a comma:
frommath
importsqrt
,pi
result
=sqrt
(9)
print(result
)# Output: 3.0
print(pi
)# Output: 3.141592653589793
·
importing everything
It's
also possible to import all functions and variables from a module using the *
wildcard. However, this is generally not recommended as it can lead to
confusion and make it harder to understand where specific functions and
variables are coming from.
frommath
import*
result
=sqrt
(9)
print(result
)# Output: 3.0
print(pi
)# Output: 3.141592653589793
Python
also allows you to rename imported modules using the as keyword. This can be
useful if you want to use a shorter or more descriptive name for a module, or
if you want to avoid naming conflicts with other modules or variables in your
code.
·
The "as" keyword
importmath
asm
result
=m
.sqrt
(9)
print(result
)# Output: 3.0
print(m
.pi
)# Output: 3.141592653589793
·
The dir function
Finally,
Python has a built-in function called “dir” that you can use to view the
names of all the functions and variables defined in a module. This can be
helpful for exploring and understanding the contents of a new module.
import math
print(dir(math
))
This
will output a list of all the names defined in the math module, including
functions like sqrt and pi, as well as other variables and constants.
In
summary, the import statement in Python allows you to access the functions and
variables defined in a module from within your current script. You can import
the entire module, specific functions or variables, or use the * wildcard to
import everything. You can also use the as keyword to rename a module,
and the dir function to view the contents of a module.
if
__name__ == "__main__" in Python
The
if __name__ == "__main__"
idiom is a common pattern used in Python
scripts to determine whether the script is being run directly or being imported
as a module into another script.
In
Python, the __name__
variable
is a built-in variable that is automatically set to the name of the current
module. When a Python script is run directly, the __name__
variable is set to the string __main__
When the script is imported as a module
into another script, the __name__
variable
is set to the name of the module.
Here's
an example of how the if __name__
== __main__
idiom can be used:
defmain():
# Code to be run when the script is run directly
print("Running script directly")
if__name__
=="__main__":
main
()
In
this example, the main function contains the code that should be run when the
script is run directly. The if statement at the bottom checks whether the __name__
variable is equal to __main__
. If it is, the main function is called.
·
Why is it useful?
This
idiom is useful because it allows you to reuse code from a script by importing
it as a module into another script, without running the code in the original
script. For example, consider the following script:
defmain():
print("Running script directly")
if__name__
=="__main__":
main
()
If
you run this script directly, it will output "Running script
directly". However, if you import it as a module into another script and
call the main function from the imported module, it will not output anything:
import scrip
script
.main
()# Output: "Running script directly"
This
can be useful if you have code that you want to reuse in multiple scripts, but
you only want it to run when the script is run directly and not when it's
imported as a module.
·
Is it a necessity?
It's
important to note that the if __name__ == "__main__"
idiom is not required to run a Python
script. You can still run a script without it by simply calling the functions
or running the code you want to execute directly. However, the if __name__ ==
"__main__"
idiom
can be a useful tool for organizing and separating code that should be run
directly from code that should be imported and used as a module.
In
summary, the if __name__ == "__main__"
idiom is a common pattern used in Python
scripts to determine whether the script is being run directly or being imported
as a module into another script. It allows you to reuse code from a script by
importing it as a module into another script, without running the code in the
original script.
os
Module in Python
The
os module in Python is a built-in library that provides functions for
interacting with the operating system. It allows you to perform a wide variety
of tasks, such as reading and writing files, interacting with the file system,
and running system commands.
Here
are some common tasks you can perform with the os module:
Reading
and writing files The os module provides functions for opening, reading, and
writing files. For example, to open a file for reading, you can use the open
function:
import os
# Open the file in read-only mode
f
=os
.open("myfile.txt",os
.O_RDONLY
)
# Read the contents of the file
contents
=os
.read
(f
,1024)
# Close the file
os
.close
(f
)
· To open a file for writing, you can use
the os.O_WRONLY flag:
import os
# Open the file in write-only mode
f
=os
.open("myfile.txt",os
.O_WRONLY
)
# Write to the file
os
.write
(f
,b"Hello, world!")
# Close the file
os
.close
(f
)
·
Interacting with the file system
The
os module also provides functions for interacting with the file system. For
example, you can use the os.listdir function to get a list of the files in a
directory:
import os
# Get a list of the files in the current directory
files
=os
.listdir
(".")
print(files
)# Output: ['myfile.txt', 'otherfile.txt']
· You can also use the os.mkdir function to
create a new directory:
import os
# Create a new directory
os
.mkdir
("newdir")
·
Running system commands
Finally,
the os module provides functions for running system commands. For example, you
can use the os.system function to run a command and get the output:
import os
# Run the "ls" command and print the output
output
=os
.system
("ls")
print(output
)# Output: ['myfile.txt', 'otherfile.txt']
· You can also use the os.popen function to
run a command and get the output as a file-like object:
import os
# Run the "ls" command and get the output as a file-like object
f
=os
.popen
("ls")
# Read the contents of the output
output
=f
.read
()
print(output
)# Output: ['myfile.txt', 'otherfile.txt']
# Close the file-like object
f
.close
()
local
and global variables
Before
we dive into the differences between local and global variables, let's first recall
what a variable is in Python.
A
variable is a named location in memory that stores a value. In Python, we can
assign values to variables using the assignment operator =. For example:
x
=5
y
="Hello, World!"
Now,
let's talk about local and global variables.
A
local variable is a variable that is defined within a function and is only
accessible within that function. It is created when the function is called and
is destroyed when the function returns.
On
the other hand, a global variable is a variable that is defined outside of a
function and is accessible from within any function in your code.
Here's
an example to help clarify the difference:
x
=10
# global variable
defmy_function():
y
=5
# local variable
print(
y
)
my_function
()
print(x
)
print(y
)# this will cause an error because y is a local variable and is not accessible outside of the function
In
this example, we have a global variable x and a local variable y. We can access
the value of the global variable x from within the function, but we cannot
access the value of the local variable y outside of the function.
·
The global keyword
Now,
what if we want to modify a global variable from within a function? This is
where the global keyword comes in.
The
global keyword is used to declare that a variable is a global variable and
should be accessed from the global scope. Here's an example:
x
=10
# global variable
defmy_function():
global
x
x
=5
# this will change the value of the global variable x
y
=5
# local variable
my_function
()
print(x
)# prints 5
print(y
)# this will cause an error because y is a local variable and is not accessible outside of the function
In
this example, we used the global keyword to declare that we want to modify the
global variable x from within the function. As a result, the value of x is
changed to 5.
Note: It's important to note that it's generally considered
good practice to avoid modifying global variables from within functions, as it
can lead to unexpected behavior and make your code harder to debug
File
IO in Python
Python
provides several ways to manipulate files. Today, we will discuss how to handle
files in Python.
·
Opening a File
Before
we can perform any operations on a file, we must first open it. Python provides
the open() function to open a file. It takes two arguments: the name of the
file and the mode in which the file should be opened. The mode can be 'r' for
reading, 'w' for writing, or 'a' for appending.
Here's
an example of how to open a file for reading:
f
=open('myfile.txt',
'r')
By
default, the open() function returns a file object that can be used to read
from or write to the file, depending on the mode.
·
Modes in file: There are various modes in which we can
open files.
1.
read
(r): This mode opens the file for reading only and gives an error if the file
does not exist. This is the default mode if no mode is passed as a parameter.
2.
write
(w): This mode opens the file for writing only and creates a new file if the
file does not exist.
3.
append
(a): This mode opens the file for appending only and creates a new file if the
file does not exist.
4.
create
(x): This mode creates a file and gives an error if the file already exists.
5.
text
(t): Apart from these modes we also need to specify how the file must be
handled. t mode is used to handle text files. t refers to the text mode. There
is no difference between r and rt or w and wt since text mode is the default.
The default mode is 'r' (open for reading text, synonym of 'rt' ).
6.
binary
(b): used to handle binary files (images, pdfs, etc).
·
Reading from a File
Once
we have a file object, we can use various methods to read from the file.
The
read() method reads the entire contents of the file and returns it as a string.
f
=open('myfile.txt',
'r')
contents
=f
.read
()
print(contents
)
·
Writing to a File
To
write to a file, we first need to open it in write mode.
f
=open('myfile.txt',
'w')
We
can then use the write() method to write to the file.
f
=open('myfile.txt',
'w')
f
.write
('Hello, world!')
Keep
in mind that writing to
a file will overwrite
its contents. If you
want to append to a file instead of overwriting it, you can open it in append
mode.
f
=open('myfile.txt',
'a')
f
.write
('Hello, world!')
·
Closing a File
It
is important to close a file after you are done with it. This releases the
resources used by the file and allows other programs to access it.
To
close a file, you can use the close() method.
f
=open('myfile.txt',
'r')
# ... do something with the file
f
.close
()
·
The 'with' statement
Alternatively,
you can use the with statement to automatically close the file after you are
done with it.
withopen('myfile.txt',
'r')
as
f
:
# ... do something with the file
· readlines() method
The
readline() method reads a single line from the file. If we want to read
multiple lines, we can use a loop.
f
=open('myfile.txt',
'r')
whileTrue:
line
=f
.readline
()
if
not
line
:
break
print(
line
)
The
readlines() method reads all the lines of the file and returns them as a list of strings.
·
writelines() method
The
writelines() method in Python writes a sequence of strings to a file. The
sequence can be any iterable object, such as a list or a tuple.
f
=open('myfile.txt',
'w')
lines
=['line 1\n',
'line 2\n',
'line 3\n']
f
.writelines
(lines
)
f
.close
()
This
will write the strings in the lines list to the file myfile.txt. The \n
characters are used to add newline characters to the end of each string.
Keep
in mind that the writelines()
method does not add newline characters between the strings in the sequence. If you want to add newlines between the
strings, you can use a
loop to write each string separately.
f
=open('myfile.txt',
'w')
lines
=['line 1',
'line 2',
'line 3']
forline
inlines
:
f
.write
(line
+'\n')
f
.close
()
It
is also a good practice to close the file after you are done with it.
seek()
and tell() functions
In
Python, the seek() and tell() functions are used to work with file objects and
their positions within a file. These functions are part of the built-in io
module, which provides a consistent interface for reading and writing to
various file-like objects, such as files, pipes, and in-memory buffers.
·
seek() function
The
seek() function allows you to move the current position within a file to a
specific point. The position is specified in bytes, and you can move either
forward or backward from the current position. For example:
withopen('file.txt',
'r')
as
f
:
# Move to the 10th byte in the file
f
.seek
(10)
# Read the next 5 bytes
data
=f
.read
(5)
·
tell() function
The
tell() function returns the current position within the file, in bytes. This
can be useful for keeping track of your location within the file or for seeking
to a specific position relative to the current position. For example:
withopen('file.txt',
'r')
as
f
:
# Read the first 10 bytes
data
=f
.read
(10)
# Save the current position
current_position
=f
.tell
()
# Seek to the saved position
f
.seek
(current_position
)
·
truncate() function
When
you open a file in Python using the open function, you can specify the mode in
which you want to open the file. If you specify the mode as 'w' or 'a', the
file is opened in write mode and you can write to the file. However, if you
want to truncate the file to a specific size, you can use the truncate function.
withopen('sample.txt',
'w')
as
f
:
f
.write
('Hello World!')
f
.truncate
(5)
withopen('sample.txt',
'r')
as
f
:
print(
f
.read
())
Lambda
Functions in Python
In
Python, a lambda function is a small anonymous function without a name. It is
defined using the lambda keyword and has the following syntax:
lambdaarguments
:expression
Lambda
functions are often used in situations where a small function is required for a
short period of time. They are commonly used as arguments to higher-order
functions, such as map, filter, and reduce.
# Function to double the input
defdouble(
x
):
return
x
*2
# Lambda function to double the input
lambdax
:x
*2
The
above lambda function has the same functionality as the double function defined
earlier. However, the lambda function is anonymous, as it does not have a name.
Lambda
functions can have multiple arguments, just like regular functions.
Here
is an example of a lambda function with multiple arguments:
# Function to calculate the product of two numbers
defmultiply(
x
,y
):
return
x
*y
# Lambda function to calculate the product of two numbers
lambdax
,y
:x
*y
Lambda
functions can also include multiple statements, but they are limited to a
single expression. For example:
# Lambda function to calculate the product of two numbers,
# with additional print statement
lambdax
,y
:print(f'{x} * {y} = {x * y}')
In
the above example, the lambda function includes a print statement, but it is
still limited to a single expression.
Lambda
functions are often used in conjunction with higher-order functions, such as
map, filter, and reduce.
Map,
Filter and Reduce
In
Python, the map, filter, and reduce functions are built-in functions that allow
you to apply a function to a sequence of elements and return a new sequence.
These functions are known as higher-order functions, as they take other
functions as arguments.
·
Map: The map function applies a function to each
element in a sequence and returns a new sequence containing the transformed
elements. The map function has the following syntax:
map(function
,iterable
)
The
function argument is a function that is applied to each element in the iterable
argument. The iterable argument can be a list, tuple, or any other iterable
object.
# List of numbers
numbers
=[1,
2,
3,
4,
5]
# Double each number using the map function
doubled
=map(lambda
x
:x
*2,
numbers
)
# Print the doubled numbers
print(list(doubled
))
In
the above example, the lambda function lambda x: x * 2 is used to double each
element in the numbers list. The map function applies the lambda function to
each element in the list and returns a new list containing the doubled numbers.
·
Filter: The filter function filters a sequence of
elements based on a given predicate (a function that returns a boolean value)
and returns a new sequence containing only the elements that meet the
predicate. The filter function has the following syntax:
filter(predicate
,iterable
)
The
predicate argument is a function that returns a boolean value and is applied to
each element in the iterable argument. The iterable argument can be a list,
tuple, or any other iterable object
# List of numbers
numbers
=[1,
2,
3,
4,
5]
# Get only the even numbers using the filter function
evens
=filter(lambda
x
:x
%2
==
0,
numbers
)
# Print the even numbers
print(list(evens
))
In
the above example, the lambda function lambda x: x % 2 == 0 is used to filter
the numbers list and return only the even numbers. The filter function applies
the lambda function to each element in the list and returns a new list
containing only the even numbers.
·
Reduce: The reduce function is a higher-order function
that applies a function to a sequence and returns a single value. It is a part
of the functools module in Python and has the following syntax:
reduce(function
,iterable
)
The
function argument is a function that takes in two arguments and returns a
single value. The iterable argument is a sequence of elements, such as a list
or tuple.
The
reduce function applies the function to the first two elements in the iterable
and then applies the function to the result and the next element, and so on.
The reduce function returns the final result.
fromfunctools
importreduce
# List of numbers
numbers
=[1,
2,
3,
4,
5]
# Calculate the sum of the numbers using the reduce function
sum=
reduce(lambda
x
,y
:x
+y
,numbers
)
# Print the sum
print(sum)
In
the above example, the reduce function applies the lambda function lambda x, y:
x + y to the elements in the numbers list. The lambda function adds the two arguments
x and y and returns the result. The reduce function applies the lambda function
to the first two elements in the list (1 and 2), then applies the function to
the result (3) and the next element (3), and so on. The final result is the sum
of all the elements in the list, which is 15.
It is important to note that the reduce function requires the
functools module to be imported in order to use it.
'is'
vs '==' in Python
In
Python, is and == are both comparison operators that can be used to check if two
values are equal. However, there are some important differences between the two
that you should be aware of.
The
is operator compares the identity of two objects, while the == operator
compares the values of the objects. This means that is will only return True if
the objects being compared are the exact same object in memory, while == will
return True if the objects have the same value.
For
example:
a
=[1,
2,
3]
b
=[1,
2,
3]
print(a
==b
)# True
print(a
isb
)# False
In
this case, a and b are two separate lists that have the same values, so ==
returns True. However, a and b are not the same object in memory, so is returns
False.
One
important thing to note is that, in Python, strings and integers are immutable,
which means that once they are created, their value cannot be changed. This
means that, for strings and integers, is and == will always return the same
result:
a
="hello"
b
="hello"
print(a
==b
)# True
print(a
isb
)# True
a
=5
b
=5
print(a
==b
)# True
print(a
isb
)# True
In
these cases, a and b are both pointing to the same object in memory, so is and
== both return True.
For
mutable objects such as lists and dictionaries, is and == can behave
differently. In general, you should use == when you want to compare the values
of two objects, and use is when you want to check if two objects are the same
object in memory.
Exercise:
Snake Water Gun
Snake,
Water and Gun is a variation of the children's game
"rock-paper-scissors" where players use hand gestures to represent a
snake, water, or a gun. The gun beats the snake, the water beats the gun, and
the snake beats the water. Write a python program to create a Snake Water Gun
game in Python using if-else statements. Do not create any fancy GUI. Use
proper functions to check for win.
Introduction
to Object-oriented Programming
Introduction
to Object-Oriented Programming in Python: In programming languages, mainly
there are two approaches that are used to write program or code.
1).
Procedural Programming
2).
Object-Oriented Programming
The
procedure we are following till now is the “Procedural Programming” approach.
So, in this session, we will learn about Object Oriented Programming (OOP). The
basic idea of object-oriented programming (OOP) in Python is to use classes and
objects to represent real-world concepts and entities.
A
class is a blueprint or template for creating objects. It defines the
properties and methods that an object of that class will have. Properties are
the data or state of an object, and methods are the actions or behaviors that
an object can perform.
An
object is an instance of a class, and it contains its own data and methods. For
example, you could create a class called "Person" that has properties
such as name and age, and methods such as speak() and walk(). Each instance of
the Person class would be a unique object with its own name and age, but they
would all have the same methods to speak and walk.
One
of the key features of OOP in Python is encapsulation, which means that the
internal state of an object is hidden and can only be accessed or modified
through the object's methods. This helps to protect the object's data and
prevent it from being modified in unexpected ways.
Another
key feature of OOP in Python is inheritance, which allows new classes to be
created that inherit the properties and methods of an existing class. This
allows for code reuse and makes it easy to create new classes that have similar
functionality to existing classes.
Polymorphism
is also supported in Python, which means that objects of different classes can
be treated as if they were objects of a common class. This allows for greater
flexibility in code and makes it easier to write code that can work with
multiple types of objects.
In
summary, OOP in Python allows developers to model real-world concepts and
entities using classes and objects, encapsulate data, reuse code through
inheritance, and write more flexible code through polymorphism.
· Python Class and Objects
A
class is a blueprint or a template for creating objects, providing initial
values for state (member variables or attributes), and implementations of
behavior (member functions or methods). The user-defined objects are created
using the class keyword.
·
Creating a Class: Let us now create a class using the class
keyword.
classDetails:
name
="Rohan"
age
=20
·
Creating an Object: Object is the instance of the
class used to access the properties of the class Now lets create an object of
the class.
Example:
obj1
=Details
()
Example:
classDetails:
name
="Rohan"
age
=20
obj1
=Details
()
print(obj1
.name
)
print(obj1
.age
)
Output:
Rohan
20
· Constructors: A constructor is a special
method in a class used to create and initialize an object of a class. There are
different types of constructors. Constructor is invoked automatically when an
object of a class is created.
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.
·
Syntax of Python Constructor
def__init__(
self
):
# initializations
init
is one of the reserved functions in Python. In Object Oriented Programming, it
is known as a constructor.
·
Types of Constructors in Python
1.
Parameterized
Constructor
2.
Default
Constructor
1.
Parameterized Constructor in Python: When the constructor accepts arguments
along with self, it is known as parameterized constructor.
These
arguments can be used inside the class to assign the values to the data
members.
Example:
classDetails:
def
__init__(
self
,animal
,group
):
self
.animal
=animal
self
.group
=group
obj1
=Details
("Crab","Crustaceans")
print(obj1
.animal
,"belongs to the",
obj1
.group
,"group.")
Output:
Crab belongs to the Crustaceans group
.
2.
Default Constructor in Python: When the constructor doesn't accept any arguments from the
object and has only one argument, self, in the constructor, it is known as a
Default constructor.
Example:
classDetails:
def
__init__(
self
):
print("animal Crab belongs to Crustaceans group")
obj1
=Details
()
Output:
animal Crab belongs to Crustaceans group
Python
Decorators
Python decorators are a
powerful and versatile tool that allows you to modify the behavior of functions
and methods. They are a way to extend the functionality of a function or method
without modifying its source code.
A
decorator is a function that takes another function as an argument and returns
a new function that modifies the behavior of the original function. The new
function is often referred to as a "decorated" function.
· syntax
@decorator_function
defmy_function():
pass
The
@decorator_function notation is just a shorthand for the following code:
defmy_function():
pass
my_function
=decorator_function
(my_function
)
Decorators
are often used to add functionality to functions and methods, such as logging, memoization, and access
control.
·
Practical use case: One common use of decorators
is to add logging to a function. For example, you could use a decorator to log
the arguments and return value of a function each time it is called
import logging
deflog_function_call(
func
):
def
decorated(*
args
,**
kwargs
):
logging
.info
(f"Calling {func.__name__} with args={args}, kwargs={kwargs}")
result
=func
(*args
,**
kwargs
)
logging
.info
(f"{func.__name__} returned {result}")
return
result
return
decorated
@log_function_call
defmy_function(
a
,b
):
return
a
+b
In this example, the log_function_call decorator takes a function
as an argument and returns a new function that logs the function call before
and after the original function is called.
Getters and Setters
·
Getters: Getters
in Python are methods that are used to access the values of an object's
properties. They are used to return the value of a specific property, and are
typically defined using the @property decorator. Here is an example of a simple
class with a getter method.
classMyClass:
def
__init__(
self
,value
):
self
._value
=value
@property
def
value(
self
):
return
self
._value
In
this example, the MyClass class has a single property, _value, which is
initialized in the __init__ method.
The value method is defined as a getter using the @property decorator, and is
used to return the value of the _value property.
To
use the getter, we can create an instance of the MyClass class, and then access
the value property as if it were an attribute:
>>>obj
=MyClass
(10)
>>>obj
.value
10
· Setters: It is
important to note that the getters do not take any parameters and we cannot set
the value through getter method.For that we need setter method which can be
added by decorating method with @property_name.setter.
Example of a class with both getter and setter
classMyClass:
def
__init__(
self
,value
):
self
._value
=value
@property
def
value(
self
):
return
self
._value
@value.setter
def
value(
self
,new_value
):
self
._value
=new_value
We
can use setter method like this:
>>>obj
=MyClass
(10)
>>>obj
.value
=20
>>>obj
.value
20
In
conclusion, getters are a convenient way to access the values of an object's
properties, while keeping the internal representation of the property hidden.
This can be useful for encapsulation and data validation.
Inheritance
in python
When
a class derives from another class. The child class will inherit all the public
and protected properties and methods from the parent class. In addition, it can
have its own properties and methods,this is called as inheritance.
Syntax
classBaseClass:
Body of base
class
classDerivedClass
(BaseClass
):
Body of derived
class
Derived
class inherits features from the base class where new features can be added to
it. This results in re-usability of code.
·
Types of inheritance:
1.
Single
inheritance
2.
Multiple
inheritance
3.
Multilevel
inheritance
4.
Hierarchical
Inheritance
5.
Hybrid
Inheritance
Access
Specifiers/Modifiers
Access
specifiers or access modifiers in python programming are used to limit the
access of class variables and class methods outside of class while implementing
the concepts of inheritance.
Let
us see the each one of access specifiers in detail:
·
Types of access specifiers
1.
Public
access modifier
2.
Private
access modifier
3.
Protected
access modifier
Example of Public Access Modifier:
class Student:
# constructor is defined
def __init__(self, age, name):
self.age = age # public
variable
self.name = name # public
variable
obj = Student(21,"Harry")
print(obj.age)
print(obj.name)
Output:
21
Harry
2. Private
Access Modifier: By definition, Private members of a class
(variables or methods) are those members which are only accessible inside the
class. We cannot use private members outside of class.
In Python, there is no strict concept of "private"
access modifiers like in some other programming languages. However, a
convention has been established to indicate that a variable or method should be
considered private by prefixing its name with a double underscore (__). This is
known as a "weak internal use indicator" and it is a convention only,
not a strict rule. Code outside the class can still access these
"private" variables and methods, but it is generally understood that
they should not be accessed or modified.
Example for Private Access
Modifier:
class Student:
def __init__(self, age, name):
self.__age = age # An
indication of private variable
def __funName(self): # An
indication of private function
self.y = 34
print(self.y)
class Subject(Student):
pass
obj = Student(21,"Harry")
obj1 = Subject
# calling by object of class Student
print(obj.__age)
print(obj.__funName())
# calling by object of class Subject
print(obj1.__age)
print(obj1.__funName())
name = "Rohan"
age = 20
Output:
AttributeError: 'student' object has no
attribute '__age'
AttributeError: 'student' object has no
method '__funName()'
AttributeError: 'subject' object has no
attribute '__age'
AttributeError: 'student' object has no
method '__funName()
Private members of
a class cannot be accessed or inherited outside of class. If we try to access
or to inherit the properties of private members to child class (derived class).
Then it will show the error.
·
Name mangling: Name mangling in Python is a technique
used to protect class-private and superclass-private attributes from being
accidentally overwritten by subclasses. Names of class-private and
superclass-private attributes are transformed by the addition of a single
leading underscore and a double leading underscore respectively.
Example for Private Access
Modifier:
class MyClass:
def __init__(self):
self._nonmangled_attribute = "I am a nonmangled attribute"
self.__mangled_attribute = "I am a mangled attribute"
my_object = MyClass()
print(my_object._nonmangled_attribute)
# Output: I am a nonmangled attribute
print(my_object.__mangled_attribute) #
Throws an AttributeError
print(my_object._MyClass__mangled_attribute)
# Output: I am a mangled attribute
In above example,
the attribute _nonmangled_attribute is marked as nonmangled by convention, but
can still be accessed from outside the class. The attribute __mangled_attribute
is private and its name is "mangled" to _MyClass__mangled_attribute,
so it can't be accessed directly from outside the class, but you can access it
by calling _MyClass__mangled_attribute.
3. Protected
Access Modifier: In object-oriented programming (OOP), the term
"protected" is used to describe a member (i.e., a method or
attribute) of a class that is intended to be accessed only by the class itself
and its subclasses. In Python, the convention for indicating that a member is
protected is to prefix its name with a single underscore (_). For example, if a
class has a method called _my_method, it is indicating that the method should
only be accessed by the class itself and its subclasses.
It's
important to note that the single underscore is just a naming convention, and
does not actually provide any protection or restrict access to the member. The
syntax we follow to make any variable protected is to write variable name
followed by a single underscore (_) ie. _varName.
Example for Protected Access
Modifier:
class Student:
def __init__(self):
self._name = "Harry"
def _funName(self): #
protected method
return "CodeWithHarry"
class Subject(Student): #inherited class
pass
obj = Student()
obj1 = Subject()
# calling by object of Student class
print(obj._name)
print(obj._funName())
# calling by object of Subject class
print(obj1._name)
print(obj1._funName())
Output:
Harry
CodeWithHarry
Harry
CodeWithHarry
Exercise
6 - Library Management System in Python
Write
a Library class with no_of_books and books as two instance variables. Write a
program to create a library from this Library class and show how you can print
all books, add a book and get the number of books using different methods. Show
that your program doesnt persist the books after the program is stopped!
Static
Methods in Python
Static
methods in Python are methods that belong to a class rather than an instance of
the class. They are defined using the @staticmethod decorator and do not
have access to the instance of the class (i.e. self). They are called on the
class itself, not on an instance of the class. Static methods are often used to
create utility functions that don't need access to instance data.
class Math:
def __init__(self, num):
self.num = num
def addtonum(self, n):
self.num = self.num +n
@staticmethod
def add(a, b):
return a + b
# result = Math.add(1, 2)
# print(result) # Output: 3
a = Math(5)
print(a.num)
a.addtonum(6)
print(a.num)
print(Math.add(7, 2))
In
this example, the add
method is a static method of the Math class. It takes two parameters a and b and returns their sum. The
method can be called on the class itself, without the need to create an
instance of the class.
Instance
vs class variables
In
Python, variables can be defined at the class level or at the instance level. Understanding
the difference between these types of variables is crucial for writing
efficient and maintainable code.
·
Class Variables: Class variables are defined at the class
level and are shared among all instances of the class. They are defined outside
of any method and are usually used to store information that is common to all
instances of the class. For example, a class variable can be used to store the
number of instances of a class that have been created.
classMyClass:
class_variable
=0
def
__init__(
self
):
MyClass
.class_variable
+=1
def
print_class_variable(
self
):
print(
MyClass
.class_variable
)
obj1
=MyClass
()
obj2
=MyClass
()
obj1
.print_class_variable
()# Output: 2
obj2
.print_class_variable
()# Output: 2
In
this example, the class_variable is shared among all instances of the class
MyClass. When we create new instances of MyClass, the value of class_variable
is incremented. When we call the print_class_variable method on obj1 and obj2,
we get the same value of class_variable.
·
Instance Variables: Instance variables are
defined at the instance level and are unique to each instance of the class.
They are defined inside the init method and are usually used to
store information that is specific to each instance of the class. For example,
an instance variable can be used to store the name of an employee in a class
that represents an employee.
classMyClass:
def
__init__(
self
,name
):
self
.name
=name
def
print_name(
self
):
print(
self
.name
)
obj1
=MyClass
("John")
obj2
=MyClass
("Jane")
obj1
.print_name
()# Output: John
obj2
.print_name
()# Output: Jane
In
this example above, each instance of the class MyClass has its own value for
the name variable. When we call the print_name method on obj1 and obj2, we get
different values for name.
·
Summary
In
summary, class variables are shared among all instances of a class and are used
to store information that is common to all instances. Instance variables are
unique to each instance of a class and are used to store information that is
specific to each instance. Understanding the difference between class variables
and instance variables is crucial for writing efficient and maintainable code
in Python.
It's
also worth noting that, in python, class variables are defined outside of any
methods and don't need to be explicitly declared as class variable. They are
defined in the class level and can be accessed via classname.varibale_name or self.class.variable_name. But instance variables are defined
inside the methods and need to be explicitly declared as instance variable by
using self.variable_name.
Exercise
7 - Clear the Clutter
Write
a program to clear the clutter inside a folder on your computer. You should use
os module to rename all the png images from 1.png all the way till n.png where
n is the number of png files in that folder. Do the same for other file
formats. For example: sfdsf.png --> 1.png vfsf.png --> 2.png this.png
--> 3.png design.png --> 4.png name.png --> 5.png
Python
Class Methods
·
An Introduction
In
Python, classes are a way to define custom data types that can store data and
define functions that can manipulate that data. One type of function that can
be defined within a class is called a "method." In this blog post, we
will explore what Python class methods are, why they are useful, and how to use
them.
·
What are Python Class Methods?
A
class method is a type of method that is bound to the class and not the
instance of the class. In other words, it operates on the class as a whole,
rather than on a specific instance of the class. Class methods are defined
using the "@classmethod" decorator, followed by a function
definition. The first argument of the function is always "cls," which represents the class itself.
·
Why Use Python Class Methods?
Class
methods are useful in several situations. For example, you might want to create
a factory method that creates instances of your class in a specific way. You
could define a class method that creates the instance and returns it to the
caller. Another common use case is to provide alternative constructors for your
class. This can be useful if you want to create instances of your class in
multiple ways, but still have a consistent interface for doing so.
·
How to Use Python Class Methods?
To
define a class method, you simply use the "@classmethod" decorator before the method
definition. The first argument of the method should always be "cls," which represents the class itself. Here is an
example of how to define a class method:
classExampleClass:
@classmethod
def
factory_method(
cls
,argument1
,argument2
):
return
cls
(argument1
,argument2
)
In
this example, the "factory_method" is a class method that takes two
arguments, "argument1" and "argument2." It creates a new
instance of the class "ExampleClass" using the "cls"
keyword, and returns the new instance to the caller.
It's
important to note that class methods cannot modify the class in any way. If you
need to modify the class, you should use a class level variable instead.
Conclusion
Python
class methods are a powerful tool for defining functions that operate on the
class as a whole, rather than on a specific instance of the class. They are
useful for creating factory methods, alternative constructors, and other types
of methods that operate at the class level. With the knowledge of how to define
and use class methods, you can start writing more complex and organized code in
Python.
Class
Methods as Alternative Constructors
In
object-oriented programming, the term "constructor" refers to a
special type of method that is automatically executed when an object is created
from a class. The purpose of a constructor is to initialize the object's
attributes, allowing the object to be fully functional and ready to use.
However,
there are times when you may want to create an object in a different way, or
with different initial values, than what is provided by the default
constructor. This is where class methods can be used as alternative
constructors.
A
class method belongs to the class rather than to an instance of the class. One
common use case for class methods as alternative constructors is when you want
to create an object from data that is stored in a different format, such as a
string or a dictionary. For example, consider a class named "Person"
that has two attributes: "name" and "age". The default
constructor for the class might look like this:
classPerson:
def
__init__(
self
,name
,age
):
self
.name
=name
self
.age
=age
But
what if you want to create a Person object from a string that contains the
person's name and age, separated by a comma? You can define a class method
named "from_string" to do this:
classPerson:
def
__init__(
self
,name
,age
):
self
.name
=name
self
.age
=age
@classmethod
def
from_string(
cls
,string
):
name
,age
=string
.split
(',')
return
cls
(name
,int(
age
))
Now
you can create a Person object from a string like this:
person
=Person
.from_string
("John Doe, 30")
Another
common use case for class methods as alternative constructors is when you want
to create an object with a different set of default values than what is
provided by the default constructor. For example, consider a class named
"Rectangle" that has two attributes: "width" and
"height". The default constructor for the class might look like this:
classRectangle:
def
__init__(
self
,width
,height
):
self
.width
=width
self
.height
=height
But
what if you want to create a Rectangle object with a default width of 10 and a
default height of 5? You can define a class method named "square" to
do this:
classRectangle:
def
__init__(
self
,width
,height
):
self
.width
=width
self
.height
=height
@classmethod
def
square(
cls
,size
):
return
cls
(size
,size
)
Now
you can create a square rectangle like this:
rectangle
=Rectangle
.square
(10)
dir(), __dict__ and help() methods
in python
We
must look into dir()
, __dict__()
and help()
attribute/methods in python. They
make it easy for us to understand how classes resolve various functions and
executes code. In Python, there are three built-in functions that are commonly
used to get information about objects: dir(), dict, and help(). Let's take a look at each of
them:
1. The dir()
method:dir()
: The dir() function returns a list of all the
attributes and methods (including dunder methods) available for an object. It
is a useful tool for discovering what you can do with an object.
Example:
x
=[1,
2,
3]
dir(x
)
Output:
['__add__','__class__',
'__contains__',
'__delattr__',
'__delitem__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__getitem__',
'__gt__',
'__hash__',
'__iadd__',
'__imul__',
'__init__',
'__init_subclass__',
'__iter__',
'__le__',
'__len__',
'__lt__',
'__mul__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__reversed__',
'__rmul__',
'__setattr__',
'__setitem__',
'__sizeof__',
'__str__',
'__subclasshook__',
'append',
'clear',
'copy',
'count',
'extend',
'index',
'insert',
'pop',
'remove',
'reverse',
'sort']
2. The __dict__
attribute: The __dict__
attribute
returns a dictionary representation of an object's attributes. It is a useful
tool for introspection.
Example:
classPerson:
def__init__(
self
,name
,age
):
self
.name
=name
self
.age
=age
p
=Person
("John",30)
p
.__dict__
Output:
{'name':'John',
'age':
30}
3. The help() mehthod: The
help() function is used to get help documentation for an object, including a
description of its attributes and methods.
Example:
help(str)
Help on
classstr
in
module builtins
:
classstr(object)
str(object='')
->
str
str(
bytes_or_buffer
[,encoding
[,errors
]])->
str
Create a new string
objectfrom
the given
object.If encoding
or
|
errors
isspecified
,then the
objectmust expose a data
buffer
|
that will be decoded using the given encoding
anderror handler
.
|
Otherwise
,returns the result of
object.__str__
()(if
defined
)
|
or
repr(object).
|
encoding defaults to sys
.getdefaultencoding
().
|
errors defaults to
'strict'.
In
conclusion, dir(), dict,
and help() are useful built-in functions in Python that can be used to
get information about objects. They are valuable tools for introspection and
discovery.
Super
keyword in Python
The
super() keyword in Python is used to refer to the parent class. It is
especially useful when a class inherits from multiple parent classes and you
want to call a method from one of the parent classes.
When
a class inherits from a parent class, it can override or extend the methods
defined in the parent class. However, sometimes you might want to use the
parent class method in the child class. This is where the super() keyword comes
in handy.
Here's
an example of how to use the super() keyword in a simple inheritance scenario:
classParentClass:
def
parent_method(
self
):
print("This is the parent method.")
classChildClass(
ParentClass
):
def
child_method(
self
):
print("This is the child method.")
super().
parent_method
()
child_object
=ChildClass
()
child_object
.child_method
()
Output:
This
isthe child method
.
This
isthe parent method
.
In
this example, we have a ParentClass with a parent_method and a ChildClass that
inherits from ParentClass and overrides the child_method. When the child_method
is called, it first prints "This is the child method." and then calls
the parent_method using the super() keyword.
The
super() keyword is also useful when a class inherits from multiple parent
classes. In this case, you can specify the parent class from which you want to
call the method.
Example:
classParentClass1:
def
parent_method(
self
):
print("This is the parent method of ParentClass1.")
classParentClass2:
def
parent_method(
self
):
print("This is the parent method of ParentClass2.")
classChildClass(
ParentClass1
,ParentClass2
):
def
child_method(
self
):
print("This is the child method.")
super().
parent_method
()
child_object
=ChildClass
()
child_object
.child_method
()
Output:
This
isthe child method
.
This
isthe parent method of ParentClass1
.
In
this example, the ChildClass inherits from both ParentClass1 and ParentClass2.
The child_method calls the parent_method of the first parent class using the
super() keyword.
In
conclusion, the super() keyword is a useful tool in Python when you want to
call a parent class method in a child class. It can be used in inheritance
scenarios with a single parent class or multiple parent classes.
Magic/Dunder
Methods in Python
These
are special methods that you can define in your classes, and when invoked, they
give you a powerful way to manipulate objects and their behaviour.
Magic
methods, also known as “dunders” from the double underscores surrounding their
names, are powerful tools that allow you to customize the behaviour of your
classes. They are used to implement special methods such as the addition,
subtraction and comparison operators, as well as some more advanced techniques
like descriptors and properties.
Let’s
take a look at some of the most commonly used magic methods in Python.
·
__init__ method:
The init method is a special method
that is automatically invoked when you create a new instance of a class. This
method is responsible for setting up the object’s initial state, and it is
where you would typically define any instance variables that you need. Also
called "constructor", we have discussed this method already.
·
__str__ and __repr__ methods:
The str and repr methods are both used
to convert an object to a string representation. The str method is used when
you want to print out an object, while the repr method is used when you want
to get a string representation of an object that can be used to recreate the
object.
·
__len__ method:
The len method is used to get the length
of an object. This is useful when you want to be able to find the size of a
data structure, such as a list or dictionary.
·
__call__ method:
The call method is used to make an object callable,
meaning that you can pass it as a parameter to a function and it will be
executed when the function is called. This is an incredibly powerful tool that
allows you to create objects that behave like functions.
These
are just a few of the many magic methods available in
Python. They are
incredibly powerful tools that allow you to customize the behaviour of your objects, and can make your code much cleaner and easier to understand. So if you’re looking for a way to take
your Python code to the
next level, take some
time to learn about these magic methods.
Method
Overriding in Python
Method
overriding is a powerful feature in object-oriented programming that allows you
to redefine a method in a derived class. The method in the derived class is
said to override the method in the base class. When you create an instance of
the derived class and call the overridden method, the version of the method in
the derived class is executed, rather than the version in the base class.
In
Python, method overriding is a way to customize the behavior of a class based
on its specific needs. For example, consider the following base class:
classShape:
def
area(
self
):
pass
In
this base class, the area method is defined, but does not have any implementation.
If you want to create a derived class that represents a circle, you can
override the area method and provide an implementation that calculates the area
of a circle.
classCircle(
Shape
):
def
__init__(
self
,radius
):
self
.radius
=radius
def
area(
self
):
return
3.14
*
self
.radius
*self
.radius
In
this example, the Circle class inherits from the Shape class, and overrides the
area method. The new implementation of the area method calculates the area of a
circle, based on its radius.
It's
important to note that when you override a method, the new implementation must
have the same method signature as the original method. This means that the
number and type of arguments, as well as the return type, must be the same.
Another
way to customize the behavior of a class is to call the base class method from
the derived class method. To do this, you can use the super function. The super
function allows you to call the base class method from the derived class
method, and can be useful when you want to extend the behavior of the base
class method, rather than replace it.
For
example, consider the following base class:
classShape:
def
area(
self
):
print("Calculating area...")
In
this base class, the area method prints a message indicating that the area is
being calculated. If you want to create a derived class that represents a
circle, and you also want to print a message indicating the type of shape, you
can use the super function to call the base class method, and add your own
message:
classCircle(
Shape
):
def
__init__(
self
,radius
):
self
.radius
=radius
def
area(
self
):
print("Calculating area of a circle...")
super().
area
()
return
3.14
*
self
.radius
*self
.radius
In
this example, the Circle class overrides the area method, and calls the base
class method using the super function. This allows you to extend the behavior
of the base class method, while still maintaining its original behavior.
In
conclusion, method overriding is a powerful feature in Python that allows you
to customize the behavior of a class based on its specific needs. By using
method overriding, you can create more robust and reliable code, and ensure
that your classes behave in the way that you need them to. Additionally, by
using the super function, you can extend the behavior of a base class method,
rather than replace it, giving you even greater flexibility and control over
the behavior of your classes.
Exercise
8 - Merge the PDF
Write a
program to manipulate pdf files using pyPDF. Your programs should be able to
merge multiple pdf files into a single pdf. You are welcome to add more
functionalities
pypdf is a
free and open-source pure-python PDF library capable of splitting, merging,
cropping, and transforming the pages of PDF files. It can also add custom data,
viewing options, and passwords to PDF files. pypdf can retrieve text and
metadata from PDFs as well.
Operator
Overloading in Python
An
Introduction:
Operator Overloading is a feature in Python that allows
developers to redefine the behavior of mathematical and comparison operators
for custom data types. This means that you can use the standard mathematical
operators (+, -, *, /, etc.) and comparison operators (>, <, ==, etc.) in
your own classes, just as you would for built-in data types like int, float,
and str.
Why do we need operator overloading?
Operator overloading allows you to create more readable
and intuitive code. For instance, consider a custom class that represents a
point in 2D space. You could define a method called 'add' to add two points
together, but using the + operator makes the code more concise and readable:
p1
=Point
(1,2)
p2
=Point
(3,4)
p3
=p1
+p2
print(p3
.x
,p3
.y
)# prints 4, 6
How to overload an operator in Python?
You can overload an operator in Python by defining
special methods in your class. These methods are identified by their names,
which start and end with double underscores (__). Here are some of the most
commonly overloaded operators and their corresponding special methods:
+:
__add__
-:
__sub__
*:
__mul__
/:
__truediv__
<:
__lt__
>:
__gt__
==:
__eq__
For example, if you want to overload the + operator to
add two instances of a custom class, you would define the add method:
classPoint:
def
__init__(
self
,x
,y
):
self
.x
=x
self
.y
=y
def
__add__(
self
,other
):
return
Point
(self
.x
+other
.x
,self
.y
+other
.y
)
Example:
class Vector:
def __init__(self, i, j, k):
self.i = i
self.j = j
self.k = k
def __str__(self):
return f"{self.i}i + {self.j}j + {self.k}k"
def __add__(self, x):
return Vector(self.i + x.i, self.j+x.j, self.k+x.k)
v1 = Vector(3, 5, 6)
print(v1)
v2 = Vector(1, 2, 9)
print(v2)
print(v1 + v2)
print(type(v1 + v2))
It's important to note that operator overloading is not
limited to the built-in operators, you can overload any user-defined operator
as well.
Conclusion
Operator overloading is a powerful feature in Python
that allows you to create more readable and intuitive code. By redefining the
behavior of mathematical and comparison operators for custom data types, you
can write code that is both concise and expressive. However, it's important to
use operator overloading wisely, as overloading the wrong operator or using it
inappropriately can lead to confusing or unexpected behavior.
Single
Inheritance in Python
Single inheritance is a type of inheritance where a
class inherits properties and behaviors from a single parent class. This is the
simplest and most common form of inheritance.
Syntax
The syntax for single inheritance in Python is
straightforward and easy to understand. To create a new class that inherits
from a parent class, simply specify the parent class in the class definition,
inside the parentheses, like this:
classChildClass(
ParentClass
):
# class body
Example:
Let's consider a simple example of single inheritance
in Python. Consider a class named "Animal" that contains the
attributes and behaviors that are common to all animals.
classAnimal:
def
__init__(
self
,name
,species
):
self
.name
=name
self
.species
=species
def
make_sound(
self
):
print("Sound made by the animal")
If we want to create a new class for a specific type of
animal, such as a dog, we can create a new class named "Dog" that
inherits from the Animal class.
classDog(
Animal
):
def
__init__(
self
,name
,breed
):
Animal
.__init__
(self
,name
,species
="Dog")
self
.breed
=breed
def
make_sound(
self
):
print("Bark!")
The Dog class inherits all the attributes and behaviors
of the Animal class, including the __init__
method and the make_sound
method.
Additionally, the Dog class has its own __init__
method
that adds a new attribute for the breed of the dog, and it also overrides
the make_sound
method to specify the sound that a dog makes.
Single inheritance is a powerful tool in Python that
allows you to create new classes based on existing classes. It allows you to
reuse code, extend it to fit your needs, and make it easier to manage complex
systems. Understanding single inheritance is an important step in becoming
proficient in object-oriented programming in Python.
Multiple
Inheritance in Python
Multiple inheritance is a powerful feature in
object-oriented programming that allows a class to inherit attributes and
methods from multiple parent classes. This can be useful in situations where a
class needs to inherit functionality from multiple sources.
Syntax
In Python, multiple inheritance is implemented by
specifying multiple parent classes in the class definition, separated by
commas.
classChildClass(
ParentClass1
,ParentClass2
,ParentClass3
):
# class body
In this example, the ChildClass
inherits
attributes and methods from all three parent classes: ParentClass1
, ParentClass2
,
and ParentClass3
.
It's important to note that, in case of multiple
inheritance, Python follows a method resolution order (MRO)
to resolve conflicts
between methods or attributes from different parent classes. The MRO determines
the order in which parent classes are searched for attributes and methods.
Example:
classAnimal:
def
__init__(
self
,name
,species
):
self
.name
=name
self
.species
=species
def
make_sound(
self
):
print("Sound made by the animal")
classMammal:
def
__init__(
self
,name
,fur_color
):
self
.name
=name
self
.fur_color
=fur_color
classDog(
Animal
,Mammal
):
def
__init__(
self
,name
,breed
,fur_color
):
Animal
.__init__
(self
,name
,species
="Dog")
Mammal
.__init__
(self
,name
,fur_color
)
self
.breed
=breed
def
make_sound(
self
):
print("Bark!")
In this example, the Dog
class
inherits from both the Animal
and Mammal
classes, so it can use
attributes and methods from both parent classes.
Multilevel
Inheritance in Python
Multilevel inheritance is a type of inheritance in
object-oriented programming where a derived class inherits from another derived
class. This type of inheritance allows you to build a hierarchy of classes
where one class builds upon another, leading to a more specialized class.
In Python, multilevel inheritance is achieved by using
the class hierarchy. The syntax for multilevel inheritance is quite simple and
follows the same syntax as single inheritance.
Syntax
classBaseClass:
# Base class code
classDerivedClass1(
BaseClass
):
# Derived class 1 code
classDerivedClass2(
DerivedClass1
):
# Derived class 2 code
In the above example, we have three classes: BaseClass
, DerivedClass1
,
and DerivedClass2
. The DerivedClass1
class
inherits from the BaseClass
, and the DerivedClass2
class
inherits from the DerivedClass1
class. This creates a
hierarchy where DerivedClass2
has access to all the
attributes and methods of both DerivedClass1
and BaseClass
.
Example
Let's take a look at an example to understand how
multilevel inheritance works in Python. Consider the following classes:
classAnimal:
def
__init__(
self
,name
,species
):
self
.name
=name
self
.species
=species
def
show_details(
self
):
print(f"Name: {self.name}")
print(f"Species: {self.species}")
classDog(
Animal
):
def
__init__(
self
,name
,breed
):
Animal
.__init__
(self
,name
,species
="Dog")
self
.breed
=breed
def
show_details(
self
):
Animal
.show_details
(self
)
print(f"Breed: {self.breed}")
classGoldenRetriever(
Dog
):
def
__init__(
self
,name
,color
):
Dog
.__init__
(self
,name
,breed
="Golden Retriever")
self
.color
=color
def
show_details(
self
):
Dog
.show_details
(self
)
print(f"Color: {self.color}")
In this example, we have three classes: Animal
, Dog
,
and GoldenRetriever
. The Dog
class
inherits from the Animal
class, and the GoldenRetriever
class
inherits from the Dog
class.
Now, when we create an object of the GoldenRetriever
class,
it has access to all the attributes and methods of the Animal
class
and the Dog
class. We can also see that the GoldenRetriever
class
has its own attributes and methods that are specific to the class.
dog
=GoldenRetriever
("Max","Golden")
dog
.show_details
()
Output:
Name
:Max
Species
:Dog
Breed
:Golden Retriever
Color
:Golden
As we can see from the output, the GoldenRetriever
object
has access to all the attributes and methods of the Animal
and Dog
classes,
and, it has also added its own unique attributes and methods. This is a
powerful feature of multilevel inheritance, as it allows you to create more
complex and intricate classes by building upon existing ones.
Another important aspect of multilevel inheritance is
that it allows you to reuse code and avoid repeating the same logic multiple
times. This can lead to better maintainability and readability of your code, as
you can abstract away complex logic into base classes and build upon them.
In conclusion, multilevel inheritance is a powerful
feature in object-oriented programming that allows you to create complex and
intricate classes by building upon existing ones. It provides the benefits of
code reuse, maintainability, and readability, while also requiring careful
consideration to avoid potential problems.
Hybrid
Inheritance in Python
Hybrid inheritance is a combination of multiple
inheritance and single inheritance in object-oriented programming. It is a type
of inheritance in which multiple inheritance is used to inherit the properties
of multiple base classes into a single derived class, and single inheritance is
used to inherit the properties of the derived class into a sub-derived class.
In Python, hybrid inheritance can be implemented by
creating a class hierarchy, in which a base class is inherited by multiple
derived classes, and one of the derived classes is further inherited by a
sub-derived class.
Syntax
The syntax for implementing Hybrid Inheritance in
Python is the same as for implementing Single Inheritance, Multiple
Inheritance, or Hierarchical Inheritance.
Here's the syntax for defining a hybrid inheritance
class hierarchy:
classBaseClass1:
# attributes and methods
classBaseClass2:
# attributes and methods
classDerivedClass(
BaseClass1
,BaseClass2
):
# attributes and methods
Example
Consider the example of a Student
class
that inherits from the Person
class, which in turn inherits from the Human
class.
The Student
class also has a Program
class
that it is associated with.
classHuman:
def
__init__(
self
,name
,age
):
self
.name
=name
self
.age
=age
def
show_details(
self
):
print("Name:",
self
.name
)
print("Age:",
self
.age
)
classPerson(
Human
):
def
__init__(
self
,name
,age
,address
):
Human
.__init__
(self
,name
,age
)
self
.address
=address
def
show_details(
self
):
Human
.show_details
(self
)
print("Address:",
self
.address
)
classProgram:
def
__init__(
self
,program_name
,duration
):
self
.program_name
=program_name
self
.duration
=duration
def
show_details(
self
):
print("Program Name:",
self
.program_name
)
print("Duration:",
self
.duration
)
classStudent(
Person
):
def
__init__(
self
,name
,age
,address
,program
):
Person
.__init__
(self
,name
,age
,address
)
self
.program
=program
def
show_details(
self
):
Person
.show_details
(self
)
self
.program
.show_details
()
In this example, the Student
class
inherits from the Person
class, which in turn inherits from the Human
class.
The Student
class also has an association with the Program
class.
This is an example of Hybrid Inheritance
in action, as it uses both
Single Inheritance and Association to achieve the desired inheritance
structure.
To create a Student
object, we can do the
following:
program
=Program
("Computer Science",4)
student
=Student
("John Doe",25,
"123 Main St.",
program
)
student
.show_details
()
Output
Name
:John Doe
Age
:25
Address
:123
Main St
.
Program Name
:Computer Science
Duration
:4
As we can see from the output, the Student
object
has access to all the attributes and methods of the Person
and Human
classes,
as well as the Program
class through association.
In this way, hybrid inheritance allows for a flexible
and powerful way to inherit attributes and behaviors from multiple classes in a
hierarchy or chain.
Exercise-9 Shoutout to everyone
Write a program to pronounce list of names using win32 API. If
you are given a list l as follows:
l = ["Rahul", "Nishant", "Harry"]
Your program should pronouce:
Shoutout to Rahul
Shoutout to Nishant
Shoutout to Harry
Note: If you are not using windows, try to figure out how to do
the same thing using some other package.
The
time Module in Python
The time
module in Python provides a set of
functions to work with time-related operations, such as timekeeping,
formatting, and time conversions. This module is part of the Python Standard
Library and is available in all Python installations, making it a convenient
and essential tool for a wide range of applications.
1. time.time(): The time.time()
function
returns the current time as a floating-point number, representing the number of
seconds since the epoch (the point in time when the time module was
initialized). The returned value is based on the computer's system clock and is
affected by time adjustments made by the operating system, such as daylight
saving time.
Example:
import time
print(time
.time
())
# Output: 1602299933.233374
As you can see, the function returns the current time as a
floating-point number, which can be used for various purposes, such as
measuring the duration of an operation or the elapsed time since a certain
point in time.
2. time.sleep():
The time.sleep()
function suspends the execution of the current thread
for a specified number of seconds. This function can be used to pause the
program for a certain period of time, allowing other parts of the program to
run, or to synchronize the execution of multiple threads.
Example:
import time
print("Start:",time
.time
())
time
.sleep
(2)
print("End:",time
.time
())
# Output:
# Start: 1602299933.233374
# End: 1602299935.233376
As
you can see, the function time.sleep()
suspends the execution of the program for 2 seconds,
allowing other parts of the program to run during that time.
3. time.strftime(): The time.strftime()
function
formats a time value as a string, based on a specified format. This function is
particularly useful for formatting dates and times in a human-readable format,
such as for display in a GUI, a log file, or a report.
Example:
import time
t
=time
.localtime
()
formatted_time
=time
.strftime
("%Y-%m-%d %H:%M:%S",t
)
print(formatted_time
)
# Output: 2022-11-08 08:45:33
As
you can see, the function time.strftime()
formats the current time (obtained using time.localtime()
) as a string, using a specified format.
The format string contains codes that represent different parts of the time
value, such as the year, the month, the day, the hour, the minute, and the
second.
·
Conclusion
The time
module in Python provides a set of
functions to work with time-related operations, such as timekeeping,
formatting, and time
conversions.
Whether you are writing a script, a library, or an application, the time
module is a powerful tool that can
help you perform time-related tasks with ease and efficiency. So, if you
haven't already, be sure to check out the time module in Python and see how it
can help you write better, more efficient code.
Creating
Command Line Utilities in Python
Command line utilities are programs that can be run
from the terminal or command line interface, and they are an essential part of
many development workflows. In Python, you can create your own command line
utilities using the built-in argparse
module.
Syntax: Here
is the basic syntax for creating a command line utility using argparse
in Python.
import argparse
parser
=argparse
.ArgumentParser
()
# Add command line arguments
parser
.add_argument
("arg1",help="description of argument 1")
parser
.add_argument
("arg2",help="description of argument 2")
# Parse the arguments
args
=parser
.parse_args
()
# Use the arguments in your code
print(args
.arg1
)
print(args
.arg2
)
·
Examples: Here are a few examples to help you get started
with creating command line utilities in Python.
1.
Adding optional arguments: The
following example shows how to add an optional argument to your command line
utility:
import argparse
parser
=argparse
.ArgumentParser
()
parser
.add_argument
("-o","--optional",
help="description of optional argument",
default
="default_value")
args
=parser
.parse_args
()
print(args
.optional
)
2.
Adding positional arguments: The
following example shows how to add a positional argument to your command line
utility:
import argparse
parser
=argparse
.ArgumentParser
()
parser
.add_argument
("positional",help="description of positional argument")
args
=parser
.parse_args
()
print(args
.positional
)
3.
Adding arguments with type: The
following example shows how to add an argument with a specified type:
import argparse
parser
=argparse
.ArgumentParser
()
parser
.add_argument
("-n",type=int,
help="description of integer argument")
args
=parser
.parse_args
()
print(args
.n
)
Video Example:
import argparse
import requests
def download_file(url, local_filename):
if local_filename is None:
local_filename = url.split('/')[-1]
# NOTE the stream=True parameter below
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(local_filename, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
# If you have chunk encoded response uncomment if
# and set chunk_size parameter to None.
#if chunk:
f.write(chunk)
return local_filename
parser = argparse.ArgumentParser()
# Add command line arguments
parser.add_argument("url", help="Url of the file to download")
# parser.add_argument("output", help="by which name do you want to save your file")
parser.add_argument("-o", "--output", type=str, help="Name of the file", default=None)
# Parse the arguments
args = parser.parse_args()
# Use the arguments in your code
print(args.url)
print(args.output, type(args.output))
download_file(args.url, args.output)
·
Conclusion
Creating command line utilities in Python is a
straightforward and flexible process thanks to the argparse
module.
With a few lines of code, you can create powerful and customizable command line
tools that can make your development workflow easier and more efficient.
Whether you're working on small scripts or large applications, the argparse
module
is a must-have tool for any Python developer.
The
Walrus Operator in Python
The Walrus Operator is a new addition to Python 3.8 and
allows you to assign a value to a variable within an expression. This can be
useful when you need to use a value multiple times in a loop, but don't want to
repeat the calculation.
The Walrus Operator is represented by the :=
syntax
and can be used in a variety of contexts including while loops and if
statements.
Here's an example of how you can use the Walrus
Operator in a while loop:
numbers
=[1,
2,
3,
4,
5]
while(
n
:=len(
numbers
))>
0:
print(
numbers
.pop
())
In this example, the length of the numbers
list
is assigned to the variable n using the Walrus Operator. The value of n
is
then used in the condition of the while loop, so that the loop will continue to
execute until the numbers
list is empty.
Another example of using the Walrus Operator in an if
statement:
names
=["John",
"Jane",
"Jim"]
if(
name
:=input("Enter a name: "))
in
names
:
print(f"Hello, {name}!")
else:
print("Name not found.")
Here is another example
# walrus operator :=
# new to Python 3.8
# assignment expression aka walrus operator
# assigns values to variables as part of a larger expression
# happy = True
# print(happy)
# print(happy := True)
# foods = list()
# while True:
# food = input("What food do you like?: ")
# if food == "quit":
# break
# foods.append(food)
foods
=list()
while(
food
:=input("What food do you like?: "))
!=
"quit":
foods
.append
(food
)
In this example, the user input is assigned to the
variable name
using the Walrus Operator. The value of name
is
then used in the if statement to determine whether it is in the names list. If
it is, the corresponding message is printed, otherwise, a different message is
printed.
It is important to note that the Walrus Operator
should be used sparingly as it can make code less readable if overused.
In conclusion, the Walrus Operator is a useful tool for
Python developers to have in their toolkit. It can help streamline code and
reduce duplication, but it should be used with care to ensure code readability
and maintainability.
Shutil
Module in Python
Shutil is a Python module that provides a higher level
interface for working with file and directories. The name "shutil" is
short for shell utility. It provides a convenient and efficient way to automate
tasks that are commonly performed on files and directories.
·
Importing shutil:
importshutil
·
Functions: The following are some of the most commonly
used functions in the shutil module.
1.
shutil.copy(src, dst)
: This
function copies the file located at src to a new location specified by dst. If
the destination location already exists, the original file will be overwritten.
2.
shutil.copy2(src, dst)
: This function is similar to
shutil.copy, but it also preserves more metadata about the original file, such
as the timestamp.
3.
shutil.copytree(src, dst)
: This function recursively
copies the directory located at src to a new location specified by dst. If the
destination location already exists, the original directory will be merged with
it.
4.
shutil.move(src, dst)
: This function moves the file
located at src to a new location specified by dst. This function is equivalent
to renaming a file in most cases.
5.
shutil.rmtree(path)
: This function recursively
deletes the directory located at path, along with all of its contents. This
function is similar to using the rm -rf command in a shell.
Examples:
import shutil
# Copying a file
shutil
.copy
("src.txt","dst.txt")
# Copying a directory
shutil
.copytree
("src_dir","dst_dir")
# Moving a file
shutil
.move
("src.txt","dst.txt")
# Deleting a directory
shutil
.rmtree
("dir")
As you can see, the shutil module provides a simple and
efficient way to perform common file and directory-related tasks in Python.
Whether you need to copy, move, delete, or preserve metadata about files and
directories, the shutil module has you covered.
In conclusion, the shutil module is a powerful tool for
automating file and directory-related tasks in Python. Whether you are a
beginner or an experienced Python developer, the shutil module is an essential
tool to have in your toolbox.
Requests
module in python
The Python Requests module is an HTTP library that
enables developers to send HTTP requests in Python. This module enables you to
send HTTP requests using Python code and makes it possible to interact with
APIs and web services.
Installation
pip install requests
1. Get Request: Once you
have installed the Requests module, you can start using it to send HTTP
requests. Here is a simple example that sends a GET request to the Google
homepage.
import requests
response
=requests
.get
("https://www.google.com")
print(response
.text
)
2. Post Request: Here is
another example that sends a POST request to a web service and includes a
custom header.
import requests
url
="https://api.example.com/login"
headers
={
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36",
"Content-Type":
"application/json"
}
data
={
"username":
"myusername",
"password":
"mypassword"
}
response
=requests
.post
(url
,headers
=headers
,json
=data
)
print(response
.text
)
In this example, we send a POST request to a web
service to authenticate a user. We include a custom User-Agent header and a
JSON payload with the user's credentials.
·
bs4 Module
There is another module called BeautifulSoup which is
used for web scraping in Python. (used in freelancing task).
import requests
from bs4 import
BeautifulSoup
url =
"https://www.codewithharry.com/blogpost/django-cheatsheet/"
r =
requests.get(url)
# print(r.text)
soup =
BeautifulSoup(r.text, 'html.parser')
print(soup.prettify())
for heading
in soup.find_all("h2"):
print(heading.text)
Exerise-10(Fetch
daily News)
Use the NewsAPI and
the requests module to fetch the daily news related to different topics. Go
to: https://newsapi.org/ and explore the various options to build you
application
Generators
in Python
Generators
in Python are special type of functions that allow you to create an iterable
sequence of values. A generator function returns a generator object, which can
be used to generate the values one-by-one as you iterate over it. Generators
are a powerful tool for working with large or complex data sets, as they allow
you to generate the values on-the-fly, rather than having to create and store
the entire sequence in memory.
·
Creating a Generator
In
Python, you can create a generator by using the yield
statement in a function. The yield
statement returns a value from the
generator and suspends the execution of the function until the next value is
requested.
Example:
defmy_generator():
for
i
inrange(5):
yield
i
gen
=my_generator
()
print(next(gen
))
print(next(gen
))
print(next(gen
))
print(next(gen
))
print(next(gen
))
# Output:
# 0
# 1
# 2
# 3
# 4
As
you can see, the generator function my_generator()
returns a generator object, which
can be used to generate the values in the range 0 to 4. The next()
function is used to request the
next value from the generator, and the generator resumes its execution until it
encounters another yield
statement
or until it reaches the end of the function.
·
Using a Generator
Once
you have created a generator, you can use it in a variety of ways, such as in a
for loop, a list comprehension, or a generator expression. Here's an example:
gen
=my_generator
()
fori
ingen
:
print(
i
)
# Output:
# 0
# 1
# 2
# 3
# 4
As
you can see, the generator can be used in a for loop, just like any other
iterable sequence. The generator is used to generate the values one-by-one as
the loop iterates over it.
·
Benefits of Generators
Generators
offer several benefits over other types of sequences, such as lists, tuples,
and sets. One of the main benefits of generators is that they allow you to
generate the values on-the-fly, rather than having to create and store the
entire sequence in memory. This makes generators a powerful tool for working
with large or complex data sets, as you can generate the values as you need
them, rather than having to store them all in memory at once.
Another
benefit of generators is that they are lazy, which means that the values are
generated only when they are requested. This allows you to generate the values
in a more efficient and memory-friendly manner, as you don't have to generate
all the values up front.
Conclusion
Generators
in Python are a powerful tool for working with large or complex data sets,
allowing you to generate the values on-the-fly and store only what you need in
memory. Whether you are working with a large dataset, performing complex
calculations, or generating a sequence of values, generators are a must-have
tool in your programming toolkit. So, if you haven't already, be sure to check
out generators in Python and see how they can help you write better, more
efficient code.
Function
Caching in Python
Function caching is a technique for improving the
performance of a program by storing the results of a function call so that you
can reuse the results instead of recomputing them every time the function is
called. This can be particularly useful when a function is computationally
expensive, or when the inputs to the function are unlikely to change
frequently.
In Python, function caching can be achieved using the
functools.lru_cache decorator. The functools.lru_cache decorator is used to
cache the results of a function so that you can reuse the results instead of
recomputing them every time the function is called.
Example:
import functools
@functools.lru_cache(maxsize
=None)
deffib(
n
):
if
n
<2:
return
n
return
fib
(n
-1)+
fib
(n
-2)
print(fib
(20))
# Output: 6765
As you can see, the functools.lru_cache
decorator
is used to cache the results of the fib
function.
The maxsize
parameter is used to specify the maximum number
of results to cache. If maxsize
is set to None
, the
cache will have an unlimited size.
from functools import lru_cache
import time
@lru_cache(maxsize=None)
def fx(n):
time.sleep(5)
return n*5
print(fx(20))
print("done
for 20")
print(fx(2))
print("done
for 2")
print(fx(6))
print("done
for 6")
print(fx(20))
print("done
for 20")
print(fx(2))
print("done
for 2")
print(fx(6))
print("done
for 6")
print(fx(61))
print("done
for 61")
# Output:
6765
·
Benefits of Function Caching
Function caching can have a significant impact on the
performance of a program, particularly for computationally expensive functions.
By caching the results of a function, you can avoid having to recompute the
results every time the function is called, which can save a significant amount
of time and computational resources.
Another benefit of function caching is that it can
simplify the code of a program by removing the need to manually cache the
results of a function. With the functools.lru_cache
decorator, the caching is
handled automatically, so you can focus on writing the core logic of your
program.
Conclusion
Function caching is a technique for improving the
performance of a program by storing the results of a function so that you can
reuse the results instead of recomputing them every time the function is
called. In Python 3, function caching can be achieved using the functools.lru_cache
decorator,
which provides an easy and efficient way to cache the results of a function.
Whether you're writing a computationally expensive program, or just want to
simplify your code, function caching is a great technique to have in your
toolbox.
Exercise
11 - Drink Water Reminder
Write a python program which reminds you of drinking
water every hour or two. Your program can either beep or send desktop
notifications for a specific operating system.
Regular
Expressions in Python
Regular expressions, or "regex" for short,
are a powerful tool for working with strings and text data in Python. They
allow you to match and manipulate strings based on patterns, making it easy to
perform complex string operations with just a few lines of code.
Meta characters in regular expressions
[]Represent a character
class
^ Matches the beginning
$ Matches the end
.Matches
anycharacter
exceptnewline
? Matches zero
orone occurrence
.
|Means OR
(Matches
withany
of the characters
separated by it
.
*Any number of occurrences
(including
0occurrences
)
+One
ormore occurrences
{} Indicate number of occurrences of a preceding RE
to
match.
()Enclose a group of REs
Find list of more meta characters here - https://www.ibm.com/docs/en/rational-clearquest/9.0.1?topic=tags-meta-characters-in-regular-expressions
·
Importing re Package
In Python, regular expressions are supported by
the re
module. The basic syntax for working with regular
expressions in Python is as follows:
importre
·
Searching for a pattern in re
using re.search() Method
re.search() method either returns None (if the pattern
doesn’t match), or a re.MatchObject that contains information about the
matching part of the string. This method stops after the first match, so this
is best suited for testing a regular expression more than extracting data. We
can use re.search method like this to search for a pattern in regular
expression:
# Define a regular expression pattern
pattern
=r"expression"
# Match the pattern against a string
text
="Hello, world!"
match=
re
.search
(pattern
,text
)
ifmatch:
print("Match found!")
else:
print("Match not found.")
·
Searching for a pattern in re
using re.findall() Method
You can also use the re.findall
function
to find all occurrences of the pattern in a string:
import re
pattern
=r"expression"
text
="The cat is in the hat."
matches
=re
.findall
(pattern
,text
)
print(matches
)
# Output: ['cat', 'hat']
· Replacing
a pattern: The following example shows how to replace a pattern in a string:
import re
pattern
=r"[a-z]+at"
text
="The cat is in the hat."
matches
=re
.findall
(pattern
,text
)
print(matches
)
# Output: ['cat', 'hat']
new_text
=re
.sub
(pattern
,"dog",
text
)
print(new_text
)
# Output: "The dog is in the dog."
· Extracting
information from a string: The following example shows how to
extract information from a string using regular expressions:
import re
text
="The email address is example@example.com."
pattern
=r"\w+@\w+\.\w+"
match=
re
.search
(pattern
,text
)
ifmatch:
match.
group
()
print(
# Output: example@example.com
Video
code:
pattern =
r"[A-Z]+yclodne"
text =
'''Cyclone Dumazile was a strong tropical cyclone in the South-West Indian
Ocean that affected Madagascar and Réunion in early March 2018. Dumazile
originated from a cyclone Dyclone low-pressure area that formed near Agaléga on
27 February. It became a tropical disturbance on 2 March, and was named the
next day after attaining tropical storm status. Dumazile reached its peak
intensity on 5 March, with 10-minute sustained winds of 165 km/h (105 mph),
1-minute sustained winds of 205 km/h (125 mph), and a central atmospheric
pressure of 945 hPa (27.91 inHg). As it tracked southeastwards, Dumazile
weakened steadily over the next couple of days due to wind shear, and became a
post-tropical cyclone on 7 March'''
match =
re.search(pattern, text)
print(match)
# matches =
re.finditer(pattern, text)
# for match
in matches:
# print(match.span())
# print(text[match.span()[0]: match.span()[1]])
Conclusion
Regular expressions are a powerful tool for working
with strings and text data in Python. Whether you're matching patterns,
replacing text, or extracting information, regular expressions make it easy to
perform complex string operations with just a few lines of code. With a little
bit of practice, you'll be able to use regular expressions to solve all sorts
of string-related problems in Python.
Async
IO in Python
Asynchronous I/O, or async for short, is a programming
pattern that allows for high-performance I/O operations in a concurrent and
non-blocking manner. In Python, async programming is achieved through the use
of the asyncio
module and asynchronous functions.
Syntax: Here
is the basic syntax for creating an asynchronous function in Python.
import asyncio
asyncdef
my_async_function():
# asynchronous code here
await
asyncio
.sleep
(1)
return
"Hello, Async World!"
asyncdef
main():
result
=await
my_async_function
()
print(
result
)
asyncio
.run
(main
())
Another way to schedule tasks concurrently is as
follows:
L
=await
asyncio
.gather
(
my_async_function
(),
my_async_function
(),
my_async_function
(),
)
print(L
)
Async IO is a powerful programming pattern that allows
for high-performance and concurrent I/O operations in Python. With the asyncio
module
and asynchronous functions, you can write efficient and scalable code that can
handle large amounts of data and I/O operations without blocking the main
thread. Whether you're working on web applications, network services, or data
processing pipelines, async IO is an essential tool for any Python developer.
Video code:
import time
import asyncio
import requests
async def
function1():
print("func 1")
URL = "https://wallpaperaccess.in/public/uploads/preview/1920x1200- desktop-background-ultra-hd-wallpaper-wiki-desktop-wallpaper-4k-.jpg"
response = requests.get(URL)
open("instagram.ico",
"wb").write(response.content)
return "Name"
async def
function2():
print("func 2")
URL =
"https://p4.wallpaperbetter.com/wallpaper/490/433/199/nature-2560x1440-tree-snow-wallpaper-preview.jpg"
response = requests.get(URL)
open("instagram2.jpg",
"wb").write(response.content)
async def
function3():
print("func 3")
URL =
"https://c4.wallpaperflare.com/wallpaper/622/676/943/3d-hd-wikipedia-3d-wallpaper-preview.jpg"
response = requests.get(URL)
open("instagram3.ico",
"wb").write(response.content)
async def
main():
# await function1()
# await function2()
# await function3()
# return 3
L = await
asyncio.gather(
function1(),
function2(),
function3(),
)
print(L)
# task =
asyncio.create_task(function1())
# # await
function1()
# await
function2()
# await
function3()
asyncio.run(main())
Multithreading
in Python
Multithreading is a technique in programming that
allows multiple threads of execution to run concurrently within a single
process. In Python, we can use the threading module to implement
multithreading.
·
Importing Threading
importthreading
·
Creating a thread
To create a thread, we need to create a Thread object
and then call its start() method. The start() method runs the thread and then
to stop the execution, we use the join() method. Here's how we can create a
simple thread.
import threading
defmy_func():
print("Hello from thread",
threading
.current_thread
().name
)
thread
=threading
.Thread
(target
=my_func
)
thread
.start
()
thread
.join
()
·
Functions: The following are some of the most commonly
used functions in the threading module.
1.
threading.Thread(target, args)
: This
function creates a new thread that runs the target function with the specified
arguments.
2.
threading.Lock()
: This
function creates a lock that can be used to synchronize access to shared
resources between threads.
·
Creating multiple threads: Creating multiple threads is a common approach
to using multithreading in Python. The idea is to create a pool of worker
threads and then assign tasks to them as needed. This allows you to take
advantage of multiple CPU cores and process tasks in parallel.
import threading
defthread_task(
task
):
# Do some work here
print("Task processed:",
task
)
if__name__
=='__main__':
tasks
=[1,
2,
3,
4,
5,
6,
7,
8,
9,
10]
threads
=[]
for
task
intasks
:
thread
=threading
.Thread
(target
=thread_task
,args
=(task
,))
threads
.append
(thread
)
thread
.start
()
for
thread
inthreads
:
thread
.join
()
·
Using a lock to synchronize access
to shared resources
When working with multithreading in python, locks can
be used to synchronize access to shared resources among multiple threads. A
lock is an object that acts as a semaphore, allowing only one thread at a time
to execute a critical section of code. The lock is released when the thread
finishes executing the critical section.
import threading
defincrement(
counter
,lock
):
for
i
inrange(10000):
lock
.acquire
()
counter
+=1
lock
.release
()
if__name__
=='__main__':
counter
=0
lock
=threading
.Lock
()
threads
=[]
for
i
inrange(2):
thread
=threading
.Thread
(target
=increment
,args
=(counter
,lock
))
threads
.append
(thread
)
thread
.start
()
for
thread
inthreads
:
thread
.join
()
print("Counter value:",
counter
)
Video code:
import threading
import time
from
concurrent.futures import ThreadPoolExecutor
# Indicates
some task being done
def
func(seconds):
print(f"Sleeping
for {seconds} seconds")
time.sleep(seconds)
return
seconds
def main():
time1 =
time.perf_counter()
# Normal
Code
# func(4)
# func(2)
# func(1)
# Same code
using Threads
t1 =
threading.Thread(target=func, args=[4])
t2 =
threading.Thread(target=func, args=[2])
t3 =
threading.Thread(target=func, args=[1])
t1.start()
t2.start()
t3.start()
t1.join()
t2.join()
t3.join()
#
Calculating Time
time2 =
time.perf_counter()
print(time2
- time1)
def
poolingDemo():
with
ThreadPoolExecutor() as executor:
# future1 =
executor.submit(func, 3)
# future2 =
executor.submit(func, 2)
# future3 =
executor.submit(func, 4)
# print(future1.result())
# print(future2.result())
# print(future3.result())
l = [3, 5,
1, 2]
results =
executor.map(func, l)
for result
in results:
print(result)
poolingDemo()
Conclusion
As you can see, the threading module provides a simple
and efficient way to implement multithreading in Python. Whether you need to
create a new thread, run a function across multiple input values, or
synchronize access to shared resources, the threading module has you covered.
In conclusion, the threading module is a powerful tool
for parallelizing code in Python. Whether you are a beginner or an experienced
Python developer, the threading module is an essential tool to have in your
toolbox. With multithreading, you can take advantage of multiple CPU cores and
significantly improve the performance of your code.
MultiProcessing
in Python
Multiprocessing is a Python module that provides a
simple way to run multiple processes in parallel. It allows you to take
advantage of multiple cores or processors on your system and can significantly
improve the performance of your code.
·
Importing Multiprocessing
importmultiprocessing
Now, to use multiprocessing we need to create a process object
which
calls a start()
method. The start() method runs the process and
then to stop the execution, we use the join()
method.
Here's how we can create a simple process.
·
Creating a process
import multiprocessing
defmy_func():
print("Hello from process",
multiprocessing
.current_process
().name
)
process
=multiprocessing
.Process
(target
=my_func
)
process
.start
()
process
.join
()
·
Functions: The following are some of the most commonly
used functions in the multiprocessing module.
1. multiprocessing.Process(target,
args)
: This function creates a new process that runs the
target function with the specified arguments.
2. multiprocessing.Pool(processes)
: This
function creates a pool of worker processes that can be used to parallelize the
execution of a function across multiple input values.
3. multiprocessing.Queue()
: This
function creates a queue that can be used to communicate data between
processes.
4. multiprocessing.Lock()
: This
function creates a lock that can be used to synchronize access to shared
resources between processes.
·
Creating a pool of worker
processes
Creating a pool of worker processes is a common
approach to using multiprocessing in Python. The idea is to create a pool of
worker processes and then assign tasks to them as needed. This allows you to
take advantage of multiple CPU cores and process tasks in parallel.
frommultiprocessing
importPool
defprocess_task(
task
):
# Do some work here
print("Task processed:",
task
)
if__name__
=='__main__':
tasks
=[1,
2,
3,
4,
5,
6,
7,
8,
9,
10]
with
Pool
(processes
=4)as
pool
:
results
=pool
.map(process_task
,tasks
)
·
Using a queue to communicate
between processes
When working with multiple processes, it is often
necessary to pass data between them. One way to do this is by using a queue. A queue
is a data structure that allows data to be inserted at one end and removed from
the other end. In the context of multiprocessing, a queue can be used to pass
data between processes.
defproducer(
queue
):
for
i
inrange(10):
queue
.put
(i
)
defconsumer(
queue
):
while
True:
item
=queue
.get
()
print(
item
)
queue
=multiprocessing
.Queue
()
p1
=multiprocessing
.Process
(target
=producer
,args
=(queue
,))
p2
=multiprocessing
.Process
(target
=consumer
,args
=(queue
,))
p1
.start
()
p2
.start
()
·
Using a lock to synchronize access
to shared resources
When working with multiprocessing in python, locks can
be used to synchronize access to shared resources among multiple processes. A
lock is an object that acts as a semaphore, allowing only one process at a time
to execute a critical section of code. The lock is released when the process
finishes executing the critical section.
defincrement(
counter
,lock
):
for
i
inrange(10000):
lock
.acquire
()
counter
.value
+=1
lock
.release
()
if__name__
=='__main__':
counter
=multiprocessing
.Value
('i',0)
lock
=multiprocessing
.Lock
()
p1
=multiprocessing
.Process
(target
=increment
,args
=(counter
,lock
))
p2
=multiprocessing
.Process
(target
=increment
,args
=(counter
,lock
))
p1
.start
()
p2
.start
()
p1
.join
()
p2
.join
()
print("Counter value:",
counter
.value
)
Video code:
import concurrent.futures
import requests
def
downloadFile(url, name):
print(f"Started
Downloading {name}")
response =
requests.get(url)
open(f"files/file{name}.jpg",
"wb").write(response.content)
print(f"Finished
Downloading {name}")
url =
"https://picsum.photos/2000/3000"
# pros = []
# for i in
range(50):
# #
downloadFile(url, i)
# p =
multiprocessing.Process(target=downloadFile, args=[url, i])
# p.start()
#
pros.append(p)
# for p in
pros:
# p.join()
with
concurrent.futures.ProcessPoolExecutor() as executor:
l1 = [url
for i in range(60)]
l2 = [i for
i in range(60)]
results = executor.map(downloadFile,
l1, l2)
for r in
results:
print(r)
Conclusion
As you can see, the multiprocessing module provides a
simple and efficient way to run multiple processes in parallel. Whether you
need to create a new process, run a function across multiple input values,
communicate data between processes, or synchronize access to shared resources,
the multiprocessing module has you covered.
In conclusion, the multiprocessing module is a powerful
tool for parallelizing code in Python. Whether you are a beginner or an
experienced Python developer, the multiprocessing module is an essential tool
to have in your toolbox.
#100 day: There
are many more topics to explore, including machine learning, web development,
game development, and more.
Where
to go from here:
To
continue your learning journey, consider exploring the following resources:
·
Python
books: There are many excellent books on Python that can help you deepen your
knowledge and skills. Some popular options include "Python Crash
Course" by Eric Matthes, "Automate the Boring Stuff with Python"
by Al Sweigart, and "Fluent Python" by Luciano Ramalho. I would also
like to recommend "Hands on Machine Learning book by Aurélien Géron"
·
YouTube
Projects: There are many YouTube projects available which can be watched after
you have some basic understanding of python
·
Python
communities: There are many online communities where you can connect with other
Python learners and experts, ask questions, and share your knowledge. Some
popular options include the Python subreddit, the Python Discord server, and
the Python community on Stack Overflow.
·
GitHub
repositories: GitHub is a great resource for finding Python projects,
libraries, and code snippets. Some useful repositories to check out include "awesome-python"
(a curated list of Python resources), "scikit-learn" (a machine
learning library), and "django" (a web development framework).
Link
to some resources
·
Tkinter - You can learn Tkinter which is used to create GUIs
from “https://www.cs.mcgill.ca/~hv/classes/MS/TkinterPres/#Overview”:
·
Machine Learning - I loved “https://www.youtube.com/watch?v=cKxRvEZd3Mw&list=PLOU2XLYxmsIIuiBfYad6rFYQU_jL2ryal” playlist from
Google Developers.
·
Django - For Django, try the “ https://docs.djangoproject.com/en/4.1/intro/tutorial01/” from the official
documentation. Trust me its really good.
Overall,
the key to mastering Python (or any programming language) is to keep practicing
and experimenting. Set yourself challenges, work on personal projects, and stay
curious. Good luck!
0 Comments