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

Data Analytics Using Python - Sem-6 - IT

Uploaded by

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

Data Analytics Using Python - Sem-6 - IT

Uploaded by

Vikash Yadav
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 136

LECTURE NOTES

ON

DATA ANALYTICS USING


PYTHON

B.Tech (CSE/IT)

SEMESTER-VI
2
3
Table of Contents
Module-1 ................................................................................................................................................ 7
INTRODUCTION TO PYTHON ........................................................................................................ 7
1.1 Brief history of python ...................................................................................................................... 7
1.2 Data types in Python ......................................................................................................................... 9
1.2.1 Python Numbers......................................................................................................................... 9
1.3 Python List ...................................................................................................................................... 10
1.4 Python Tuple ................................................................................................................................... 11
1.5 Python Set ....................................................................................................................................... 11
1.6 Python Strings ................................................................................................................................. 11
1.7 Python Dictionary ........................................................................................................................... 12
1.8 Python Variables ............................................................................................................................. 12
1.8.1 Assigning a value to a Variable in Python ............................................................................... 13
1.9 Constants ......................................................................................................................................... 14
1.10 Literals .......................................................................................................................................... 14
1.10.1 Numeric Literals .................................................................................................................... 14
1.10.2 String literals .......................................................................................................................... 15
1.10.3 Boolean literals ...................................................................................................................... 16
1.11 Python Keywords .......................................................................................................................... 17
1.12 Rules and Naming Convention for Variables and Constants ........................................................ 17
1.13 Operators ....................................................................................................................................... 18
1.9. Precedence and Associativity of Operators in Python ................................................................... 23
1.10 File Handling in Python ................................................................................................................ 24
1.11 Control Statements ........................................................................................................................ 26
Module-2 .............................................................................................................................................. 28
FUNCTIONS AND DATA STRUCTURES IN PYTHON .............................................................. 28
2.1 Functions- Basics of functions ........................................................................................................ 28
2.2 Recursive Functions ........................................................................................................................ 29
2.3 First Class functions in Python or Functions as Objects ................................................................. 30
2.4 Lists in Python ................................................................................................................................ 31
2.5 Lists – Methods to process lists ...................................................................................................... 35
2.6 Copy in Python (Deep Copy and Shallow Copy) ........................................................................... 40
2.7 Using List as Stack and Queues in Python ..................................................................................... 44

4
2.8 Nested lists ...................................................................................................................................... 45
2.9 List as Matrix .................................................................................................................................. 45
2.10 Tuples in Python ........................................................................................................................... 47
2.11 Nested Tuples................................................................................................................................ 51
2.12 Dictionary ..................................................................................................................................... 52
2.13 Ordered Dictionary in Python ....................................................................................................... 58
2.14 Iterate over a dictionary in Python ................................................................................................ 61
2.15 Conversion of list and strings into dictionary ............................................................................... 63
2.16 Sets and Frozen sets in Python...................................................................................................... 66
2.17 Lambda function in python ........................................................................................................... 69
2.18 Filter() in python ........................................................................................................................... 70
2.19 reduce() in Python ......................................................................................................................... 71
2.20 Map() function .............................................................................................................................. 73
2.21 Iterators in Python ......................................................................................................................... 73
2.22 List Comprehension ...................................................................................................................... 77
Module-3 .............................................................................................................................................. 79
OBJECTS IN PYTHON ..................................................................................................................... 79
3.1 Classes and Instance attributes........................................................................................................ 79
3.2 Inheritance....................................................................................................................................... 80
3.3 Different forms of Inheritance ........................................................................................................ 81
3.4 Method Resolution Order (MRO) ................................................................................................... 82
3.5 Magic methods ................................................................................................................................ 84
3.6 Operator Overloading in Python ..................................................................................................... 87
3.7 Meta Classes ................................................................................................................................... 89
3.8 Abstract and Inner classes ............................................................................................................... 91
3.9 Exception Handling ........................................................................................................................ 94
3.10 Modular Programs and Packages .................................................................................................. 96
Module-4 ............................................................................................................................................ 100
Numerical Analysis in python .......................................................................................................... 100
4.1 Introduction to NumPy ................................................................................................................. 100
4.2 NumPy - Ndarray Object .............................................................................................................. 100
4.3 NumPy Numerical types ............................................................................................................... 107
4.3.1 Data type Object (dtype) in NumPy Python .......................................................................... 107
4.3.2 Character Codes ..................................................................................................................... 109

5
4.3.3 One Dimensional Indexing using index arrays ...................................................................... 109
4.4 Creating a Two-dimensional Array............................................................................................... 112
4.5 Stacking Arrays using numpy.stack() in Python ........................................................................... 113
4.6 Splitting NumPy arrays ................................................................................................................. 114
4.7 NumPy - Array Attributes ............................................................................................................. 115
4.8 Converting 1-d and 2-d Arrays ..................................................................................................... 118
4.9 Creating Array views and copies .................................................................................................. 119
4.10 Indexing Numpy arrays with Booleans ....................................................................................... 123
4.11 Broadcasting numPy arrays ........................................................................................................ 124
Module-5 ............................................................................................................................................ 128
DATA MANIPULATION AND VISUALIZATION IN PYTHON.......................................... 128
5.1 Data Frames in Panda ................................................................................................................... 128
5.2 Creating Data frames from .csv and excel files ............................................................................ 128
5.3 Creating DataFrame from dict of ndarray/lists ............................................................................. 129
5.4 Dataframes Aggregation and concatenation ................................................................................. 130
5.5 Plotting using matplotlib & panda ................................................................................................ 133

6
Module-1

INTRODUCTION TO PYTHON

1.1 Brief history of python

Python is a widely used general-purpose, high-level programming language. It was initially


designed by Guido van Rossum in 1991 and developed by Python Software Foundation. It
was mainly developed for emphasis on code readability, and its syntax allows programmers
to express concepts in fewer lines of code.

It was that time when working on Python started. Soon after that, Guido Van Rossum began
doing its application based work in December of 1989 by at Centrum Wiskunde &
Informatica (CWI) which is situated in Netherland. It was started firstly as a hobby project
because he was looking for an interesting project to keep him occupied during Christmas.

The programming language which Python is said to have succeeded is ABC Programming
Language, which had the interfacing with the Amoeba Operating System and had the feature
of exception handling. He had already helped to create ABC earlier in his career and he had
seen some issues with ABC but liked most of the features. He had taken the syntax of ABC,
and some of its good features. It came with a lot of complaints too, so he fixed those issues
completely and had created a good scripting language which had removed all the flaws.

The inspiration for the name came from BBC’s TV Show – ‘Monty Python’s Flying Circus’,
as he was a big fan of the TV show and also he wanted a short, unique and slightly
mysterious name for his invention and hence he named it Python!

The language was finally released in 1991. When it was released, it used a lot fewer codes to
express the concepts, when we compare it with Java, C++ & C. Its design philosophy was
quite good too. Its main objective is to provide code readability and advanced developer
productivity. When it was released it had more than enough capability to provide classes with
inheritance, several core data types exception handling and functions.

Following are the illustrations of different versions of Python along with the timeline.

7
8
1.2 Data types in Python
Every value in Python has a datatype. Since everything is an object in Python programming,
data types are actually classes and variables are instance (object) of these classes.
There are various data types in Python. Some of the important types are listed below.

1.2.1 Python Numbers


Integers, floating point numbers and complex numbers fall under Python numbers category.
They are defined as int, float and complex class in Python.
We can use the type() function to know which class a variable or a value belongs to and
the isinstance() function to check if an object belongs to a particular class.

a=5
print(a, "is of type", type(a))

a = 2.0
print(a, "is of type", type(a))

9
a = 1+2j
print(a, "is complex number?", isinstance(1+2j,complex))

Integers can be of any length, it is only limited by the memory available.

A floating point number is accurate up to 15 decimal places. Integer and floating points are
separated by decimal points. 1 is integer, 1.0 is floating point number.

Complex numbers are written in the form, x + yj, where x is the real part and y is the
imaginary part. Here are some examples.

>>> a = 1234567890123456789
>>> a
1234567890123456789
>>> b = 0.1234567890123456789
>>> b
0.12345678901234568
>>> c = 1+2j
>>> c
(1+2j)
Notice that the float variable b got truncated.

1.3 Python List


List is an ordered sequence of items. It is one of the most used data type in Python and is very
flexible. All the items in a list do not need to be of the same type.

Declaring a list is pretty straight forward. Items separated by commas are enclosed within
brackets [ ].

>>> a = [1, 2.2, 'python']

a = [5,10,15,20,25,30,35,40]

# a[2] = 15
print("a[2] = ", a[2])

# a[0:3] = [5, 10, 15]


print("a[0:3] = ", a[0:3])

# a[5:] = [30, 35, 40]


print("a[5:] = ", a[5:])

Lists are mutable, meaning, value of elements of a list can be altered.

>>> a = [1,2,3]
>>> a[2]=4
>>> a

10
[1, 2, 4]

1.4 Python Tuple


Tuple is an ordered sequence of items same as list.The only difference is that tuples are
immutable. Tuples once created cannot be modified.

Tuples are used to write-protect data and are usually faster than list as it cannot change
dynamically. It is defined within parentheses () where items are separated by commas.

1. >>> t = (5,'program', 1+3j)

We can use the slicing operator [] to extract items but we cannot change its value.

t = (5,'program', 1+3j)

# t[1] = 'program'
print("t[1] = ", t[1])

# t[0:3] = (5, 'program', (1+3j))


print("t[0:3] = ", t[0:3])

# Generates error
# Tuples are immutable
t[0] = 10

1.5 Python Set


Set is an unordered collection of unique items. Set is defined by values separated by comma
inside braces { }. Items in a set are not ordered.

a = {5,2,3,1,4}
# printing set variable
print("a = ", a)

# data type of variable a


print(type(a))

1.6 Python Strings


String is sequence of Unicode characters. We can use single quotes or double quotes to
represent strings. Multi-line strings can be denoted using triple quotes, ''' or """.

>>> s = "This is a string"

>>> s = '''a multiline

Like list and tuple, slicing operator [ ] can be used with string. Strings are immutable.

11
s = 'Hello world!'

# s[4] = 'o'
print("s[4] = ", s[4])

# s[6:11] = 'world'
print("s[6:11] = ", s[6:11])

# Generates error
# Strings are immutable in Python
s[5] ='d'

1.7 Python Dictionary


Dictionary is an unordered collection of key-value pairs.

It is generally used when we have a huge amount of data. Dictionaries are optimized for
retrieving data. We must know the key to retrieve the value.

In Python, dictionaries are defined within braces {} with each item being a pair in the
form key:value. Key and value can be of any type.
1. >>> d = {1:'value','key':2}
2. >>> type(d)
3. <class 'dict'>

We use key to retrieve the respective value. But not the other way around.

d = {1:'value','key':2}
print(type(d))

print("d[1] = ", d[1]);

print("d['key'] = ", d['key']);

# Generates error
print("d[2] = ", d[2]);

1.8 Python Variables

A variable is a named location used to store data in the memory. It is helpful to think
of variables as a container that holds data which can be changed later throughout
programming. For example,

1. number = 10

12
Here, we have created a named number. We have assigned value 10 to the variable.

You can think variable as a bag to store books in it and those books can be replaced at any
time.

1. number = 10
2. number = 1.1
Initially, the value of number was 10. Later it's changed to 1.1.

Note: In Python, we don't assign values to the variables, whereas Python gives the reference
of the object (value) to the variable.

1.8.1 Assigning a value to a Variable in Python


As you can see from the above example, you can use the assignment operator = to assign a
value to a variable.

Example 1: Declaring and assigning a value to a variable

website = "apple.com"
print(website)
When you run the program, the output will be:
apple.com
In the above program, we assigned a value apple.com to the variable website. Then we print
the value assigned to website i.e. apple.com

Example 2: Changing the value of a variable

website = "apple.com"
print(website)

# assigning a new variable to website


website = "programiz.com"

print(website)

When you run the program, the output will be:

apple.com
programiz.com

In the above program, we have assigned apple.com to the website variable initially. Then, it's
value is changed to programiz.com.

Example 3: Assigning multiple values to multiple variables

a, b, c = 5, 3.2, "Hello"

print (a)
print (b)
print (c)

13
If we want to assign the same value to multiple variables at once, we can do this as

x = y = z = "same"

print (x)
print (y)
print (z)

1.9 Constants
A constant is a type of variable whose value cannot be changed. It is helpful to think of
constants as containers that hold information which cannot be changed later.

Non technically, you can think of constant as a bag to store some books and those books
cannot be replaced once placed inside the bag.

Assigning value to a constant in Python


In Python, constants are usually declared and assigned on a module. Here, the module means
a new file containing variables, functions etc which is imported to main file. Inside the
module, constants are written in all capital letters and underscores separating the words.

Example 3: Declaring and assigning value to a constant

Create a constant.py

PI = 3.14
GRAVITY = 9.8
Create a main.py

import constant
print(constant.PI)
print(constant.GRAVITY)
When you run the program, the output will be:

3.14
9.8

1.10 Literals

Literal is a raw data given in a variable or constant. In Python, there are various types of
literals they are as follows:

1.10.1 Numeric Literals


Numeric Literals are immutable (unchangeable). Numeric literals can belong to 3 different
numerical types Integer, Float, and Complex.

14
Numeric Literals are immutable (unchangeable). Numeric literals can belong to 3 different
numerical types Integer, Float, and Complex.

Example 4: How to use Numeric literals in Python?


a = 0b1010 #Binary Literals
b = 100 #Decimal Literal
c = 0o310 #Octal Literal
d = 0x12c #Hexadecimal Literal

#Float Literal
float_1 = 10.5
float_2 = 1.5e2

#Complex Literal
x = 3.14j

print(a, b, c, d)
print(float_1, float_2)
print(x, x.imag, x.real)

When you run the program, the output will be:

10 100 200 300


10.5 150.0
3.14j 3.14 0.0
In the above program,

We assigned integer literals into different variables. Here, a is binary literal, b is a decimal
literal, c is an octal literal and d is a hexadecimal literal.
When we print the variables, all the literals are converted into decimal values.
10.5 and 1.5e2 are floating-point literals. 1.5e2 is expressed with exponential and is
equivalent to 1.5 * 102.
We assigned a complex literal i.e 3.14j in variable x. Then we use imaginary literal (x.imag)
and real literal (x.real) to create imaginary and real part of complex number.

1.10.2 String literals

A string literal is a sequence of characters surrounded by quotes. We can use single, double
or triple quotes for a string. And, a character literal is a single character surrounded by single
or double quotes.

Example 7: How to use string literals in Python?

strings = "This is Python"


char = "C"
multiline_str = """This is a multiline string with more than one line code."""
unicode = u"\u00dcnic\u00f6de"
raw_str = r"raw \n string"

15
print(strings)
print(char)
print(multiline_str)
print(unicode)
print(raw_str)

When you run the program, the output will be:

This is Python
C
This is a multiline string with more than one line code.
Ünicöde
raw \n string

