Python - Material Ashok IT
Python - Material Ashok IT
Course Material
Unit-1 : Python Introduction
1. Introduction to Python
2. History of Python
3. Applications of Python
4. Features of Python
5. Limitations of Python
6. Flavors of Python
7. Versions of Python
8. Python Setup
FUNDAMENTALS OF PYTHON
Introduction to Python:
In Java:
In Python:
History of Python:
The name Python was selected from the TV Show: "The Complete Monty
Python's Circus", which was broadcasted in BBC from 1969 to 1974.
Guido developed Python language by taking almost all programming features
from different languages
1. Functional Programming Features from C
2. Object Oriented Programming Features from C++
3. Scripting Language Features from Perl and Shell Script.
4. Modular Programming Features from Modula-3
Note: Most of syntax in Python Derived from C and ABC languages.
Applications of Python:
Features of Python:
We can use Python software without any license and it is freeware. Source code
is open, so that we can we can customize based on our requirement.
4. Portability:
Python programs are portable. I.e., we can migrate from one platform to another
platform very easily. Python programs will provide same results on any platform.
In Python we are not required to declare type for variables. Whenever we are
assigning the value, based on value, type will be allocated automatically. Hence Python
is considered as dynamically typed language. This feature will provide more flexibility to
the programmer.
9. Scripting Language:
Python is scripting language, because we can able to develop the scripts to test
the functionality in application in automation testing.
We can use other language programs in Python. The main advantages of this
approach are:
1. We can use already existing legacy non-Python code
2. We can improve performance of the application
Python has a rich inbuilt library. Being a programmer, we can use this library
directly and we are not responsible to implement the functionality.
Limitations of Python:
1. CPython:
2. Jython or JPython:
3. IronPython:
4. PyPy:
The main advantage of PyPy is performance will be improved because JIT compiler
is available inside PVM.
5. RubyPython
6. AnacondaPython
Versions of Python:
There are many IDEs are available to develop complex applications using Python.
Usually with only Python software, we can’t develop and build complex applications
because, the Python is interpreter dependent language.
Download PyCharm: The Python IDE for data science and web
development by JetBrains
Keywords
In Python, there are some words which reserved to represent some meaning or
functionality are called as “Reserved Words” or “Keywords”.
Identifiers
Note:
Ex: __add__
Datatypes
Data Type represent the type of data present inside a variable. In Python we are
not required to specify the type explicitly. Based on value provided, the type will be
assigned automatically. Hence Python is Dynamically Typed Language.
To get the properties of the data, there are three pre-defined methods are available in
python. Those are:
type():
It is a pre-defined method, which is used to find the type of the specified data/value.
Syntax:
type(data/value)
id():
It is a pre-defined method, which is used to get the address of the specified data/value.
Syntax:
id(data/value)
print():
Integer Datatype:
1) Decimal form
2) Binary form
3) Octal form
4) Hexadecimal form
Ex: a = 1223
Binary number is base-2 number system, means which can be represented with
allowed digits are: 0 and 1.
And the binary number system in python can always prefixed with ‘0b’ or ‘0B’.
Ex: 0b11001, 0B11000101
Octal form (base-8 number system):
Note:
In Python2 we have long data type to represent very large integral values.
But in Python3 there is no long type explicitly and we can represent long values
also by using int type only.
Being a programmer, we can specify literal values in decimal, binary, octal and
hexadecimal forms. But PVM will always provide values only in decimal form.
Base Conversions:
1. bin():
Note: Other than the integer value like: floating-point, boolean, complex etc. not
allowed for the conversion into binary.
2. oct():
Syntax:
oct(any value)
Note: Other than the integer value like: floating-point, boolean, complex etc. not
allowed for the conversion into octal.
3. hex():
It is a pre-defined/inbuilt method in python, which is used to convert any integer
value into hexadecimal value.
Syntax:
hex(any value)
Note: Other than the integer value like: floating-point, boolean, complex etc. not
allowed for the conversion into hexadecimal.
Floating-point Datatypes:
We can use float data type to represent floating point values (decimal values).
We can also represent floating point values by using exponential form (scientific
notation).
Note:
Complex Datatype:
A complex number is of the form:
Real +/- imaginary
Ex: a + bj
In the real part if we use int value then we can specify that either by decimal,
octal, binary or hexadecimal form. But imaginary part should be specified only by
using decimal form.
Boolean datatype:
String Datatype:
String Slicing:
[ ] operator is called slice operator, which can be used to retrieve parts of String.
In Python Strings follows zero based index.
The index can be either + ve or -ve.
+ve index means forward direction from Left to Right.
-ve index means backward direction from Right to Left.
Note:
All the above datatypes: int, float, complex, bool and str are primitive type of the
datatypes.
And all primitive datatypes are “Immutable type”.
Immutable type means, once we can define the data cannot be modified. If the
re-definition of the value to the variable is take place, the new address will be
created.
Bytes Datatype:
bytes data type represents a group of byte numbers just like an array.
The only allowed values for byte data type are 0 to 256. By mistake if we are
trying to provide any other values then we will get value error.
Once we create bytes data type value, we cannot change its values, otherwise
we will get TypeError.
Bytearray Datatype:
bytearray is exactly same as bytes data type except that its elements can be
modified.
List Datatype:
Tuple Datatype:
Tuple data type is exactly same as list data type except that it is immutable., we
cannot change values.
Tuple elements can be represented within parenthesis.
Range Datatype:
Set Datatype:
It is exactly same as set except that it is immutable. Hence, we cannot use add
or remove functions.
Dict Datatype:
int():
It is a pre-defined method/inbuilt method used to convert any data to integer
(decimal).
Syntax:
int(any value)
float():
Syntax:
float(Any Value)
complex():
A pre-defined method which can be allowed to convert any data to complex data.
Syntax:
complex(Any value)
Any integer data (with any base) can be allowed to convert into complex.
The float value can be allowed to convert into complex data using complex().
Boolean value also allowed for the complex conversion.
String with complex, integer, float are allowed for the complex data conversion.
Any Data to Boolean Conversion:
bool()
bool() is a pre-defined/inbuilt method which is used to convert any data into boolean
data.
Syntax:
bool(Any Value)
Note:
Any non-zero value is the “True” by bool() method.
Any zero value is the “False” by bool() method.
String with empty quotes is equals to ‘0’ by bool() method.
Any Data to String Conversion:
str():
str() is the method which is used to convert any data to string data.
Syntax:
str(Any data)
IO Operations
IO Operations is represented as “Input and Output Operations”. To perform IO
operations in python, there are two inbuilt/pre-defined methods:
1) input()
2) print()
Input Operations:
input():
input() is an inbuilt method, which is used to read a value which is entered from
keyboard during the time of running of the program.
input() method can read a string value by default.
To read other type of the data/value, we required to perform the type conversion
to input() method with the required type.
Output Operations:
print():
print() method is reserved with new line after printing of any data in all the time.
Interview Questions:
OPERAND:
A data/value/variable on which we can define an operation is called as an
“Operand”.
Ex: 10 + 20
Here: 10 and 20 are operands
We are defining ‘+’ operation on these operands.
OPERATOR:
A symbol which is used to define an operation is called as an “Operator”.
Ex: 10 + 20
Here: + is an operator, which denotes sum/addition operation.
EXPRESSION:
A combination with an operator and operands is called as an “Expression”.
Ex: 10 + 20 is an expression
Operands: 10 and 20 are joined with an operator ‘+’
STATEMENT:
A line of code which may or may not be terminate with semi-colon is called as a
“statement”.
Block of statements:
A block of statement/code can be defined with one or more number of
statements. In python, the block of code can be represented with indentation.
TYPES OF OPERATORS:
2) Binary Operators:
An operator can be defined with two operands is called as “Binary
operator”.
Ex: +, -, *, ** etc.
3) Ternary Operators
An operator can be defined with three operands is called as “Ternary
operator”. Also called as “Conditional operator”.
1) Arithmetic Operators
Note:
(/) Operator always performs floating point arithmetic. Hence it will always return
float value.
But Floor division (//) can perform both floating point and integral arithmetic. If
arguments are int type then result is int type. If at least one argument is float
type, then result is float type.
Note:
2) Assignment Operator:
Symbol: =
Assignment operator is used to assign anything to the variable/expression. Assignment
operator’s associativity is from right to left.
3) COMPOUND OPERATOR:
Ex: x += 10 or x = x + 10
X -= 10 or x = x – 10
X *= 10 or x = x * 10
X /= 10 or x = x /10
X //= 10 or x = x // 10
X %= 10 or x = x % 10
X **= 3 or x = x ** 3
4) RELATIONAL OPEARTORS:
Note:
Chaining of relational operators is possible. In the chaining, if all comparisons
return True then only result is True. If at least one comparison returns False then
the result is False.
Difference between ‘==’ and ‘=’
If we can use an assignment operator (=) in place of equal operator (==) “Type
Error” is returned.
If an equal operator is written in place of assignment operator (=) “Name Error” is
returned.
5) LOGICAL OPERATORS:
To join two or more expressions into single expression using logical operators.
Logical operators are:
1) Logical And == and
2) Logica Or == or
3) Logical Not == not
Note:
For logical and operation, when we define with other than boolean values:
If both inputs are defined with non-zero values, the output is the second
operand/input value.
If the first input is zero and the second input is non-zero, the output is “zero”
without decode the second operand/input value.
If the first input is non-zero and the second input is zero, the output is “zero”.
Note:
Logical or operator is a binary operator which always allowed to define with two
possible operands/values.
It can also be allowed to define with any type of values like: decimal, binary, float
etc.
Note:
For logical or operation, when we define with other than boolean values:
If both inputs are defined with non-zero values, the output is the first
operand/input value.
If the first input is zero and the second input is non-zero, the output is “second
operand/input value”.
If the first input is non-zero and the second input is zero, the output is “first
operand value”.
Syntax:
resultant-variable = expression1 if condition else expression2
here:
if and else ==> keywords
All Bitwise operations can define on individual bits of the given data.
Bitwise operations are allowed to define with: boolean data and integer data only.
bitwise operations are:
bitwise and ==> &
bitwise or ==> |
bitwise xor ==> ^
bitwise complement ==> ~
shift operators
left shift ==> <<
right shift => >>
BINARY OPERATOR
a b a&b
==============
1 1 1
1 0 0
0 1 0
0 0 0
Binary operator
a b a|b
==============
0 0 0
0 1 1
1 0 1
1 1 1
Binary operator
a b a^b
==============
0 0 0
0 1 1
1 0 1
1 1 0
For same inputs, the output is ‘0’.
For different inputs the output is ‘1’.
When we define the bitwise Xor on integer data, each input value can convert to
binary and define the bitwise Xor can perform the operation from right to left on
each individual bits.
print(~0)
print(~7)
print(~-7)
Shift Operators:
Binary Operator.
Syntax:
Data << n
Here:
n = number of times
Left shift operation can be defined on the data by converting into binary with
‘n’ number of times.
Left shift operation defines: shifting of bits from right to left bit by bit and place
‘0’ in LSB place after the shifting of bits.
Binary Operator.
Syntax:
Data >> n
Here:
n = number of times
Right shift operation can be defined on the data by converting into binary with
‘n’ number of times.
Right shift operation defines: shifting of bits from left to right bit by bit and
place ‘0’ in MSB place and discard the LSB after the shifting bit by bit.
SPECIAL OPERATORS:
1) Membership Operators:
in, not in
Identity Operators are used to check whether two objects are pointing to the
same location or not.
Returns: Boolean values.
Practice Programs:
Transfer Statements
Break statement
Continue statement
Pass statement
Patterns
Control Statements
In general, all python programs can be executed in sequential (statement by statement).
Instead of executing the python program in sequential, to execute only the selected part
of the program or to execute the part of the program repeatedly or to stop executing of
the program certainly control statements can be used.
1. Conditional Statements:
if statement:
Syntax:
if condition:
statements
condition: can be defined with relational operators and with any values.
Working Operation:
If the condition is evaluated as “True”, then the statements in if-block will be get
executed otherwise, the statements in if-block will be not executed.
Program to define if statement with integer value as condition
Program to define if condition with boolean value
If-else Statement:
Syntax:
If condition:
Statement-1
Statement-2
else:
Statement-3
Statement-4
Working Operation:
If “condition” is “True”, then the statements in if-block can be executed. Otherwise, the
statements in else-block can be executed.
If-elif-else statement:
Syntax:
If condition1:
Statements
elif condition2:
statements
elif condition3:
Statements
else:
statements
Working Operation:
2. Loop Statements:
while loop:
In Python, while is the keyword which we can use to define the while loop
statements. If we want to execute a group of statements iteratively until some condition
false, then we should go for while loop.
Syntax:
initialization
while condition:
loop body statements
update statement
for loop:
If we want to execute some action for every element present in some sequence (it may
be string or collection) then we can use for loop.
Syntax:
here:
sequence strings, list, tuple etc.
range ():
Syntax:
Syntax:
A Program to sum of all odd numbers from 100 to 1 using for loop
Infinite Loops:
In Python, an infinite loop can be useful in various scenarios. One of the prime
uses of an infinite loop can be seen in a client-server architecture model in networking.
As we know a server is central storage that is always awake and ready to handle
client requests. So, a server runs in an infinite loop which makes it always awake and
ready to handle various situations like new requests from the client, new connections
from the client, etc.
Nested Loops:
Nested loops are described as a loop can be defined within other loop statements.
Syntax:
Outer_Loop:
Statement-1
Statement-2
Inner_Loop:
Statement-3
Statement-4
Transfer Statements:
Break Statement:
Syntax:
break
Continue Statement:
Syntax:
continue
Note:
Python cannot support to use switch statement, do-while and goto like other
languages.
Practice Programs:
Syntax:
List-object-name = [list elements with comma separation]
Ex: a = [1,2,3,4,5]
eval ():
To define the list in run-time or to define dynamical changed list, eval() method is used.
Syntax:
eval(input())
3) list ()
Syntax:
List-object-name = list (any collection)
This method can use for the conversion of any collection to list.
4) split ():
Syntax:
List-object-name = str-data-object.split(‘separator’)
This method can use to split the string based on the separator. The separator can be
any character within single quotes or double quotes.
Traversing on the List:
Syntax:
Initialization
while condition_to_iterate_loop:
block of operation
update
Syntax:
for loop-variable in list-data:
block of code
Membership Check:
To check the element whether it is the member to the list or not we have two types of
membership operators:
1) in
2) not in
List Comparison:
List comparison is defined with relational operators like: <, >, <=, >=, == , !=
Equality check:
List comparison with <, >, <=, >= should be element by element on from both lists with
any size of lists.
List is Mutable:
Once we create a List object, we can modify its content. Hence List objects are mutable.
count():
count() method can use to find the total number of occurrences of the specified element
within the list.
Syntax:
List-data.count(list element)
If the specified element in count() is not the member of the list, count() can return = '0'.
we cannot count the number of occurrences of the specified within the range.
Finding of first occurrence of the specified element in a list:
index():
index() method use to find the first occurrence of the specified element in the given list.
Syntax:
list_data/list_object.index(element)
When the specified element is not in the given list, index() can return: “value error”.
To add elements into the list, there are different methods in python:
1) append()
2) insert()
3) extend()
append():
append() is the method used to add the element at the end of the list by default.
Syntax:
List-data-name.append(element)
Note:
Using append(), we can add only one element into the list at a time.
insert():
Syntax:
List-data.insert(index, element)
Note:
If the specified index is from out of the index range of the list data, index() can add the
specified element at the end automatically.
extend():
extend() method can add the group of elements into the given list.
Syntax:
Main-list.extend(list of elements)
Note:
extend() method can add list of elements into the given list at the end by default.
1) remove():
remove() is the method can use to remove the specified element from the list.
Syntax:
List-data-name.remove(element)
Note:
If the specified element is not in the list, remove() can return “value error”.
2) pop():
Syntax:
List-data-name.pop()
ii) pop() can also remove the element from the list based on the specified index.
Syntax:
List-data-name.pop(index)
3) del
del is the property/attribute can use to delete the specified element from the list based
on the index.
Syntax:
del list-data-name[index]
del property can also use to delete the total list data permanently from the memory.
Once we deleted using del property, we cannot use or access it again. If we can access
the list variable after the delete using del property we can get “Name Error”.
Note:
Using del property, we can delete any data from the program.
4) clear():
This can use to clear the total list elements from the list.
Syntax:
List-data-name.clear()
Note:
After the clearing/deleting of list using clear(), we can access that list.
reverse():
Syntax:
List-data-name.reverse()
1) Forward Sorting:
2) Reverse Sorting:
Syntax:
List-data-name.sort(reverse = True)
The process of giving another reference variable to the existing list is called
aliasing.
The problem in this approach is by using one reference variable if we are
changing content, then those changes will be reflected to the other reference
variable.
To overcome this problem we should go for cloning.
The process of creating exactly duplicate independent object is called cloning.
copy():
Syntax:
New-list = List-data-name.copy()
Math Operations
1) List Concatenation:
Joining of two or more lists into one list is called as “List Concatenation”.
List concatenation can define with symbol: ‘+’.
Syntax:
List-data-name1 + List-data-name2
2) List Repetition:
Syntax:
List-data-name * num-times
Nested List:
String Definition
Multi-line string literal
Accessing of characters of the strings data
Accessing the part of the string data
Traversing on the string data
Math Operations
Finding of string length
Membership check
String Comparison
Removal of spaces from the string
Finding of sub-strings of the string
Counting number of occurrences of the sub-string in a string
String replacement
String to List conversion
Joining of strings into one string
Changing case of the string
Checking starting and ending part of the string
Checking type of characters present in a string
Formatting of the string
Strings
What is string?
Ex: ‘python’
“Python”
Note:
In most of other languages like C, C++, Java a single character with in single
quotes is treated as char data type value. But in Python we are not having char
data type. Hence it is treated as String only.
Like C, strings in Python cannot end with null character (‘\0’).
We can define multi-line String literals by using triple single or double quotes.
Ex:
'''Python is High-level,
General-purpose,
Object Oriented
Programming language.'''
"""Python is High-level,
General-purpose,
Object Oriented
Programming language."""
Note:
====
1) adding of double quotes in between double quotes ==> not possible.
2) adding of single quotes in between single quotes ==> not possible
==> to add:
\ start-quotes ........ \ end-quotes
Accessing of characters of the string data:
1) Unsing Index:
Negative index can use to access the string characters from right to left.
Also called as "reverse accessing".
Default start value: -1.
Default end value: -total characters of string.
range of negative indexing ==> -1 to -total number of characters of string
Syntax:
String-data-name [index value]
2) Slicing:
Syntax:
Str-data [start: stop] ==> slicing start at "start" value and end with "stop-1" value
Str-data [start: stop: step] ==> slicing start with "start" value and end with "stop-
1" value with the difference of "step"
Str-data [: stop] ==> by default, slicing can start with first character and end
with "stop-1" value
Str-data [start:] ==> slicing can start with "start" value and end with "last" by
default
Str-data [: :] ==> start with first character and end with last
Str-data [: : step] ==> start with first character and end with last with difference
of step value.
Finding length of the string:
len():
Syntax:
len(string-data)
Without len() method:
To traverse the string data, we can use while loop and for loop.
Math Operations:
1) String Concatenation:
Joining of two or more strings into one string is called as “string concatenation”.
String concatenation can represent with ‘+’ operator.
2) String Repetition:
This can use to repeat the string data for number times. And it can represent with string
repetition operator (*).
Syntax:
String-data * number-times
Note:
String is immutable type, for any operation there will be the new object address
can create.
Membership Check:
String Comparison:
This is an inbuilt method in python which can use to convert the total given string
into upper case string.
Syntax:
String-data. upper ()
lower()
This an inbuilt method in python can use to convert the given string into lower
case string.
Syntax:
String-data. lower ()
swapcase()
This is an inbuilt method in python can use to convert a lower case string to
upper case and upper case string to lower case
Syntax:
String-data. swapcase ()
title()
Title case means that every word of the same string should be start with capital letter.
ex: python programming language
title case ==> Python Programming Language
title() is an inbuilt method in python can use to convert any case string into title
case.
Syntax:
String-data. title ()
Capitalize ()
Capitalize case means that the entire string (might be with more than one word), that
only the first word should start with capital remaining all the characters in lower case
Syntax:
String-data. capitalize ()
Checking start and end part of the string:
1) string.startswith(sub-string):
2) string.endswith(sub-string):
Syntax:
String-data.rstrip()
Syntax:
String-data.lstrip()
Syntax:
String-data.strip()
Finding of sub-strings in a given string
In forward direction:
To find sub-strings in a given string from left to right, there are inbuilt methods in python
are:
1) find()
2) index()
find():
Syntax:
String-data.find(sub-string)
when the sub-string is at multiple places, find() can return the first occurrence.
when the sub-string is not the part of the string, find() can return '-1'.
using find(), we can search about the sub-string from the given range.
when we defined the sub-string with more than one character, find() returns: the
index of First character of the sub-string only.
index():
Syntax:
String-data.index(sub-string)
when the sub-string is at multiple places, index() can return the first occurrence.
when the sub-string is not the part of the string, index() can return 'value error'.
using find(), we can search about the sub-string from the given range.
when we defined the sub-string with more than one character, index() returns:
the index of First character of the sub-string only.
In backward direction:
To find sub-strings in a given string from right to left, there are inbuilt methods in python
are:
1) rfind()
2) rindex()
rfind():
Syntax:
String-data-name.rfind(‘sub-string’, start-index, stop-index)
rindex():
Syntax:
String-data-name.rindex(‘sub-string’, start-index, stop-index)
Counting number of occurrences of the sub-string in a string:
count():
We can find the number of occurrences of substring present in the given string by using
count() method.
Syntax:
String-data-name.count(sub-string)
replace():
Syntax:
String-data-name.replace(old-string,new-string)
String to list conversion:
Split():
Syntax:
String-data-name.split(‘separator’)
List to string conversion:
join():
Syntax:
‘separator’.join(list-data-name)
Practice Programs:
Tuple-Features
Creation of the tuple
Traversing on tuple data
Tuple Math Operations
Tuple comparison
Counting number of occurrences of the specified element of tuple
Finding of the specified element of tuple
Tuple Sorting
Finding of minimum and maximum from collection data
Tuple packing and unpacking
Tuple Operations
Tuple-Features:
Syntax:
Tuple-object-name = (item1, item2, item3, …)
Syntax:
Tuple-object-name[index]
Note:
====
Like strings and list, Tuple can also support both positive index and negative index.
1) positive indexing can use to access the elements of tuple using forward access.
Forward access means accessing of tuple data from left to right.
2) negative indexing can use to access the elements of tuple using reverse access.
Reverse access means accessing of tuple data from right to left.
Tuple can allow to access the part of the data using slicing.
Syntax:
Tuple-object-name[start : stop : step]
Note:
list can also be nested with other collections.
list():
list() is an inbuilt method which we can use to convert any collection data to list data.
Ex: tuple data can convert to list using list().
Syntax:
list(any collection data)
tuple():
tuple() is an inbuilt method which can use to convert any collection to tuple data.
Ex: list data can convert to tuple using tuple().
Syntax:
tuple(any collection data)
Creation of Tuple:
Compile time definition is nothing but the direct assignment of the tuple data to
tuple object using assignment operator.
Syntax:
Tuple-object-name = (e1, e2, e3, …)
For the tuple definition, () is optional but comma between elements is mandatory.
Syntax:
Tuple-object-name = e1, e2, e3, …
Note:
For the list representation [] is mandatory.
Syntax:
eval(input(“Enter tuple data:”))
3) Using tuple():
tuple() method can use to convert any collection data to tuple data.
Syntax:
tuple(any collection data like: list, string etc.)
Traversing on Tuple:
Syntax:
Initialization
While condition:
Block of code
Update
Syntax:
for iteration-variable in tuple-collection:
block of code
Math Operations:
1) Tuple Concatenation:
The joining of two or more tuples into one called as "tuple concatenation".
Symbol for tuple concatenation: ‘+’
Syntax:
Tuple1 + Tuple2 + Tuple3 + ….
2) Tuple Repetition:
To make repeat the data of tuple for number of times, we can use tuple
repetition.
Symbol of denote is: ‘*’
Syntax:
Tuple-data-name * n
Tuple comparison:
Tuple is possible with relational operators (<, >, <=, >=, ==, !=)
count():
Syntax:
Tuple-data-name.count(element)
Note:
count() can return '0' if the specified element is unknown to the tuple data.
count() method cannot find the element in between the indexes.
index():
Syntax:
Tuple-data-name.index(element)
Note:
index() can also find the element within the specified range.
Syntax:
Tuple-data-name.index(element, start-index, stop-index)
Tuple sorting:
sorted():
sorted() is an inbuilt method in python to arrange the tuple data in ascending order
(forward sorting) and/or descending order (reverse sorting).
Forward Sorting:
Syntax:
sorted(tuple-data)
Reverse Sorting:
Syntax:
sorted(tuple-data, reverse = True)
min():
min() is an inbuilt method which we can use to find the minimum value from the given
collection data.
Syntax:
min(collection data)
max():
max() is an inbuilt method which we can use to find the maximum value from the given
collection data.
Syntax:
max(collection data)
Tuple packing and unpacking:
Syntax:
Tuple-object = d1,d2,d3,d4,…
Syntax:
D1,d2,d3,d4, = tuple-data
Practice Programs:
1) Write a program to take a tuple of numbers from the keyboard and print its sum
and average?
2) Write a program find the length of the tuple data.
3) Write a program to add elements into a tuple.
4) Write a program remove all tuples of length K.
5) WAP to create tuple in different ways.
6) WAP to convert a tuple to list without inbuilt function.
7) WAP to add new element into a tuple data.
8) WAP to find repeated items in a tuple data.
9) Write a Python program to unzip a list of tuples into individual lists.
10) Write a Python program to reverse a tuple without inbuilt functions.
11) Write a Python program to count the elements in a list until an element is a
tuple.
12) Write a Python program to calculate the average value of the numbers in a
given tuple of tuples.
Unit-8: Set Operations
Features of set data
Creation of set data
Traversing on set data
Set Comparison
Adding Elements into set data
Set Aliasing
Cloning of set data
Deleting Elements from set data
Set Math Operations
Set Data Operations
Note:
limitation with list, set, dictionary.
set never be nested with list
Ex: If a set with list data returns "Type Error".
Creation of Set Data:
Syntax:
Set-data-object = {d1, d2, d3, d4, d5, …}
To define the set in run time which can dynamically change “eval()” method can use.
Syntax:
eval(input(“Enter the Set data:”))
3) Using set():
set() is an inbuilt method which we can use to create a set data from any collection
(means to convert any collection data to set data, set() method can use).
Syntax:
Set-data-object = set() for an empty set creation
Set-data-object = set(any collection data)
Traversing on Set Data:
Syntax:
for loop-variable in set-data:
block of code
Set Comparison:
1) add():
add() is an inbuilt method which can add an element/item (only one at a time) to the
set.
Syntax:
add(element/item)
2) update():
update() is an inbuilt method which can use to add more than one item/element to
the set.
Syntax:
Set-data-object.update(collection data)
Set Aliasing:
Assigning the same set data to two or more set objects using assignment
operator is called as set aliasing. In this case, if any change at any set object can
reflect on other set data automatically.
Set cloning:
Syntax:
New set-data-object = Old-set-data-object.copy()
1) pop():
Syntax:
Set-data-object.pop()
Note:
pop() can delete an element from set randomly.
2) remove():
Syntax:
Set-data-object.remove(element)
Note:
if the specified element is not in the set, then: remove() can return "Key Error".
3) discard():
dicard() is an inbuilt method which we can use to remove the specified element from
the given set data.
Syntax:
Set-data-object.discard(element)
Note:
if the specified element is not known to the set, then: discard() not return any
error.
4) del:
del is a property which we can use to delete the entire set permanently.
Syntax:
del set-data-object
5) clear():
1) Set Union:
Joining of two sets into one by eliminating common elements from set2.
union():
Syntax:
Set-object1.union(set-object2)
2) Set Intersection:
Set Intersection can create a new set with only common elements from both the
sets.
intersection():
Syntax:
Set-object1.intersection(set-object2)
3) Set Difference:
Set difference can return a set with elements from only the first set.
difference():
Syntax:
Set-object1.difference(set-object2)
symmetric_difference():
Syntax:
Set-object1.symmetric_difference(set-object2)
Practice Programs:
Dictionary in Python is one of the most popular data structures. They are used to store
data in a key-value pair format. The keys are always unique within a dictionary and are
the attribute that helps us locate the data in the memory. The values of the Python
dictionary may or may not be unique. The values within a dictionary can be of any data
type, but the thing to note is that the keys are immutable. Hence, the key can only be
strings, numbers or tuples.
We can use List, Tuple and Set to represent a group of individual objects as a
single entity.
If we want to represent a group of objects as key-value pairs then we should go
for Dictionary.
Dictionary data is an inbuilt datatype because in python there is an inbuilt class
named as “dict”.
Duplicate keys are not allowed but values can be duplicated.
To access the values from the dictionary, “keys” can be used.
Heterogeneous objects are allowed for both key and values.
insertion order is not preserved.
Dictionaries are mutable.
Dictionaries are not support with dynamic indexing and slicing concepts.
Creating a Dictionary Data:
To create a Python dictionary is as simple as placing the required key and value pairs
within a curly bracket “{}”. A colon separates the key-value pair “:”. When there are
multiple key-value pairs, they are separated by a comma “,”
Syntax:
Dictionary-object = {key1 : value1, key2 : value2, key3 : value3}
To define the dictionary data in run time which can dynamically change “eval()” method
can use.
eval():
Syntax:
eval(input(“Enter the Dictionary Data:”))
Using dict() method:
dict() is an inbuilt method which we can use to create the dictionary data.
Syntax:
dict({key : value1, key2 : value2, key3 : value3})
Duplicate keys are not allowed. When duplicate keys are encountered in Python,
the last assignment is the one that wins.
Keys are immutable- they can only be numbers, strings or tuples.
Using keys:
Syntax:
Dictionary-object[key]
Note:
If we tried to reference a key that is not present in our Python dictionary, we
would get the “key error”.
Write a program to enter name and percentage marks in a dictionary and display
information on the screen.
We can do multiple things when trying to update a dictionary in Python. Some of them
are:
1. Add a new entry.
2. Modify an existing entry.
3. Adding multiple values to a single key.
4. Adding a nested key.
Deleting Dictionary Data:
del:
clear():
Syntax:
Dictionary-object.clear()
Dictionary Operations:
len():
len() is an inbuilt method which we can use to find the length of any collection
data.
Syntax:
len(dictionary-object)
Syntax:
Dictionary-name[key-name]
Way_02: Using get() Method:
Syntax:
Dictionary-name.get(key-name)
If the specified key is in the dictionary, associated value can be returned by the
get().
If the specified key is not in the dictionary, then the get() can return “None”.
To return some “default value” when the specified key is not in the dictionary, we
can use:
Syntax:
Dictionary-name.get(key-name, default-value)
keys():
keys() is an inbuilt method which can use to get all the keys from the given dictionary.
Syntax:
Dictionary-name.keys()
Getting all values from the Dictionary:
Values():
Values() is an inbuilt method which we can use to get all the values from the dictionary.
Syntax:
Dictionary-name.values()
Getting both keys and values in arbitrary from the dictionary:
Items():
Items() is an inbuilt method which can be used to get all the items (key : value) from the
given dictionary.
Syntax:
Dictionary-name.items()
Aliasing of Dictionary:
Using copy():
Copy() it is an inbuilt method which we can use to create a new dictionary from another
dictionary.
Syntax:
New-dictionary-name = old-dictionary-name.copy()
Comprehensions:
Comprehensions are very easy and compact way to create collection objects like: list,
set, dictionary from any iterable object like: range(), list, tuple etc. based on some
condition.
List Comprehension:
Syntax:
identifier = [condition for lv in collection/range]
Tuple Comprehension:
Syntax:
identifier = {condition for lv in collection/range}
Dictionary Comprehension:
Syntax:
identifier = {key : value for condition for lv in collection/range}
Practice Programs:
1) Write a program to enter name and percentage marks in a dictionary and display
information on the screen.
2) Write a program to take dictionary from the keyboard and print the sum of
values?
3) Write a program to find number of occurrences of each letter present in the given
string?
4) Write a program to find number of occurrences of each vowel present in the
given string?
5) Write a program to accept student name and marks from the keyboard and
creates a dictionary. Also display student marks by taking student name as
input?
Unit-10: Functions
What is function?
Function definition
Function call
Types of Functions
Returning multiple values
Types of arguments
Scope of Variables
Recursion
Passing collection to function
Function within the function
Passing a function as an argument to function
Pass by Reference and Pass by Value
Returning of Collection from function
Anonymous function
Function Aliasing
Function Decorators
Function Generators
Functions
What is function?
Functions are modular blocks of code designed to perform specific tasks. They
enhance code efficiency and clarity by reducing code repetition and enabling code
reuse.
Advantages:
1) solving the complex or larger programs easily.
2) debugging the application is easy.
Function Definition:
In Python, a function is declared using the keyword def, succeeded by the name of the
function and enclosed parentheses, which may enclose parameters.
Syntax:
def functions-name(parameters/arguments):
Function body
block of statements
Function-name: This is the identifier for the function. It follows the same naming
conventions as variables in Python. The function name should be descriptive
enough to indicate what the function does.
Parameters (Optional): These are variables that accept values passed into the
function. Parameters are optional; a function may have none. Inside the function,
parameters behave like local variables.
Function Body: This block of code performs a specific task. It starts with a colon
(:) and is indented. The function body typically contains at least one statement.
The return statement can be used to send back a result from the function to the
caller. None is returned if no return statement is used.
Creating of Function:
Calling of Function:
Syntax:
Function-name(values for parameters)
Types of Functions:
Syntax:
def function-name():
function-body
2) Function without Parameters and Return type
Syntax:
def function-name():
function-body
return
3) Function with Parameters and no Return type
Syntax:
def function-name(parameters):
function body
4) Function with Parameters and Return type
Syntax:
def function-name(parameters):
function-body
return
RETURNING MULTIPLE VALUES FROM FUNCTION:
Types of Arguments:
1. Positional Arguments:
These are the most common arguments, where the argument's value is based on its
position. For example, in func(a, b), a and b are positional arguments.
2. Keyword Arguments:
The parameter name identifies these and can be supplied in any order, making your
code more readable. For instance, func(a=1, b=2) explicitly states which parameter each
argument corresponds to.
3. Default Arguments:
A parameter with a default value can be omitted in the function call. The function will
then use the default value.
4. Variable Length Arguments:
You may need to determine the number of arguments supplied to your function.
Python allows you to handle this with variable-length arguments, defined with an
asterisk *args and **kwargs.
Docstring:
Syntax:
print(function_name.__doc__)
Types of Variables:
1) Local Variables:
2) Global Variables:
The variables from outside the function are called as “Global variables”.
And we can access in anywhere of the program.
Recursion:
A function that calls itself again and again is known as "recursion". And that function is
called as “recursive function”.
Advanced Functions
Syntax:
def function-name(string-data):
function body
Syntax:
def function-name(list-data):
function-body
Passing a tuple to function:
Syntax:
def function-name(tuple-data):
function-body
Syntax:
def function-name(set-data):
function-body
Syntax:
def function-name(dictionary-data):
function-body
Function within another function:
In Python, functions can be defined inside other functions. These nested functions help
organize code into more manageable pieces, encapsulating functionality or creating
closures and decorators. Also called as “Higher Order Functions”.
Syntax:
def function-name(function-name):
function-body
Pass By Reference:
Pass by value means the actual value is passed. The function works on a copy,
and changes within the function do not affect the original data.
With immutable objects (like integers and strings), Python's behavior is akin to
pass-by-value. Changes made to an immutable object in a function do not reflect
in the original object.
Anonymous Function:
Syntax:
lambda arguments: expression
Note:
By using Lambda Functions, we can write very concise code so that readability of the
program will be improved.
filter():
We can use filter() function to filter values from the given sequence based on some
condition.
Syntax:
filter(function-name, sequence)
here function argument is responsible to perform conditional check sequence can be list
or tuple or string.
map():
For every element present in the given sequence, apply some functionality and
generate new element with the required modification. For this requirement we should go
for map() function. The function can be applied on each element of sequence and
generates new sequence.
Syntax:
map(function-name, sequence)
We can apply map() function on multiple lists also. But make sure all list should have
same length.
reduce():
reduce() function reduces sequence of elements into a single element by applying the
specified function. reduce() function present in functools module and hence we should
write import statement.
Syntax:
reduce(function-name, sequence)
Function Aliasing:
For the existing function we can give another name, which is nothing but function
aliasing.
Function Decorators:
Decorators in Python are functions that takes another function as an argument and
extends its behavior without explicitly modifying it. It is one of the most powerful features
of Python. It has several usages in the real world like logging, debugging,
authentication, measuring execution time, and many more. The main objective of
decorator functions is we can extend the functionality of existing functions without
modifies that function.
Suppose, you have a set of functions and you only want authenticated users to access
them. Therefore, you need to check whether a user is authenticated or not before
proceeding with the rest of the code in the function. One way to do this is by calling a
separate function inside all the functions and using conditional statements. But this will
require us to change the code for each function. A better solution here would be to use
a Decorator. A Decorator is just a function that takes another function as an argument
and extends its behavior without explicitly modifying it. This means that a decorator
adds new functionality to a function. By the end of this article, you will understand what
does "extending a function without actually modifying it" means.
First-class Object:
In Python, a function is treated as a first-class object. This means that a function has all
the rights as any other variable in the language. That's why, we can assign a function to
a variable, pass it to a function or return it from a function. Just like any other variable.
As everything is an object in Python, the names we define are simply identifiers
referencing these objects. Thus, both foo and also_foo points to the same function
object as shown below in the diagram:
There are multiple use cases for passing a function as an argument to another function
in Python. For instance, passing a key function to sort lists. Decorators also use this technique as
we will see later.
Inner Functions:
We can define a function inside other functions. Such functions are called inner
functions or nested functions. Decorators in Python also use inner functions.
Note:
The inner functions are locally scoped to the parent. They are not available outside of
the parent function. If you try calling the first_child outside of the parent body, you will get a Name
Error.
Inner functions can access variables in the outer scope of the enclosing function. This
pattern is known as a Closure.
Decorators function with arguments:
Now that we have the pre-requisite knowledge for understanding decorators, let's go on
to learn about Python decorators. As discussed before, a decorator in Python is used to
modify the behavior of a function without actually changing it.
Syntax:
Function-name = decorator(function-name)
where function-name is the function being decorated and decorator is the function used to
decorate it.
We have two functions here:
We passed the say_hello function to the decorator function. In effect, the say_hello now points to
the wrapper function returned by the decorator. However, the wrapper function has a reference to the
original say_hello() as func, and calls that function between the two calls to print().
Syntactic Decorator:
The above decorator pattern got popular in the Python community but it was a little
inelegant. We have to write the function name thrice and the decoration gets a bit
hidden below the function definition. Therefore, Python introduced a new way to use decorators
by providing syntactic sugar with the @ symbol.
Syntax:
@decorator
def function-name(arg1, arg2, arg3, ….):
pass
In Python, functions have a name attribute and a docstring to help with debugging and
documentation.
Although technically true, this is not what we wanted. As the say_hello now points to
the wrapper function, it is showing its information instead of the original function. To fix this, we need
to use another decorator called wraps on the wrapper function. The wraps decorator is imported from
the in-built functools modules.
Reusing Decorator:
We imported any used the do_twice decorator on both the functions and called them.
Therefore, we got two outputs for each function.
What happens to the returned value from the decorated function? Let's check out
with an example. Consider the following add function, it prints a statement then returns
the sum of the two numbers, we are decorating it with the previously
created do_twice decorator:
The add function was called twice as expected but we got None in the return value. This
is because the wrapper function does not return any value. To fix this, we need to make
sure the wrapper function returns the return value of the decorated function.
Chaining Decorators:
Chaining the decorators means that we can apply multiple decorators to a single
function. These are also called nesting decorators.
The first one takes a function that returns a string and then splits it into a list of
words.
The second one takes a function that returns a string and converts it into
uppercase.
Fancy Decorators:
Python provides the following built-in decorators to use with the methods of a class:
@classmethod: It is used to create methods that are bound to the class and not
the object of the class. It is shared among all the objects of that class. The class
is passed as the first parameter to a class method. Class methods are often used
as factory methods that can create specific instances of the class.
@staticmethod: Static methods can't modify object state or class state as they
don't have access to cls or self. They are just a part of the class namespace.
We created a class called Browser. The class contains a getter and setter for
the page attribute created with the @property decorator. It contains a class method
called with_incognito which acts as a factory method to create incognito window
objects. It also contains a static method to get the information for the browser which will
be the same for all objects (windows).
Decorating a complete class:
Writing a class decorator is very similar to writing a function decorator. The only
difference is that the decorator will receive a class and not a function as an argument.
Decorating a class does not decorate its methods.
Syntax:
className = decorator(className)
Classes as Decorators:
We can also use a class as a decorator. Classes are the best option to store the state of
some data, so let's understand how to implement a stateful decorator with a class that
will record the number of calls made for a function.
There are two requirements to make a class as a decorator:
The __init__ function needs to take a function as an argument.
The class needs to implement the __call__ method. This is required because the
class will be used as a decorator and a decorator must be a callable object.
Also note that we use functools.update_wrapper instead of functools.wraps in case of a
class as a decorator.
Real world usage of Decorators:
Generators in Python:
Generators in Python are used to create iterators and return a traversal object. It helps
in traversing all the items one at a time with the help of the keyword yield.
Generator functions are defined as the normal function, but to identify the difference
between the normal function and generator function is that in the normal function, we
use the return keyword to return the values, and in the generator function, instead of
using the return, we use yield to execute our iterator.
Yield Vs Return:
Yield Return
It is used in generator functions. It is used in normal functions.
It is responsible for controlling the flow of the
generator function. After returning the value Return statement returns the value and
from yield, it pauses the execution by saving terminates the function.
the states.
Generative Function Vs Decorative Function:
In generator functions, there are one or more yield functions, whereas, in Normal
functions, there is only one function
When the generator function is called, the normal function pauses its execution,
and the call is transferred to the generator function.
Local variables and their states are remembered between successive calls.
When the generator function is terminated, StopIteration is called automatically
on further calls.
The function seq will run 10 times, and when seq is called using next for the 11th time, it
will show an error StopIteration. But when using for loop, instead of next.
It will not show any error. for loop automatically handle the exception statements.
Creation of Generator Function:
Yield Statement:
Yield keyword in Python that is used to return from the function without destroying the
state of a local variable. We have already discussed how to create a generator function
using yield.
Uses of Generators:
1. Easy to Implement:
Generator Functions are memory efficient, as they save a lot of memory while using
generators. A normal function will return a sequence of items, but before giving the
result, it creates a sequence in memory and then gives us the result, whereas the
generator function produces one output at a time.
3. Infinite Sequence:
We all are familiar that we can't store infinite sequences in a given memory. This is
where generators come into the picture. As generators can only produce one item at a
time, so they can present an infinite stream of data/sequence.
Practice Programs:
Modules in Python are the python files containing definitions and statements of the
same. It contains Python Functions, Classes or Variables. Modules in Python are
saved with the extension .py.
Consider a bookstore. In the bookstore, there are a lot of sections like fiction, physics,
finance, language, and a lot more, and in every section, there are over a hundred
books.
In the above example, consider the book store as a folder, the section as
python modules or files, and the books in each section as python functions, classes,
or python variables.
Features of modules:
Modules provide us the flexibility to organize the code logically. Modules help
break down large programs into small manageable, organized files.
It provides reusability of code.
Code(example_.py):
Now, we have created Python modules example_.
Now, create a second file at the same location where we have created
our example_ module. Let's name that file as test_.py.
Code(test_.py):
Types of Modules:
Inbuilt Modules:
This module defines several functions to generate random numbers. We can use these
functions while developing games, in cryptography and to generate random numbers on
fly for authentication.
1. random():
This function always generate some float value between 0 and 1 ( not inclusive).
Syntax:
Import random
Value = randint()
2. ranint():
Syntax:
randint(n1, n2)
3. uniform():
Syntax:
uniform(n1, n2)
4. randrange():
Syntax:
randrange(start, stop, step)
5. choice():
It cannot return random number. It will return a random object from the given list or
tuple.
Syntax:
choice(collection)
Variables in Modules
We have already discussed that modules contain functions and classes. But apart from
functions and classes, modules in Python can also contain variables in
them. Variables like tuples, lists, dictionaries, objects, etc.
Let's create one more module variables, and save the .py as variables.py.
Create another Python file, and use the variables module to print the factorial of a
number, print the power of 6, and what is the second alphabet in the alphabet_list.
Import Statement:
The import statement is used to import all the functionality of one module to another.
Here, we must notice that we can use the functionality of any Python source file by
importing that file as the module into another Python source file. We can import multiple
modules with a single import statement, but a module is loaded once regardless of the
number of times it has been imported into our file.
For importing modules in Python, we need an import statement to import the modules in
a Python file.
When we are using the import statement to import either built-in modules or user-
defined modules, that states we are importing all the functions/classes/variables
available in that modules. But if we want to import a specific function/class/variable of
that module.
Module Aliasing:
Syntax:
import module-name as new-name
Reloading a Module:
Suppose you are using two modules, variables_ and example_ simultaneously in a
Python file, and the variables_ module is updated while you are using these modules.
You want the updated code of that module, which is updated. Now that we know, we
can import a module in our session only once.
So, we will use the reload function available in the imp module to get the updated
version of our module.
In the previous sections, we have seen how to import the modules using the import
statement. Now we will see how Python searches for the module.
In Python, when we use the import statement to import the modules. The Python
interpreter looks at the different locations.
After using the import statement to import modules, firstly, the Python interpreter will
check for the built-in modules. If the module is not found, then the Python interpreter will
look for the directories defined in the path sys. path.
The order of search is in the following order:
At first, the interpreter looks in the current working directory.
If the module is not found in the current working directory, then the interpreter will
search each directory in the PYTHONPATH environmental variable.
If now also the module is not found, then it will search in the default installation
directory.
The dir() is a built-in function returns a sorted list of strings containing the names
defined by a module. The list contains the names of all the classes, variables, and
functions that are defined in a module.
Practice Programs:
Packages
Introduction to Packages:
We usually organize our files in different folders and subfolders based on criteria
so that they can be managed quickly and efficiently. A Python module may contain
several classes, functions, variables, etc., whereas a Python package can contain
several modules. In simpler terms, a package is a folder that contains various modules
as files.
The meaning of Packages lies in the word itself. Packages do the work of
organizing files in Python. Physically a package is a folder containing sub-packages or
one or more modules (or files). They provide a well-defined organizational hierarchy
of modules in Python. Packages usually are named such that their usage is apparent to
the user. Python packages ensure modularity by dividing the packages into sub-
packages, making the project easier to manage and conceptually clear.
Have you come across this way of organization somewhere? The most common
example would be that of files on your phone. All your files would be saved in a folder
that could further be distinguished based on the source (WhatsApp Documents,
Downloads, etc.).
Every package in Python must contain an __init__.py file since it identifies the
folder as a package. It generally contains the initialization code but may also be left
empty. A possible hierarchical representation of the shifting items package in the first
example can be given below. Here, shifting items is our main package. We further
divide this into three sub packages: books, CDs and toys. Each package and sub
package contains the mandatory __init__.py file. Further, the sub packages contain files
based on their utility. Books contain two files fiction.py and non_fiction.py, the package
CDs contain music.py and dvd.py, and the package toys contain soft_toys.py and
games.py.
Packages help in ensuring the reusability of code. To access any module or file from a
Python package, use an import statement in the Python source file where you want to
access it. Import of modules from Python Packages is done using the dot operator (.).
Importing modules and packages helps us make use of existing functions and code that
can speed up our work.
Syntax:
import module1[, module2,... moduleN]
Where import is a keyword used to import the module, module1 is the module to be
imported. The other modules enclosed in brackets are optional and can be mentioned
only when more than 1 module is to be imported.
Where import is a keyword used to import the module, module1 is the module to be
imported. The other modules enclosed in brackets are optional and can be mentioned
only when more than 1 module is to be imported.
Consider the writing package given below.
To access a function called plagiarism_check() of the edit module, you use the following
code:
The calling method seems lengthy and confusing, right? Another way to import a
module would be to simply import the package prefix instead of the whole package and
call the function required directly.
However, the above method may cause problems when 2 or more packages have
similarly named functions, and the call may be ambiguous. Thus, this method is avoided
in most cases.
To ensure system-wide use of the Python package just created, you need to run the
setup script. This script uses the setup() function from the setup tools module. As a
prerequisite, you need to have the latest versions of pip and setup tools installed on
your system. Pip and setup tools are usually installed along with the Python binary
installers. To upgrade the version of pip, use the following command:
Syntax:
python -m pip install --upgrade pip
Once you confirm that you have the latest versions of pip and setup tools installed, you
can create a setup.py file in the main package (Writing) folder. The setup() function that
will be imported here takes various arguments like the package's name, version,
description, author, license, etc. The zip_safe argument is used to know the mode of
storage of the package (compressed or uncompressed).
Now to install the Writing package, open a terminal in your parent package folder
(Writing) and type in the following command:
Syntax:
pip install Writing
The Writing package, which contains functions to assist writing (like count_words which
is used to count the number of words in a string) will now be available for use anywhere
on the system and can be imported using any script or interpreter by using the following
commands:
Import statement:
The files in packages that contain Python code are called modules. Modules are used to
break down large code into smaller and more understandable parts. Commonly used
code (functions) can be written in the form of modules and imported as and when
needed, thus ensuring the reusability of code.
Let’s create a function prod(x,y) to multiply two numbers x and y, which are passed as
arguments to a function, and store it in a module named product.py.
To import the prod function in another module or use it in the interactive interpreter shell
of Python, type:
This statement does not import the module's functions into the symbol table. To access
functions of the given module, we use the dot (.) operator as follows:
Python has a lot of in-built modules which can be accessed in the same way. For
example, to print the value of pi, we can import the math module.
We can also import individual attributes from the module. This reduces the complexity of
writing the function calls.
Syntax:
from <module_name> import <attribute_name(s)>
In the previous example, we could import pi directly from the math module as follows:
You can import more than one attribute by separating them with commas (,). In the
below example, we import the functions pi, floor (used to find the smallest integer
greater than or equal to the given number) and fabs (used to find the absolute value of a
number) from the math package.
Importing modules using from import * statement:
Syntax:
from <module_name> import *
You can alter how a module is called in your program by aliasing it, i.e. giving it another
name. The as operator is used for this purpose.
Syntax:
import <module_name> as <new_module_name>
Importing Class/Function from module:
To import classes or functions from a module in Python, use the following syntax:
Syntax:
from <module_name> import <class_name/function_name>
Example: To import the prod function from the math module, which is used to calculate
the product of 2 given numbers, we import prod specifically as shown. We then can
access prod() directly without using the dot (.) operator.
To import modules defined by the user from different code files, use the following
syntax:
Syntax:
import <user_defined_module_name>
To import the val function in another module or use it in the interactive interpreter shell
of Python, type:
Interview Questions:
Python file handling is a versatile and powerful mechanism for performing operations on
file. Python file handling allows users to work on different types of files and allows them
to perform different operations on files. File handling is important as it allows us to store
data in file after running the program.
As the part of programming requirement, we have to store our data permanently for
future purpose. For this requirement we should go for files. Files are very common
permanent storage areas to store our data.
1. Text Files:
Ex: any_file.txt
2. Binary Files:
Usually, we can use binary files to store binary data like images, video files, audio
files etc...
User–friendly: Python provides a user-friendly, simple and short way for file
handling.
Error-prone: Python file handling sometimes throws an error when the code is
not written properly or if there is some issue in the file system.
Opening files:
Before performing any operation (like read or write) on the file, first we have to open that
file. For this we should use Python's inbuilt function open() But at the time of open, we
have to specify mode, which represents the purpose of opening file.
Open():
Syntax:
Open(file-name, mode-name)
In the above code, we have created the object of the file with the name f. This name will
be used further for performing operations on file.
File modes:
r-mode:
open an existing file for read operation. The file pointer is positioned at the beginning of
the file. If the specified file does not exist then we will get FileNotFoundError. This is
default mode.
w-mode:
open an existing file for write operation. If the file already contains some data then it will
be overridden. If the specified file is not already available then this mode will create that
file.
a-mode:
open an existing file for append operation. It won't override existing data. If the specified
file is not already available then this mode will create a new file.
r+-mode:
To read and write data into the file. The previous data in the file will not be deleted. The
file pointer is placed at the beginning of the file.
w+-mode:
a+-mode:
To append and read data from the file. It won’t override existing data.
x-mode:
To open a file in exclusive creation mode for write operation. If the file already exists
then we will get FileExistsError.
Once we opened a file and we got file object, we can get various details related to that
file by using its properties.
readable(): Returns boolean value indicates that whether file is readable or not.
writeable(): Returns boolean value indicates that whether file is writable or not.
Closing of files:
After completing our operations on the file, it is highly recommended to close the file.
For this we have to use close() function.
Syntax:
File-name.close()
Writing data into files:
write():
The write() method is used for writing data into the file, we need to open the file in write
mode for writing data into it, and we need to pass w as the second of the open() method
while writing to the file two things can happen:
If the file does not exist, then a new file will be created and data will be written
into it.
If the file already exists, then the whole data of the file will be deleted, and new
content will be inserted into it.
Syntax:
File-object.write(“any text”)
writelines():
Syntax:
File-object.writelines(“lines of text”)
Reading data from the file:
The with statement can be used while opening a file. We can use this to group file
operation statements within a block. The advantage of with statement is it will take care
closing of file, after completing all operations automatically even in the case of
exceptions also, and we are not required to close explicitly.
tell():
We can use tell() method to return current position of the cursor(file pointer) from
beginning of the file. The position(index) of first character in files is zero just like string
index.
Syntax:
File-object.tell()
seek():
Syntax:
File-object.seek(offset, from where)
Here:
offset represents the number of positions
from where:
0---->From beginning of file (default value)
1---->From current position
2--->From end of the file
Note:
Python 2 supports all 3 values but Python 3 supports only zero.
It is very common requirement to read or write binary data like images, video files, audio
files etc.
It is very common requirement to zip and unzip files. The main advantages are:
1. To improve memory utilization
2. We can reduce transport time
3. We can improve performance.
To perform zip and unzip operations, Python contains one in-built module zip file. This
module contains a class : ZipFile.
We have to create ZipFile class object with name of the zip file, mode and constant
ZIP_DEFLATED. This constant represents we are creating zip file.
Syntax:
f = ZipFile("files.zip","w","ZIP_DEFLATED")
Once we create ZipFile object, we can add files by using write() method.
Syntax:
Zipfile-object.write(file-name)
Unzip Operation:
Syntax:
f = ZipFile("files.zip","r",ZIP_STORED)
ZIP_STORED represents unzip operation. This is default value and hence we are not
required to specify. Once we created ZipFile object for unzip operation, we can get all
file names present in that zip file by using namelist() method.
Syntax:
Names = file-object.namelist()
Pickling and Unpickling:
Sometimes we have to write total state of object to the file and we have to read total
object from the file. The process of writing state of object to the file is called pickling and
the process of reading state of an object from the file is called unpickling. We can
implement pickling and unpickling by using pickle module of Python. pickle module
contains dump() function to perform pickling.
Syntax:
pickle.dump(object, file)
Syntax:
Object = pickle.load(file)
Unpickling:
Practice Programs:
Introduction:
Syntax Error:
The errors which occur because of invalid syntax are called syntax errors.
Note:
Programmer is responsible to correct these syntax errors. Once all syntax errors
are corrected then only program execution will be started.
Also known as exceptions. While executing the program if something goes wrong
because of end user input or programming logic or memory problems etc., then we will
get Runtime Errors.
Note:
Exception Handling concept applicable for Runtime Errors but not for syntax
errors.
What is an Exception?
An unwanted and unexpected event that disturbs normal flow of program is called
exception.
Ex: ZeroDivisionError, TypeError, ValueError, FileNotFoundError, EOFError,
SleepingError, TyrePuncturedError
It is highly recommended to handle exceptions. The main objective of exception
handling is Graceful Termination of the program (i.e., we should not block our resources
and we should not miss anything) Exception handling does not mean repairing
exception. We have to define alternative way to continue rest of the program normally.
Default Exception:
Every exception in Python is an object. For every exception type the corresponding
classes are available. Whenever an exception occurs PVM will create the
corresponding exception object and will check for handling code. If handling code is not
available then Python interpreter terminates the program abnormally and prints
corresponding exception information to the console. The rest of the program won't be
executed.
Exception Hierarchy:
Every Exception in Python is a class. All exception classes are child classes of
BaseException. i.e., every exception class extends BaseException either directly or
indirectly. Hence BaseException acts as root for Python Exception Hierarchy. Most of
the times being a programmer we have to concentrate Exception and its child classes.
Customized Exceptions:
It is highly recommended to handle exceptions. The code which may raise exception is
called risky code and we have to take risky code inside try block. The corresponding
handling code we have to take inside except block.
The way of handling exception is varied from exception to exception. Hence for every
exception type a separate except block we have to provide. i.e., try with multiple except
blocks is possible and recommended to use.
If try with multiple except blocks available then based on raised exception the
corresponding except block will be executed.
We can use default except block to handle any type of exceptions. In default except
block generally we can print normal error messages.
Syntax:
except:
statements
Finally Block:
Syntax:
try:
Risky Code
except:
Handling Code
finally:
Cleanup code
Types of Exceptions:
Pre-defined Exceptions:
Also known as in-built exceptions. The exceptions which are raised automatically by
Python virtual machine whenever a particular event occurs, are called pre-defined
exceptions.
Ex: Whenever we are trying to perform Division by zero, automatically Python will raise
ZeroDivisionError. print(10/0)
Ex:
InSufficientFundsException
InvalidInputException
TooYoungException
TooOldException
Interview Questions:
Introduction to Logging:
Logging is widely used in the software development process and software testing for
debugging and future testing. Python logging is a built-in module that is used to store
the log messages generated by Python programs into a file. The Python logging module
contains several functions and methods that are used to log several events. We can use
various methods to detect the error causing part in program execution and the exact
problem. For logging a program, we first import the module, and then the logger must
be configured. Finally, we can create an object of the logger and start using various
methods.
what is logging?
Logging refers to tracking the events that occur when we run a particular program or
software so that we can use the data for further improvement or error checking. Let us
learn about Python logging.
Python logging is a built-in module that comes with a Python interpreter. We can use
the Python logging module to store the log messages generated by Python programs
(or software working with Python frameworks) into a file. Logging is widely used in the
software development process and software testing process where developers log the
running process of the program for debugging and future testing. We can store the log
results in a file and can use it as a reference for other programs as well.
To understand the need for logging, let us suppose a situation where there is nothing
like logging. We have developed a program having a large code base but it is crashing
due to some reason that we need to find. Since the program is pretty large, we need to
check every step of the program and this can be pretty hectic. We may not even get the
exact reason for the problem. In such scenarios, we use something like a logging tool
that will trace the entire program execution and store it in a file so that we can refer to
the file and get the exact problem. Logging saves us time as well because debugging is
a time-consuming process.
By default, while executing Python program only WARNING and higher-level messages
will be displayed.
To perform logging, first we required to create a file to store messages and we have to
specify which level messages we have to store. We can do this by using basicConfig()
function of logging module.
Syntax:
logging.basicConfig(filename='log.txt',level=logging.WARNING)
The above line will create a file log.txt and we can store either WARNING level or
higher-level messages to that file. After creating log file, we can write messages to that
file by using the following methods.
logging.debug(message)
logging.info(message)
logging. Warning(message)
logging.error(message)
logging.critical(message)
How to write Python program exceptions to the log file:
By using the following function we can write exceptions information to the log file.
Syntax:
logging.exception(msg)
The process of identifying and fixing the bug is called debugging. Very common way of
debugging is to use print() statement. But the problem with the print() statement is after
fixing the bug, compulsory we have to delete the extra added print() statements,
otherwise these will be executed at runtime which creates performance problems and
disturbs console output. To overcome this problem we should go for assert statement.
The main advantage of assert statement over print() statement is after fixing bug we are
not required to delete assert statements. Based on our requirement we can enable or
disable assert statements. Hence the main purpose of assertions is to perform
debugging. Usually we can perform debugging either in development or in test
environments but not in production environment. Hence assertions concept is applicable
only for dev and test environments but not for production environment.
Simple Version:
Syntax:
assert conditional_expression
Augmented Version:
Syntax:
assert conditional_expression, message
Here:
conditional_expression will be evaluated and if it is true then the program will be
continued.
Introduction
OOPs Concepts
Benefits of OOPs
Class and Object
__init__() Method
Types of Attributes
Instance Methods
OOPs Concepts
Inheritance
super() method
Polymorphism
Encapsulation
Access Modifiers
Abstraction
Object Oriented Programming
Introduction:
OOPS concepts in Python are very closely related to our real world, where we write
programs to solve our problems. Solving any problem by creating objects is the most
popular approach in programming. This approach is termed as Object Oriented
Programming. Object-oriented programming maps our code instructions with real-
world problems, making it easier to write and simpler to understand. They map real-
world entities (such as companies and employees) as 'software objects' that have some
'data' associated with them and can perform some 'functions'.
Benefits of OOPs:
1. They reduce the redundancy of the code by writing clear and reusable codes
(using inheritance).
2. They are easier to visualize because they completely relate to real-world
scenarios. For example, the concept of objects, inheritance, and abstractions,
relate very closely to real-world scenarios.
3. Every object in OOPS represent a different part of the code and has its own logic
and data to communicate with each other. So, there are no complications in the
code.
Suppose you wish to store the number of books you have, you can simply do that by
using a variable. Or, say you want to calculate the sum of 5 numbers and store it in a
variable, well, that can be done too! Primitive data structures like numbers, strings, and
lists are designed to store simple values in a variable. Suppose, your name, or square
of a number, or count of some marbles (say). But what if you need to store the details of
all the Employees in your company? For example, you may try to store every employee
in a list, you may later be confused about which index of the list represents what details
of the employee (e.g. which is the name field, or the empID etc.)
Even if you try to store them in a dictionary, after an extent, the whole codebase will be
too complex to handle. So, in these scenarios, we use Classes in python. A class is
used to create user-defined data structures in Python. Classes define functions, which
are termed methods, that describe the behaviors and actions that an object created
from a class can perform. OOPS concepts in Python majorly deal with classes and
objects. Classes make the code more manageable by avoiding complex codebases. It
does so, by creating a blueprint or a design of how anything should be defined. It
defines what properties or functions, any object which is derived from the class should
have.
Note:
A class just defines the structure of how anything should look. It does not point to
anything or anyone in particular. For example, say, HUMAN is a class, which has suppose --
name, age, gender, city. It does not point to any specific HUMAN out there, but yes, it explains the
properties and functions any HUMAN should or any object of class HUMAN should have.
An instance of a class is called the object. It is the implementation of the class and
exists in real. An object is a collection of data (variables) and methods (functions) that
access the data. It is the real implementation of a class.
Consider this example, here Human is a class - It is just a blueprint that defines
how Human should be, and not a real implementation. You may say that "Human" class
just exists logically.
However, "Ron" is an object of the Human class (please refer to the image given above
for understanding). That means, Ron is created by using the blueprint of
the Human class, and it contains the real data. "Ron" exists physically,
unlike "Human" (which just exists logically). He exists in real, and implements all
the properties of the class Human, such as, Ron have a name, he is 15 years old, he is
a male, and lives in Delhi. Also, Ron implements all the methods of Human class,
suppose, Ron can walk, speak, eat, and sleep. And many humans can be created using
the blueprint of class Human. Such as, we may create 1000s of more humans by
referring to the blueprint of the class Human, using objects.
Note:
class = blueprint (suppose an architectural drawing). The Object is an actual thing that
is built based on the ‘blueprint’ (suppose a house). An instance is a virtual copy (but not
a real copy) of the object.
When a class is defined, only the blueprint of the object is created, and no memory is
allocated to the class. Memory allocation occurs only when the object or instance is
created. The object or instance contains real data or information.
Class Definition:
Classes in Python can be defined by the keyword class, which is followed by the name
of the class and a colon.
Syntax:
class Name-Of-Class:
implementation of Class
Indented code below the class definition is considered part of the class body.
The properties that all Human objects must have been defined in a method called init(). Every
time a new Human object is created, __init__() sets the initial state of the object by
assigning the values we provide inside the object’s properties. That
is, __init__() initializes each new instance of the class.
__init__() can take any number of parameters, but the first parameter is always a
variable called self.
The self parameter is a reference to the current instance of the class. It means,
the self parameter points to the address of the current object of a class, allowing us to access the data of
its(the object's) variables.
So, even if we have 1000 instances (objects) of a class, we can always get each of their individual
data due to this self because it will point to the address of that particular object and return the
respective value.
Note:
We can use any name in place of self, but it has to be the first parameter of any function in the
class.
Types of Attributes:
1. Class Attribute:
These are the variables that are the same for all instances of the class. They do not
have new values for each new instance created. They are defined just below the
class definition.
2. Instance Attribute:
Instance attributes are the variables that are defined inside of any function in class.
Instance attributes have different values for every instance of the class. These
values depend upon the value we pass while creating the instance.
Object Creation:
When we create a new object from a class, it is called instantiating an object. An object
can be instantiated by the class name followed by the parentheses. We can assign the object of a class
to any variable.
Syntax:
Identifier-for-Object = ClassName()
Note:
If we do not pass the required arguments, it will throw a TypeError: TypeError: init()
missing 3 required positional arguments: 'name', 'age', and 'gender'.
However, we can change the value of class attributes, by
assigning classname.classAttribute with any new value.
Instance Methods:
An instance method is a function defined within a class that can be called only from
instances of that class. Like init(), an instance method's first parameter is always self.
OOPs Concepts:
1. Inheritance
2. Encapsulation
3. Polymorphism
4. Data abstraction
Inheritance:
People often say to newborn babies that they have got similar facial features to their
parents, or that they have inherited certain features from their parents. It is likely that
you too have noticed that you have inherited some or the other features from your
parents.
Inheritance too is very similar to the real-life scenario. But here, the " child classes" inherit
features from their "parent classes." And the features they inherit here are termed as "properties" and
"methods"!
Inheritance is the process by which a class can inherit or derive the properties(or data)
and methods(or functions) of another class. Simply, the process of inheriting the
properties of a parent class into a child class is known as inheritance.
The class whose properties are inherited is the Parent class, and the class that inherits the
properties from the Parent class is the Child class.
So, we define a normal class as we were defining in our previous examples. Then, we
can define the child class and mention the parent class name, which it is inheriting in
parentheses.
Let's see the issue we face if we are trying to call child class's methods using parent
class's object:
So, here we get the AttributeError: 'Human' object has no attribute 'schoolName'. Because the
child classes can access the data and properties of parent class but vice versa is not possible.
super() method:
The super() function in python is a inheritance-related function that refers to the parent
class. We can use it to find the method with a particular name in an object’s superclass.
It is a very useful function.
Syntax:
super().methodName()
Polymorphism:
Suppose, you are scrolling through your Instagram feeds on your phone. You suddenly
felt like listening to some music as well, so you opened Spotify and started playing your
favorite song. Then, after a while, you got a call, so you paused all the background
activities you were doing, to answer it. It was your friend's call, asking you to text the
phone number of some person. So, you messaged him the number, and resumed your
activities.
Did you notice one thing? You could scroll through feeds, listen to music, attend/make
phone calls, message -- everything just with a single device - your Mobile Phone! Whoa!
So, Polymorphism is something similar to that. 'Poly' means multiple and 'morph' means
forms. So, polymorphism altogether means something that has multiple forms. Or, 'some thing' that can
have multiple behaviors depending upon the situation.
Polymorphism in OOPS refers to the functions having the same names but carrying
different functionalities. Or, having the same function name, but different function
signature (parameters passed to the function).
A child class inherits all properties from its parent class methods. But sometimes, it
wants to add its own implementation to the methods. There are ample of ways we can
use polymorphism in Python.
We also have polymorphism with the '+' addition operator. We can use it to 'add'
integers or floats or any arithmetic addition operation. In the other hand, with String, it
performs the 'concatenation' operation.
You must have seen medicine capsules, where all the medicines remain enclosed
inside the cover of the capsule. Basically, a capsule encapsulates several combinations
of medicine.
Similarly, in programming, the variables and the methods remain enclosed inside a
capsule called the 'class'! Yes, we have learned a lot about classes in Python and we
already know that all the variables and functions we create in OOP remain inside the class.
The process of binding data and corresponding methods (behavior) together into a
single unit is called encapsulation in Python.
In other words, encapsulation is a programming technique that binds the class members
(variables and methods) together and prevents them from being accessed by other
classes. It is one of the concepts of OOPS in Python.
Encapsulation is a way to ensure security. It hides the data from the access of outsiders. An
organization can protect its object/information against unwanted access by clients or any unauthorized
person by encapsulating it.
We mainly use encapsulation for Data Hiding. We do so by defining getter and setter methods
for our classes. If anyone wants some data, they can only get it by calling the getter method. And, if they
want to set some value to the data, they must use the setter method for that, otherwise, they won't be
able to do the same. But internally, how these getter and setter methods are performed remains hidden
from the outside world.
Access Modifiers:
Access modifiers limit access to the variables and methods of a class. Python
provides three types of access modifiers private, public, and protected.
In Python, we don’t have direct access modifiers like public, private, and protected. We
can achieve this by using single underscore and double underscores.
We can access private members from outside of a class by creating public method to access
private members (just like we did above). There is one more method to get access called name
mangling.
A protected data member is used when inheritance is used and you want the data members to have
access only to the child classes.
So, encapsulation protects an object from unauthorized access. It allows private and
protected access levels to prevent accidental data modification.
Abstraction:
It is likely that you are reading this article on your laptop, phone, or tablet. You are also
probably making notes, and highlighting important points, and you may be saving some
points in your internal files while reading it. As you read this, all you see before you is a
'screen' and all this data that is shown to you. As you type, all you see are the keys on
the keyboard and you don't have to worry about the internal details, like how pressing a
key may lead to displaying that word onscreen. Or, how clicking on a button on your
screen could open a new tab! So, everything we can see here is at an abstract level. We are not
able to see the internal details, but just the result it is producing (which actually matters to us).
Abstraction in a similar way just shows us the functionalities anything holds, hiding all
the implementations or inner details.
The main goal of Abstraction is to hide background details or any unnecessary implementation
about the data so that users only see the required information. It helps in handling the complexity of the
codes.
Syntax:
from abc import ABC
class ClassName(ABC):
ABC stands for Abstract Base class. The abc module provides the base for defining
Abstract Base classes (ABC).
Note:
Advantages of OOPs:
There are numerous advantages of OOPS concepts in Python, making it favorable for
writing serious software’s.
1. Effective problem solving because, for each mini-problem, we write a class that
does what is required. And then we can reuse those classes, which makes it
even quicker to solve the next problem.
2. Flexibility of having multiple forms of a single class, through polymorphism
3. Reduced high complexity of code, through abstraction.
4. High security and data privacy through encapsulation.
5. Reuse of code, by the child class inheriting properties of parent class through
inheritance.
6. Modularity of code allows us to do easy debugging, instead of looking into
hundreds of lines of code to find a single issue.
Practice Programs:
1. Finding patterns in a string or file. (Ex: find all the numbers present in a string)
2. Replace a part of the string with another string.
3. Search substring in string or file.
4. Split string into substrings.
5. Validate email format.
RegEx Module:
RegEx Functions:
findall(pattern, string):
This function is the same as search but it matches all the occurrences of the pattern in
the given string and returns a list. The list contains the number of times it is present in
the string.
search(pattern, string):
This is the same as match function but this function can search patterns irrespective of
the position at which the pattern is present. The pattern can be present anywhere in the
string. This function matches the first occurrence of the pattern.
split(pattern, string):
This function splits a string on the given pattern. This returns the result as a list after
splitting.
This function replaces a pattern with the given substring in a given string.
Math Object:
Whenever we call any regex method/function it searches the pattern in the string. If it
finds a match then it returns a match object else return None. We will see how the
match object looks like and how to access methods and properties of that object.
Now we will see the attributes and properties of re.Match objects one by one. They are
as follows:
match.group(): This returns the part of the string where the match was there.
match.start(): This returns the start position of the matching pattern in the string.
match.end(): This returns the end position of the matching pattern in the string.
match.span(): This returns a tuple which has start and end positions of matching
pattern.
match.re: This returns the pattern object used for matching.
match.string: This returns the string given for matching.
Using r prefix before regex: This is used to convert the pattern to raw string.
This means any special character will be treated as normal character. Ex: \
character will not be treated as an escape character if we user before the pattern.
Interview Questions:
1) Write a Python program to check that a string contains only a certain set of
characters (in this case a-z, A-Z and 0-9).
2) Write a Python program that matches a string that has an a followed by zero or
more b's.
3) Write a Python program that matches a string that has an a followed by one or
more b's.
4) Write a Python program that matches a string that has an a followed by zero or
one 'b'.
5) Write a Python program that matches a string that has an a followed by three 'b'.
6) Write a Python program to find sequences of lowercase letters joined by an
underscore.
7) Write a Python program that matches a string that has an 'a' followed by anything
ending in 'b'.
8) Write a Python program that matches a word at the end of a string, with optional
punctuation.
9) Write a Python program that matches a word containing 'z', not the start or end
of the word.
10) Write a Python program that starts each string with a specific number.
Unit-17: Multithreading
Introduction
What is Process
What is Thread
What is Multithreading
What is Multiprocessing
Why Multithreading?
Starting the thread
The Threading Module
Working with Multiple Threads
Race Conditions
Synchronizing Threads
Multithreading Priority Queues
Threading Objects
Advantages of Multithreading
Multithreading
Introduction:
We all know the famous saying- Time is money. It is always said that humans are not
built for multitasking. But that is where machines come in. So while you might not be
able to multitask easily, we will talk about the tips and tricks that increase performance
and reduce time consumption, in the case of computers. Can you guess what we are
going to learn about today? The multitasking approach that we will discuss in this
tutorial is multithreading in Python!
What is Process?
A program in execution is known as a process. When you start any app or program on
your computer, such as the internet browser, the operating system treats it as a
process.
A process may consist of several threads of execution that may execute concurrently. In
other words, we can say a process facilitates multithreading.
What is Thread?
Thread Module
Threading Module
With the Threading module in Python, which provides a very intuitive API for spawning
threads, we can perform multithreading in Python quite effectively.
What is multithreading?
If you wish to save time and improve performance, you should use multithreading in
Python! Multithreading in Python is a popular technique that enables multiple tasks to
be executed simultaneously. In simple words, the ability of a processor to execute
multiple threads simultaneously is known as multithreading. Python multithreading
facilitates sharing data space and resources of multiple threads with the main thread. It
allows efficient and easy communication between the threads.
What is Multiprocessing?
Multiprocessing breaks down processes into smaller routines that run independently.
The more tasks a single processor is burdened with, the more difficult it becomes for the
processor to keep track of them.
It evidently gives rise to the need for multiprocessing. Multiprocessing tries to ensure
that every processor gets its own processor/processor core and that execution is
hassle-free.
Note:
In the case of multicore processor systems like Intel i3, a processor core is
allotted to a process.
Multithreading Vs Multiprocessing:
Why Multithreading?
If you wish to break down your tasks and applications into multiple sub-tasks and then
execute them simultaneously, then multithreading in Python is your best bet.
All important aspects such as performance, rendering, speed and time consumption will
drastically be improved by using proper Python multithreading.
Multithreading in Python should be used only when there is no existing inter-
dependency between the threads.
After learning what a thread is, the next step is to learn how to create one. Python offers
a standard library called "threading" to perform multithreading in Python.
In Python multithreading, there are two ways in which you can start a new thread:
More often than not, you will be working with multiple threads and doing exciting work
with them. You can create the threads individually, as we saw above. But there is an
easier and more efficient way of doing that. We do this by using the
ThreadPoolExecutor in Python!
Using theThreadPoolExecutor:
The easiest way to work with multiple threads is by using the ThreadPoolExecutor, part
of the standard Python library. It falls under the concurrent.features library. Using
the with statement, you can create a context manager. It would enable you to create
and delete a pool efficiently. We can also import the ThreadPoolExecutor directly from
the concurrent.features library.
Syntax:
executor = ThreadPoolExecutor(max_workers=””)
threading.enumerate() −This returns the list of all thread objects that are
presently active
Race Condition:
Race conditions are one of the primary issues you will face while working with
multithreading in Python. Most commonly, race conditions happen when two or more
threads access the shared piece of data and resource. In real-time multithreading in
Python, it can occur when threads overlap. The solution to this is synchronizing threads
which we will see further.
Synchronizing Threads:
In Python, you can implement the locking mechanism to enable you to synchronize the
threads.
Locked
Unlocked
The class that is used to implement primitive locks is known as Lock. Lock objects are
created to make the threads run synchronously. Only one thread at a time can have a
lock.
The parameter that we pass through the Lock class' acquire() method is known as the
blocking parameter. Let's assume we have a thread object T to understand how all
these work together. As mentioned before, if we wish to call the acquire() method for T,
we will pass the blocking parameter through it. The blocking parameter can have only
two possible values- True or False. It gives rise to two scenarios.
Scenario 1: When the blocking parameter is set to True, and we call the acquire
method as T.acquire (blocking=True), the thread object will acquire the lock T.
This can happen only when T has no existing locks. On the flip side, if the thread
object T is already locked, the acquire() call is suspended, and it waits until T
releases the lock. The moment thread T frees up, the calling thread immediately
re-locks it. The calling thread then acquires the released lock.
A new queue object can be created using the Queue module. It can hold a specific
number of items. You can use the following methods to control the queue:
Threading Objects:
1. Semaphore
2. Timer
3. Barrier
Semaphore:
Time:
The object used to schedule a function to be called after a certain amount of time
has passed is the threading.Timer.
The Timer is started by using the .start() method.
The Timer is stopped by using the .cancel() method.
Barrier:
The object used to keep multiple threads in sync is the threading.Barrier() object.
You need to specify the number of threads to be synchronized while creating the
Barrier.
The .wait() method is called by each thread on a Barrier.
Advantages of Multithreading:
1) Write a Python program to create multiple threads and print their names.
2) Write a Python program to download multiple files concurrently using threads.
3) Write a Python program that creates two threads to find and print even and odd
numbers from 30 to 50.
4) Write a Python program to implement a multi-threaded merge sort algorithm.
5) Write a Python program to calculate the factorial of a number using multiple
threads.
6) Write a Python program that performs concurrent HTTP requests using threads.
7) Write a Python program to implement a multi-threaded quicksort algorithm.
Unit-18: Data Structures
Collection Module
Counters
Ordered Dict
Default Dict
Chain Map
Named Tuple
Deque
User Dict
User String
Linked List
Stack
Queue
Priority Queue
Heap Queue
Binary Tree
Graphs
Counters:
Counters are a subclass of dictionary designed to count hashable objects. They are an
incredibly useful tool for tallying elements and implementing counting algorithms.
Ordered Dict:
Default Dict:
A Default Dict is a dictionary subclass that calls a factory function to supply missing
values, simplifying handling of missing keys.
Chain Map:
A Chain Map groups multiple dictionaries into a single view, making it convenient to
manage multiple scopes (e.g., variable scopes in programming languages).
Named Tuple:
Named Tuples enable the creation of objects akin to tuples that are indexable, iterable,
and whose fields can be accessed via attribute lookup.
Deque:
A deque (double-ended queue) is a generalization of stacks and queues which supports
memory-efficient and fast appends and pops from either side.
User Dict:
User Dict is a wrapper around dictionary objects for easier dictionary subclassing.
User String:
User String is a wrapper around string objects for easier string subclassing.
Linked List:
A linked list is a linear collection of data elements where each element points to the
next, allowing for a dynamic data structure with efficient insertions and deletions.
Stack:
A stack is a linear data structure that follows the Last In, First Out (LIFO) principle.
Queue:
In a list-based implementation, the append() method is used for enqueue operations, while
the pop(0) method is employed for dequeue operations, as shown below:
Implementation using collections.deque:
The collections.deque is preferred for queue implementations due to its efficient O(1) time complexity
for append and pop operations from both ends, compared to the list's O(n) for certain operations.
Implementation using queue.queue:
The queue. Queue class provides a FIFO queue implementation suitable for multi-
threading environments, with methods to check if the queue is full or empty.
Priority Queue:
Priority queues in Python are specialized data structures using Python that organize
elements such that each is assigned a certain priority. This concept in data structures
using Python mirrors real-world situations where tasks of higher importance are
addressed first, irrespective of the sequence in which they come up.
Heap Queue:
The heap queue module in Python provides an array of functions for managing heaps,
which are a specialized data structure using Python that follows the heap queue or
priority queue algorithm. In these data structures using Python, heaps are implemented
as binary trees where the value of each parent node is less than or equal to the values
of its children, ensuring the smallest element is consistently positioned at the
root, heap[0]. The module facilitates efficient operations—such as inserting and
extracting the smallest element—within O(log n) time, making it exceptionally suitable
for tasks that demand regular retrieval of the smallest item.
Binary Tree:
A binary tree is a specialized form of a tree utilized in data structures using python,
where each node can have no more than two children, commonly identified as the left
and right child. In the realm of data structures using Python, this structure is vital for a
multitude of computing tasks, ranging from straightforward data storage to the execution
of intricate algorithms.
Graphs:
Graphs as one of the more complex data structures in Python, are characterized by
their capacity to depict intricate connections through nodes (or vertices) and edges that
link these nodes. This type of data structures in Python is defined by a collection of
vertices (V) and edges (E) which join vertex pairs, thereby showcasing the interlinked
attributes of the data they represent. Graphs can be represented in Python using two
primary methods: the Adjacency Matrix and the Adjacency List.
Adjacency Matrix:
An Adjacency Matrix takes the form of a square matrix and serves to depict a finite
graph. The matrix entries denote the adjacency between vertex pairs; a non-zero value
implies the presence of an edge connecting those vertices. In the matrix representation,
if there is an edge between vertex (i) and vertex (j), then the matrix cell ([i][j]) is set to
(1), or a weight in the case of a weighted graph. This method is excellent for
representing dense graphs, where the number of edges is large.
Adjacency List:
The Adjacency List is a more space-efficient way to represent graphs, especially sparse
ones. It consists of an array of lists, where the index of the array represents a vertex
and the list at each index contains the vertices adjacent to that vertex. This method
allows for faster and more efficient storage of graphs when you have a large number of
vertices but few edges.
Interview Questions:
What is NumPy?
Indexing:
Indexing is used for accessing elements from an array. It starts from 0. Below is a code
example where the element of the index (0,2)(0,2) are accessed, where 0 stands for the
1st row and 1 for the 3rd column from the 2-D array.
Slicing:
Slicing is the method for getting substrings from the original arrays by mentioning the
start and end inside the slice operator []. Let's see the below example where the
substring from the 2nd element to the 5th element is sliced.
Note:
elements are accessed through indexing.
array.ndim:
array.itemsize:
array.itemsize is used to find the size of each element of the Numpy array in bytes.
array.dtype:
array.size is used to find the size of the array by counting the number of elements from
the given array.
array.shape:
By using the array.shape function, we can find the shape, i.e., the number of rows and
columns of an array.
It returns a tuple.
The lengths of the corresponding array dimensions are given by the tuple items.
array.reshape():
array.reshape is used to reshape the array; it means changing the shape, i.e., rows and
columns of the array.
array.sum():
Why Numpy?
Fast
It works very well with SciPy and other Libraries
Matrix arithmetic
It has lot of inbuilt functions.
it has universal functions
Features of NumPy:
Applications of NumPy:
NumPy Installation:
On Windows:
1. Install NumPy using the following PIP command in the command prompt
terminal:
Syntax:
pip install numpy
The installation will start automatically, and Numpy will be successfully installed
with its latest version.
2. Verify NumPy Installation by typing the command given below in command:
Syntax:
pip show Numpy
Let's now see what is pandas in Python. Pandas is an open-source Python library that
has a BSD license (BSD licenses are a low-restriction type of license for open source
software that imposes minimum restrictions on the use and distribution of open source
software) and is used in data science, data analysis, and machine learning activities.
Both readily and intuitively, it functions with relational or labeled data.
It offers a variety of data structures and operations for working with time series and
numerical data. This library is developed on top of the NumPy library, which supports
multi-dimensional arrays. As a result, pandas are quick and offer users high
performance and productivity. Being one of the most widely used data-wrangling tools,
Pandas integrates well with a variety of different data science modules within the
Python environment and is frequently available in all Python distributions, including
those that come with your operating system and those sold by commercial vendors like
Active State’s ActivePython.
Features of Pandas:
Advantages of Pandas:
Less writing and more productivity It is one of the Pandas' best features. With
the help of Pandas, multiple lines of Python code in the absence of any support
libraries can be easily completed in one or two lines. As a result, Pandas help to
reduce time and procedures while also speeding up the data-handling process.
As a result, we can devote more time to data analysis algorithms.
Efficiently handles large amounts of data Pandas handle large datasets very
efficiently. Pandas save a lot of time by importing large amounts of data quickly.
A large number of features Pandas provide you with a large set of important
commands and features by which data can be easily analyzed. In addition,
pandas can perform various tasks, such as data filtering based on certain
conditions, segmenting and segregating the data by preferences, and so on.
Flexibility and customization of data With the help of Pandas, you may apply a
wide range of features. For example, we can alter, customize, and pivot the
existing data according to our wishes. Your data may be used to its greatest
extent by doing this.
Series:
A series is a one-dimensional array that contains elements of the same data type.
Series are mutable means we can modify the elements of a series but its size is
immutable, i.e. we cannot change the size of the series once declared. It has two main
components: data and an index.
Parameters:
data(required): This is the input data, which can be any list, dictionary, etc.
index(Optional): The index for the value you use for the series is represented by
this number.
dtype(Optional): This describes the values contained in the series.
copy(Optional): This makes a copy of the input data.
Dataframe:
Dataframe is a 2-dimensional data structure that contains elements of the same data. It
is mutable, and its size is also mutable, i.e. we can change both data and size of the
dataframe data structure. It has labeled axes (rows and columns) and has two different
indexes (row index and column index) as both rows and columns are indexed.
Parameters:
data(required): Input data, can be ndarray, series, map, lists, dict, constants,
and another DataFrame.
index(optional): For labeling rows.
columns(Optional): For labeling columns.
dtype(Optional): Data type of each column.
copy(Optional): This makes a copy of the input data.
To open the start menu, use the Windows key on your keyboard or click the Start
button. For example, when you type "cmd" the Command Prompt app should display in
the start menu, and once you can view the command prompt app, launch the app.
Alternatively, you may hit the Windows key + r to bring up the "RUN" box, where you
can input “cmd” and then press enter. It will also launch the Command prompt.
After you open the command prompt, the following step is to enter the needed
command to begin the pip installation.
Syntax:
pip install pandas
(or)
pip3 install pandas
Using Conda:
Installing Pandas using Anaconda is the best option if you are unfamiliar with command-
line programming. Anaconda is a sophisticated Python distribution that provides access
to various libraries besides Pandas. Anaconda will become increasingly handy as you
learn further about Python.
To install Anaconda, go to this page and then click on the "Download" button
on the right.
Start your installation from the website by clicking the "Next" button.
Then, click the "I Agree" option to accept the licensing agreement.
Then, pick the user accounts for whom Pandas should be installed. We proceeded by
selecting the recommended "Just Me" option.
In the wizard's concluding stage, you must specify where the distribution will be
downloaded.
Finally, under the advanced installation options area, tick the "Add Anaconda to my
PATH environment variable" and "Register Anaconda3 as my preferred Python 3.x (x
over here denotes whatever the current version could be)" choices.
The installation of Anaconda will begin when you click the "Install" button. When the
setup is finished, you will see the "Installation Complete" screen within a few minutes.
=== Learn Here.. Lead Anywhere..!! ===