In the above program, This is Python is a string literal and C is a character literal. The value
with triple-quote """ assigned in the multiline_str is multi-line string literal. The
u"\u00dcnic\u00f6de" is a unicode literal which supports characters other than English and
r"raw \n string" is a raw string literal.

1.10.3 Boolean literals


A Boolean literal can have any of the two values: True or False.

Example 8: How to use Boolean literals in Python?

x = (1 == True)
y = (1 == False)
a = True + 4
b = False + 10

print("x is", x)
print("y is", y)
print("a:", a)
print("b:", b)

When you run the program, the output will be:


3.
x is True
y is False
a: 5
b: 10
In the above program, we use Boolean literal True and False. In Python, True represents the
value as 1 and False as 0. The value of x is true because 1 is equal to True. And, the value of
y is False because 1 is not equal to False.

Similarly, we can use the True and False in numeric expressions as the value. The value of a
is 5 because we add True which has value of 1 with 4. Similarly, b is 10 because we add the
False having value of 0 with 10.

16
1.11 Python Keywords

Keywords are the reserved words in Python.

We cannot use a keyword as a variable name, function name or any other identifier. They are
used to define the syntax and structure of the Python language.

In Python, keywords are case sensitive.There are 33 keywords in Python 3.7. This number
can vary slightly in the course of time.All the keywords except True, False and None are in
lowercase and they must be written as it is. The list of all the keywords is given below.

1.12 Rules and Naming Convention for Variables and Constants

1. Constant and variable names should have a combination of letters in lowercase (a to z) or


uppercase (A to Z) or digits (0 to 9) or an underscore (_). For example:
snake_case
MACRO_CASE
camelCase
CapWords

2. Create a name that makes sense. For example, vowel makes more sense than v.
3. If you want to create a variable name having two words, use underscore to separate them.
For example:
my_name
current_salary
17
4. Use capital letters possible to declare a constant. For example:
PI
G
MASS
SPEED_OF_LIGHT
TEMP

5. Never use special symbols like !, @, #, $, %, etc.


6. Don't start a variable name with a digit.

1.13 Operators

Operators are the constructs which can manipulate the value of operands.

Consider the expression 4 + 5 = 9. Here, 4 and 5 are called operands and + is called operator.

Types of Operator: Python language supports the following types of operators.

Arithmetic Operators
Comparison (Relational) Operators
Assignment Operators
Logical Operators
Bitwise Operators
Membership Operators
Identity Operators
Let us have a look on all operators one by one.

1. Arithmetic operators: Arithmetic operators are used to perform mathematical operations


like addition, subtraction, multiplication and division.

OPERATOR DESCRIPTION SYNTAX


+ Addition: adds two operands x+y
- Subtraction: subtracts two operands x-y
* Multiplication: multiplies two operands x*y
/ Division (float): divides the first operand by the second x/y
// Division (floor): divides the first operand by the second x // y
% Modulus: returns the remainder when first operand is divided by the second x % y
# Examples of Arithmetic Operator
a=9
b=4

# Addition of numbers
add = a + b

# Subtraction of numbers
sub = a - b

# Multiplication of number

18
mul = a * b

# Division(float) of number
div1 = a / b

# Division(floor) of number
div2 = a // b

# Modulo of both number


mod = a % b

# print results
print(add)
print(sub)
print(mul)
print(div1)
print(div2)
print(mod)

Output:

13
5
36
2.25
2
1

2. Comparison Operators
These operators compare the values on either sides of them and decide the relation among
them. They are also called Relational operators.
Assume variable a holds 10 and variable b holds 20, then −

19
3. Assignment Operators
Assume variable a holds 10 and variable b holds 20, then −

20
4. Bitwise Operators
Bitwise operator works on bits and performs bit by bit operation. Assume if a = 60; and b =
13; Now in the binary format their values will be 0011 1100 and 0000 1101 respectively.
Following table lists out the bitwise operators supported by Python language with an example
each in those, we use the above two variables (a and b) as operands −

a = 0011 1100

b = 0000 1101

-----------------

a&b = 0000 1100

a|b = 0011 1101

a^b = 0011 0001

~a = 1100 0011

There are following Bitwise operators supported by Python language

21
5. Logical Operators
There are following logical operators supported by Python language. Assume variable a holds
10 and variable b holds 20 then

6. Membership Operators
Python’s membership operators test for membership in a sequence, such as strings, lists, or
tuples. There are two membership operators as explained below –

22
7. Identity Operators
Identity operators compare the memory locations of two objects. There are two Identity
operators explained below –

1.9. Precedence and Associativity of Operators in Python

The combination of values, variables, operators and function calls is termed as an expression.
Python interpreter can evaluate a valid expression.

>>> 5 - 7
-2
Here 5 - 7 is an expression. There can be more than one operator in an expression.

To evaluate these type of expressions there is a rule of precedence in Python. It guides the
order in which operation are carried out.For example, multiplication has higher precedence
than subtraction.

# Multiplication has higher precedence than subtraction


# Output: 2
10 - 4 * 2

But we can change this order using parentheses () as it has higher precedence. Parentheses ()
has higher precendence.
# Output: 12
(10 - 4) * 2

The operator precedence in Python are listed in the following table. It is in descending order,
upper group has higher precedence than the lower ones.

23
1.10 File Handling in Python

Python too supports file handling and allows users to handle files i.e., to read and write files,
along with many other file handling options, to operate on files. The concept of file handling
has stretched over various other languages, but the implementation is either complicated or
lengthy, but alike other concepts of Python, this concept here is also easy and short. Python
treats file differently as text or binary and this is important. Each line of code includes a
sequence of characters and they form text file. Each line of a file is terminated with a special
character, called the EOL or End of Line characters like comma {,} or newline character. It
ends the current line and tells the interpreter a new one has begun. Let’s start with Reading
and Writing files.

 Working of open() function

24
We use open () function in Python to open a file in read or write mode. As explained above,
open ( ) will return a file object. To return a file object we use open() function along with two
arguments, that accepts file name and the mode, whether to read or write. So, the syntax
being: open(filename, mode). There are three kinds of mode, that Python provides and how
files can be opened:

“ r “, for reading.

“ w “, for writing.

“ a “, for appending.

“ r+ “, for both reading and writing

One must keep in mind that the mode argument is not mandatory. If not passed, then Python
will assume it to be “ r ” by default. Let’s look at this program and try to analyze how the
read mode works:

# a file named "geek", will be opened with the reading mode.


file = open('geek.txt', 'r')
# This will print every line one by one in the file
for each in file:
print (each)
The open command will open the file in the read mode and the for loop will print each line
present in the file.
 Working of read() mode

There is more than one way to read a file in Python. If you need to extract a string that
contains all characters in the file then we can use file.read(). The full code would work like
this:
# Python code to illustrate read() mode
file = open("file.text", "r")
print file.read()
Another way to read a file is to call a certain number of characters like in the following code
the interpreter will read the first five characters of stored data and return it as a string:
# Python code to illustrate read() mode character wise
file = open("file.txt", "r")
print file.read(5)
 Creating a file using write() mode

Let’s see how to create a file and how write mode works:
To manipulate the file, write the following in your Python environment:
# Python code to create a file
file = open('geek.txt','w')
file.write("This is the write command")
file.write("It allows us to write in a particular file")
file.close()

25
The close() command terminates all the resources in use and frees the system of this
particular program.
 Working of append() mode
Let’s see how the append mode works:

# Python code to illustrate append() mode


file = open('geek.txt','a')
file.write("This will add this line")
file.close()

1.11 Control Statements


Control statements in python are used to control the order of execution of the program based
on the values and logic.

Python provides us with 3 types of Control Statements:

Continue
Break
Pass

1) Continue Statement:
When the program encounters continue statement, it will skip the statements which are
present after the continue statement inside the loop and proceed with the next iterations.

Syntax:

continue

Example:

for char in ‘Python’:

if (char == ‘y’):
continue;
print(“Current character: “, char)
Output:

Current character: P
Current character: t
Current character: h
Current character: o
Current character: n

In the above example during the second iteration if the condition evaluates to true, then it will
execute the continue statement. So whatever statements are present below, for loop will be
skipped, hence letter ‘y’ is not printed.

2) Break Statement:
26
The break statement is used to terminate the loop containing it, the control of the program
will come out of that loop.

Syntax:
for char in ‘Python’:
if (char == ‘h’):
break;
print(“Current character: “, char)
Output:

Current character: P
Current character: y
Current character: t

3) Pass Statement:

Pass statement is python is a null operation, which is used when the statement is required
syntactically.

Syntax:

pass

Example:

for char in ‘Python’:


if (char == ‘h’):
pass
print(“Current character: “, char)

Output:

Current character: P
Current character: y
Current character: t
Current character: h
Current character: o
Current character: n

27
Module-2

FUNCTIONS AND DATA STRUCTURES IN PYTHON

2.1 Functions- Basics of functions

A function is a block of code which only runs when it is called.You can pass data, known as
parameters, into a function. A function can return data as a result.

Creating a Function
In Python a function is defined using the def keyword:

Example
def my_function():
print("Hello from a function")

Calling a Function
To call a function, use the function name followed by parenthesis:

Example
def my_function():
print("Hello from a function")

my_function()

Parameters
Information can be passed to functions as parameter. Parameters are specified after the
function name, inside the parentheses. You can add as many parameters as you want, just
separate them with a comma.

The following example has a function with one parameter (fname). When the function is
called, we pass along a first name, which is used inside the function to print the full name:

Example
def my_function(fname):
print(fname + " Refsnes")

my_function("Emil")
my_function("Tobias")
my_function("Linus")

Passing a List as a Parameter

You can send any data types of parameter to a function (string, number, list, dictionary etc.),
and it will be treated as the same data type inside the function.

E.g. if you send a List as a parameter, it will still be a List when it reaches the function:

28
Example
def my_function(food):
for x in food:
print(x)

fruits = ["apple", "banana", "cherry"]


my_function(fruits)

Return Values
To let a function return a value, use the return statement:

Example
def my_function(x):
return 5 * x

print(my_function(3))
print(my_function(5))
print(my_function(9))

2.2 Recursive Functions


Python also accepts function recursion, which means a defined function can call itself.

Recursion is a common mathematical and programming concept. It means that a function


calls itself. This has the benefit of meaning that you can loop through data to reach a result.

The developer should be very careful with recursion as it can be quite easy to slip into writing
a function which never terminates, or one that uses excess amounts of memory or processor
power. However, when written correctly recursion can be a very efficient and
mathematically-elegant approach to programming.

In this example, tri_recursion() is a function that we have defined to call itself ("recurse").
We use the k variable as the data, which decrements (-1) every time we recurse. The
recursion ends when the condition is not greater than 0 (i.e. when it is 0).

To a new developer it can take some time to work out how exactly this works, best way to
find out is by testing and modifying it.

Example
Recursion Example

def tri_recursion(k):
if(k>0):
result = k+tri_recursion(k-1)
print(result)
else:
result = 0
return result

print("\n\nRecursion Example Results")

29
tri_recursion(6)

2.3 First Class functions in Python or Functions as Objects

First class objects in a language are handled uniformly throughout. They may be stored in
data structures, passed as arguments, or used in control structures. A programming language
is said to support first-class functions if it treats functions as first-class objects. Python
supports the concept of First Class functions.

Properties of first class functions:


 A function is an instance of the Object type.
 You can store the function in a variable.
 You can pass the function as a parameter to another function.
 You can return the function from a function.
 You can store them in data structures such as hash tables, lists, …

Examples illustrating First Class functions in Python

1. Functions are objects: Python functions are first class objects. In the example below, we
are assigning function to a variable. This assignment doesn’t call the function. It takes the
function object referenced by shout and creates a second name pointing to it, yell.

# Python program to illustrate functions can be treated as objects

def shout(text):
return text.upper()

print shout('Hello')

yell = shout

print yell('Hello')

Output

HELLO
HELLO

2. Functions can be passed as arguments to other functions: Because functions are objects
we can pass them as arguments to other functions. Functions that can accept other functions
as arguments are also called higher-order functions. In the example below, we have created a
function greet which takes a function as an argument.

# Python program to illustrate functions can be passed as arguments to other functions


def shout(text):
return text.upper()

def whisper(text):
return text.lower()

30
def greet(func):
# storing the function in a variable
greeting = func("Hi, I am created by a function passed as an argument.")
print greeting

greet(shout)
greet(whisper)

Output

HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT.


hi, i am created by a function passed as an argument.

3. Functions can return another function: Because functions are objects we can return a
function from another function. In the below example, the create_adder function returns
adder function.

# Python program to illustrate functions can return another function

def create_adder(x):
def adder(y):
return x+y

return adder

add_15 = create_adder(15)

print add_15(10)

Output
25

2.4 Lists in Python

Lists are just like the arrays, declared in other languages. Lists need not be homogeneous
always which makes it a most powerful tool in Python. A single list may contain Data Types
like Integers, Strings, as well as Objects. Lists are mutable, and hence, they can be altered
even after their creation.
List in Python are ordered and have a definite count. The elements in a list are indexed
according to a definite sequence and the indexing of a list is done with 0 being the first index.
Each element in the list has its definite place in the list, which allows duplicating of elements
in the list, with each element having its own distinct place and credibility.

Lists in Python can be created by just placing the sequence inside the square brackets[].
Unlike Sets, list doesn’t need a built-in function for creation of list.

Note – Unlike Sets, list may contain mutable elements.

31
# Python program to demonstrate a Creation of List

# Creating a List
List = []
print("Intial blank List: ")
print(List)

# Creating a List with


# the use of a String
List = ['GeeksForGeeks']
print("\nList with the use of String: ")
print(List)

# Creating a List with


# the use of multiple values
List = ["Geeks", "For", "Geeks"]
print("\nList containing multiple values: ")
print(List[0])
print(List[2])

# Creating a Multi-Dimensional List


# (By Nesting a list inside a List)
List = [['Geeks', 'For'] , ['Geeks']]
print("\nMulti-Dimensional List: ")
print(List)
Output:

Intial blank List:


[]

List with the use of String:


['GeeksForGeeks']

List containing multiple values:


Geeks
Geeks

Multi-Dimensional List:
[['Geeks', 'For'], ['Geeks']]

Creating a list with multiple distinct or duplicate elements


A list may contain duplicate values with their distinct positions and hence, multiple distinct
or duplicate values can be passed as a sequence at the time of list creation.

# Creating a List with the use of Numbers (Having duplicate values)


List = [1, 2, 4, 4, 3, 3, 3, 6, 5]
print("\nList with the use of Numbers: ")
print(List)

32
# Creating a List with
# mixed type of values
# (Having numbers and strings)
List = [1, 2, 'Geeks', 4, 'For', 6, 'Geeks']
print("\nList with the use of Mixed Values: ")
print(List)
Output:

List with the use of Numbers:


[1, 2, 4, 4, 3, 3, 3, 6, 5]

List with the use of Mixed Values:


[1, 2, 'Geeks', 4, 'For', 6, 'Geeks']

Adding Elements to a List Using append() method


Elements can be added to the List by using built-in append() function. Only one element at a
time can be added to the list by using append() method, for addition of multiple elements
with the append() method, loops are used. Tuples can also be added to the List with the use of
append method because tuples are immutable. Unlike Sets, Lists can also be added to the
existing list with the use of append() method.

# Python program to demonstrate Addition of elements in a List

# Creating a List
List = []
print("Initial blank List: ")
print(List)

# Addition of Elements in the List


List.append(1)
List.append(2)
List.append(4)
print("\nList after Addition of Three elements: ")
print(List)

# Adding elements to the List using Iterator


for i in range(1, 4):
List.append(i)
print("\nList after Addition of elements from 1-3: ")
print(List)

# Adding Tuples to the List


List.append((5, 6))
print("\nList after Addition of a Tuple: ")
print(List)

# Addition of List to a List


List2 = ['For', 'Geeks']
List.append(List2)
print("\nList after Addition of a List: ")

33
print(List)

Output:

Initial blank List:


[]

List after Addition of Three elements:


[1, 2, 4]

List after Addition of elements from 1-3:


[1, 2, 4, 1, 2, 3]

List after Addition of a Tuple:


[1, 2, 4, 1, 2, 3, (5, 6)]

List after Addition of a List:


[1, 2, 4, 1, 2, 3, (5, 6), ['For', 'Geeks']]

Using insert() method


append() method only works for addition of elements at the end of the List, for addition of
element at the desired position, insert() method is used. Unlike append() which takes only one
argument, insert() method requires two arguments(position, value).

# Python program to demonstrate Addition of elements in a List

# Creating a List
List = [1,2,3,4]
print("Initial List: ")
print(List)

# Addition of Element at
# specific Position
# (using Insert Method)
List.insert(3, 12)
List.insert(0, 'Geeks')
print("\nList after performing Insert Operation: ")
print(List)
Output:

Initial List:
[1, 2, 3, 4]

List after performing Insert Operation:


['Geeks', 1, 2, 3, 12, 4]

Using extend() method

Other than append() and insert() methods, there’s one more method for Addition of elements,
extend(), this method is used to add multiple elements at the same time at the end of the list.

34
# Creating a List
List = [1,2,3,4]
print("Initial List: ")
print(List)

# Addition of multiple elements to the List at the end (using Extend Method)

List.extend([8, 'Geeks', 'Always'])


print("\nList after performing Extend Operation: ")
print(List)
Output:

Initial List:
[1, 2, 3, 4]

List after performing Extend Operation:


[1, 2, 3, 4, 8, 'Geeks', 'Always']

2.5 Lists – Methods to process lists


List methods are discussed in this article.

1. “in” operator :- This operator is used to check if an element is present in the list or not.
Returns true if element is present in list else returns false.

2. “not in” operator :- This operator is used to check if an element is not present in the list
or not. Returns true if element is not present in list else returns false.

# Python code to demonstrate the working of "in" and "not in" initializing list

lis = [1, 4, 3, 2, 5]

# checking if 4 is in list using "in"


if 4 in lis:
print ("List is having element with value 4")
else : print ("List is not having element with value 4")

# checking if 4 is not list using "not in"


if 4 not in lis:
print ("List is not having element with value 4")
else : print ("List is having element with value 4")

Output:

List is having element with value 4


List is having element with value 4

3. len() :- This function returns the length of list.

35
4. min() :- This function returns the minimum element of list.

5. max() :- This function returns the maximum element of list.

# Python code to demonstrate the working of len(), min() and max() initializing list 1

lis = [2, 1, 3, 5, 4]

# using len() to print length of list


print ("The length of list is : ", end="")
print (len(lis))

# using min() to print minimum element of list


print ("The minimum element of list is : ", end="")
print (min(lis))

# using max() to print maximum element of list


print ("The maximum element of list is : ", end="")
print (max(lis))
Output:

The length of list is : 5


The minimum element of list is : 1
The maximum element of list is : 5

6. “+” operator :- This operator is used to concatenate two lists into a single list.

7. “*” operator :- This operator is used to multiply the list “n” times and return the single
list.

# Python code to demonstrate the working of "+" and "*" initializing list 1
lis = [1, 2, 3]

# initializing list 2
lis1 = [4, 5, 6]

# using "+" to concatenate lists


lis2= lis + lis1

# priting concatenated lists


print ("list after concatenation is : ", end="")
for i in range(0,len(lis2)):
print (lis2[i], end=" ")

print ("\r")

#using '*' to combine lists


lis3 = lis * 3

36
# priting combined lists
print ("list after combining is : ", end="")
for i in range(0,len(lis3)):
print (lis3[i], end=" ")

Output:
list after concatenation is : 1 2 3 4 5 6
list after combining is : 1 2 3 1 2 3 1 2 3

8. index(ele, beg, end) :- This function returns the index of first occurrence of element after
beg and before end.

9. count() :- This function counts the number of occurrences of elements in list.

# Python code to demonstrate the working of index() and count() initializing list 1
lis = [2, 1, 3, 5, 4, 3]

# using index() to print first occurrence of 3

print ("The first occurrence of 3 after 3rd position is : ", end="")


print (lis.index(3, 3, 6))

# using count() to count number of occurrence of 3


print ("The number of occurrences of 3 is : ", end="")
print (lis.count(3))
Output:

The first occurrence of 3 after 3rd position is : 5


The number of occurrences of 3 is : 2

Negative indexing
In Python, negative sequence indexes represent positions from the end of the array. Instead of
having to compute the offset as in List[len(List)-3], it is enough to just write List[-3].
Negative indexing means beginning from the end, -1 refers to the last item, -2 refers to the
second last item etc.

List = [1, 2, 'Geeks', 4, 'For', 6, 'Geeks']

# accessing a element using


# negative indexing
print("Acessing element using negative indexing")

# print the last element of list


print(List[-1])

# print the third last element of list


print(List[-3])
Output:

Acessing element using negative indexing

37
Geeks
For

Removing Elements from the List

Using remove() method


Elements can be removed from the List by using built-in remove() function but an Error
arises if element doesn’t exist in the set. Remove() method only removes one element at a
time, to remove range of elements, iterator is used. The remove() method removes the
specified item.

Note – Remove method in List will only remove the first occurrence of the searched element.

# Python program to demonstrate Removal of elements in a List

# Creating a List
List = [1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12]
print("Intial List: ")
print(List)

# Removing elements from List using Remove() method


List.remove(5)
List.remove(6)
print("\nList after Removal of two elements: ")
print(List)

# Removing elements from List using iterator method

for i in range(1, 5):


List.remove(i)
print("\nList after Removing a range of elements: ")
print(List)
Output:

Intial List:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

List after Removal of two elements:


[1, 2, 3, 4, 7, 8, 9, 10, 11, 12]

List after Removing a range of elements:


[7, 8, 9, 10, 11, 12]

Slicing of a List
In Python List, there are multiple ways to print the whole List with all the elements, but to
print a specific range of elements from the list, we use Slice operation. Slice operation is
performed on Lists with the use of colon(:). To print elements from beginning to a range use
[:Index], to print elements from end use [:-Index], to print elements from specific Index till
the end use [Index:], to print elements within a range, use [Start Index:End Index] and to print

38
whole List with the use of slicing operation, use [:]. Further, to print whole List in reverse
order, use [::-1].

Note – To print elements of List from rear end, use Negative Indexes.

# Python program to demonstrate Removal of elements in a List

# Creating a List
List = ['G','E','E','K','S','F',
'O','R','G','E','E','K','S']
print("Intial List: ")
print(List)

# Print elements of a range using Slice operation

Sliced_List = List[3:8]
print("\nSlicing elements in a range 3-8: ")
print(Sliced_List)

# Print elements from a pre-defined point to end

Sliced_List = List[5:]
print("\nElements sliced from 5th "
"element till the end: ")
print(Sliced_List)

# Printing elements from beginning till end

Sliced_List = List[:]
print("\nPrinting all elements using slice operation: ")
print(Sliced_List)

Output:

Intial List:
['G', 'E', 'E', 'K', 'S', 'F', 'O', 'R', 'G', 'E', 'E', 'K', 'S']

Slicing elements in a range 3-8:


['K', 'S', 'F', 'O', 'R']

Elements sliced from 5th element till the end:


['F', 'O', 'R', 'G', 'E', 'E', 'K', 'S']

Printing all elements using slice operation:


['G', 'E', 'E', 'K', 'S', 'F', 'O', 'R', 'G', 'E', 'E', 'K', 'S']

39
2.6 Copy in Python (Deep Copy and Shallow Copy)

In Python, Assignment statements do not copy objects, they create bindings between a target
and an object. When we use = operator user thinks that this creates a new object; well, it
doesn’t. It only creates a new variable that shares the reference of the original object.
Sometimes a user wants to work with mutable objects, in order to do that user looks for a way
to create “real copies” or “clones” of these objects. Or, sometimes a user wants copies that
user can modify without automatically modifying the original at the same time, in order to do
that we create copies of objects.
A copy is sometimes needed so one can change one copy without changing the other. In
Python, there are two ways to create copies :

 Deep copy
 Shallow copy

In order to implement these copy, we use copy module. We use copy module for shallow and
deep copy operations. For Example

# importing copy module

import copy

# initializing list 1

li1 = [1, 2, [3,5], 4]

# using copy for shallow copy


li2 = copy.copy(li1)

# using deepcopy for deepcopy


li3 = copy.deepcopy(li1)
In the above code, the copy() returns a shallow copy of list and deepcopy() return a deep copy
of list.

2.6.1 Deep copy

40
Deep copy is a process in which the copying process occurs recursively. It means first
constructing a new collection object and then recursively populating it with copies of the
child objects found in the original. In case of deep copy, a copy of object is copied in other
object. It means that any changes made to a copy of object do not reflect in the original
object. In python, this is implemented using “deepcopy()” function.

# Python code to demonstrate copy operations

# importing "copy" for copy operations

import copy

# initializing list 1

li1 = [1, 2, [3,5], 4]

# using deepcopy to deep copy

li2 = copy.deepcopy(li1)

# original elements of list

print ("The original elements before deep copying")


for i in range(0,len(li1)):
print (li1[i],end=" ")

print("\r")

# adding and element to new list

li2[2][0] = 7

# Change is reflected in l2

41
print ("The new list of elements after deep copying ")
for i in range(0,len( li1)):
print (li2[i],end=" ")

print("\r")

# Change is NOT reflected in original list as it is a deep copy

print ("The original elements after deep copying")


for i in range(0,len( li1)):
print (li1[i],end=" ")

Output:

The original elements before deep copying


1 2 [3, 5] 4
The new list of elements after deep copying
1 2 [7, 5] 4
The original elements after deep copying
1 2 [3, 5] 4

In the above example, the change made in the list did not effect in other lists, indicating the
list is deep copied.

2.6.2 Shallow copy

A shallow copy means constructing a new collection object and then populating it with
references to the child objects found in the original. The copying process does not recurse and
therefore won’t create copies of the child objects themselves. In case of shallow copy, a
reference of object is copied in other object. It means that any changes made to a copy of
object do reflect in the original object. In python, this is implemented using “copy()”
function.

# Python code to demonstrate copy operations

42
# importing "copy" for copy operations

import copy

# initializing list 1
li1 = [1, 2, [3,5], 4]

# using copy to shallow copy


li2 = copy.copy(li1)

# original elements of list

print ("The original elements before shallow copying")


for i in range(0,len(li1)):
print (li1[i],end=" ")

print("\r")

# adding and element to new list

li2[2][0] = 7

# checking if change is reflected

print ("The original elements after shallow copying")


for i in range(0,len( li1)):
print (li1[i],end=" ")

Output:

The original elements before shallow copying


1 2 [3, 5] 4
The original elements after shallow copying
1 2 [7, 5] 4

In the above example, the change made in the list did effect in other list, indicating the list is
shallow copied.

Important Points:
The difference between shallow and deep copying is only relevant for compound objects
(objects that contain other objects, like lists or class instances):

 A shallow copy constructs a new compound object and then (to the extent possible)
inserts references into it to the objects found in the original.
 A deep copy constructs a new compound object and then, recursively, inserts copies
into it of the objects found in the original.

43
2.7 Using List as Stack and Queues in Python

The concept of Stack and Queue is easy to implement in Python.

Stack
Stack works on the principle of “Last-in, first-out”. Also, the inbuilt functions in Python
make the code short and simple. To add an item to the top of the list, i.e., to push an item, we
use append() function and to pop out an element we use pop() function. These functions
work quiet efficiently and fast in end operations.
Let’s look at an example and try to understand the working of push() and pop() function:

Example:
# Python code to demonstrate Implementing stack using list
stack = ["Amar", "Akbar", "Anthony"]
stack.append("Ram")
stack.append("Iqbal")
print(stack)
print(stack.pop())
print(stack)
print(stack.pop())
print(stack)

Output :

['Amar', 'Akbar', 'Anthony', 'Ram', 'Iqbal']


Iqbal
['Amar', 'Akbar', 'Anthony', 'Ram']
Ram
['Amar', 'Akbar', 'Anthony']

Queue
Implementing Queue is a bit different. Queue works on the principle of “First-in, first-out”.
Time plays an important factor here. We saw that during the implementation of stack we used
append() and pop() function which was efficient and fast because we inserted and popped
elements from the end of the list, but in queue when insertion and pops are made from the
beginning of the list, it is slow. This occurs due to the properties of list, which is fast at the
end operations but slow at the beginning operations, as all other elements have to be shifted
one by one. So, we prefer the use of collections.deque over list, which was specially designed
to have fast appends and pops from both the front and back end.

Let’s look at an example and try to understand queue using collections.deque:

#Python code to demonstrate Implementing Queue using deque and list from collections
import deque
queue = deque(["Ram", "Tarun", "Asif", "John"])
print(queue)
queue.append("Akbar")
print(queue)
queue.append("Birbal")

44
print(queue)
print(queue.popleft())
print(queue.popleft())
print(queue)

Output:

deque(['Ram', 'Tarun', 'Asif', 'John'])


deque(['Ram', 'Tarun', 'Asif', 'John', 'Akbar'])
deque(['Ram', 'Tarun', 'Asif', 'John', 'Akbar', 'Birbal'])
Ram
Tarun
deque(['Asif', 'John', 'Akbar', 'Birbal'])

2.8 Nested lists

A list can even have another list as an item. This is called nested list.
# nested list

my_list = ["mouse", [8, 4, 6], ['a']]


Nested list are accessed using nested indexing.
n_list = ["Happy", [2,0,1,5]]

# Nested indexing
print(n_list[0][1])

# Output: a
print(n_list[1][3])
# Output: 5

2.9 List as Matrix

A matrix is a two-dimensional data structure where numbers are arranged into rows and
columns. For example:

45
This matrix is a 3x4 (pronounced "three by four") matrix because it has 3 rows and 4
columns.

Python Matrix

Python doesn't have a built-in type for matrices. However, we can treat list of a list as a
matrix. For example:

A = [[1, 4, 5],

[-5, 8, 9]]

We can treat this list of a list as a matrix having 2 rows and 3 columns.

Let's see how to work with a nested list.

A = [[1, 4, 5, 12],
[-5, 8, 9, 0],
[-6, 7, 11, 19]]
print("A =", A)
print("A[1] =", A[1]) # 2nd row
print("A[1][2] =", A[1][2]) # 3rd element of 2nd row
print("A[0][-1] =", A[0][-1]) # Last element of 1st Row
column = []; # empty list

for row in A:
column.append(row[2])
print("3rd column =", column)
When we run the program, the output will be:

A = [[1, 4, 5, 12], [-5, 8, 9, 0], [-6, 7, 11, 19]]


A[1] = [-5, 8, 9, 0]
A[1][2] = 9
A[0][-1] = 12

46
3rd column = [5, 9, 11]

Source Code: Matrix Multiplication using Nested Loop


# Program to multiply two matrices using nested loops

# 3x3 matrix
X = [[12,7,3],
[4 ,5,6],
[7 ,8,9]]

# 3x4 matrix

Y = [[5,8,1,2],
[6,7,3,0],
[4,5,9,1]]

# result is 3x4

result = [[0,0,0,0],
[0,0,0,0],
[0,0,0,0]]
# iterate through rows of X

for i in range(len(X)):
# iterate through columns of Y
for j in range(len(Y[0])):
# iterate through rows of Y
for k in range(len(Y)):
result[i][j] += X[i][k] * Y[k][j]
for r in result:
print(r)

2.10 Tuples in Python

A Tuple is a collection of Python objects separated by commas. In someways a tuple is


similar to a list in terms of indexing, nested objects and repetition but a tuple is immutable
unlike lists which are mutable.
Creating Tuples

# An empty tuple
empty_tuple = ()
print (empty_tuple)
Output:
()

# Creating non-empty tuples One way of creation

47
tup = 'python', 'geeks'
print(tup)

# Another for doing the same


tup = ('python', 'geeks')
print(tup)
Output

('python', 'geeks')
('python', 'geeks')

Note: In case your generating a tuple with a single element, make sure to add a comma
after the element.

Concatenation of Tuples

# Code for concatenating 2 tuples

tuple1 = (0, 1, 2, 3)
tuple2 = ('python', 'geek')

# Concatenating above two


print(tuple1 + tuple2)
Output:

(0, 1, 2, 3, 'python', 'geek')

Nesting of Tuples

# Code for creating nested tuples

tuple1 = (0, 1, 2, 3)
tuple2 = ('python', 'geek')
tuple3 = (tuple1, tuple2)
print(tuple3)
Output :

((0, 1, 2, 3), ('python', 'geek'))

Repetition in Tuple : Code for deleting a tuple

tuple3 = ( 0, 1)
del tuple3
print(tuple3)
Error:

Traceback (most recent call last):

48
File "d92694727db1dc9118a5250bf04dafbd.py", line 6, in <module>
print(tuple3)
NameError: name 'tuple3' is not defined
Output:

(0, 1)

Finding Length of a Tuple

# Code for printing the length of a tuple

tuple2 = ('python', 'geek')


print(len(tuple2))
Output

Converting list to a Tuple

# Code for converting a list and a string into a tuple

list1 = [0, 1, 2]
print(tuple(list1))
print(tuple('python')) # string 'python'

Output

(0, 1, 2)
('p', 'y', 't', 'h', 'o', 'n')

Takes a single parameter which may be a list,string,set or even a dictionary( only keys are
taken as elements) and converts them to a tuple.# Code for deleting a tuple

tuple3 = ( 0, 1)
del tuple3
print(tuple3)
Error:

Traceback (most recent call last):


File "d92694727db1dc9118a5250bf04dafbd.py", line 6, in <module>
print(tuple3)
NameError: name 'tuple3' is not defined

Output:

(0, 1)

49
Finding Length of a Tuple

# Code for printing the length of a tuple

tuple2 = ('python', 'geek')


print(len(tuple2))
Output

Converting list to a Tuple

# Code for converting a list and a string into a tuple

list1 = [0, 1, 2]
print(tuple(list1))
print(tuple('python')) # string 'python'
Output

(0, 1, 2)
('p', 'y', 't', 'h', 'o', 'n')
Takes a single parameter which may be a list,string,set or even a dictionary( only keys are
taken as elements) and converts them to a tuple.

Tuples in a loop

#python code for creating tuples in a loop

tup = ('geek',)
n = 5 #Number of time loop runs
for i in range(int(n)):
tup = (tup,)
print(tup)
Output :

(('geek',),)
((('geek',),),)
(((('geek',),),),)
((((('geek',),),),),)
(((((('geek',),),),),),)

Using cmp(), max() , min()

# A python program to demonstrate the use of cmp(), max(), min()

tuple1 = ('python', 'geek')


tuple2 = ('coder', 1)

if (cmp(tuple1, tuple2) != 0):

50
# cmp() returns 0 if matched, 1 when not tuple1
# is longer and -1 when tuple1 is shoter
print('Not the same')
else:
print('Same')
print ('Maximum element in tuples 1,2: ' +
str(max(tuple1)) + ',' +
str(max(tuple2)))
print ('Minimum element in tuples 1,2: ' +
str(min(tuple1)) + ',' + str(min(tuple2)))
Output

Not the same

Maximum element in tuples 1,2: python,coder


Minimum element in tuples 1,2: geek,1

Note: max() and min() checks the based on ASCII values. If there are two strings in a
tuple, then the first different character in the strings are checked.

Remove Items from tuple


Note: You cannot remove items in a tuple.

Tuples are unchangeable, so you cannot remove items from it, but you can delete the tuple
completely:

Example
The del keyword can delete the tuple completely:

thistuple = ("apple", "banana", "cherry")


del thistuple
print(thistuple) #this will raise an error because the tuple no longer exists

2.11 Nested Tuples

Nested tuples are accessed using nested indexing, as shown in the example below.

n_tuple = ("mouse", [8, 4, 6], (1, 2, 3))

# nested index
print(n_tuple[0][3]) # 's'
print(n_tuple[1][1]) #4

Advantages of Tuple over List


Since tuples are quite similar to lists, both of them are used in similar situations as well.

However, there are certain advantages of implementing a tuple over a list. Below listed are
some of the main advantages:

51
We generally use tuple for heterogeneous (different) datatypes and list for homogeneous
(similar) datatypes.
Since tuples are immutable, iterating through tuple is faster than with list. So there is a slight
performance boost.
Tuples that contain immutable elements can be used as a key for a dictionary. With lists, this
is not possible.
If you have data that doesn't change, implementing it as tuple will guarantee that it remains
write-protected.

2.12 Dictionary
A dictionary is a collection which is unordered, changeable and indexed. In Python
dictionaries are written with curly brackets, and they have keys and values.

Example
Create and print a dictionary:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
print(thisdict)

Accessing Items
You can access the items of a dictionary by referring to its key name, inside square brackets:

Example
Get the value of the "model" key:

x = thisdict["model"]
There is also a method called get() that will give you the same result:

Example
Get the value of the "model" key:

x = thisdict.get("model")

Change Values
You can change the value of a specific item by referring to its key name:

Example
Change the "year" to 2018:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

52
thisdict["year"] = 2018

Loop Through a Dictionary

You can loop through a dictionary by using a for loop.When looping through a dictionary, the
return value are the keys of the dictionary, but there are methods to return the values as well.

Example
Print all key names in the dictionary, one by one:

for x in thisdict:
print(x)

Example
Print all values in the dictionary, one by one:

for x in thisdict:
print(thisdict[x])

Example
You can also use the values() function to return values of a dictionary:

for x in thisdict.values():
print(x)

Example
Loop through both keys and values, by using the items() function:

for x, y in thisdict.items():
print(x, y)

Check if Key Exists


To determine if a specified key is present in a dictionary use the in keyword:

Example
Check if "model" is present in the dictionary:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
if "model" in thisdict:
print("Yes, 'model' is one of the keys in the thisdict dictionary")

Dictionary Length
To determine how many items (key-value pairs) a dictionary has, use the len() method.

Example
Print the number of items in the dictionary:

53
print(len(thisdict))
Adding Items
Adding an item to the dictionary is done by using a new index key and assigning a value to it:

Example
thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict["color"] = "red"
print(thisdict)

Removing Items
There are several methods to remove items from a dictionary:

Example
The pop() method removes the item with the specified key name:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.pop("model")
print(thisdict)

Example
The popitem() method removes the last inserted item (in versions before 3.7, a random item
is removed instead):

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.popitem()
print(thisdict)
Example
The del keyword removes the item with the specified key name:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict["model"]
print(thisdict)

54
Example
The del keyword can also delete the dictionary completely:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict
print(thisdict) #this will cause an error because "thisdict" no longer exists.

Example
The clear() keyword empties the dictionary:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.clear()
print(thisdict)

Copy a Dictionary
You cannot copy a dictionary simply by typing dict2 = dict1, because: dict2 will only be a
reference to dict1, and changes made in dict1 will automatically also be made in dict2.

There are ways to make a copy, one way is to use the built-in Dictionary method copy().

Example
Make a copy of a dictionary with the copy() method:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = thisdict.copy()
print(mydict)
Another way to make a copy is to use the built-in method dict().

Example
Make a copy of a dictionary with the dict() method:

thisdict = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = dict(thisdict)
print(mydict)

55
POP items from dictionary

The pop() method removes the specified item from the dictionary.The value of the removed
item is the return value of the pop() method, see example below.

Syntax
dictionary.pop(keyname, defaultvalue)

Clear method on dictionary

The clear() method removes all the elements from a dictionary.

Syntax

dictionary.clear()

Example

Remove all elements from the car list:

car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

car.clear()
print(car)

Key values of Dictionary

The keys() method returns a view object. The view object contains the keys of the dictionary,
as a list.

The view object will reflect any changes done to the dictionary, see example below.

Syntax

dictionary.keys()

Example

Return the keys:

car = {
"brand": "Ford",

56
"model": "Mustang",
"year": 1964
}

x = car.keys()
print(x)

Note: When an item is added in the dictionary, the view object also gets updated:

Example
car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

x = car.keys()

car["color"] = "white"
print(x)

Update method on Dictionary

The update() method inserts the specified items to the dictionary.


The specified items can be a dictionary, or an iterable object.

Syntax
dictionary.update(iterable)

Insert an item to the dictionary:


car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

car.update({"color": "White"})

print(car)

Fromkey method on Dictionary

The fromkeys() method returns a dictionary with the specified keys and values.

Syntax
dict.fromkeys(keys, value)

x = ('key1', 'key2', 'key3')

57
y=0

thisdict = dict.fromkeys(x, y)
print(thisdict)

Output:
['key1': 0, 'key2': 0, 'key3': 0]

Get method on Dictionary

The get() method returns the value of the item with the specified key.

Syntax
dictionary.get(keyname, value)

car = {
"brand": "Ford",
"model": "Mustang",
"year": 1964
}

x = car.get("model")

print(x)

Output:

Mustang

2.13 Ordered Dictionary in Python

An OrderedDict is a dictionary subclass that remembers the order that keys were first
inserted. The only difference between dict() and OrderedDict() is that:

OrderedDict preserves the order in which the keys are inserted. A regular dict doesn’t track
the insertion order, and iterating it gives the values in an arbitrary order. By contrast, the
order the items are inserted is remembered by OrderedDict.

# A Python program to demonstrate working of OrderedDict

from collections import OrderedDict

print("This is a Dict:\n")
d = {}
d['a'] = 1
d['b'] = 2
d['c'] = 3
d['d'] = 4

58
for key, value in d.items():
print(key, value)

print("\nThis is an Ordered Dict:\n")


od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4

for key, value in od.items():


print(key, value)
Output:

This is a Dict:
('a', 1)
('c', 3)
('b', 2)
('d', 4)

This is an Ordered Dict:


('a', 1)
('b', 2)
('c', 3)
('d', 4)

Important Points:

Key value Change: If the value of a certain key is changed, the position of the key remains
unchanged in OrderedDict.
# A Python program to demonstrate working of key
# value change in OrderedDict
from collections import OrderedDict

print("Before:\n")
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4
for key, value in od.items():
print(key, value)

print("\nAfter:\n")
od['c'] = 5
for key, value in od.items():
print(key, value)
Output:

Before:

59
('a', 1)
('b', 2)
('c', 3)
('d', 4)

After:

('a', 1)
('b', 2)
('c', 5)
('d', 4)

Deletion and Re-Inserting: Deleting and re-inserting the same key will push it to the back as
OrderedDict however maintains the order of insertion.

# A Python program to demonstrate working of deletion and re-inserion in OrderedDict


from collections import OrderedDict

print("Before deleting:\n")
od = OrderedDict()
od['a'] = 1
od['b'] = 2
od['c'] = 3
od['d'] = 4

for key, value in od.items():


print(key, value)

print("\nAfter deleting:\n")
od.pop('c')
for key, value in od.items():
print(key, value)

print("\nAfter re-inserting:\n")
od['c'] = 3
for key, value in od.items():
print(key, value)
Output:

Before deleting:

('a', 1)
('b', 2)
('c', 3)
('d', 4)

After deleting:

('a', 1)

60
('b', 2)
('d', 4)

After re-inserting:

('a', 1)
('b', 2)
('d', 4)
('c', 3)

2.14 Iterate over a dictionary in Python


Dictionary in Python is an unordered collection of data values, used to store data values like a
map, which unlike other Data Types that hold only single value as an element, Dictionary
holds key:value pair.

There are multiple ways to iterate over a dictionary in Python.

Iterate through all keys


Iterate through all values
Iterate through all key, value pairs

Iterate through all keys:

The order of states in the below code will change every time because the dictionary doesn’t
store keys in a particular order.

# Python3 code to iterate through all keys in a dictionary

statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}

print('List Of given states:\n')

# Iterating over keys


for state in statesAndCapitals:
print(state)
Output:
List Of given states:

Rajasthan
Bihar
Maharashtra
Gujarat

61
In order to maintain the order of keys and values in a dictionary, use OrderedDict.

# Python3 code to iterate through all keys in a dictionary in a specific order

from collections import OrderedDict

statesAndCapitals = OrderedDict([
('Gujarat', 'Gandhinagar'),
('Maharashtra', 'Mumbai'),
('Rajasthan', 'Jaipur'),
('Bihar', 'Patna')
])

print('List Of given states:\n')

# Iterating over keys for state in statesAndCapitals:


print(state)
Output:
List Of given states:

Gujarat
Maharashtra
Rajasthan
Bihar

Above dictionary is an OrderedDict as the keys and values are stored in the order in which
they were defined in the dictionary. Hence the above method should be used when we want
to maintain the order of (key, value) stored in the dictionary.

Iterate through all values:

Again, in this case, the order in which the capitals are printed in the below code will change
every time because the dictionary doesn’t store them in a particular order.

filter_none
edit
play_arrow

brightness_4
# Python3 code to iterate through all values in a dictionary

statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}

print('List Of given capitals:\n')

62
# Iterating over values
for capital in statesAndCapitals.values():
print(capital)
Output:
List Of given capitals:

Gandhinagar
Jaipur
Mumbai
Patna

Iterate through all key, value pairs:

# Python3 code to iterate through all key, value pairs in a dictionary

statesAndCapitals = {
'Gujarat' : 'Gandhinagar',
'Maharashtra' : 'Mumbai',
'Rajasthan' : 'Jaipur',
'Bihar' : 'Patna'
}

print('List Of given states and their capitals:\n')

# Iterating over values


for state, capital in statesAndCapitals.items():
print(state, ":", capital)
Output:
List Of given states and their capitals:

Bihar : Patna
Gujarat : Gandhinagar
Rajasthan : Jaipur
Maharashtra : Mumbai

2.15 Conversion of list and strings into dictionary


Given a list, write a Python program to convert the given list to dictionary such that all the
odd elements have the key, and even number elements have the value. Since python
dictionary is unordered, the output can be in any order.
Examples:
Input : ['a', 1, 'b', 2, 'c', 3]
Output : {'a': 1, 'b': 2, 'c': 3}

Input : ['Delhi', 71, 'Mumbai', 42]


Output : {'Delhi': 71, 'Mumbai': 42}

63
Method #1 : dict comprehension
To convert a list to dictionary, we can use list comprehension and make a key:value pair of
consecutive elements. Finally, typecase the list to dict type.

# Python3 program to Convert a list to dictionary

def Convert(lst):
res_dct = {lst[i]: lst[i + 1] for i in range(0, len(lst), 2)}
return res_dct

# Driver code
lst = ['a', 1, 'b', 2, 'c', 3]
print(Convert(lst))

Output:
{'a': 1, 'b': 2, 'c': 3}

Method #2 : Using zip() method

First create an iterator, and intialise it to variable ‘it’. Then use zip method, to zip keys and
values together. Finally typecast it to dict type.

# Python3 program to Convert a list to dictionary

def Convert(a):
it = iter(lst)
res_dct = dict(zip(it, it))
return res_dct

# Driver code
lst = ['a', 1, 'b', 2, 'c', 3]
print(Convert(lst))
Output:
{'c': 3, 'b': 2, 'a': 1}

Split a string into a dict.

str = "key1=value1;key2=value2;key3=value3"

d = dict(x.split("=") for x in str.split(";"))

for k, v in d.items():
print(k, v)

Output

key1 value1
key2 value2
key3 value3

64
Python program to create a dictionary from a string

Dictionary in python is a very useful data structure and at many times we see problems
regarding converting a string to a dictionary.
So, let us discuss how we can tackle this problem.

Method # 1: Using eval()


If we get a string input which completely resembles a dictionary object(if the string looks like
dictionary as in python) then we can easily convert it to dictionary using
eval() in Python.

# Python3 code to convert a string to a dictionary

# Initializing String
string = "{'A':13, 'B':14, 'C':15}"

# eval() convert string to dictionary


Dict = eval(string)
print(Dict)
print(Dict['A'])
print(Dict['C'])
Output:
{'C': 15, 'B': 14, 'A': 13}
13
15

Method # 2: Using generator expressions in python


If we get a string input does not completely resemble a dictionary object then we can use
generator expressions to convert it to a dictionary.

# Python3 code to convert a string to a dictionary

# Initializing String
string = "A - 13, B - 14, C - 15"

# Converting string to dictionary


Dict = dict((x.strip(), y.strip()) for x, y in (element.split('-') for element in string.split(', ')))

print(Dict)
print(Dict['A'])
print(Dict['C'])

Output:
{'C': '15', 'A': '13', 'B': '14'}
13
15

65
2.16 Sets and Frozen sets in Python
A set is an unordered collection of items. Every element is unique (no duplicates) and must
be immutable (which cannot be changed).However, the set itself is mutable. We can add or
remove items from it. Sets can be used to perform mathematical set operations like union,
intersection, symmetric difference etc.

How to create a set?


A set is created by placing all the items (elements) inside curly braces {}, separated by
comma or by using the built-in function set().

It can have any number of items and they may be of different types (integer, float, tuple,
string etc.). But a set cannot have a mutable element, like list, set or dictionary, as its element.

# set of integers
my_set = {1, 2, 3}
print(my_set)

# set of mixed datatypes


my_set = {1.0, "Hello", (1, 2, 3)}
print(my_set)

Access Items in set


You cannot access items in a set by referring to an index, since sets are unordered the items
has no index.But you can loop through the set items using a for loop, or ask if a specified
value is present in a set, by using the in keyword.

Example
Loop through the set, and print the values:

thisset = {"apple", "banana", "cherry"}

for x in thisset:
print(x)

Add Items
To add one item to a set use the add() method.To add more than one item to a set use the
update() method.

Example
Add an item to a set, using the add() method:

thisset = {"apple", "banana", "cherry"}


thisset.add("orange")
print(thisset)

{'apple', 'banana', 'orange', 'cherry'}

Get the Length of a Set


To determine how many items a set has, use the len() method.

66
Example
Get the number of items in a set:

thisset = {"apple", "banana", "cherry"}


print(len(thisset))

Output: 3

Remove Item
To remove an item in a set, use the remove(), or the discard() method.

Example
Remove "banana" by using the remove() method:

thisset = {"apple", "banana", "cherry"}


thisset.remove("banana")
print(thisset)

Note: If the item to remove does not exist, remove() will raise an error.

Remove "banana" by using the discard() method:

thisset = {"apple", "banana", "cherry"}


thisset.discard("banana")
print(thisset)

Note: If the item to remove does not exist, discard() will NOT raise an error.

The del keyword will delete the set completely:

thisset = {"apple", "banana", "cherry"}


del thisset
print(thisset)

Join Two Sets


There are several ways to join two or more sets in Python.

You can use the union() method that returns a new set containing all items from both sets, or
the update() method that inserts all the items from one set into another:

Example
The union() method returns a new set with all items from both sets:

set1 = {"a", "b" , "c"}


set2 = {1, 2, 3}

set3 = set1.union(set2)
print(set3)

67
Example
The update() method inserts the items in set2 into set1:

set1 = {"a", "b" , "c"}


set2 = {1, 2, 3}

set1.update(set2)
print(set1)

Note: Both union() and update() will exclude any duplicate items.

Set intersection() Method


The intersection() method returns a set that contains the similarity between two or more sets.

Example

x = {"apple", "banana", "cherry"}


y = {"google", "microsoft", "apple"}

z = x.intersection(y)
print(z)

Output: apple

Frozen sets

The frozenset() method returns an immutable frozenset object initialized with elements from
the given iterable.
Frozen set is just an immutable version of a Python set object. While elements of a set can be
modified at any time, elements of frozen set remain the same after creation.

Due to this, frozen sets can be used as key in Dictionary or as element of another set. But like
sets, it is not ordered (the elements can be set at any index).

The syntax of frozenset() method is:

frozenset([iterable])

frozenset() Parameters
The frozenset() method optionally takes a single parameter:

iterable (Optional) - the iterable which contains elements to initialize the frozenset with.
Iterable can be set, dictionary, tuple, etc.

Return value from frozenset()


The frozenset() method returns an immutable frozenset initialized with elements from the
given iterable.

68
If no parameters are passed, it returns an empty frozenset.

Example 1: How frozenset() works in Python?

vowels = ('a', 'e', 'i', 'o', 'u')

fSet = frozenset(vowels)
print('The frozen set is:', fSet)
print('The empty frozen set is:', frozenset())

When you run the program, the output will be:

The frozen set is: frozenset({'i', 'a', 'u', 'e', 'o'})


The empty frozen set is: frozenset()

Example 2: frozenset() for Dictionary


When you use dictionary as an iterable for a frozen set. It only takes key of the dictionary to
create the set.

person = {"name": "John", "age": 23}


fSet = frozenset(person)
print('The frozen set is:', fSet)

When you run the program, the output will be:

The frozen set is: frozenset({'name', 'age'})

2.17 Lambda function in python

In Python, anonymous function means that a function is without a name. As we already know
that def keyword is used to define the normal functions and the Lambda keyword is used to
create anonymous functions. It has the following syntax:

Lambda arguments: expression

This function can have any number of arguments but only one expression, which is evaluated
and returned. One is free to use lambda functions wherever function objects are required. You
need to keep in your knowledge that lambda functions are syntactically restricted to a single
expression.
It has various uses in particular fields of programming besides other types of expressions in
functions.
Let’s look at this example and try to understand the difference between a normal def defined
function and lambda function. This is a program that returns the cube of a given value:

# Python code to illustrate cube of a number showing difference between def() and lambda().

69
def cube(y):
return y*y*y;

g = lambda x: x*x*x
print(g(7))

print(cube(5))
Output:

343
125

Without using Lambda: Here, both of them returns the cube of a given number. But, while
using def, we needed to define a function with a name cube and needed to pass a value to it.
After execution, we also needed to return the result from where the function was called using
the return keyword.

Using Lambda: Lambda definition does not include a “return” statement, it always contains
an expression which is returned. We can also put a lambda definition anywhere a function is
expected, and we don’t have to assign it to a variable at all. This is the simplicity of lambda
functions.

2.18 Filter() in python


The filter() method filters the given sequence with the help of a function that tests each
element in the sequence to be true or not.

syntax:

filter(function, sequence)

Parameters:
function: function that tests if each element of a
sequence true or not.
sequence: sequence which needs to be filtered, it can
be sets, lists, tuples, or containers of any iterators.

Returns:
returns an iterator that is already filtered.

# function that filters vowels


def fun(variable):
letters = ['a', 'e', 'i', 'o', 'u']
if (variable in letters):
return True
else:
return False

70
# sequence

sequence = ['g', 'e', 'e', 'j', 'k', 's', 'p', 'r']

# using filter function


filtered = filter(fun, sequence)

print('The filtered letters are:')


for s in filtered:
print(s)

Output:

The filtered letters are:


e
e

Application:It is normally used with Lambda functions to separate list, tuple, or sets.

# a list contains both even and odd numbers.


seq = [0, 1, 2, 3, 5, 8, 13]

# result contains odd numbers of the list


result = filter(lambda x: x % 2, seq)
print(list(result))

# result contains even numbers of the list


result = filter(lambda x: x % 2 == 0, seq)
print(list(result))
Output:

[1, 3, 5, 13]
[0, 2, 8]

2.19 reduce() in Python

The reduce(fun,seq) function is used to apply a particular function passed in its argument to
all of the list elements mentioned in the sequence passed along.This function is defined in
“functools” module.

Working :

 At first step, first two elements of sequence are picked and the result is obtained.
 Next step is to apply the same function to the previously attained result and the
number just succeeding the second element and the result is again stored.
 This process continues till no more elements are left in the container.
 The final returned result is returned and printed on console.

71
# python code to demonstrate working of reduce() by importing functools for reduce()

import functools

# initializing list
lis = [ 1 , 3, 5, 6, 2, ]

# using reduce to compute sum of list


print ("The sum of the list elements is : ",end="")
print (functools.reduce(lambda a,b : a+b,lis))

# using reduce to compute maximum element from list

print ("The maximum element of the list is : ",end="")


print (functools.reduce(lambda a,b : a if a > b else b,lis))

Output:

The sum of the list elements is : 17


The maximum element of the list is : 6

reduce() vs accumulate()

Both reduce() and accumulate() can be used to calculate the summation of a sequence
elements. But there are differences in the implementation aspects in both of these.

reduce() is defined in “functools” module, accumulate() in “itertools” module.


reduce() stores the intermediate result and only returns the final summation value. Whereas,
accumulate() returns a list containing the intermediate results. The last number of the list
returned is summation value of the list.
reduce(fun,seq) takes function as 1st and sequence as 2nd argument. In contrast
accumulate(seq,fun) takes sequence as 1st argument and function as 2nd argument.

# python code to demonstrate summation using reduce() and accumulate()

# importing itertools for accumulate()


import itertools

# importing functools for reduce()


import functools

# initializing list
lis = [ 1, 3, 4, 10, 4 ]

# priting summation using accumulate()


print ("The summation of list using accumulate is :",end="")
print (list(itertools.accumulate(lis,lambda x,y : x+y)))

# priting summation using reduce()


print ("The summation of list using reduce is :",end="")

72
print (functools.reduce(lambda x,y:x+y,lis))

Output:
The summation of list using accumulate is :[1, 4, 8, 18, 22]
The summation of list using reduce is :22

2.20 Map() function

map() function returns a list of the results after applying the given function to each item of a
given iterable (list, tuple etc.)

Syntax :

map(fun, iter)
Parameters :
fun : It is a function to which map passes each element of given iterable.
iter : It is a iterable which is to be mapped.

NOTE : You can pass one or more iterable to the map() function.

Returns :

Returns a list of the results after applying the given function


to each item of a given iterable (list, tuple etc.)

NOTE : The returned value from map() (map object) then can be passed to functions like
list() (to create a list), set() (to create a set) .

CODE 1

# Python program to demonstrate working of map.

# Return double of n
def addition(n):
return n + n

# We double all numbers using map()


numbers = (1, 2, 3, 4)
result = map(addition, numbers)
print(list(result))
Output :

{2, 4, 6, 8}

2.21 Iterators in Python


Iterator in python is any python type that can be used with a ‘for in loop’. Python lists, tuples,
dicts and sets are all examples of inbuilt iterators. These types are iterators because they

73
implement following methods. In fact, any object that wants to be an iterator must implement
following methods.

1. __iter__ method that is called on initialization of an iterator. This should return an object
that has a next or __next__ (in Python 3) method.

2. next ( __next__ in Python 3) The iterator next method should return the next value for the
iterable. When an iterator is used with a ‘for in’ loop, the for loop implicitly calls next() on
the iterator object. This method should raise a StopIteration to signal the end of the iteration.
Below is a simple Python program that creates iterator type that iterates from 10 to given
limit. For example, if limit is 15, then it prints 10 11 12 13 14 15. And if limit is 5, then it
prints nothing.

# A simple Python program to demonstrate working of iterators using an example type that
iterates from 10 to given value

# An iterable user defined type


class Test:

# Cosntructor
def __init__(self, limit):
self.limit = limit

# Called when iteration is initialized


def __iter__(self):
self.x = 10
return self

# To move to next element. In Python 3,


# we should replace next with __next__
def next(self):

# Store current value ofx


x = self.x

# Stop iteration if limit is reached


if x > self.limit:
raise StopIteration

# Else increment and return old value


self.x = x + 1;
return x

# Prints numbers from 10 to 15


for i in Test(15):
print(i)

# Prints nothing
for i in Test(5):
print(i)

74
Output :
10
11
12
13
14
15

2.21 Generators in Python

Prerequisites: Yield Keyword and Iterators

There are two terms involved when we discuss generators.

Generator-Function: A generator-function is defined like a normal function, but whenever it


needs to generate a value, it does so with the yield keyword rather than return. If the body of
a def contains yield, the function automatically becomes a generator function.

# A generator function that yields 1 for first time, 2 second time and 3 third time

def simpleGeneratorFun():
yield 1
yield 2
yield 3

# Driver code to check above generator function

for value in simpleGeneratorFun():


print(value)
Output :
1
2
3

Generator-Object: Generator functions return a generator object. Generator objects are used
either by calling the next method on the generator object or using the generator object in a
“for in” loop (as shown in the above program).

# A Python program to demonstrate use of generator object with next()

# A generator function

def simpleGeneratorFun():
yield 1
yield 2
yield 3

# x is a generator object
x = simpleGeneratorFun()

75
# Iterating over the generator object using next
print(x.next()); # In Python 3, __next__()
print(x.next());
print(x.next());

Output :

1
2
3
So a generator function returns an generator object that is iterable, i.e., can be used as an
Iterators .As another example, below is a generator for Fibonacci Numbers.

# A simple generator for Fibonacci Numbers

def fib(limit):

# Initialize first two Fibonacci Numbers


a, b = 0, 1

# One by one yield next Fibonacci Number


while a < limit:
yield a
a, b = b, a + b

# Create a generator object


x = fib(5)

# Iterating over the generator object using next


print(x.next()); # In Python 3, __next__()
print(x.next());
print(x.next());
print(x.next());
print(x.next());

# Iterating over the generator object using for


# in loop.
print("\nUsing for in loop")
for i in fib(5):
print(i)

Output :

0
1
1
2
3

76
Using for in loop
0
1
1
2
3

Applications : Suppose we to create a stream of Fibonacci numbers, adopting the generator


approach makes it trivial; we just have to call next(x) to get the next Fibonacci number
without bothering about where or when the stream of numbers ends.
A more practical type of stream processing is handling large data files such as log files.
Generators provide a space efficient method for such data processing as only parts of the file
are handled at one given point in time. We can also use Iterators for these purposes, but
Generator provides a quick way (We don’t need to write __next__ and __iter__ methods
here).

2.22 List Comprehension

List comprehension is an elegant way to define and create list in python. We can create lists
just like mathematical statements and in one line only. The syntax of list comprehension is
easier to grasp.
A list comprehension generally consist of these parts :
Output expression,
input sequence,
a variable representing member of input sequence and
an optional predicate part.

For example :

lst = [x ** 2 for x in range (1, 11) if x % 2 == 1]

here, x ** 2 is output expression,


range (1, 11) is input sequence,
x is variable and
if x % 2 == 1 is predicate part.

# Python program to demonstrate list comprehension in Python

# below list contains square of all odd numbers from range 1 to 10


odd_square = [x ** 2 for x in range(1, 11) if x % 2 == 1]
print odd_square

# for understanding, above generation is same as,


odd_square = []
for x in range(1, 11):
if x % 2 == 1:
odd_square.append(x**2)
print odd_square

77
# below list contains power of 2 from 1 to 8
power_of_2 = [2 ** x for x in range(1, 9)]
print power_of_2

# below list contains prime and non-prime in range 1 to 50


noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
primes = [x for x in range(2, 50) if x not in noprimes]
print primes

# list for lowering the characters


print [x.lower() for x in ["A","B","C"]]

# list which extracts number


string = "my phone number is : 11122 !!"

print("\nExtracted digits")
numbers = [x for x in string if x.isdigit()]
print numbers

# A list of list for multiplication table


a=5
table = [[a, b, a * b] for b in range(1, 11)]

print("\nMultiplication Table")
for i in table:
print i
Output:

[1, 9, 25, 49, 81]


[1, 9, 25, 49, 81]
[2, 4, 8, 16, 32, 64, 128, 256]
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
['a', 'b', 'c']

Extracted digits
['1', '1', '1', '2', '2']

Multiplication Table
[5, 1, 5]
[5, 2, 10]
[5, 3, 15]
[5, 4, 20]
[5, 5, 25]
[5, 6, 30]
[5, 7, 35]
[5, 8, 40]
[5, 9, 45]
[5, 10, 50]

78
Module-3

OBJECTS IN PYTHON

3.1 Classes and Instance attributes

Class attributes

Class attributes belong to the class itself they will be shared by all the instances. Such
attributes are defined in the class body parts usually at the top, for legibility.

# Write Python code here

class sampleclass:
count = 0 # class attribute

def increase(self):
sampleclass.count += 1

# Calling increase() on an object


s1 = sampleclass()
s1.increase()
print s1.count

# Calling increase on one more


# object
s2 = sampleclass()
s2.increase()
print s2.count

print sampleclass.count
Output:
1
2
2

Instance Attributes

Unlike class attributes, instance attributes are not shared by objects. Every object has its own
copy of the instance attribute (In case of class attributes all object refer to single copy).

To list the attributes of an instance/object, we have two functions:-


1. vars()- This function displays the attribute of an instance in the form of an dictionary.
2. dir()- This function displays more attributes than vars function,as it is not limited to
instance. It displays the class attributes as well.

# Python program to demonstrate


# instance attributes.

79
class emp:
def __init__(self):
self.name = 'xyz'
self.salary = 4000

def show(self):
print self.name
print self.salary

e1 = emp()
print "Dictionary form :", vars(e1)
print dir(e1)
Output :

Dictionary form :{'salary': 4000, 'name': 'xyz'}


['__doc__', '__init__', '__module__', 'name', 'salary', 'show']

3.2 Inheritance

Inheritance is the capability of one class to derive or inherit the properties from some another
class. The benefits of inheritance are:

 It represents real-world relationships well.


 It provides reusability of a code. We don’t have to write the same code again and
again. Also, it allows us to add more features to a class without modifying it.
 It is transitive in nature, which means that if class B inherits from another class A,
then all the subclasses of B would automatically inherit from class A.

Below is a simple example of inheritance in Python

# A Python program to demonstrate inheritance

# Base or Super class. Note object in bracket.


# (Generally, object is made ancestor of all classes)
# In Python 3.x "class Person" is
# equivalent to "class Person(object)"

class Person(object):

# Constructor
def __init__(self, name):
self.name = name

# To get name
def getName(self):
return self.name

80
# To check if this person is employee
def isEmployee(self):
return False

# Inherited or Sub class (Note Person in bracket)


class Employee(Person):

# Here we return true


def isEmployee(self):
return True

# Driver code

emp = Person("Geek1") # An Object of Person


print(emp.getName(), emp.isEmployee())
emp = Employee("Geek2") # An Object of Employee
print(emp.getName(), emp.isEmployee())

Output:

Geek1 False
Geek2 True

3.3 Different forms of Inheritance

1. Single inheritance: When a child class inherits from only one parent class, it is called as
single inheritance. We saw an example above.

2. Multiple inheritance: When a child class inherits from multiple parent classes, it is called
as multiple inheritance.
Unlike Java and like C++, Python supports multiple inheritance. We specify all parent classes
as comma separated list in bracket.When a child class inherits from multiple parent classes, it
is called as multiple inheritance.
Unlike Java and like C++, Python supports multiple inheritance. We specify all parent classes
as comma separated list in bracket.

# Python example to show working of multiple inheritance

class Base1(object):
def __init__(self):
self.str1 = "Geek1"
print "Base1"

class Base2(object):
def __init__(self):
self.str2 = "Geek2"
print "Base2"

81
class Derived(Base1, Base2):
def __init__(self):

# Calling constructors of Base1


# and Base2 classes
Base1.__init__(self)
Base2.__init__(self)
print "Derived"

def printStrs(self):
print(self.str1, self.str2)

ob = Derived()
ob.printStrs()

Output:
Base1
Base2
Derived
('Geek1', 'Geek2')

Output :
Base1
Base2
Derived
Geek1 True E101

3.4 Method Resolution Order (MRO)

It denotes the way a programming language resolves a method or attribute. Python supports
classes inheriting from other classes. The class being inherited is called the Parent or
Superclass, while the class that inherits is called the Child or Subclass. In python, method
resolution order defines the order in which the base classes are searched when executing a
method. First, the method or attribute is searched within a class and then it follows the order
we specified while inheriting. This order is also called Linearization of a class and set of rules
are called MRO(Method Resolution Order). While inheriting from another class, the
interpreter needs a way to resolve the methods that are being called via an instance. Thus we
need the method resolution order. For Example

# Python program showing how MRO works

class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):

82
print(" In class B")

r = B()
r.rk()

Output:

In class B

In the above example the methods that are invoked is from class B but not from class A, and
this is due to Method Resolution Order(MRO).
The order that follows in the above code is- class B - > class A
In multiple inheritances, the methods are executed based on the order specified while
inheriting the classes. For the languages that support single inheritance, method resolution
order is not interesting, but the languages that support multiple inheritance method resolution
order plays a very crucial role. Let’s look over another example to deeply understand the
method resolution order:

Python program showing how MRO works

class A:
def rk(self):
print(" In class A")
class B(A):
def rk(self):
print(" In class B")
class C(A):
def rk(self):
print("In class C")

# classes ordering
class D(B, C):
pass

r = D()
r.rk()

Output:
In class B

In the above example we use multiple inheritances and it is also called Diamond
inheritance or Deadly Diamond of Death and it looks as follows:

83
Python follows a depth-first lookup order and hence ends up calling the method from class A.
By following the method resolution order, the lookup order as follows.
Class D -> Class B -> Class C -> Class A
Python follows depth-first order to resolve the methods and attributes. So in the above
example, it executes the method in class B.

3.5 Magic methods

Magic methods in Python are the special methods which add "magic" to your class. Magic
methods are not meant to be invoked directly by you, but the invocation happens internally
from the class on a certain action. For example, when you add two numbers using the +
operator, internally, the __add__() method will be called.

Built-in classes in Python define many magic methods. Use the dir() function to see the
number of magic methods inherited by a class. For example, the following lists all the
attributes and methods defined in the int class.

>>> dir(int)

['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__',


'__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__',
'__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__',
'__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__',
'__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__',
'__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__',
'__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__',
'__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
'__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate',
'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

As you can see above, the int class includes various magic methods surrounded by double
underscores. For example, the __add__ method is a magic method which gets called when we
add two numbers using the + operator. Consider the following example.

>>> num=10
>>> num + 5
15
>>> num.__add__(5)
15
As you can see, when you do num+10, the + operator calls the __add__(10) method. You can
also call num.__add__(5) directly which will give the same result. However, as mentioned
before, magic methods are not meant to be called directly, but internally, through some other
methods or actions.

Magic methods are most frequently used to define overloaded behaviours of predefined
operators in Python. For instance, arithmetic operators by default operate upon numeric
operands. This means that numeric objects must be used along with operators like +, -, *, /,

84
etc. The + operator is also defined as a concatenation operator in string, list and tuple classes.
We can say that the + operator is overloaded.

In order to make the overloaded behaviour available in your own custom class, the
corresponding magic method should be overridden. For example, in order to use the +
operator with objects of a user-defined class, it should include the __add__() method.

Let's see how to implement and use some of the important magic methods.

1. __new__() method
Languages such as Java and C# use the new operator to create a new instance of a class. In
Python the __new__() magic method is implicitly called before the __init__() method. The
__new__() method returns a new object, which is then initialized by __init__().

Example: __new__()
class employee:
def __new__(cls):
print ("__new__ magic method is called")
inst = object.__new__(cls)
return inst
def __init__(self):
print ("__init__ magic method is called")
self.name='Satya'
The above example will produce the following output when you create an instance of the
Employee class.

>>> e1=employee()
__new__ magic method is called
__init__ magic method is called
Thus, the __new__() method is called before the __init__() method.

2. __str__() method

Another useful magic method is __str__(). It is overridden to return a printable string


representation of any user defined class. We have seen str() built-in function which returns a
string from the object parameter. For example, str(12) returns '12'. When invoked, it calls the
__str__() method in the int class.

>>> num=12
>>> str(num)
'12'
>>> #This is equivalent to
>>> int.__str__(num)
'12'
Let us now override the __str__() method in the employee class to return a string
representation of its object.

Example:
class employee:
def __init__(self):

85
self.name='Swati'
self.salary=10000
def __str__(self):
return 'name='+self.name+' salary=$'+str(self.salary)
See how the str() function internally calls the __str__() method defined in the employee class.
This is why it is called a magic method!

>>> e1=employee()
>>> print(e1)
name=Swati salary=$10000
3. __add__() method
In following example, a class named distance is defined with two instance attributes - ft and
inch. The addition of these two distance objects is desired to be performed using the
overloading + operator.

To achieve this, the magic method __add__() is overridden, which performs the addition of
the ft and inch attributes of the two objects. The __str__() method returns the object's string
representation.

Example: __add__()
class distance:
def __init__(self, x=None,y=None):
self.ft=x
self.inch=y
def __add__(self,x):
temp=distance()
temp.ft=self.ft+x.ft
temp.inch=self.inch+x.inch
if temp.inch>=12:
temp.ft+=1
temp.inch-=12
return temp
def __str__(self):
return 'ft:'+str(self.ft)+' in: '+str(self.inch)
Run the above Python script to verify the overloaded operation of the + operator.

>>> d1=distance(3,10)
>>> d2=distance(4,4)
>>> print("d1= {} d2={}".format(d1, d2))
d1= ft:3 in: 10 d2=ft:4 in: 4
>>>d3=d1+d2
>>>print(d3)
ft:8 in: 2

4. __ge__() method
The following method is added in the distance class to overload the >= operator.

Example: __ge__()
class distance:
def __init__(self, x=None,y=None):

86
self.ft=x
self.inch=y
def __ge__(self, x):
val1=self.ft*12+self.inch
val2=x.ft*12+x.inch
if val1>=val2:
return True
else:
return False
This method gets invoked when the >= operator is used and returns True or False.
Accordingly, the appropriate message can be displayed

>>>d1=distance(2,1)
>>>d2=distance(4,10)
>>>d1>=d2
False

3.6 Operator Overloading in Python


Operator Overloading means giving extended meaning beyond their predefined operational
meaning. For example operator + is used to add two integers as well as join two strings and
merge two lists. It is achievable because ‘+’ operator is overloaded by int class and str class.
You might have noticed that the same built-in operator or function shows different behaviour
for objects of different classes, this is called Operator Overloading.

# Python program to show use of + operator for different purposes.

print(1 + 2)

# concatenate two strings


print("Geeks"+"For")

# Product two numbers


print(3 * 4)

# Repeat the String


print("Geeks"*4)

Output:

3
GeeksFor
12
GeeksGeeksGeeksGeeks

How to overload the operators in Python?


Consider that we have two objects which are a physical representation of a class (user-
defined data type) and we have to add two objects with binary ‘+’ operator it throws an error,

87
because compiler don’t know how to add two objects. So we define a method for an operator
and that process is called operator overloading. We can overload all existing operators but we
can’t create a new operator. To perform operator overloading, Python provides some special
function or magic function that is automatically invoked when it is associated with that
particular operator. For example, when we use + operator, the magic method __add__ is
automatically invoked in which the operation for + operator is defined.

Overloading binary + operator in Python :


When we use an operator on user defined data types then automatically a special function or
magic function associated with that operator is invoked. Changing the behavior of operator is
as simple as changing the behavior of method or function. You define methods in your class
and operators work according to that behavior defined in methods. When we use + operator,
the magic method __add__ is automatically invoked in which the operation for + operator is
defined. There by changing this magic method’s code, we can give extra meaning to the +
operator.

Code 1:

# Python Program illustrate how to overload an binary + operator

class A:
def __init__(self, a):
self.a = a

# adding two objects


def __add__(self, o):
return self.a + o.a
ob1 = A(1)
ob2 = A(2)
ob3 = A("Geeks")
ob4 = A("For")

print(ob1 + ob2)
print(ob3 + ob4)

Output :
3
GeeksFor

Overloading comparison operators in Python :

# Python program to overload a comparison operators

class A:
def __init__(self, a):
self.a = a
def __gt__(self, other):
if(self.a>other.a):
return True

88
else:
return False
ob1 = A(2)
ob2 = A(3)
if(ob1>ob2):
print("ob1 is greater than ob2")
else:
print("ob2 is greater than ob1")

Output :
ob2 is greater than ob1

Overloading equality and less than operators :

# Python program to overload equality and less than operators

class A:
def __init__(self, a):
self.a = a
def __lt__(self, other):
if(self.a<other.a):
return "ob1 is lessthan ob2"
else:
return "ob2 is less than ob1"
def __eq__(self, other):
if(self.a == other.a):
return "Both are equal"
else:
return "Not equal"

ob1 = A(2)
ob2 = A(3)
print(ob1 < ob2)

ob3 = A(4)
ob4 = A(4)
print(ob1 == ob2)

Output :
ob1 is lessthan ob2
Not equal

3.7 Meta Classes

In Python everything have some type associated with it. For example if we have a variable
having integer value then it’s type is int. You can get type of anything using type() function.
num = 23
print("Type of num is:", type(num))

89
lst = [1, 2, 4]
print("Type of lst is:", type(lst))

name = "Atul"
print("Type of name is:", type(name))
Output:

Type of num is: <class 'int'>


Type of lst is: <class 'list'>
Type of name is: <class 'str'>
Every type in Python is defined by Class. So in above example, unlike C or Java where int,
char, float are primary data types, in Python they are object of int class or str class. So we can
make a new type by creating a class of that type. For example we can create a new type
Student by creating Student class.

class Student:
pass
stu_obj = Student()

# Print type of object of Student class


print("Type of stu_obj is:", type(stu_obj))

Output:

Type of stu_obj is: <class '__main__.Student'>

A Class is also an object, and just like any other object it’s a instance of something called
Metaclass. A special class type creates these Class object. The type class is default metaclass
which is responsible for making classes. For example in above example if we try to find out
the type of Student class, it comes out to be a type.

class Student:
pass

# Print type of Student class


print("Type of Student class is:", type(Student))

Output:

Type of Student class is: <class 'type'>


Because Classes are also an object, they can be modified in same way. We can add or
subtract fields or methods in class in same way we did with other objects. For example –

# Defined class without anyclass methods and variables


class test:pass

# Defining method variables


test.x = 45

90
# Defining class methods
test.foo = lambda self: print('Hello')

# creating object
myobj = test()

print(myobj.x)
myobj.foo()

Output:
45
Hello

This whole meta thing can be summarized as – Metaclass create Classes and Classes creates
objects. Metaclass is responsible for generation of classes, so we can write our own custom
metaclasses to modify the way classes are generated by performing extra actions or injecting
code.

3.8 Abstract and Inner classes


An inner class or nested class is a defined entirely within the body of another class. If an
object is created using a class, the object inside the root class can be used. A class can have
more than one inner classes, but in general inner classes are avoided.

We create a class (Human) with one inner class (Head). An instance is created that calls a
method in the inner class:

class Human:

def __init__(self):
self.name = 'Guido'
self.head = self.Head()

class Head:
def talk(self):
return 'talking...'

if __name__ == '__main__':
guido = Human()
print guido.name
print guido.head.talk()

Output:

Guido
talking...

91
In the program above we have the inner class Head() which has its own method. An inner
class can have both methods and variables. In this example the constructor of the class
Human (init) creates a new head object.

Abstract Classes

An abstract class can be considered as a blueprint for other classes, allows you to create a set
of methods that must be created within any child classes built from your abstract class. A
class which contains one or abstract methods is called an abstract class. An abstract method is
a method that has declaration but not has any implementation. Abstract classes are not able to
instantiated and it needs subclasses to provide implementations for those abstract methods
which are defined in abstract classes. While we are designing large functional units we use an
abstract class. When we want to provide a common implemented functionality for all
implementations of a component, we use an abstract class. Abstract classes allow partially to
implement classes when it completely implements all methods in a class, then it is called
interface.

Why use Abstract Base Classes:

Abstract classes allow you to provide default functionality for the subclasses. Compared to
interfaces abstract classes can have an implementation. By defining an abstract base class,
you can define a common Application Program Interface(API) for a set of subclasses. This
capability is especially useful in situations where a third-party is going to provide
implementations, such as with plugins in an application, but can also help you when working
on a large team or with a large code-base where keeping all classes in your head at the same
time is difficult or not possible.

How Abstract Base classes works:

In python by default, it is not able to provide abstract classes, but python comes up with a
module which provides the base for defining Abstract Base classes (ABC) and that module
name is ABC. ABC works by marking methods of the base class as abstract and then
registering concrete classes as implementations of the abstract base. A method becomes an
abstract by decorated it with a keyword @abstractmethod. For Example –

Code 1:

# Python program showing abstract base class work

from abc import ABC, abstractmethod

class Polygon(ABC):

# abstract method
def noofsides(self):
pass

class Triangle(Polygon):

# overriding abstract method

92
def noofsides(self):
print("I have 3 sides")

class Pentagon(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 5 sides")

class Hexagon(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 6 sides")

class Quadrilateral(Polygon):

# overriding abstract method


def noofsides(self):
print("I have 4 sides")

# Driver code
R = Triangle()
R.noofsides()

K = Quadrilateral()
K.noofsides()

R = Pentagon()
R.noofsides()

K = Hexagon()
K.noofsides()

Output:

I have 3 sides
I have 4 sides
I have 5 sides
I have 6 sides

Code 2:

# Python program showing abstract base class work

from abc import ABC, abstractmethod


class Animal(ABC):

def move(self):
pass

93
class Human(Animal):

def move(self):
print("I can walk and run")

class Snake(Animal):

def move(self):
print("I can crawl")

class Dog(Animal):

def move(self):
print("I can bark")

class Lion(Animal):

def move(self):
print("I can roar")

# Driver code
R = Human()
R.move()

K = Snake()
K.move()

R = Dog()
R.move()

K = Lion()
K.move()

Output:

I can walk and run


I can crawl
I can bark
I can roar

3.9 Exception Handling

Exception is the base class for all the exceptions in python. You can check the exception
hierarchy here. Let us try to access the array element whose index is out of bound and handle
the corresponding exception.

# Python program to handle simple runtime error

94
a = [1, 2, 3]
try:
print "Second element = %d" %(a[1])

# Throws error since there are only 3 elements in array


print "Fourth element = %d" %(a[3])

except IndexError:
print "An error occurred"

Output:
Second element = 2
An error occurred

A try statement can have more than one except clause, to specify handlers for different
exceptions. Please note that at most one handler will be executed.

# Program to handle multiple errors with one except statement


try :
a=3
if a < 4 :

# throws ZeroDivisionError for a = 3


b = a/(a-3)

# throws NameError if a >= 4


print "Value of b = ", b

# note that braces () are necessary here for multiple exceptions


except(ZeroDivisionError, NameError):
print "\nError Occurred and Handled"

Output:

Error Occurred and Handled


If you change the value of ‘a’ to greater than or equal to 4, the output will be

Value of b =
Error Occurred and Handled
The output above is so because as soon as python tries to access the value of b, NameError
occurs.

Else Clause:
In python, you can also use else clause on try-except block which must be present after all the
except clauses. The code enters the else block only if the try clause does not raise an
exception.

# Program to depict else clause with try-except Function which returns a/b

95
def AbyB(a , b):
try:
c = ((a+b) / (a-b))
except ZeroDivisionError:
print "a/b result in 0"
else:
print c

# Driver program to test above function


AbyB(2.0, 3.0)
AbyB(3.0, 3.0)
The output for above program will be :

-5.0
a/b result in 0

Raising Exception:
The raise statement allows the programmer to force a specific exception to occur. The sole
argument in raise indicates the exception to be raised. This must be either an exception
instance or an exception class (a class that derives from Exception).

# Program to depict Raising Exception

try:
raise NameError("Hi there") # Raise Error
except NameError:
print "An exception"
raise # To determine whether the exception was raised or not

The output of the above code will simply line printed as “An exception” but a Runtime error
will also occur in the last due to raise statement in the last line. So, the output on your
command line will look like

Traceback (most recent call last):


File "003dff3d748c75816b7f849be98b91b8.py", line 4, in
raise NameError("Hi there") # Raise Error
NameError: Hi there

3.10 Modular Programs and Packages

In programming, a module is a piece of software that has a specific functionality. For


example, when building a ping pong game, one module would be responsible for the game
logic, and another module would be responsible for drawing the game on the screen. Each
module is a different file, which can be edited separately.

Writing modules in python

96
Modules in Python are simply Python files with a .py extension. The name of the module will
be the name of the file. A Python module can have a set of functions, classes or variables
defined and implemented.
Let's create a module. We save the following code in the file fibonacci.py:

def fib(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
def ifib(n):
a, b = 0, 1
for i in range(n):
a, b = b, a + b
return a

We can import this module in the interactive python shell and call the functions by prefixing
them with "fibonacci.":

>>> import fibonacci


>>> fibonacci.fib(30)
832040
>>> fibonacci.ifib(100)
354224848179261915075L

Usually, modules contain functions, but there can be statements in them as well. These
statements can be used to initialize the module. They are only executed when the module is
imported.

A module has a private symbol table, which is used as the global symbol table by all
functions defined in the module. This is a way to prevent that a global variable of a module
accidentally clashes with a user's global variable with the same name. Global variables of a
module can be accessed with the same notation as functions, i.e. modname.name
A module can import other modules. It is customary to place all import statements at the
beginning of a module or a script.
Importing Names from a Module Directly
Names from a module can directly be imported into the importing module's symbol table:

>>> from fibonacci import fib, ifib


>>> ifib(500)

Output:
1 1 2 3 5 8 13 21 34 55 89 144 233 377

This does not introduce the module name from which the imports are taken in the local
symbol table. It's possible but not recommended to import all names defined in a module,
except those beginning with an underscore "_":

97
>>> from fibonacci import *
>>> fib(500)

Output:

1 1 2 3 5 8 13 21 34 55 89 144 233 377

Packeges in python

Suppose you have developed a very large application that includes many modules. As the
number of modules grows, it becomes difficult to keep track of them all if they are dumped
into one location. This is particularly so if they have similar names or functionality. You
might wish for a means of grouping and organizing them.

Packages allow for a hierarchical structuring of the module namespace using dot notation. In
the same way that modules help avoid collisions between global variable names, packages
help avoid collisions between module names.

Creating a package is quite straightforward, since it makes use of the operating system’s
inherent hierarchical file structure. Consider the following arrangement:

Here, there is a directory named pkg that contains two modules, mod1.py and mod2.py. The
contents of the modules are:

mod1.py

def foo():
print('[mod1] foo()')

class Foo:
pass
mod2.py

def bar():
print('[mod2] bar()')

class Bar:
pass

Given this structure, if the pkg directory resides in a location where it can be found (in one of
the directories contained in sys.path), you can refer to the two modules with dot notation
(pkg.mod1, pkg.mod2) and import them with the syntax you are already familiar with:

import <module_name>[, <module_name> ...]

>>> import pkg.mod1, pkg.mod2


>>> pkg.mod1.foo()
>>> x = pkg.mod2.Bar()
>>> x
<pkg.mod2.Bar object at 0x033F7290>

98
from <module_name> import <name(s)>
>>> from pkg.mod1 import foo
>>> foo()

from <module_name> import <name> as <alt_name>


>>> from pkg.mod2 import Bar as Qux
>>> x = Qux()
>>> x

<pkg.mod2.Bar object at 0x036DFFD0>

You can import modules with these statements as well:

from <package_name> import <modules_name>[, <module_name> ...]


from <package_name> import <module_name> as <alt_name>
>>> from pkg import mod1
>>> mod1.foo()

>>> from pkg import mod2 as quux


>>> quux.bar()

99
Module-4

Numerical Analysis in python

4.1 Introduction to NumPy

NumPy is a Python package. It stands for 'Numerical Python'. It is a library consisting of


multidimensional array objects and a collection of routines for processing of array. Numeric,
the ancestor of NumPy, was developed by Jim Hugunin. Another package Numarray was also
developed, having some additional functionalities. In 2005, Travis Oliphant created NumPy
package by incorporating the features of Numarray into Numeric package. There are many
contributors to this open source project.

Operations using NumPy

Using NumPy, a developer can perform the following operations −Mathematical and logical
operations on arrays. Fourier transforms and routines for shape manipulation.Operations
related to linear algebra. NumPy has in-built functions for linear algebra and random number
generation.

NumPy – A Replacement for MatLab

NumPy is often used along with packages like SciPy (Scientific Python) and Mat−plotlib
(plotting library). This combination is widely used as a replacement for MatLab, a popular
platform for technical computing. However, Python alternative to MatLab is now seen as a
more modern and complete programming language. It is open source, which is an added
advantage of NumPy.

4.2 NumPy - Ndarray Object

The most important object defined in NumPy is an N-dimensional array type called ndarray.
It describes the collection of items of the same type. Items in the collection can be accessed
using a zero-based index.Every item in an ndarray takes the same size of block in the
memory. Each element in ndarray is an object of data-type object (called dtype). Any item
extracted from ndarray object (by slicing) is represented by a Python object of one of array
scalar types. The following diagram shows a relationship between ndarray, data type object
(dtype) and array scalar type –

100
An instance of ndarray class can be constructed by different array creation routines
described later in the tutorial. The basic ndarray is created using an array function in NumPy
as follows −
numpy.array
It creates an ndarray from any object exposing array interface, or from any method that
returns an array.
numpy.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
The above constructor takes the following parameters –

Take a look at the following examples to understand better.

101
Example 1

import numpy as np
a = np.array([1,2,3])
print a
The output is as follows −

[1, 2, 3]

Example 2

# more than one dimensions

import numpy as np
a = np.array([[1, 2], [3, 4]])
print a
The output is as follows −

[[1, 2]
[3, 4]]

Example 3

# minimum dimensions

import numpy as np
a = np.array([1, 2, 3,4,5], ndmin = 2)
print a
The output is as follows −

[[1, 2, 3, 4, 5]]

Example 4

# dtype parameter

import numpy as np
a = np.array([1, 2, 3], dtype = complex)
print a
The output is as follows −

[ 1.+0.j, 2.+0.j, 3.+0.j]

The ndarray object consists of contiguous one-dimensional segment of computer memory,


combined with an indexing scheme that maps each item to a location in the memory block.

102
The memory block holds the elements in a row-major order (C style) or a column-major
order (FORTRAN or MatLab style).

Arrays in NumPy: NumPy’s main object is the homogeneous multidimensional array.

It is a table of elements (usually numbers), all of the same type, indexed by a tuple of positive
integers. In NumPy dimensions are called axes. The number of axes is rank. NumPy’s array
class is called ndarray. It is also known by the alias array.

Example :

[[ 1, 2, 3],
[ 4, 2, 5]]

Here,
rank = 2 (as it is 2-dimensional or it has 2 axes)
first dimension(axis) length = 2, second dimension has length = 3
overall shape can be expressed as: (2, 3)

# Python program to demonstrate basic array characteristics


import numpy as np

# Creating array object


arr = np.array( [[ 1, 2, 3],
[ 4, 2, 5]] )

# Printing type of arr object


print("Array is of type: ", type(arr))

# Printing array dimensions (axes)


print("No. of dimensions: ", arr.ndim)

# Printing shape of array


print("Shape of array: ", arr.shape)

# Printing size (total number of elements) of array


print("Size of array: ", arr.size)

# Printing type of elements in array


print("Array stores elements of type: ", arr.dtype)
Output :

Array is of type:
No. of dimensions: 2
Shape of array: (2, 3)
Size of array: 6
Array stores elements of type: int64

Array creation: There are various ways to create arrays in NumPy.

103
For example, you can create an array from a regular Python list or tuple using the array
function. The type of the resulting array is deduced from the type of the elements in the
sequences. Often, the elements of an array are originally unknown, but its size is known.
Hence, NumPy offers several functions to create arrays with initial placeholder content.
These minimize the necessity of growing arrays, an expensive operation.

For example: np.zeros, np.ones, np.full, np.empty, etc.

To create sequences of numbers, NumPy provides a function analogous to range that returns
arrays instead of lists.
arange: returns evenly spaced values within a given interval. step size is specified.
linspace: returns evenly spaced values within a given interval. num no. of elements are
returned.
Reshaping array: We can use reshape method to reshape an array. Consider an array with
shape (a1, a2, a3, …, aN). We can reshape and convert it into another array with shape (b1,
b2, b3, …, bM). The only required condition is:
a1 x a2 x a3 … x aN = b1 x b2 x b3 … x bM . (i.e original size of array remains unchanged.)
Flatten array: We can use flatten method to get a copy of array collapsed into one
dimension. It accepts order argument. Default value is ‘C’ (for row-major order). Use ‘F’ for
column major order.

Note: Type of array can be explicitly defined while creating array.

# Python program to demonstrate array creation techniques


import numpy as np

# Creating array from list with type float


a = np.array([[1, 2, 4], [5, 8, 7]], dtype = 'float')
print ("Array created using passed list:\n", a)

# Creating array from tuple


b = np.array((1 , 3, 2))
print ("\nArray created using passed tuple:\n", b)

# Creating a 3X4 array with all zeros


c = np.zeros((3, 4))
print ("\nAn array initialized with all zeros:\n", c)

# Create a constant value array of complex type


d = np.full((3, 3), 6, dtype = 'complex')
print ("\nAn array initialized with all 6s."
"Array type is complex:\n", d)

# Create an array with random values


e = np.random.random((2, 2))
print ("\nA random array:\n", e)

# Create a sequence of integers


# from 0 to 30 with steps of 5
f = np.arange(0, 30, 5)

104
print ("\nA sequential array with steps of 5:\n", f)

# Create a sequence of 10 values in range 0 to 5


g = np.linspace(0, 5, 10)
print ("\nA sequential array with 10 values between"
"0 and 5:\n", g)

# Reshaping 3X4 array to 2X2X3 array


arr = np.array([[1, 2, 3, 4],
[5, 2, 4, 2],
[1, 2, 0, 1]])

newarr = arr.reshape(2, 2, 3)

print ("\nOriginal array:\n", arr)


print ("Reshaped array:\n", newarr)

# Flatten array
arr = np.array([[1, 2, 3], [4, 5, 6]])
flarr = arr.flatten()

print ("\nOriginal array:\n", arr)


print ("Fattened array:\n", flarr)

Output :

Array created using passed list:


[[ 1. 2. 4.]
[ 5. 8. 7.]]

Array created using passed tuple:


[1 3 2]

An array initialized with all zeros:


[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]

An array initialized with all 6s. Array type is complex:


[[ 6.+0.j 6.+0.j 6.+0.j]
[ 6.+0.j 6.+0.j 6.+0.j]
[ 6.+0.j 6.+0.j 6.+0.j]]

A random array:
[[ 0.46829566 0.67079389]
[ 0.09079849 0.95410464]]

A sequential array with steps of 5:


[ 0 5 10 15 20 25]

105
A sequential array with 10 values between 0 and 5:
[ 0. 0.55555556 1.11111111 1.66666667 2.22222222 2.77777778
3.33333333 3.88888889 4.44444444 5. ]

Original array:
[[1 2 3 4]
[5 2 4 2]
[1 2 0 1]]
Reshaped array:
[[[1 2 3]
[4 5 2]]

[[4 2 1]
[2 0 1]]]

Original array:
[[1 2 3]
[4 5 6]]
Fattened array:
[1 2 3 4 5 6]

Array Indexing: Knowing the basics of array indexing is important for analysing and
manipulating the array object. NumPy offers many ways to do array indexing.

Slicing: Just like lists in python, NumPy arrays can be sliced. As arrays can be
multidimensional, you need to specify a slice for each dimension of the array.

Integer array indexing: In this method, lists are passed for indexing for each dimension.
One to one mapping of corresponding elements is done to construct a new arbitrary array.

Boolean array indexing: This method is used when we want to pick elements from array
which satisfy some condition.

# Python program to demonstrate indexing in numpy

import numpy as np

# An exemplar array

arr = np.array([[-1, 2, 0, 4],


[4, -0.5, 6, 0],
[2.6, 0, 7, 8],
[3, -7, 4, 2.0]])

# Slicing array
temp = arr[:2, ::2]
print ("Array with first 2 rows and alternate"

106
"columns(0 and 2):\n", temp)

# Integer array indexing example


temp = arr[[0, 1, 2, 3], [3, 2, 1, 0]]
print ("\nElements at indices (0, 3), (1, 2), (2, 1),"
"(3, 0):\n", temp)

# boolean array indexing example

cond = arr > 0 # cond is a boolean array


temp = arr[cond]
print ("\nElements greater than 0:\n", temp)

Output :

Array with first 2 rows and alternatecolumns(0 and 2):


[[-1. 0.]
[ 4. 6.]]

Elements at indices (0, 3), (1, 2), (2, 1),(3, 0):


[ 4. 6. 0. 3.]

Elements greater than 0:


[ 2. 4. 4. 6. 2.6 7. 8. 3. 4. 2. ]

4.3 NumPy Numerical types

4.3.1 Data type Object (dtype) in NumPy Python

Every ndarray has an associated data type (dtype) object. This data type object (dtype)
informs us about the layout of the array. This means it gives us information about :

Type of the data (integer, float, Python object etc.)


Size of the data (number of bytes)
Byte order of the data (little-endian or big-endian)
If the data type is a sub-array, what is its shape and data type.
The values of an ndarray are stored in a buffer which can be thought of as a contiguous block
of memory bytes. So how these bytes will be interpreted is given by the dtype object.

Constructing a data type (dtype) object : Data type object is an instance of numpy.dtype
class and it can be created using numpy.dtype.

Parameters:
obj: Object to be converted to a data type object.
align : bool, optional

Add padding to the fields to match what a C compiler would output for a similar C-struct.

107
copy : bool, optional

Make a new copy of the data-type object. If False, the result may just be a reference to a
built-in data-type object.

# Python Program to create a data type object


import numpy as np

# np.int16 is converted into a data type object.


print(np.dtype(np.int16))
Output:

int16

# Python Program to create a data type object containing a 32 bit big-endian integer

import numpy as np

# i4 represents integer of size 4 byte


# > represents big-endian byte ordering and < represents little-endian encoding.
# dt is a dtype object
dt = np.dtype('>i4')

print("Byte order is:",dt.byteorder)

print("Size is:",dt.itemsize)

print("Data type is:",dt.name)


Output:

Byte order is: >


Size is: 4
Name of data type is: int32

dtype is different from type.

# Python program to differentiate between type and dtype.


import numpy as np

a = np.array([1])

print("type is: ",type(a))


print("dtype is: ",a.dtype)

Output:
type is:
dtype is: int32

108
4.3.2 Character Codes
Each built-in data-type has a character code (the updated Numeric typecodes), that uniquely
identifies it.

Example
>>> dt = np.dtype('b') # byte, native byte order
>>> dt = np.dtype('>H') # big-endian unsigned short
>>> dt = np.dtype('<f') # little-endian single-precision float
>>> dt = np.dtype('d') # double-precision floating-point number

The first character specifies the kind of data and the remaining characters specify the number
of bytes per item, except for Unicode, where it is interpreted as the number of characters. The
item size must correspond to an existing type, or an error will be raised. The supported kinds
are
'?' boolean
'b' (signed) byte
'B' unsigned byte
'i' (signed) integer
'u' unsigned integer
'f' floating-point
'c' complex-floating point
'm' timedelta
'M' datetime
'O' (Python) objects
'S', 'a' zero-terminated bytes (not recommended)
'U' Unicode string
'V' raw data (void)

4.3.3 One Dimensional Indexing using index arrays

Indexing can be done in numpy by using an array as an index. In case of slice, a view or
shallow copy of the array is returned but in index array a copy of the original array is
returned. Numpy arrays can be indexed with other arrays or any other sequence with the
exception of tuples. The last element is indexed by -1 second last by -2 and so on.

# Python program to demonstrate the use of index arrays.

Example-1
import numpy as np

# Create a sequence of integers from 10 to 1 with a step of -2


a = np.arange(10, 1, -2)
print("\n A sequential array with a negative step: \n",a)

# Indexes are specified inside the np.array method.


newarr = a[np.array([3, 1, 2 ])]
print("\n Elements at these indices are:\n",newarr)

Output :

109
A sequential array with a negative step:
[10 8 6 4 2]

Elements at these indices are:


[4 8 6]

Example-2
import numpy as np

# NumPy array with elements from 1 to 9


x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])

# Index values can be negative.


arr = x[np.array([1, 3, -3])]
print("\n Elements are : \n",arr)

Output :

Elements are:
[2 4 7]

Types of Indexing: There are two types of indexing:

Basic Slicing and indexing: Consider the syntax x[obj] where x is the array and obj is the
index. Slice object is the index in case of basic slicing. Basic slicing occurs when obj is:

 a slice object that is of the form start : stop : step


 an integer or a tuple of slice objects and integers
 All arrays generated by basic slicing are always view of the original array.

# Python program for basic slicing.


import numpy as np

# Arrange elements from 0 to 19


a = np.arange(20)
print("\n Array is:\n ",a)

# a[start:stop:step]
print("\n a[-8:17:1] = ",a[-8:17:1])

# The : operator means all elements till the end.


print("\n a[10:] = ",a[10:])
Output :

Array is:
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]

a[-8:17:1] = [12 13 14 15 16]

a[10:] = [10 11 12 13 14 15 16 17 18 19]

110
Ellipsis can also be used along with basic slicing. Ellipsis (…) is the number of : objects
needed to make a selection tuple of the same length as the dimensions of the array.

# Python program for indexing using basic slicing with ellipsis


import numpy as np

# A 3 dimensional array.
b = np.array([[[1, 2, 3],[4, 5, 6]],
[[7, 8, 9],[10, 11, 12]]])

print(b[...,1]) #Equivalent to b[: ,: ,1 ]

Output :

[[ 2 5]
[ 8 11]]

Advanced indexing : Advanced indexing is triggered when obj is :


 an ndarray of type integer or Boolean
 or a tuple with at least one sequence object
 is a non tuple sequence object

Advanced indexing returns a copy of data rather than a view of it. Advanced indexing is of
two types integer and Boolean.

Purely integer indexing: When integers are used for indexing. Each element of first
dimension is paired with the element of the second dimension. So the index of the elements
in this case are (0,0),(1,0),(2,1) and the corresponding elements are selected.

# Python program showing advanced indexing


import numpy as np

a = np.array([[1 ,2 ],[3 ,4 ],[5 ,6 ]])


print(a[[0 ,1 ,2 ],[0 ,0 ,1]])

Output :

[1 3 6]

Boolean Indexing: This indexing has some boolean expression as the index. Those elements
are returned which satisfy that Boolean expression. It is used for filtering the desired element
values.

# You may wish to select numbers greater than 50


import numpy as np

a = np.array([10, 40, 80, 50, 100])


print(a[a>50])

111
Output :

[80 100]

# You may wish to square the multiples of 40

import numpy as np

a = np.array([10, 40, 80, 50, 100])


print(a[a%40==0]**2)

Output :

[1600 6400])

# You may wish to select those elements whose sum of row is a multiple of 10.
import numpy as np

b = np.array([[5, 5],[4, 5],[16, 4]])


sumrow = b.sum(-1)
print(b[sumrow%10==0])
Output :

array([[ 5, 5], [16, 4]])

4.4 Creating a Two-dimensional Array


Let's talk about creating a two-dimensional array. If you only use the arange function, it will
output a one-dimensional array. To make it a two-dimensional array, chain its output with the
reshape function.

array = np.arange(20).reshape(4,5)
array
python

Output:

array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19]])

First, 20 integers will be created and then it will convert the array into a two-dimensional
array with 4 rows and 5 columns. Let's check the dimensionality of this array.

array.shape
python
Output:

112
(4, 5)
Since we get two values, this is a two-dimensional array. To access an element in a two-
dimensional array, you need to specify an index for both the row and the column.
array[3][4]
python

Output:
19

4.5 Stacking Arrays using numpy.stack() in Python

numpy.stack() function is used to join a sequence of same dimension arrays along a new
axis.The axis parameter specifies the index of the new axis in the dimensions of the result.
For example, if axis=0 it will be the first dimension and if axis=-1 it will be the last
dimension.

Syntax : numpy.stack(arrays, axis)


Parameters :
arrays : [array_like] Sequence of arrays of the same shape.
axis : [int] Axis in the resultant array along which the input arrays are stacked.

# Python program explaining stack() function

import numpy as geek

# input array
in_arr1 = geek.array([ 1, 2, 3] )
print ("1st Input array : \n", in_arr1)

in_arr2 = geek.array([ 4, 5, 6] )
print ("2nd Input array : \n", in_arr2)

# Stacking the two arrays along axis 0


out_arr1 = geek.stack((in_arr1, in_arr2), axis = 0)
print ("Output stacked array along axis 0:\n ", out_arr1)

# Stacking the two arrays along axis 1


out_arr2 = geek.stack((in_arr1, in_arr2), axis = 1)
print ("Output stacked array along axis 1:\n ", out_arr2)

Output:
1st Input array :
[1 2 3]

2nd Input array :


[4 5 6]

Output stacked array along axis 0:

113
[[1 2 3]
[4 5 6]]

Output stacked array along axis 1:


[[1 4]
[2 5]
[3 6]]

4.6 Splitting NumPy arrays

numpy.split
numpy.split(ary, indices_or_sections, axis=0)[source]

Split an array into multiple sub-arrays.

Parameters:
ary : ndarray

Array to be divided into sub-arrays.

indices_or_sections : int or 1-D array


If indices_or_sections is an integer, N, the array will be divided into N equal arrays along
axis. If such a split is not possible, an error is raised.

If indices_or_sections is a 1-D array of sorted integers, the entries indicate where along axis
the array is split. For example, [2, 3] would, for axis=0, result in

ary[:2]
ary[2:3]
ary[3:]

If an index exceeds the dimension of the array along axis, an empty sub-array is returned
correspondingly.

axis : int, optional


The axis along which to split, default is 0.

Returns:
sub-arrays : list of ndarrays
A list of sub-arrays.

Raises:
ValueError
If indices_or_sections is given as an integer, but a split does not result in equal division.

Example:
>>> x = np.arange(9.0)
>>> np.split(x, 3)

114
[array([0., 1., 2.]), array([3., 4., 5.]), array([6., 7., 8.])]

>>> x = np.arange(8.0)
>>> np.split(x, [3, 5, 6, 10])

[array([0., 1., 2.]),


array([3., 4.]),
array([5.]),
array([6., 7.]),
array([], dtype=float64)]

4.7 NumPy - Array Attributes

ndarray.shape
This array attribute returns a tuple consisting of array dimensions. It can also be used to
resize the array.

Example 1

import numpy as np
a = np.array([[1,2,3],[4,5,6]])
print a.shape
The output is as follows −

(2, 3)

Example 2

# this resizes the ndarray


import numpy as np

a = np.array([[1,2,3],[4,5,6]])
a.shape = (3,2)
print a
The output is as follows −

[[1, 2]
[3, 4]
[5, 6]]

Example 3

NumPy also provides a reshape function to resize an array.

import numpy as np
a = np.array([[1,2,3],[4,5,6]])
b = a.reshape(3,2)

115
print b
The output is as follows −

[[1, 2]
[3, 4]
[5, 6]]

ndarray.ndim
This array attribute returns the number of array dimensions.

Example 1

# an array of evenly spaced numbers


import numpy as np
a = np.arange(24)
print a
The output is as follows −

[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23]

Example 2

# this is one dimensional array


import numpy as np
a = np.arange(24)
a.ndim

# now reshape it
b = a.reshape(2,4,3)
print b
# b is having three dimensions
The output is as follows −

[[[ 0, 1, 2]
[ 3, 4, 5]
[ 6, 7, 8]
[ 9, 10, 11]]
[[12, 13, 14]
[15, 16, 17]
[18, 19, 20]
[21, 22, 23]]]

numpy.itemsize
This array attribute returns the length of each element of array in bytes.

Example 1

# dtype of array is int8 (1 byte)


import numpy as np
x = np.array([1,2,3,4,5], dtype = np.int8)

116
print x.itemsize
The output is as follows −

Example 2

# dtype of array is now float32 (4 bytes)


import numpy as np
x = np.array([1,2,3,4,5], dtype = np.float32)
print x.itemsize
The output is as follows −

4
numpy.flags
The ndarray object has the following attributes. Its current values are returned by this
function.

This array is a copy of some other array. When this array is deallocated, the base array will be
updated with the contents of this array

Example
The following example shows the current values of flags.

117
import numpy as np
x = np.array([1,2,3,4,5])
print x.flags

The output is as follows −

C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False

4.8 Converting 1-d and 2-d Arrays

We can use numpy ndarray tolist() function to convert the array to a list. If the array is multi-
dimensional, a nested list is returned. For one-dimensional array, a list with the array
elements is returned. The tolist() function doesn’t accept any argument. It’s a simple way to
convert an array to a list representation.

1. Converting 1-dimensional NumPy Array to List

from array import *


array_num = array('i', [1, 3, 5, 3, 7, 1, 9, 3])
print("Original array: "+str(array_num))
num_list = array_num.tolist()
print("Convert the said array to an ordinary list with the same items:")
print(num_list)

Output:

Original array: array('i', [1, 3, 5, 3, 7, 1, 9, 3])


Convert the said array to an ordinary list with the same items:
[1, 3, 5, 3, 7, 1, 9, 3]

2. Converting multi-dimensional NumPy Array to List

import numpy as np

# 2d array to list
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(f'NumPy Array:\n{arr}')
list1 = arr.tolist()
print(f'List: {list1}')

Output:
NumPy Array:
[[1 2 3]

118
[4 5 6]]

List: [[1, 2, 3], [4, 5, 6]]

4.9 Creating Array views and copies

While executing the functions, some of them return a copy of the input array, while some
return the view. When the contents are physically stored in another location, it is called Copy.
If on the other hand, a different view of the same memory content is provided, we call it as
View.

No Copy
Simple assignments do not make the copy of array object. Instead, it uses the same id() of the
original array to access it. The id() returns a universal identifier of Python object, similar to
the pointer in C.

Furthermore, any changes in either gets reflected in the other. For example, the changing
shape of one will change the shape of the other too.

Example

import numpy as np
a = np.arange(6)

print 'Our array is:'


print a

print 'Applying id() function:'


print id(a)

print 'a is assigned to b:'


b=a
print b

print 'b has same id():'


print id(b)

print 'Change shape of b:'


b.shape = 3,2
print b

print 'Shape of a also gets changed:'


print a
It will produce the following output −

Our array is:


[0 1 2 3 4 5]

Applying id() function:

119
139747815479536

a is assigned to b:
[0 1 2 3 4 5]
b has same id():
139747815479536

Change shape of b:
[[0 1]
[2 3]
[4 5]]

Shape of a also gets changed:


[[0 1]
[2 3]
[4 5]]

View or Shallow Copy


NumPy has ndarray.view() method which is a new array object that looks at the same data of
the original array. Unlike the earlier case, change in dimensions of the new array doesn’t
change dimensions of the original.

Example

import numpy as np
# To begin with, a is 3X2 array
a = np.arange(6).reshape(3,2)

print 'Array a:'


print a

print 'Create view of a:'


b = a.view()
print b

print 'id() for both the arrays are different:'


print 'id() of a:'
print id(a)
print 'id() of b:'
print id(b)

# Change the shape of b. It does not change the shape of a


b.shape = 2,3

print 'Shape of b:'


print b

print 'Shape of a:'


print a
It will produce the following output −

120
Array a:
[[0 1]
[2 3]
[4 5]]

Create view of a:
[[0 1]
[2 3]
[4 5]]

id() for both the arrays are different:


id() of a:
140424307227264
id() of b:
140424151696288

Shape of b:
[[0 1 2]
[3 4 5]]

Shape of a:
[[0 1]
[2 3]
[4 5]]

Slice of an array creates a view.

Example

import numpy as np
a = np.array([[10,10], [2,3], [4,5]])

print 'Our array is:'


print a

print 'Create a slice:'


s = a[:, :2]
print s
It will produce the following output −

Our array is:


[[10 10]
[ 2 3]
[ 4 5]]

Create a slice:
[[10 10]
[ 2 3]
[ 4 5]]

121
Deep Copy
The ndarray.copy() function creates a deep copy. It is a complete copy of the array and its
data, and doesn’t share with the original array.

Example

import numpy as np
a = np.array([[10,10], [2,3], [4,5]])

print 'Array a is:'


print a

print 'Create a deep copy of a:'


b = a.copy()
print 'Array b is:'
print b

#b does not share any memory of a


print 'Can we write b is a'
print b is a

print 'Change the contents of b:'


b[0,0] = 100

print 'Modified array b:'


print b

print 'a remains unchanged:'


print a
It will produce the following output −

Array a is:
[[10 10]
[ 2 3]
[ 4 5]]

Create a deep copy of a:


Array b is:
[[10 10]
[ 2 3]
[ 4 5]]

Can we write b is a
False

Change the contents of b:


Modified array b:
[[100 10]
[ 2 3]

122
[ 4 5]]

a remains unchanged:
[[10 10]
[ 2 3]
[ 4 5]]

4.10 Indexing Numpy arrays with Booleans

import numpy as np

A = np.array([4, 7, 3, 4, 2, 8])

print(A == 4)

[ True False False True False False]


Every element of the Array A is tested, if it is equal to 4. The results of these tests are the
Boolean elements of the result array.

Of course, it is also possible to check on "<", "<=", ">" and ">=".

print(A < 5)
[ True False True True True False]

It works also for higher dimensions:

B = np.array([[42,56,89,65],
[99,88,42,12],
[55,42,17,18]])

print(B>=42)
[[ True True True True]
[ True True True False]
[ True True False False]]

It is a convenient way to threshold images.

import numpy as np

A = np.array([
[12, 13, 14, 12, 16, 14, 11, 10, 9],
[11, 14, 12, 15, 15, 16, 10, 12, 11],
[10, 12, 12, 15, 14, 16, 10, 12, 12],
[ 9, 11, 16, 15, 14, 16, 15, 12, 10],
[12, 11, 16, 14, 10, 12, 16, 12, 13],
[10, 15, 16, 14, 14, 14, 16, 15, 12],
[13, 17, 14, 10, 14, 11, 14, 15, 10],
[10, 16, 12, 14, 11, 12, 14, 18, 11],

123
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 17, 19, 16, 17, 18, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 12, 14, 11, 12, 14, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11]])

B = A < 15
B.astype(np.int)
Output::
array([[1, 1, 1, 1, 0, 1, 1, 1, 1],
[1, 1, 1, 0, 0, 0, 1, 1, 1],
[1, 1, 1, 0, 1, 0, 1, 1, 1],
[1, 1, 0, 0, 1, 0, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 0, 1, 1],
[1, 0, 0, 1, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 0, 1]])

4.11 Broadcasting numPy arrays

The term broadcasting refers to how numpy treats arrays with different Dimension during
arithmetic operations which lead to certain constraints, the smaller array is broadcast across
the larger array so that they have compatible shapes.
Broadcasting provides a means of vectorizing array operations so that looping occurs in C
instead of Python as we know that Numpy implemented in C. It does this without making
needless copies of data and which leads to efficient algorithm implementations. There are
cases where broadcasting is a bad idea because it leads to inefficient use of memory that slow
down the computation.

Example –

import numpy as np

A = np.array([5, 7, 3, 1])
B = np.array([90, 50, 0, 30])

# array are compatible because of same Dimension


c=a*b
print (c)

124
Example to get deeper understanding –

Let’s assume that we have a large data set, each datum is a list of parameters. In Numpy we
have a 2-D array, where each row is a datum and the number of rows is the size of the data
set. Suppose we want to apply some sort of scaling to all these data every parameter gets its
own scaling factor or say Every parameter is multiplied by some factor.

Just to have some clear understanding, let’s count calories in foods using a macro-nutrient
breakdown. Roughly put, the caloric parts of food are made of fats (9 calories per gram),
protein (4 cpg) and carbs (4 cpg). So if we list some foods (our data), and for each food list its
macro-nutrient breakdown (parameters), we can then multiply each nutrient by its caloric
value (apply scaling) to compute the caloric breakdown of every food item.

With this transformation, we can now compute all kinds of useful information. For example,
what is the total number of calories present in some food or, given a breakdown of my dinner
know how much calories did I get from protein and so on.

Let’s see a naive way of producing this computation with Numpy:

macros = array([
[0.8, 2.9, 3.9],
[52.4, 23.6, 36.5],
[55.2, 31.7, 23.9],
[14.4, 11, 4.9]
])

# Create a new array filled with zeros, of the same shape as macros.
result = zeros_like(macros)

cal_per_macro = array([3, 3, 8])

# Now multiply each row of macros by cal_per_macro. In Numpy, `*` is


# element-wise multiplication between two arrays.
for i in range(macros.shape[0]):
result[i, :] = macros[i, :] * cal_per_macro

result
output:

array([[ 2.4, 8.7, 31.2 ],


[ 157.2, 70.8, 292 ],
[ 165.6, 95.1, 191.2],
[ 43.2, 33, 39.2]])

Algorithm:
Inputs: Array A with m dimensions and array B with n dimensions

p = max(m, n)
if m < p:

125
left-pad A's shape with 1s until it also has p dimensions

else if n < p:
left-pad B's shape with 1s until it also has p dimensions
result_dims = new list with p elements

for i in p-1 ... 0:


A_dim_i = A.shape[i]
B_dim_i = B.shape[i]
if A_dim_i != 1 and B_dim_i != 1 and A_dim_i != B_dim_i:
raise ValueError("could not broadcast")
else:
# Pick the Array which is having maximum Dimension
result_dims[i] = max(A_dim_i, B_dim_i)

Broadcasting Rules:

Broadcasting two arrays together follow these rules:

 If the arrays don't have the same rank then prepend the shape of the lower rank array
with 1s until both shapes have the same length.
 The two arrays are compatible in a dimension if they have the same size in the
dimension or if one of the arrays has size 1 in that dimension.
 The arrays can be broadcast together iff they are compatible with all dimensions.
 After broadcasting, each array behaves as if it had shape equal to the element-wise
maximum of shapes of the two input arrays.
 In any dimension where one array had size 1 and the other array had size greater than
1, the first array behaves as if it were copied along that dimension.

Example #1: Single Dimension array

import numpy as np
a = np.array([17, 11, 19]) # 1x3 Dimension array
print(a)
b=3
print(b)

# Broadcasting happened beacuse of


# miss match in array Dimension.
c=a+b
print(c)
Output:

[17 11 19]
3
[20 14 22]

Example 2: Two Dimensional Array

import numpy as np

126
A = np.array([[11, 22, 33], [10, 20, 30]])
print(A)

b=4
print(b)

C=A+b
print(C)
Output:

[[11 22 33]
[10 20 30]]
4
[[15 26 37]
[14 24 34]]

127
Module-5

DATA MANIPULATION AND VISUALIZATION IN PYTHON

5.1 Data Frames in Panda

Pandas DataFrame is two-dimensional size-mutable, potentially heterogeneous tabular data


structure with labeled axes (rows and columns). A Data frame is a two-dimensional data
structure, i.e., data is aligned in a tabular fashion in rows and columns. Pandas DataFrame
consists of three principal components, the data, rows, and columns.

5.2 Creating Data frames from .csv and excel files


In the real world, a Pandas DataFrame will be created by loading the datasets from existing
storage, storage can be SQL Database, CSV file, and Excel file. Pandas DataFrame can be
created from the lists, dictionary, and from a list of dictionary etc. Dataframe can be created
in different ways here are some ways by which we create a dataframe:

Pandas provide a unique method to retrieve rows from a Data frame. DataFrame.loc[] method
is used to retrieve rows from Pandas DataFrame. Rows can also be selected by passing
integer location to an iloc[] function.

128
Note: We’ll be using nba.csv file in below examples.

# importing pandas package


import pandas as pd
# making data frame from csv file
data = pd.read_csv("nba.csv", index_col ="Name")

# retrieving row by loc method


first = data.loc["Avery Bradley"]
second = data.loc["R.J. Hunter"]

print(first, "\n\n\n", second)

Output:
As shown in the output image, two series were returned since there was only one parameter
both of the times.

5.3 Creating DataFrame from dict of ndarray/lists

To create DataFrame from dict of narray/list, all the narray must be of same length. If index
is passed then the length index should be equal to the length of arrays. If no index is passed,
then by default, index will be range(n) where n is the array length.

# Python code demonstrate creating


# DataFrame from dict narray / lists
# By default addresses.

import pandas as pd

129
# intialise data of lists.
data = {'Name':['Tom', 'nick', 'krish', 'jack'],
'Age':[20, 21, 19, 18]}

# Create DataFrame
df = pd.DataFrame(data)

# Print the output.


print(df)

5.4 Dataframes Aggregation and concatenation

Python is a great language for doing data analysis, primarily because of the fantastic
ecosystem of data-centric Python packages. Pandas is one of those packages and makes
importing and analyzing data much easier.
Dataframe.aggregate() function is used to apply some aggregation across one or more
column. Aggregate using callable, string, dict, or list of string/callables. Most frequently used
aggregations are:
sum: Return the sum of the values for the requested axis
min: Return the minimum of the values for the requested axis
max: Return the maximum of the values for the requested axis

Syntax: DataFrame.aggregate(func, axis=0, *args, **kwargs)

Parameters:
func : callable, string, dictionary, or list of string/callables. Function to use for aggregating
the data. If a function, must either work when passed a DataFrame or when passed to
DataFrame.apply. For a DataFrame, can pass a dict, if the keys are DataFrame column
names.
axis : (default 0) {0 or ‘index’, 1 or ‘columns’} 0 or ‘index’: apply function to each column. 1
or ‘columns’: apply function to each row.

Returns: Aggregated DataFrame

For link to CSV file Used in Code, click here

130
Example #1: Aggregate ‘sum’ and ‘min’ function across all the columns in data frame.

# importing pandas package


import pandas as pd

# making data frame from csv file


df = pd.read_csv("nba.csv")

# printing the first 10 rows of the dataframe


df[:10]

Aggregation works with only numeric type columns.


# Applying aggregation across all the columns sum and min will be found for each numeric type
column in df dataframe .

df.aggregate(['sum', 'min'])

Output:
For each column which are having numeric values, minimum and sum of all values has been
found. For dataframe df , we have four such columns Number, Age, Weight, Salary.

Concatenate DataFrames using Panda

A dataframe is a two-dimensional data structure having multiple rows and columns. In a


dataframe, the data is aligned in the form of rows and columns only. A dataframe can
perform arithmetic as well as conditional operations. It has mutable size.

Below is the implementation using Numpy and Pandas.


131
Modules needed:

import numpy as np
import pandas as pd

Code #1 : DataFrames Concatenation

concat() function does all of the heavy lifting of performing concatenation operations along
an axis while performing optional set logic (union or intersection) of the indexes (if any) on
the other axes.
# Python program to concatenate dataframes using Panda

# Creating first dataframe


df1 = pd.DataFrame({'A': ['A0', 'A1', 'A2', 'A3'],
'B': ['B0', 'B1', 'B2', 'B3'],
'C': ['C0', 'C1', 'C2', 'C3'],
'D': ['D0', 'D1', 'D2', 'D3']},
index = [0, 1, 2, 3])
# Creating second dataframe
df2 = pd.DataFrame({'A': ['A4', 'A5', 'A6', 'A7'],
'B': ['B4', 'B5', 'B6', 'B7'],
'C': ['C4', 'C5', 'C6', 'C7'],
'D': ['D4', 'D5', 'D6', 'D7']},
index = [4, 5, 6, 7])
# Creating third dataframe
df3 = pd.DataFrame({'A': ['A8', 'A9', 'A10', 'A11'],
'B': ['B8', 'B9', 'B10', 'B11'],
'C': ['C8', 'C9', 'C10', 'C11'],
'D': ['D8', 'D9', 'D10', 'D11']},
index = [8, 9, 10, 11])

# Concatenating the dataframes


pd.concat([df1, df2, df3])
Output:

132
5.5 Plotting using matplotlib & panda

Getting started ( Plotting a line)

# importing the required module


import matplotlib.pyplot as plt

# x axis values
x = [1,2,3]
# corresponding y axis values
y = [2,4,1]

# plotting the points


plt.plot(x, y)

# naming the x axis


plt.xlabel('x - axis')
# naming the y axis
plt.ylabel('y - axis')

# giving a title to my graph


plt.title('My first graph!')

# function to show the plot


plt.show()
Output:

133
the code seems self explanatory. Following steps were followed:
 Define the x-axis and corresponding y-axis values as lists.
 Plot them on canvas using .plot() function.
 Give a name to x-axis and y-axis using .xlabel() and .ylabel() functions.
 Give a title to your plot using .title() function.
 Finally, to view your plot, we use .show() function.

Plotting two or more lines on same plot

import matplotlib.pyplot as plt

# line 1 points
x1 = [1,2,3]
y1 = [2,4,1]
# plotting the line 1 points
plt.plot(x1, y1, label = "line 1")

# line 2 points
x2 = [1,2,3]
y2 = [4,1,3]
# plotting the line 2 points
plt.plot(x2, y2, label = "line 2")

# naming the x axis


plt.xlabel('x - axis')
# naming the y axis
plt.ylabel('y - axis')
# giving a title to my graph
plt.title('Two lines on same graph!')

# show a legend on the plot

134
plt.legend()

# function to show the plot


plt.show()

Output:

Plot of different data: Using more than one list of data in a plot.

# importing libraries
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

ts = pd.Series(np.random.randn(1000), index = pd.date_range(


'1/1/2000', periods = 1000))

df = pd.DataFrame(np.random.randn(1000, 4),
index = ts.index, columns = list('ABCD'))

df = df.cumsum()
plt.figure()
df.plot()
plt.show()
Output:

135
136

You might also like