Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
86% found this document useful (7 votes)
8K views

Python-Programming-Modular-Approach (Sheetal Taneja and Naveen Kumar)

This document provides an overview of Pearson, which is an international education company. It discusses Pearson's presence in 70 countries and expertise in working with educators. The document encourages feedback to help Pearson continue improving its education products and services.

Uploaded by

simran singh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
86% found this document useful (7 votes)
8K views

Python-Programming-Modular-Approach (Sheetal Taneja and Naveen Kumar)

This document provides an overview of Pearson, which is an international education company. It discusses Pearson's presence in 70 countries and expertise in working with educators. The document encourages feedback to help Pearson continue improving its education products and services.

Uploaded by

simran singh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1035

About Pearson

Pearson is the world’s learning company, with presence


across 70 countries worldwide. Our unique insights and
world-class expertise comes from a long history of
working closely with renowned teachers, authors and
thought leaders, as a result of which, we have emerged
as the preferred choice for millions of teachers and
learners across the world.

We believe learning opens up opportunities, creates


fulfilling careers and hence better lives. We hence
collaborate with the best of minds to deliver you
classleading products, spread across the Higher
Education and K12 spectrum.

Superior learning experience and improved outcomes


are at the heart of everything we do. This product is the
result of one such effort.

Your feedback plays a critical role in the evolution of


our products and you can contact us -
reachus@pearson.com. We look forward to it.
PYTHON PROGRAMMING: A MODULAR
APPROACH

A Modular Approach With Graphics, Database, Mobile,


and Web Applications

Sh eet a l T a n eja
Department of Computer Science
Dyal Singh College
Univers ity of Delhi
Delhi, India
and

Na v een Ku m a r
Department of Computer Science
Univers ity of Delhi
Delhi, India
Contents

Forew ord

Preface

About the Authors

1 . Py th on Pr og r a m m in g : A n In tr odu ction

1 .1 IDLE – A n In ter pr eter for Py th on

1 .2 Py th on Str in g s

1 .3 Rela tion a l Oper a tor s

1 .4 Log ica l Oper a tor s

1 .5 Bitw ise Oper a tor s

1 .6 V a r ia bles a n d A ssig n m en t Sta tem en ts

As s ignment Statement

Shorthand Notation

1 .7 Key w or ds

1 .8 Scr ipt Mode

Summary

Exercis es

2 . Fu n ction s

2 .1 Bu ilt-in Fu n ction s

input Function

eval Function

Composition

print Function

type Function

round Function

Type Convers ion

min and max Fu n ction s

pow Function

Random Number Generation

Functions from math Module


Complete Lis t of Built-in Functions

2 .2 Fu n ction Defin ition a n d Ca ll

Fruitful Functions vs Void Functions

Function help

Default Parameter Values

Keyw ord Arguments

2 .3 Im por tin g User -defin ed Modu le

2 .4 A sser t Sta tem en t

2 .5 Com m a n d Lin e A r g u m en ts

Summary

Exercis es

3 . Con tr ol Str u ctu r es

3 .1 if Con dition a l Sta tem en t

General Form of if Conditional Statement

Conditional Expres s ion

General Form of if-else Conditional Statement

General Form of if-elif-else Conditional Statement

Nes ted if-elif-else Conditional Statement

3 .2 Iter a tion (for a n d while Sta tem en ts)

3 .2 .1 for Loop

General Format of for Statement

3 .2 .2 while Loop

General Format of while Statement

Infinite Loops

3 .2 .3 while Sta tem en t v s. for Sta tem en t

3 .2 .4 Ex a m ple: To Pr in t Som e Pictu r es

3 .2 .5 Nested Loops

3 .2 .6 break, continue, a n d pass Sta tem en ts

3 .2 .7 Ex a m ple: To Com pu te sin (x )

3 .2 .8 else Sta tem en t

Summary

Exercis es

4 . Debu g g in g

4 .1 Testin g
An Example: Finding Maximum of Three Numbers

4 .2 Debu g g in g

Summary

Exercis es

5 . Scope

5 .1 Objects a n d Object ids

5 .2 Scope of Objects a n d Na m es

5 .2 .1 Na m espa ces

5 .2 .2 Scope

LEGB Rule

Summary

Exercis es

6 . Str in g s

6 .1 Str in g s

6 .1 .1 Slicin g

6 .1 .2 Mem ber sh ip

6 .1 .3 Bu ilt-in Fu n ction s on Str in g s

Function count

Functions find and rfind

Functions capitalize, title, lower, upper, and


swapcase

Functions islower, isupper, and istitle

Function replace

Functions strip, lstrip, and rstrip

Functions split and partition

Function join

Functions isspace, isalpha, isdigit, and isalnum

Function startswith and endswith

Functions encode and decode

Lis t of Functions

6 .2 Str in g Pr ocessin g Ex a m ples

6 .2 .1 Cou n tin g th e Nu m ber of Ma tch in g Ch a r a cter s in a


Pa ir of Str in g s

6 .2 .2 Cou n tin g th e Nu m ber of Com m on Ch a r a cter s in a


Pa ir of Str in g s

6 .2 .3 Rev er sin g a Str in g


6 .3 Pa tter n Ma tch in g

6 .3 .1 Som e Im por ta n t Defin ition s

Summary

Exercis es

7 . Mu ta ble a n d Im m u ta ble Objects

7 .1 Lists

7 .1 .1 Su m m a r y of List Oper a tion s

7 .1 .2 Fu n ction list

7 .1 .3 Fu n ction s append, extend, count, remove, index,


pop, a n d insert

7 .1 .4 Fu n ction insert

7 .1 .5 Fu n ction reverse

7 .1 .6 Fu n ction s sort a n d reverse

7 .1 .7 List Fu n ction s

7 .1 .8 List Com pr eh en sion

7 .1 .9 Lists a s A r g u m en ts

7 .1 .1 0 Copy in g List Objects

7 .1 .1 1 map, reduce, a n d filter Oper a tion s on a Sequ en ce

7 .2 Sets

7 .2 .1 Set Fu n ction s add, update, remove, pop, a n d clear

7 .2 .2 Set Fu n ction s union, intersection, difference,


a n d symmetric_difference

7 .2 .3 Fu n ction copy

7 .2 .4 Su bset a n d Su per set Test

7 .2 .5 List of Fu n ction s

7 .2 .6 Fin din g Com m on Fa ctor s

7 .2 .7 Un ion a n d In ter section Oper a tion on Lists

7 .3 Tu ples

7 .3 .1 Su m m a r y of Tu ple Oper a tion s

7 .3 .2 Fu n ction s tuple a n d zip

7 .3 .3 Fu n ction s count a n d index

7 .4 Diction a r y

7 .4 .1 Diction a r y Oper a tion s

7 .4 .2 Deletion

7 .4 .3 Fu n ction get
7 .4 .4 Fu n ction update

7 .4 .5 Fu n ction copy

7 .4 .6 List of Fu n ction s

7 .4 .7 In v er ted Diction a r y

Summary

Exercis es

8 . Recu r sion

8 .1 Recu r siv e Solu tion s for Pr oblem s on Nu m er ic Da ta

8 .1 .1 Fa ctor ia l

Iterative Approach

Recurs ive Approach

8 .1 .2 Fibon a cci Sequ en ce

Iterative Approach

Recurs ive Approach

8 .2 Recu r siv e Solu tion s for Pr oblem s on Str in g s

8 .2 .1 Len g th of a Str in g

8 .2 .2 Rev er sin g a Str in g

8 .2 .3 Pa lin dr om e

8 .3 Recu r siv e Solu tion s for Pr oblem s on Lists

8 .3 .1 Fla tten a List

8 .3 .2 Copy

8 .3 .3 Deep Copy

8 .3 .4 Per m u ta tion

8 .4 Pr oblem of Tow er of Ha n oi

Summary

Exercis es

9 . Files a n d Ex ception s

9 .1 File Ha n dlin g

9 .2 Wr itin g Str u ctu r es to a File

9 .3 Er r or s a n d Ex ception s

9 .4 Ha n dlin g Ex ception s Usin g try…except

9 .5 File Pr ocessin g Ex a m ple

Summary

Exercis es
1 0. Cla sses I

1 0.1 Cla sses a n d Objects

1 0.2 Per son : A n Ex a m ple of Cla ss

1 0.2 .1 Destr u ctor

1 0.3 Cla ss a s A bstr a ct Da ta Ty pe

1 0.4 Da te Cla ss

Summary

Exercis es

1 1 . Cla sses II

1 1 .1 Poly m or ph ism

1 1 .1 .1 Oper a tor Ov er loa din g

Comparing Dates

1 1 .1 .2 Fu n ction Ov er loa din g

1 1 .2 En ca psu la tion , Da ta Hidin g , a n d Da ta A bstr a ction

1 1 .3 Modifier a n d A ccessor Meth ods

1 1 .4 Sta tic Meth od

1 1 .5 A ddin g Meth ods Dy n a m ica lly

1 1 .6 Com position

1 1 .7 In h er ita n ce

1 1 .7 .1 Sin g le In h er ita n ce

Scope Rule

Extending Scope of int Clas s Us ing a Us er Defined Clas s

1 1 .7 .2 Hier a r ch ica l In h er ita n ce

1 1 .7 .3 Mu ltiple In h er ita n ce

1 1 .7 .4 A bstr a ct Meth ods

1 1 .7 .5 A ttr ibu te Resolu tion Or der for In h er ita n ce

1 1 .8 Bu ilt-in Fu n ction s for Cla sses

Summary

Exercis es

1 2 . List Ma n ipu la tion

1 2 .1 Sor tin g

1 2 .1 .1 Selection Sor t

1 2 .1 .2 Bu bble Sor t

1 2 .1 .3 In ser tion Sor t


1 2 .2 Sea r ch in g

1 2 .2 .1 Lin ea r Sea r ch

1 2 .2 .2 Bin a r y Sea r ch

1 2 .3 A Ca se Stu dy

1 2 .3 .1 Oper a tion s for Cla ss Section

Complete Script

1 2 .4 Mor e on Sor tin g

1 2 .4 .1 Mer g e Sor t

1 2 .4 .2 Qu ick Sor t

Summary

Exercis es

1 3 . Da ta Str u ctu r es I: Sta ck a n d Qu eu es

1 3 .1 Sta cks

1 3 .1 .1 Ev a lu a tin g A r ith m etic Ex pr ession s

1 3 .1 .2 Con v er sion of In fix Ex pr ession to Postfix Ex pr ession

1 3 .2 Qu eu es

Summary

Exercis es

1 4 . Da ta Str u ctu r es II: Lin ked Lists

1 4 .1 In tr odu ction

1 4 .2 In ser tion a n d Deletion a t th e Beg in n in g of a Lin ked List

1 4 .3 Deletin g a Node w ith a Pa r ticu la r V a lu e fr om a Lin ked


List

1 4 .4 Tr a v er sin g a Lin ked List

1 4 .5 Ma in ta in in g Sor ted Lin ked List Wh ile In ser tin g

1 4 .6 Sta ck Im plem en ta tion Usin g Lin ked List

1 4 .7 Qu eu e Im plem en ta tion Usin g Lin ked List

Summary

Exercis es

1 5 . Da ta Str u ctu r es III: Bin a r y Sea r ch Tr ees

1 5 .1 Defin ition s a n d Nota tion s

1 5 .2 Bin a r y Sea r ch Tr ee

1 5 .3 Tr a v er sa l of Bin a r y Sea r ch Tr ees

1 5 .3 .1 In or der Tr a v er sa l

1 5 .3 .2 Pr eor der Tr a v er sa l
1 5 .3 .3 Postor der Tr a v er sa l

1 5 .3 .4 Heig h t of a Bin a r y Tr ee

1 5 .4 Bu ildin g Bin a r y Sea r ch Tr ee

Summary

Exercis es

1 6 . Mor e on Recu r sion

1 6 .1 Pa tter n w ith in a Pa tter n

1 6 .2 Gen er a lized Eig h t Qu een s Pr oblem

1 6 .3 Kn ig h t's Tou r Pr oblem

1 6 .4 Sta ble Ma r r ia g e Pr oblem

1 6 .5 Fr a cta l (Hilber t Cu r v e a n d Sier pin ski Tr ia n g le)

1 6 .6 Su doku

1 6 .7 Gu idelin es on Usin g Recu r sion

Summary

Exercis es

1 7 . Gr a ph ics

1 7 .1 2 D Gr a ph ics

1 7 .1 .1 Poin t a n d Lin e

Axis , Title, and Label

Plotting Multiple Functions in the Same Figure

Multiple Plots

Saving Figure

1 7 .1 .2 Histog r a m a n d Pi Ch a r t

1 7 .1 .3 Sin e a n d Cosin e Cu r v es

1 7 .1 .4 Gr a ph ica l Objects: Cir cle, Ellipse, Recta n g le,


Poly g on ,
a n d A r r ow

Circle

Ellips e

Rectangle

Polygon

Arrow

1 7 .2 3 D Objects

Box

Sphere
Ring

Cylinder

Arrow

Cone

Curve

1 7 .3 A n im a tion – Bou n cin g Ba ll

Summary

Exercis es

1 8 . A pplica tion s of Py th on

1 8 .1 Collectin g In for m a tion fr om Tw itter

Open Authentication

An Example – Collecting Us er Information

Collecting Follow ers , Friends , and Tw eets of a Us er

Collecting Tw eets Having Specific Words

1 8 .2 Sh a r in g Da ta Usin g Sockets

Client-Server Communication on the Same Machine – A


Simple Example

An Echo Server

Acces s ing Web Data (Dow nloading a Pdf File)

1 8 .3 Ma n a g in g Da ta ba ses Usin g Str u ctu r ed Qu er y


La n g u a g e (SQL)

1 8 .3 .1 Da ta ba se Con cepts

1 8 .3 .2 Cr ea tin g Da ta ba se a n d Ta bles

1 8 .3 .3 In ser tin g Da ta in to Ta ble

1 8 .3 .4 Retr iev in g Da ta fr om Ta ble

1 8 .3 .5 Upda tin g Da ta in a Ta ble

1 8 .3 .6 Deletin g Da ta fr om Ta ble/Deletin g Ta ble

1 8 .4 Dev elopin g Mobile A pplica tion for A n dr oid

1 8 .4 .1 A Sim ple A pplica tion Con ta in in g Reg istr a tion


In ter fa ce

1 8 .4 .2 Tic-Ta c-Toe Ga m e

1 8 .4 .3 Ru n n in g Kivy A pplica tion s on A n dr oid

1 8 .5 In teg r a tin g Ja v a w ith Py th on

1 8 .5 .1 A ccessin g Ja v a Collection s a n d A r r a y s in Py th on

1 8 .5 .2 Con v er tin g Python Collection s to Java Collection s


1 8 .5 .3 In v okin g a Pa r a m eter ized Ja v a Meth od fr om
Py th on

1 8 .5 .4 In v okin g Pa r a m eter ized Py th on Meth od fr om Ja v a

1 8 .6 Py th on Ch a t A pplica tion Usin g Kiv y a n d Socket


Pr og r a m m in g

Summary

Exercis es

Index

Colour Illus trations


Foreword

Since the early days of teaching programming


languages, the science of programming has changed
substantially. Since the times of COBOL, FORTRAN,
ALGOL, C, and ADA, Python reflects a major paradigm
shift. The classical book ‘The Art of Computer
Programming’ by D. E. Knuth changed the landscape by
making programming independent of any language. As
programmers found it hard to design structured code in
languages like FORTRAN and COBOL, subsequent
languages like C, C++, and Java provided a natural
framework for structured programming. While C++
introduced object-oriented programming as an add on
feature, Java was designed to be an object-oriented
platform independent language with extensive support
for web development. Although implemented efficiently,
Java lacks the conciseness and flexibility that the
amateur and professional programmers cherish so
much. This is where Python steps in as a language of
choice.
This book ‘Python Programming: A Modular
Approach’ is ideally suited for the undergraduate
students who do not have any prior exposure to
programming. The experience has shown that when the
students are taught the good programming practices
later in the course, they tend to ignore them in the
programs/software they develop subsequently. For
example, it is my considered opinion that the use of
functions should be introduced as early as possible in a
programming course, and this is where this book scores
over typical programming texts. Also, the book stresses
the use of named constants and documentation right
from the beginning.
The book contains several examples that illustrate the
use of syntactic features of Python in the context of the
problem at hand. It uses Python Tutor to present the
concept of recursion and data structures in a simplified
manner. The chapter on applications is particularly
inviting as it includes examples from databases,
networking, web, and mobile technologies.

Pr of. S K Gu pt a
Department of Computer Science and Engineering
Indian Ins titute of Technology Delhi
New Delhi, India
Preface

This book introduces programming concepts through


Python language. The simple syntax of Python makes it
an ideal choice for learning programming. Because of
the availability of extensive standard libraries and third-
party support, it is rapidly evolving as the preferred
programming language amongst the application
developers.
As old habits die hard, the book encourages the reader
to follow good programming practices right from the
beginning. We have tried to introduce the programming
constructs in the context of the examples that justify the
use of those constructs. We have devoted the first twelve
chapters of the book to introduce the fundamental
programming concepts. These chapters would serve as a
foundation for the advanced concepts covered later in
the book. The first three chapters cover the basic building
blocks of the Python language. We introduce the
concepts of modularity early in the book (Chapter 2) so
that it gets integrated with the student’s approach to
problem-solving. In the same spirit, we emphasize the
use of the named objects in preference to the ones hard-
coded. Further, as sound documentation is a key to the
success of any software engineering project, we
consistently document the code throughout the book,
describing the objective of each piece of the code and
how it interfaces with rest of the system under
discussion.
As the real-life problems usually require non-
sequential and repetitive execution of instructions, the
discussion on modularity in Chapter 2 has been followed
by a detailed study of control structures in Chapter 3. As
debugging is an essential skill for discovering the bugs
and making the program error-free, we have devoted a
full chapter (Chapter 4) to it. The parameter passing
mechanisms and the scope of names are fundamental
concepts in the study of a programming language, and
in Chapter 5, we discuss these concepts in detail.
Chapters 6 and 7 cover the mutable and immutable
objects for storing data in a program. Often, we need to
save the data permanently in the form of files and
retrieve it for use at a later point in time. As many errors
creep in during the input/output process, in Chapter 9,
we discuss the concepts of file processing and error
handling side by side.
In Chapter 10, we introduce classes that lie at the
heart of an important programming methodology called
object-oriented programming (OOP). In Chapter 11, we
continue the discussion on classes in the context of OOP
concepts like polymorphism, encapsulation, data hiding,
data abstraction, and inheritance.
In Chapter 12, we cover basic sorting and searching
techniques, namely, insertion sort, selection sort, bubble
sort, merge sort, quick sort, and linear and binary
search. Recursion being a valuable tool for problem-
solving, we devote two chapters (Chapters 8 and 16) to
it. Beginning with the recursive functions for computing
the factorial of a number and the terms in a Fibonacci
sequence, we move on to more sophisticated problems
like the tower of Hanoi, permutation generation, list
manipulation, 8-queens problem, stable marriage
problem, and plotting Hilbert curves that demonstrate
the power of recursion. We introduce the basic data
structures – stacks, queues, linked lists, and trees
(Chapters 13, 14, and 15), and show how these data
structures may be implemented efficiently using Python.
As several applications require visualization of
information, we devote a chapter to 2D and 3D graphics,
and animation (Chapter 17). We conclude the book with
a chapter (Chapter 18) that briefly covers the application
areas such as twitter, web, database management, and
mobile app development. As a lot of application code is
developed in Java, in this chapter we also discuss, how
Python code may be seamlessly integrated with Java
code and vice-versa. Recently, Philip J. Guo of the
University of California, San Diego has made a Python
Tutor available as an opensource tool for visualizing the
execution of Python scripts, and we make use of it to
illustrate various concepts throughout the book.

ACKNOWLEDGEMENTS

We are grateful to Hitarth, first-year undergraduate


student at Dyal Singh College of University of Delhi, for
going through the entire book with great care and
suggesting dozens of subtle corrections and
modifications. We are thankful to Arpit of Amazon Inc.
for his help in identifying the suitable level of abstraction
in several chapters of the book. We are also grateful to
Prof. S K Gupta, IIT Delhi, Mr. Suraj Prakash, Director
Training, Bal Bharati group of institutions, Dr Anamika
Gupta of SS College of Business Studies, Dr Sharanjeet
Kaur of Acharya Narendra Dev College, Mr. Ashok Jain
of Sugal Infotech, and our former students Abhishek,
Ajay, Kanika, Mitul and Sunil, for their comments on
various sections of the book.
We are grateful to the entire Pearson team, especially
Ms. Neha Goomer and Mr. M. Balakrishnan who were
readily available for any help during the preparation of
the book. Ms. Neha’s suggestion to include margin notes
in the book has significantly improved the readability of
the book. Last but not the least, we would like to express
our gratitude to our family members for their support
and patience.

Sh eet a l T a n eja
Na v een Ku m a r
About the Authors

Sheetal Taneja is currently working as an Assistant


Professor at Department of Computer Science, Dyal
Singh College, University of Delhi, Delhi, India. She
earned her B.Sc. (Honours) and M.Sc. degrees in
Computer Science from University of Delhi. Being the
topper in the M.Sc. programme, she was awarded a gold
medal by University of Delhi. Being passionate about
teaching, she qualified the National Eligibility Test
(NET) for university teachers while studying for the
M.Sc. degree, and joined a faculty position immediately
on completing her postgraduate studies. She is currently
pursuing her Ph.D. in Computer Science from University
of Delhi. She is a co-author of two books on information
technology, published by Central Board of Secondary
Education (CBSE). She has authored several research
articles, and has attended many national and
international workshops and conferences. She is a
member of the Association of Computing Machinery
(ACM), USA.

Naveen Kumar is a Professor at Department of


Computer Science, University of Delhi, Delhi, India. He
holds a Ph.D. degree in Computer Science from IIT,
Delhi. Prior to his doctoral studies, he earned his M.Tech.
(Computer Science) and M.Sc. (Mathematics) degrees
from IIT Delhi, and an honours degree in Mathematics
from University of Delhi. He has taught a varied array of
courses to undergraduate and postgraduate students and
has teaching experience of about 35 years. He has
supervised many Ph.D. students in areas such as soft
computing and social networks. His current areas of
interest include data analysis, evolutionary algorithms,
and parallel computing. He has contributed several
articles in national and international journals and
conferences. He has also attended many conferences,
seminars and workshops. He has been a member of the
curriculum design committees of various universities
and the CBSE. He has also been an organizing
chair/program committee member of several
workshops, conferences, and symposia. He is a member
of professional bodies like ACM, Institution of
Electronics and Telecommunication Engineers (IETE),
and Computer Society of India.
CHAPTER 1
PYTHON PROGRAMMING: AN
INTRODUCTION

CHAPTER OUTLINE
1 .1 IDLE – A n In ter pr eter for Py th on

1 .2 Py th on Str in g s

1 .3 Rela tion a l Oper a tor s

1 .4 Log ica l Oper a tor s

1 .5 Bitw ise Oper a tor s

1 .6 V a r ia bles a n d A ssig n m en t Sta tem en ts

1 .7 Key w or ds

1 .8 Scr ipt Mode

Python is an interactive programming language. Simple


syntax of the language makes Python programs easy to
read and write. Python was developed by Guido Van
Rossum in 1991 at the National Research Institute for
Mathematics and Computer Science in the Netherlands.
Guido Van Rossum named Python by getting inspired
from his favourite comedy show Monty Python’s Flying
Circus.

Ever since the language was developed, it is becoming


popular day by day amongst the programmers. Various
versions of Python have been released till date ranging
from version 1.0. This book uses Python 3.6. Python is
used in various application areas such as the web,
gaming, scientific and numeric computing, text
processing, and network programming.

1.1 IDLE – AN INTERPRETER FOR PYTHON

IDLE stands for Integrated Development and Learning


Environment. Python IDLE comprises Python shell and
Python Editor. While Python shell is an interactive
interpreter, Python Editor allows us to work in script
mode. While using Python shell, we just need to type
Python code at the >>> prompt and press the enter
key, and the shell will respond with the result of the
computation. For example, when we type

Py th on sh ell displa y s th e pr om pt >>> to in dica te th a t it is


w a itin g for a u ser com m a n d

>>> print('hello world')

th e tex t to be pr in ted is en closed betw een a postr oph e m a r ks

and press enter key, Python shell will display:

hello world

th e a postr oph e m a r ks a r e n ot displa y ed in th e ou tpu t

Python shell may also be used as a calculator, for


example, when we type 18 + 5 followed by enter,
Python shell outputs the value of the expression, i.e. 23,
as shown below:

>>> 18 + 5

23

oper a tor + a cts on th e oper a n ds 18 a n d 5

In the expression 18 + 5, + is called the operator. The


numbers, 18 and 5 on which the operator + is applied,
are called the operands. In general, an expression is a
valid combination of operators and operands. In Python,
all forms of data are called values or objects. For
example, 18, 5, and 23 are objects. The expression 18
+ 5 yields the value 23. Similarly, the expression 18 - 5
yields the value 13. The expression 18 * 5 yields 90, as
Python uses * as the symbol for the multiplication
operation. The expression 27 / 5 yields 5.4. Note that
the result of division 27 / 5 is real number. In Python,
result of division is always a real number. However, if
you wish to obtain an integer result (for example,
floor(5.4)), Python operator // (two slashes without any
intervening blank) can be used. For example, 27 // 5
yields 5. However, while using the operator //, if at
least, one of the two operands is a real number; the
result is a real number, for example, the expression 27.0
// 5 yields 5.0. Real numbers are called floating point
numbers in Computer Science terminology in view of
the floating point representation used to represent real
numbers. However, the number representation is not the
subject matter of this book. Python operator %
(percentage sign), known as modulus, yields the
remainder of the division, for example, 27 % 5 yields 2
because on dividing 27 by 5 we get 2 as the remainder.
In Fig. 1.1, we illustrate these examples in Python shell.

oper a tor s: +, -, *, /, //, %, a n d **


Fig. 1.1 Com pu ta tion of a r ith m etic ex pr ession s

Py th on sh ell w in dow

The exponentiation operator


b
(**) yields2raise to the
power operation, i.e. a . For example, 3 is expressed as
3 ** 2, and yields the value 9. Similarly, 2 ** -1
yields 0.5 as expected. The expressions in each of the
examples mentioned above involved only single
mathematical operator, but in practice, we would
require more complex expressions. Note that whereas
the expression 6 / 3 / 2 yields 1.0(= (6 / 3) /
2), the expression 2 ** 3 ** 2 yields 512 (= 2 **
(3 ** 2)). This is so because whereas the operator /
(as also +, -, *, //, %) is evaluated left to right, the
exponentiation operator is evaluated right to left. We say
that the operators, +, -, *, /, //, and %, are left
associative operators and the operator ** is right
associative. Python operator – (negation) yields negative
of the operand. For example, 10 * -5 multiplies 10
and -5 (negative of 5), yielding -50 as a result. Next,
we evaluate the foregoing expressions in Python shell:

left a ssocia tiv e oper a tor s: +, -, *, /, //, %


r ig h t a ssocia tiv e oper a tor : **

>>> 3 ** 2

>>> 6 / 3 / 2

1.0

>>> 2 ** 3 ** 2

512

>>> 10 * -5

-50

- oper a tor w or ks a s n eg a tion oper a tor

When we enter the expression 7 + 4 * 3, the system


responds with value 19 as a result. Note that in the
expression 7 + 4 * 3, Python evaluates the operator *
before + as if the input expression was 7 + (4 * 3)
because the operator * has higher precedence than +. In
Table 1.1, we list the operators in decreasing order of
their precedence. The expressions within parentheses are
evaluated first; for example, given the expression (7 +
3) * 10 / 5, the system would yield 20.0.
Parentheses are often used to improve the readability of
an expression.
T a bl e 1.1 Pr eceden ce of a r ith m etic oper a tor s

w h ile th e pa r en th eses h a v e th e h ig h est pr eceden ce, a ddition


a n d su btr a ction a r e a t th e low est lev el

An error occurs when the input expression is not


correctly formed. For example, the expression 7 + 3(4
+ 5) generates an error because the operator between 3
and ( is missing:

Py th on com pla in s w h en it en cou n ter s a w r on g ly for m ed


ex pr ession

>>> 7 + 3(4 + 5)

Traceback (most recent call last):

File "<pyshell#17>", line 1, in <module>

7 + 3(4 + 5)

TypeError: 'int' object is not callable

Similarly, the expression 7 / 0 yields a zero division


error since division by zero is a meaningless operation.

>>> 7 / 0

Traceback (most recent call last):

File "<pyshell#18>", line 1, in <module>


7 / 0

ZeroDivisionError: division by zero

div ision by zer o is a m ea n in g less oper a tion

1.2 PYTHON STRINGS

A string is a sequence of characters. To specify a string,


we may enclose a sequence of characters between single,
double, or triple quotes. Thus, 'Hello world', '
"Ajay " ', "what's ", '''today's "action"
plan?''' are the examples of strings. A string enclosed
in single quotes may include double quote marks and
vice versa. A string enclosed in triple quotes (also known
as docstring, i.e. documentation string) may include
both single and double quote marks and may extend
over several lines, for example:

>>> 'Hello World'

'Hello World'

>>> print('Hello World')

Hello World

>>> """Hello

What's

happening"""

"Hello\nWhat's\nhappening"

>>> print("""Hello

What's

happening""")

Hello
What's

happening

a Py th on str in g m a y be en closed w ith in sin g le, dou ble, or


tr iple qu otes

Note that enclosing quote marks are used only to specify


a string, and they do not form part of the string. When
we print a string using the print instruction, the value
of the string, i.e. the sequence of characters within
quotes is printed. Also, note that, within a string, \n
denotes the beginning of a new line. When a string
having \n is printed, everything after \n (excluding
\n) is printed on the next line. In this section, we shall
study basic operations on strings. Let us begin with the
concatenation operator (+), which is used to produce a
string by concatenating two strings; for example, the
expression 'hello ' + '!!' yields the string
'hello !!'. Similarly, the expression 'how' + '
are' + ' you?' yields 'how are you?' (=('how'
+ ' are') + ' you') as shown below:

>>> 'hello ' + '!!'

'hello !!'

>>> 'how' + ' are' + ' you?'

'how are you?'

esca pe sequ en ce \n m a r ks a n ew lin e

u se of + a s th e con ca ten a tion oper a tor

The operator * (multiplication) is used to repeat a string


a specified number of times; for example, the expression
'hello' * 5 yields the string
'hellohellohellohellohello':
>>> 'hello' * 5

'hellohellohellohellohello'

u se of * oper a tor for r epea tin g a str in g sev er a l tim es

1.3 RELATIONAL OPERATORS

Relational operators are used for comparing two


expressions and yield True or False. In an expression
involving both arithmetic and relational operators, the
arithmetic operators have higher precedence than the
relational operators. In Table 1.2, we give a list of
relational operators

T a bl e 1.2 Rela tion a l oper a tor s

r ela tion a l oper a tor s for com pa r in g ex pr ession v a lu es

A relational operator applied on expressions takes the


following form:

expression <comparison operator>


expression
Thus, the expressions, 23 < 25, 23 != 23, and 23
- 2.5 >= 5 * 4, yield True, False, and True,
respectively. As arithmetic operators have higher
precedence than the relational operators, the expression
23 - 2.5 >= 5 * 4 is evaluated as if it were (23 -
2.5) >= (5 * 4). When the relational operators are
applied to strings, strings are compared left to right,
character by character, based on their ASCII codes, also
called ASCII values. For example, ASCII codes of 'A'-
'Z', 'a'-'z', and '0'-'9' lie in the range [65, 90],
[97, 122], and [48, 57], respectively. Thus, 'h' > 'H'
yields True as ASCII value of 'h' (= 104) is greater
than ASCII value of 'H' (= 72). Also, 'hello' >
'Hello' yields True since 'h' is greater than 'H'.
Similarly, 'hi' > 'hello' yields True because the
first character in the two strings is identical and ASCII
code of 'i' is greater than ASCII code of 'e'. Also, if a
string is a prefix of another string, the longer string will
be considered larger.

r ela tion a l oper a tor s y ield v a lu es: True, False

A SCII v a lu es of ch a r a cter s a r e u sed for str in g com pa r ison

Py th on 3 does n ot a llow str in g v a lu es to be com pa r ed w ith


n u m er ic v a lu es

1.4 LOGICAL OPERATORS

The logical operators not, and, and or are applied


to logical operands True and False, also called
Boolean values, and yield either True or False. The
operator not is a unary operator, i.e. it requires only one
operand. The expressions not True and not False
yield False and True, respectively. An expression
involving two Boolean operands and the and operator
yields True if both the operands are True, and False
otherwise. Similarly, an expression involving two
Boolean operands and the or operator yields True if at
least one operand is True, and False otherwise. This
is shown in Table 1.3.

com bin in g ex pr ession s u sin g log ica l oper a tor s

log ica l oper a tor s not, and, or y ield v a lu es: True, False

T a bl e 1.3 not, and, a n d or oper a tor s

Precedence of logical operators is shown in Table 1.4.


T a bl e 1.4 Pr eceden ce of log ica l oper a tor s

While evaluating an expression involving an and


operator, the second sub-expression is evaluated only if
the first sub-expression yields True. For example, in the
expression (10 < 5) and ((5 / 0) < 10), since
the first sub-expression (10 < 5) yields False, and
thus determines the value of the entire expression as
False, Python does not evaluate the second sub-
expression. This is called short-circuit evaluation of
boolean expression. However, the expression (10 > 5)
and ((5 / 0) < 10) yields an error since the first
sub-expression yields True, and Python attempts to
evaluate the second sub-expression ((5 / 0) < 10)
that yields an error because division by zero is an illegal
operation:

sh or t-cir cu it ev a lu a tion of a boolea n ex pr ession

>>> (10 < 5) and ((5 / 0) < 10)

False

>>> (10 > 5) and ((5 / 0) < 10)

Traceback (most recent call last):

File "<pyshell#104>", line 1

(10 > 5) and ((5 / 0) < 10)

ZeroDivisionError: division by zero


Similarly, while evaluating an expression involving an
or operator, the second sub-expression is evaluated only
if the first sub-expression yields False. Thus, whereas
the expression (10 > 5) or ((5 / 0) < 10) yields
True, the expression (10 < 5) or ((5 / 0) <
10) yields an error.

To evaluate an expression comprising arithmetic,


relational, and logical operators, the operators are
applied according to precedence order for the operators
given in Table 1.5. For example, the expression not 9
== 8 and 7 + 1 != 8 or 6 < 4.5 is evaluated as
if it were the following equivalent parenthesized
expression:

ex pr ession s in v olv in g a r ith m etic, r ela tion a l, a n d log ica l


oper a tor s

((not (9 == 8)) and ((7 + 1) != 8)) or (6


< 4.5)

i.e. ((not False) and ((7 + 1) != 8)) or (6


< 4.5)

i.e. (True and ((7 + 1) != 8)) or (6 < 4.5)

i.e. (True and (8 != 8)) or (6 < 4.5)

i.e. (True and False) or (6 < 4.5)

i.e. False or (6 < 4.5)

i.e. False or False

i.e. False

ex pr ession ev a lu a tion u sin g pr eceden ce r u les


T a bl e 1.5 Pr eceden ce of oper a tor s

1.5 BITWISE OPERATORS

Bitwise operators are the operators that operate on


integers interpreted as strings of binary digits 0 and 1,
also called bits. In Table 1.6, we list bitwise operators,
their description, along with examples. For the sake of
brevity, we assume that all numbers are eight-bit long.

bitw ise oper a tor s oper a te bit by bit

T a bl e 1.6 Boolea n oper a tor s


Table 1.7 shows precedence order of different operators
in Python
T a bl e 1.7 Pr eceden ce of oper a tor s

pa r en th eses h a v e th e h ig h est pr eceden ce w h ile log ica l


oper a tor s h a v e th e low est pr eceden ce

1.6 VARIABLES AND ASSIGNMENT STATEMENTS

Variables provide a means to name values so that they


can be used and manipulated later on. Indeed, a
program essentially carries out variable manipulations to
achieve the desired objective. For example, variables
english, maths, and commerce may be used to deal
with the marks obtained in these subjects, and the
variables totalMarks and percentage may be used
to deal with aggregate marks and the overall percentage
of marks, respectively. If a student has obtained 57
marks in english, this may be expressed in Python
using the following statement:

>> english = 57

a v a r ia ble is a n a m e g iv en to a v a lu e

When the above statement is executed, Python


associates the variable english with value 57. We can
also say that the the variable english is assigned the
value 57, or that the variable english refers to value
57. Such a statement that assigns value to a variable is
called an assignment statement. In Fig. 1.2, we see that
the variable english refers to the value 57. A figure
such as Fig. 1.2 is known as reference diagram or state
diagram as it shows the current state of the variable.

a ssig n m en t sta tem en t

Fig. 1.2 Cu r r en t sta te dia g r a m of v a r ia ble english

v a r ia ble english r efer s to v a lu e 57

In Python style (often called Pythonic style, or


Pythonic way), variables are called names, and an
assignment is called an association or a binding. Thus,
we say that the name english has been associated
with the data object 57, or that the variable english
has been bound to the data object 57. Note that, unlike
an expression, on the execution of an assignment
statement, IDLE does not respond with any output. Of
course, the value of the variable english can be
displayed as follows:

>>> english

57

in Py th on , v a r ia bles a r e often ca lled n a m es

a n a ssig n m en t sta tem en t bin ds a v a r ia ble to a n object

In the above example, english is a variable whose


value is 57. Similarly, the following statements will
assign values 64 and 62 to the variables maths and
commerce, respectively.

>>> maths = 64

>>> commerce = 62

In this example, we assume that maximum mark in


each subject is 100. Total marks in these three subjects
and overall percentage can be computed using another
sequence of statements:

>>> totalMarks = english + maths +


commerce

>>> percentage = (totalMarks / 300) * 100

>>> percentage

61.0

com pu tin g ov er a ll per cen ta g e fr om m a r ks in differ en t


su bjects
Assignment Statement

As discussed above, values are assigned to variables


using an assignment statement. The syntax for
assignment statement is as follows:

variable = expression

sy n ta x for a ssig n m en t sta tem en t

where expression may yield a value such as numeric,


string, or Boolean. In an assignment statement, the
expression on the right-hand side of the equal to
operator (=) is evaluated and the value so obtained is
assigned to the variable on the left-hand side of the =
operator. We have already seen some examples of
variables. In general, we must follow the following rules
while using the variables:

r u les for n a m in g v a r ia bles

A v a r ia ble m u st beg in w ith a letter or _ (u n der scor e


ch a r a cter )
A v a r ia ble m a y con ta in a n y n u m ber of letter s, dig its, or
u n der scor e ch a r a cter s. No oth er ch a r a cter a pa r t fr om
th ese is a llow ed.

Thus, marks, name, max_marks, _emp,


maxMarks, n1, and max_of_3_numbers are valid
variables. However, note that the following are not valid
variables:

total_no. #use of dot (.)

1st_number #begins with a digit

AmountIn$ #use of dollar symbol ($)

#Presence of blank between two


Total Amount
words

It is a good programming practice to make sure that the


variables are meaningful as carefully chosen variables
make your code readable. For example, to denote the
total marks obtained, it is easy to understand what the
variable totalMarks represents than a variable a, x,
marks or total used for the same purpose. There are
several styles of forming variables, for example:

total_marks

TotalMarks

totalMarks

TOTAL_MARKS

a lw a y s u se m ea n in g fu l v a r ia ble n a m es

However, one must be consistent in following a style. In


this book, we prefer to use the lowerCamelCase style in
which the first letter of every word is capitalized, except
the first word which begins with a lowercase letter, for
example, totalMarks. While forming variables, it is
important to note that Python is case-sensitive. Thus,
age and Age are different variables. So, if we assign a
value to the variable age and display the value of Age,
the system will respond with an error message.

follow a con sisten t sty le in ch oosin g v a r ia bles

>>> age = 24

>>> Age

Traceback (most recent call last):

File "<pyshell#1>", line 1, in <module>

Age

NameError: name 'Age' is not defined


Py th on is ca se-sen sitiv e.
age a n d Age a r e differ en t n a m es

Next, let us examine the following statements:

>>> a = 5

>>> b = a

>>> a = 7

m or e th a n on e v a r ia ble m a y r efer to th e sa m e object

The first statement assigns name a to an integer value 5


as shown in Fig. 1.3(a). The next statement assigns
another name b to the same value 5 (Fig. 1.3 (b)).
Finally, the third statement assigns a different value 7 to
a (Fig. 1.3 (c)). Now the variables a and b refer to
different values.

Shorthand Notation

By now, we have seen several examples of assignment


statements. The following assignment statement updates
value of the variable a by adding 5 to the existing value.

>> a = a + 5

Fig. 1.3 Cu r r en t sta te dia g r a m


Alternatively, we can write the above statement as

>>> a += 5

a sh or th a n d n ota tion

Thus, the operator += serves as shorthand notation in


assignment statement. Similarly, the statements

>>> a = a + b + c

>>> a = a ** (b + c)

can be written as follows, respectively:

>>> a += b + c

>>> a **= b + c

As the shorthand notation works for all binary


mathematical operators,

a = a <operator> b

is equivalent to

a <operator>= b

Python also allows multiple assignments in a single


statement; for example, the following sequence of three
assignment statements

>>> msg = 'Meeting'

>>> day = 'Mon'

>>> time = '9'

may be replaced by a single statement:

>>> msg, day, time = 'Meeting', 'Mon', '9'


m u ltiple a ssig n m en ts in a sin g le sta tem en t

Thus, we can specify more variables than one on the left


side of an assignment statement, and the corresponding
number of expressions, like <expr1>, <expr2>,
..., <exprK>, on the right side. Formally, the syntax
for an assignment statement may be described as
follows:

<name1>, <name2>, ..., <nameK> = <expr1>,


<expr2>, ..., <exprK>

This notation can be used to enhance the readability of


the program. We may also assign a common value to
multiple variables, for example, the assignment
statement

>>> totalMarks = count = 0

a ssig n in g sa m e v a lu e to m u ltiple v a r ia bles in a sin g le


sta tem en t

may be used to replace the following two assignments:

>>> totalMarks = 0

>>> count = 0

Suppose we wish to swap values of two variables, say,


num1 and num2. For this purpose, we use a variable
temp as follows:

>>> num1, num2 = 10, 20

>>> temp = num1

>>> num1 = num2

>>> num2 = temp

>>> print(num1, num2)

20 10
Note that before executing the assignment statement

num1 = num2

we save the value of the variable num1 in the variable


temp, so that the same can be assigned to the variable
num2 in the following assignment statement. A variable
that is used to hold the value of another variable
temporarily is often called temporary variable.

Alternatively, we can use the following statement to


swap the values of two variables:

>>> num1, num2 = num2, num1

1.7 KEYWORDS

Keywords are the reserved words that are already


defined by the Python for specific uses. They cannot be
used for any other purpose. Hence, make sure that none
of the names used in a program should match any of the
keywords. The list of the keywords in Python 3.6 is given
in Fig. 1.4.

key w or ds h a v e specia l m ea n in g

Fig. 1.4 List of Py th on key w or ds


key w or ds ca n n ot be u sed for n a m in g objects

1.8 SCRIPT MODE

So far, we have done all work using Python shell, an


interactive environment of IDLE. The definitions of
objects, names, etc., exist only during an IDLE session.
When we exit an IDLE session, and start another IDLE
session, we must redo all computations. This is not a
convenient mode of operation for most of the
computational tasks. Python provides another way of
working called script mode. All the instructions
necessary for a task are stored in a file often called a
source file script, program, source code, or a module.
Python requires that such a file must have extension
.py or .pyw. To create a script, Python IDLE provides a
New Window option in the File menu. On clicking the
New Window option, a Python Editor window opens,
where we can write a sequence of instructions,
collectively called a program or a script. A script can be
saved using the Save As option in the File menu. It
may be executed in shell by selecting Run Module
option in the Run menu.

in scr ipt m ode, in str u ction s a r e w r itten in a file

a scr ipt sh ou ld h a v e ex ten sion .py or .pyw

As a trivial example, the script readNshow in Fig. 1.5


takes two numbers from the user and outputs these
numbers. On executing the first line of the script, the
system waits for the user to enter a number which is
assigned to the variable number1. On executing the
second line of the script, the system waits for the user to
enter another number which is assigned to the variable
number2. The values of variables number1 and
number2 are displayed on executing the third line of the
script.
Fig. 1.5 In pu t–ou tpu t pr og r a m

a sim ple scr ipt

ou tpu t on ex ecu tin g th e scr ipt

The problem with the above script is that as we have


developed it just now, we remember that the program
requires two numbers as the input. However, if we wish
to use it a month later, we may forget what inputs are
required by the program, and we will need to examine
the program again before running it. Surely, we would
like to avoid this effort. A good programming practice is
to display to the user what data is to be entered. The
modified script readNshowWell (Fig. 1.6) achieves this
by displaying a message to the user as the system waits
for user input.

Fig. 1.6 In pu t–ou tpu t pr og r a m

SUMMARY

1 . Py th on in ter pr eter ex ecu tes on e ex pr ession (com m a n d)


a t a tim e.
2 . A n ex pr ession is a v a lid com bin a tion of oper a tor s a n d
oper a n ds. Oper a n ds a r e th e objects on w h ich oper a tor s
a r e a pplied.
3 . A r ith m etic, r ela tion a l, log ica l, a n d bitw ise oper a tor s
a r e u sed for per for m in g com pu ta tion s in a pr og r a m .
4 . A str in g is a sequ en ce of ch a r a cter s. To specify a str in g ,
w e m a y u se sin g le, dou ble, or tr iple qu otes.
5 . Th e oper a tor + (a ddition ) a pplied on tw o str in g
oper a n ds is u sed for con ca ten a tin g th em . Sim ila r ly ,
th e oper a tor * (m u ltiplica tion ) is u sed to r epea t a
str in g a specific n u m ber of tim es.
6 . Wh en r ela tion a l oper a tor s a r e a pplied on str in g s,
str in g s a r e com pa r ed left to r ig h t ch a r a cter by
ch a r a cter a ccor din g to th eir A SCII v a lu es.
7 . Wh ile ev a lu a tin g a Boolea n ex pr ession in v olv in g and
oper a tor , th e secon d su b-ex pr ession is ev a lu a ted on ly if
th e fir st su b-ex pr ession y ields True.
8 . Wh ile ev a lu a tin g a n ex pr ession in v olv in g or oper a tor ,
th e secon d su b-ex pr ession is ev a lu a ted on ly if th e fir st
su b-ex pr ession y ields False.
9 . Pr eceden ce or der for th e oper a tor s is a s follow s:

1 0. A v a r ia ble is a n a m e th a t r efer s to a v a lu e. We m a y
a lso sa y th a t a v a r ia ble a ssocia tes a n a m e w ith a da ta
object su ch a s n u m ber , ch a r a cter , str in g , or Boolea n .
1 1 . V a lu es a r e a ssig n ed to v a r ia bles u sin g a ssig n m en t
sta tem en t. Th e sy n ta x for a ssig n m en t sta tem en t is a s
follow s:
variable = expression
w h er e ex pr ession m a y y ield a n y v a lu e su ch a s
n u m er ic, str in g , or Boolea n .
1 2 . In a n a ssig n m en t sta tem en t, th e expression on th e
right-hand s ide of th e equ a l to oper a tor (=) is ev a lu a ted
a n d th e v a lu e so obta in ed is a ssig n ed to th e v a r ia ble on
th e left-hand s ide of th e = oper a tor .
1 3 . A v a r ia ble n a m e m u st beg in w ith a letter or _
(u n der scor e ch a r a cter ). It m a y con ta in a n y n u m ber of
letter s, dig its or u n der scor e ch a r a cter s. No oth er
ch a r a cter a pa r t fr om th ese is a llow ed.
1 4 . Py th on is ca se-sen sitiv e. Th u s, age a n d Age a r e
differ en t v a r ia bles.
1 5 . Th e sh or th a n d n ota tion for a = a <operator> b is
a <operator>= b
1 6 . In Py th on , m u ltiple a ssig n m en t sta tem en ts ca n be
specified in a sin g le lin e a s follow s:
<name1>, <name2>, ... = <expression1>,
<expression2>, ...
1 7 . A key w or d is a r eser v ed w or d th a t is a lr ea dy defin ed by
Py th on for a specific u se. Key w or ds ca n n ot be u sed for
a n y oth er pu r pose. Th e list of th e Py th on key w or ds is
g iv en below :

False class finally is return None

continue for lambda try True def

from nonlocal while and del global

not with as if or yield

assert else import pass break except

in raise elif

1 8 . Py th on pr og r a m m in g ca n be don e in a n in ter a ctiv e


a n d scr ipt m ode.

EXERCISES

1 . Ev a lu a te th e follow in g ex pr ession s:
(x < y) or (not(z == y) and (z < x))
1 . x = 0, y = 6 , z = 1 0
2. x = 1, y = 1, z = 1
2 . Ev a lu a te th e follow in g ex pr ession s in v olv in g
a r ith m etic oper a tor s:
1 . -7 * 20 + 8 / 16 * 2 + 54
2 . 7 ** 2 // 9 % 3
3 . ( 7 – 4 * 2 ) * 10 / 5 ** 2 + 15
4 . 5 % 10 + 10 – 25 * 8 // 5
5 . ' hello' * 2 - 5
3 . Ev a lu a te th e follow in g ex pr ession s in v olv in g r ela tion a l
a n d log ica l oper a tor s:
1 . 'hi' > 'hello' and 'bye' < 'Bye'
2 . 'hi' > 'hello' or 'bye' < 'Bye'
3 . 7 > 8 or 5 < 6 and 'I am fine' > 'I am
not fine'
4 . 10 != 9 and 29 >= 29
5 . 10 != 9 and 29 >= 29 and 'hi' > 'hello'
or 'bye' < 'Bye' and 7 <= 2.5
4 . Ev a lu a te th e follow in g ex pr ession s in v olv in g
a r ith m etic, r ela tion a l, a n d log ica l oper a tor s:
1 . 5 % 10 + 10 < 50 and 29 >= 29
2 . 7 ** 2 <= 5 // 9 % 3 or 'bye' < 'Bye'
3 . 5 % 10 < 10 and – 25 > 1 * 8 // 5
4 . 7 ** 2 // 4 + 5 > 8 or 5 != 6
5 . 7 / 4 < 6 and 'I am fine' > 'I am not
fine'
6 . 10 + 6 * 2 ** 2 != 9 // 4 - 3 and 29 >=
29 / 9
7 . 'hello' * 5 > 'hello' or 'bye' < 'Bye'
5 . Ev a lu a te th e follow in g ex pr ession s in v olv in g bitw ise
oper a tor s:
1 . 15 & 22
2 . 15 | 22
3 . -15 & 22
4 . -15 | 22
5 . ~15
6 . ~22
7 . ~-20
8 . 15 ^ 22
9 . 8 << 3
1 0. 40 >> 3
6 . Differ en tia te betw een th e follow in g oper a tor s w ith th e
h elp of ex a m ples:
1 . = a n d ==
2. / and %
3 . / a n d //
4 . * a n d **
7 . Wh a t ou tpu t w ill be displa y ed w h en th e follow in g
com m a n ds a r e ex ecu ted in Py th on sh ell in sequ en ce:
1 . >>> a = 6
>>> a == 6
>>> a < 5.9
>>> a > 5.9
2 . >>> b = 7
>>> b / 6
>>> b // 6
>>> b / 4
>>> b % 4
>>> b % 7
>>> b * 2
>>> b ** 2
8 . Con str u ct log ica l ex pr ession s for r epr esen tin g th e
follow in g con dition s:
1 . marks scor ed sh ou ld be g r ea ter th a n 300 a n d less
th a n 400.
2 . Wh eth er th e v a lu e of grade is a n u pper ca se
letter .
3 . Th e post is engineer a n d experience is m or e
th a n fou r y ea r s.
9 . Iden tify Py th on key w or ds fr om th e follow in g list of
w or ds:

And class PASS if exec PRINT Not

1 0. Wr ite Py th on sta tem en ts for th e follow in g equ a tion s:

1.

2.

3.

1 1 . How does th e effect of th e follow in g tw o sta tem en ts


differ ?
1 . x += x + 10
2 . x = x + 10
CHAPTER 2
FUNCTIONS

CHAPTER OUTLINE
2 .1 Bu ilt-in Fu n ction s

2 .2 Fu n ction Defin ition a n d Ca ll

2 .3 Im por tin g User -defin ed Modu le

2 .4 assert Sta tem en t

2 .5 Com m a n d Lin e A r g u m en ts

In this chapter, we will learn how simple statements can


be put together in the form of functions to do useful
tasks. We can easily deal with problems whose solutions
can be written in the form of small Python programs. As
a problem becomes complex, the program also increases
in size and complexity, and it is impossible for a
programmer to keep track of the data and control
statements in the whole program. Indeed, experience
has shown that the most programmers cannot keep
track of more than ten statements or so at a time.
Therefore, we cannot apply the crude method of
attacking the whole problem at the same time. Instead,
we opt for a more systematic way of problem solving by
dividing the given problem into several sub-problems,
finding their individual solutions in the form of functions
(also called sub-programs) and integrating them to form
the final program. If necessary, the sub-problems may
be further divided into still smaller problems, and the
process of dividing a problem into a set of problems of
smaller size can be continued up to any appropriate
level. Later on, solutions of the small problems are
merged to form programs aimed at solving the complex
problem. This approach to problem solving is called
stepwise refinement method or modular approach.

to solv e a pr oblem , div ide it in to sim pler su b-pr oblem s


In this chapter, we shall begin by giving examples of
built-in functions that are already made available in
Python for use by the programmers. Subsequently, we
shall learn how to develop functions for the specific need
of the problems at hand. The chapter concludes with a
description of assertions that serve as an error-checking
mechanism.

2.1 BUILT-IN FUNCTIONS

Built-in functions are predefined functions that are


already available in Python. Recall that we have already
used the built-in functions input and print. Next, we
will discuss some more examples of built-in functions.

input Function

The function input enables us to accept an input string


from the user without evaluating its value. The function
input continues to read input text from the user until it
encounters a newline, for example:

in v okin g input fu n ction to ta ke u ser in pu t

>>> name = input('Enter a name: ')

Enter a name: Alok

>>> name

'Alok'

The variable name now refers to the string value 'Alok'


entered by the user. Making use of a function is called
calling the function, or invoking the function. In the
above statement, the string 'Enter a name: '
specified within the parentheses is called an argument.
So, we say that the function input has been called with
the argument 'Enter a number: '. Further, we say
that the function returns the string entered by the user
('Alok') which is subsequently assigned to the variable
name.

eval Function
The function eval is used to evaluate the value of a
string, for example:

ev a lu a tin g a str in g

>>> eval('15')

15

>>> eval('15+10')

25

Composition

The value returned by a function may be used as an


argument for another function in a nested manner. This
is called composition. For example, if we wish to take a
numeric value or an expression as an input from the
user, we take the input string from the user using the
function input, and apply eval function to evaluate its
value, for example:

n ested ca lls: ou tpu t of in n er fu n ction ser v es a s in pu t


a r g u m en t to ou ter fu n ction

>>> n1 = eval(input('Enter a number: '))

Enter a number: 234

>>> n1

234

>>> n2 = eval(input('Enter an arithmetic


expression: '))

Enter an arithmetic expression: 12.0 +


13.0 * 2

>>> n2
38.0

Note that the inputs 234 and 12.0 + 13.0 * 2 were


correctly evaluated as int and float values
respectively.

print Function

Recall from the previous chapter that the following


statement enables us to produce the output in Python.
On execution of the statement:

print('hello')

the system will output hello:

>>> print('hello')

hello

Statement print('hello') calls the function print


with the argument 'hello'. Note that the output of
print function does not include any apostrophe marks
as it displays the value of the string that comprises the
sequence of characters: hello. Apostrophe marks are
used just to tell Python where a string begins and ends
and do not form part of the string. Any number of
comma-separated expressions may be used while
invoking a print function, for example:

pr in tin g m u ltiple v a lu es in a sin g le ca ll to print fu n ction

>>> print(2, 567, 234)

2 567 234

>>> name = 'Raman'

>>> print('hello', name, '2 + 2 =', 2 + 2)

hello Raman 2 + 2 = 4
Note that when several values are included in a call to
the print function separated by commas, they are
displayed on the same line, separated by single spaces
between them. It is important to point out that after
printing the values of the expressions included as
arguments while invoking the print function, the print
control moves to the beginning of the next line. Thus,
the output of a sequence of print function calls appears
on separate lines. In the next example, the output of a
single call to the print function is displayed on two
lines:

>>> print('hello', name, '\n2 + 2 =', 2 +


2)

hello Raman

2 + 2 = 4

The backslash character \ has a special meaning. The


character sequence \n serves as a line feed character and
transfers the print control to the beginning of the next
line. The character sequences like \n and \t are called
escape sequences. Next, we give an example of the
escape sequence \t which is interpreted as a tab
character:

u se of Py th on esca pe sequ en ces

>>> print('hello', name, '\t2 + 2 =',2 +


2)

hello Raman 2 + 2 = 4

If we do not want Python to interpret an escape


sequence, it should be preceded by another backslash.
Another way of achieving the same thing is to use R or r
before the string containing escape symbol, for example:

>>> print('Use \\n for newline')

Use \n for newline


>>> print(R'Use \n for newline')

Use \n for newline

>>> print(r'Use \n for newline')

Use \n for newline

>>> print('Use', R'\n', 'for newline')

Use \n for newline

Python also supports various other escape sequences


such as \a (ASCII bell), \b (ASCII backspace),
\f (ASCII form feed), and \r (ASCII carriage return).
However, some of these are not supported by Python
IDLE.

type Function

Values or objects in Python are classified into types or


classes, for example, 12 is an integer, 12.5 is a floating
point number, and 'hello' is a string. Python function
type tells us the type of a value, for example:

deter m in in g da ta ty pe

>>> print(type(12), type(12.5),


type('hello'), type(int))

<class 'int'> <class 'float'> <class


'str'>

<class 'type'>

round Function

The round function rounds a number up to specific


number of decimal places, for example:

r ou n din g to n ea r est v a lu e
>>> print(round(89.625,2), round(89.635),
round(89.635,0))

89.62 90 90.0

>>> print(round(34.12, 1), round(-34.63))

34.1 -35

When calling the function round, the first argument is


used to specify the value to be rounded, and the second
argument is used to specify the number of decimal digits
desired after rounding. In a call to function round, if the
second argument is missing, the system rounds the value
of first argument to an integer, for example,
round(89.635) yields 90.

Type Conversion

Let the variables costPrice and profit denote cost


price and desired profit for a grocery item in a shop. We
wish to compute the selling price for the item (Fig. 2.1).

Fig. 2.1 Pr og r a m to fin d sellin g pr ice

While executing the above script, if we enter 50 and 5


as the values for costPrice and profit respectively,
the system will respond as follows:

u n desir a ble u se of + oper a tor

Enter cost price: 50

Enter profit: 5
Selling Price: 505

Note that the input function considers all inputs as


strings. Therefore, the value of sellingPrice shown
above as 505 is the concatenation of the input values of
costPrice and profit, i.e., '50' and '5',
respectively. To convert the input strings to equivalent
integers, we need to use the function int explicitly (Fig.
2.2):

con v er sion fr om str to int

Fig. 2.2 Pr og r a m to fin d sellin g pr ice

On executing the above script, the system will respond as


follows:

Enter cost price: 50

Enter profit: 5

Selling Price: 55

We may also use float function if we wish to take


decimal value as input from the user. The function str
can be used to convert a numeric value to a str value.
Next, we give some examples, illustrating the use of
some functions for type conversion:

con v er sion fr om int to str

>>> str(123)
'123'

>>> float(123)

123.0

>>> int(123.0)

123

>>> str(123.45)

'123.45'

>>> float('123.45')

123.45

>>> int('123.45')

Traceback (most recent call last):

File "<pyshell#3>", line 1, in <module>

int('123.45')

ValueError: invalid literal for int() with


base 10: '123.45'

con v er sion fr om str to float

str in g in com pa tible for con v er sion

Note that last example yields an error since function int


cannot be used for converting a string containing
decimal value to its integer equivalent. We already know
that the eval function converts the value of the
argument to the appropriate type, for example:

>>> eval('50+5')
55

min and max Functions

The functions max and min are used to find maximum


and minimum value respectively out of several values.
These functions can also operate on string values. Next,
we illustrate the use of these functions.

>>> max(59, 80, 95.6, 95.2)

95.6

>>> min(59, 80, 95.6, 95.2)

59

>>> max('hello', 'how', 'are', 'you')

'you'

>>> min('hello', 'how', 'are', 'you',


'Sir')

'Sir'

Note that the integer and floating point values are


compatible for comparison. However, numeric values
cannot be compared with string values.

oper a n ds m u st be com pa tible for com pa r ison

pow Function
b
The function pow(a, b)computes a . Thus, given the
side of a cube, if we want to find its volume, we may
just write pow(side, 3).

com pu tin g pow er

Random Number Generation


Imagine a two-player (say, player A and player B) game
in which we want to decide who will play the first turn.
Python provides a function random that generates a
random number in the range [0,1). Python module
random contains this function and needs to be imported
for using it. Let us agree that player A will play the first
turn if the random number generated falls in the range
[0,0.5). Otherwise, player B will play the first turn.
The following sequence of statements achieves this:

import random

if random.random() < 0.5:

print('Player A plays the first turn.')

else:

print('Player B plays the first turn.')

g en er a tin g a r a n dom n u m ber in th e r a n g e [0,1)

The if-else statement used here will be discussed in


detail in the next chapter. In the case of multiple players,
using the above approach for deciding who will play the
first turn will make the program complex. The random
module provides another function randint that
randomly chooses an integer in the specified range; for
example, randint(1,n) will randomly generate a
number in the range 1 to n (both 1 and n included).

Functions from math Module

There are various operations such as floor, ceil,


log, square root, cos, and sin that may be
required in different applications. The math module
provides these functions, among several others. In Table
2.1, we describe some important mathematical
functions.

fu n ction s for m a th em a tica l com pu ta tion s


T a bl e 2.1 Fu n ction s fr om math m odu le
In order to make these functions available for use in a
script, we need to import the math module. The import
statement serves this purpose:

import math

im por t a m odu le befor e u sin g it

The math module also defines a constant math.pi


having value 3.141592653589793. Next, we illustrate
the use of the functions in the math module discussed
above:

n a m e of th e m odu le, follow ed by th e sepa r a tor dot, sh ou ld


pr ecede fu n ction n a m e

>>> import math

>>> math.ceil(3.4)

>>> math.floor(3.7)

>>> math.fabs(-3)

3.0
>>> math.exp(2)

7.38905609893065

>>> math.log(32, 2)

5.0

>>> math.log10(100)

2.0

>>> math.pow(3, 3)

27.0

>>> math.sqrt(65)

8.06225774829855

>>> math.cos(math.pi)

-1.0

>>> math.sin(math.pi/2)

1.0

>>> math.tan(math.pi/4)

0.9999999999999999

>>> math.acos(1)

0.0

>>> math.asin(1)

1.5707963267948966

>>> math.atan(1)

0.7853981633974483
>>> math.degrees(math.pi)

180.0

>>> math.radians(180)

3.141592653589793

Note that the name of a function in a module is preceded


by the name of the module and the separator '.'.

Complete List of Built-in Functions

If we want to see the complete list of built-in functions,


we can use the built-in function dir as
dir(__builtins__). To know the purpose of a
function and how it is used, we may make use of the
function help, for example, to display help on cos
function in the math module, we may give the following
instructions:

g ettin g h elp on a fu n ction

>>> import math

>>> help(math.cos)

Help on built-in function cos in module


math:

cos(...)

cos(x)

Return the cosine of x (measured in


radians).

2.2 FUNCTION DEFINITION AND CALL

We have already mentioned that the functions provide a


systematic way of problem solving by dividing the given
problem into several sub-problems, finding their
individual solutions, and integrating the solutions of
individual problems to solve the original problem.
Suppose we wish to print a picture that consists of a
triangle followed by a square as shown in Fig. 2.3.

Fig. 2.3 Pictu r e

A program segment to achieve this would require the


following steps:

ou tlin e of a solu tion

print a triangle

print a blank line

print a square

If we replace the above outline with Python code, our


job would be done. We call this script picture and store
it in the file picture.py as per Python convention
(Fig. 2.4).
Fig. 2.4 Pr og r a m to pr in t a tr ia n g le follow ed by squ a r e
(picture.py)

In Fig. 2.4 (and elsewhere in the book), line numbers


are not part of Python program but used only for the
purpose of explanation. In this program, line number 2
begins with # (hash). This line is a comment. A
comment is a non-executable text in the program that is
not processed by the system. Comments are ignored by
the Python interpreter as if they are not present. They
are placed to make the intent of Python code clear to the
reader. In general, if # appears anywhere in a line in the
Python program, rest of the line is ignored by the
system. For example:
com m en ts en h a n ce r ea da bility of th e code

# side of an equilateral triangle

sin g le lin e com m en ts sta r t w ith #

is a comment in the statement,

side = 6 # side of an equilateral triangle

Another way of writing a comment is to use a docstring


(documentation string). As mentioned earlier, a
docstring may extend to several lines. In Fig. 2.4, note
that the function definition begins in line 1 with keyword
def, followed by the name of the function main, empty
parenthesis, and a colon. The following statements (lines
2–16) that form the body of the function main do not
begin in column number 1, just below def, but begin
with four spaces. This is called indentation. We have
used four spaces for indentation as per advice in Google’s
coding guidelines. However, one may choose a different
number of spaces, say, two or three, for indentation. But
it is desirable to be consistent, across all the programs
that we write. In general, the syntax for a function
definition is as follows:

m u lti-lin e com m en t

Py th on in sists on str ict in den ta tion r u les

def function_name
(comma_separated_list_of_parameters):

statements

sy n ta x for fu n ction defin ition


Python also requires that a function_name should not
be a Python keyword. The list of parameters (if any)
specifies the information required for using the function.
The statements inside the function have to be indented
from the left margin as shown in Fig. 2.4. It is important
to emphasize that apart from the fact that indented code
looks elegant, it is also a requirement of Python that the
code following a colon must be indented.

Py th on code follow in g colon m u st be in den ted, i.e., sh ifted


r ig h t

Having developed the function main in the script


picture, we would like to execute it. To do this, we
need to invoke the function main. This can be done by
performing the following two steps:

1 . In Run m en u , click on th e option Run Module.


2 . Usin g Py th on sh ell, in v oke (ca ll) th e fu n ction main by
ex ecu tin g th e follow in g com m a n d:
>>> main()

We can eliminate the need to call function main


explicitly from the shell, by including in the script
picture, the following call to function main:

if __name__=='__main__':

main()

in v okin g th e fu n ction main in th e scr ipt

The revised script is shown in Fig. 2.5. Every Python


module has a built-in variable called __name__
containing the name of the module. When the module
itself is being run as the script, this variable __name__ is
assigned the string '__main__' designating it to be a
__main__ module. The __main__ module, i.e. script
picture in this case (Fig. 2.5), comprises:

bu ilt-in v a r ia ble __name__


1 . th e defin ition of fu n ction main
2 . a n if sta tem en t

When a script is executed, Python creates a run-time


environment, called global frame. In the script
picture, when the definition of the function main is
encountered, Python makes a note of its definition in the
global frame. Next, on encountering the if statement,
Python checks whether the name of the current module
is __main__. This being true, the expression __name__
== '__main__' evaluates as True, and the function
main is invoked. The check __name__ ==
'__main__' is performed to prevent the accidental
calling of a function from an imported module. The if
statement is used in a script to specify the starting point
of execution for the module being run. So, if we have a
code that should only be executed when the module is
run, and not when it is imported, we need to execute the
code using if clause as shown in lines 18-19. For the
module being imported, variable __name__ contains the
name of imported module.

y ou m a y r ea d th is pa r a g r a ph ca su a lly for n ow , a n d com e


ba ck to it la ter w h en y ou h a v e som e ex per ien ce in
pr og r a m m in g
Fig. 2.5 Pr og r a m to pr in t a tr ia n g le follow ed by squ a r e
(picture.py)

Now, the statements in the main function are


executed in a sequence. Thus, a triangle and a square,
separated by a blank line get printed. In Fig. 2.5, we note
that printing a triangle and printing a square are
independent activities, having nothing to do with each
other. We can make the above program more elegant by
first developing independent functions to print a square
and a triangle and then making use of these functions in
the main function to print a picture that comprises a
triangle and a square separated by a blank line. In Fig.
2.6, we give the modified script picture1.

dev elopin g fu n ction s for pr in tin g a squ a r e a n d tr ia n g le

The script in Fig. 2.6 works as follows: Python makes


a note of the definition of functions triangle,
square, and main as it sees their definitions. As
described above, on the execution of the if statement
(line 22), the control is transferred to the function main
(line 15). Line 16 being a comment, is ignored by
Python. In line 17, the function triangle is called, and
the body of function triangle gets executed. As the
main function calls the function triangle, it is said to
be the caller function, and the function triangle that
is called is said to be the callee function or called
function.

fu n ction main ser v es a s a ca ller fu n ction for th e ca lled


fu n ction s triangle a n d square
Fig. 2.6 Pr og r a m to pr in t a tr ia n g le follow ed by squ a r e
(picture1.py)

Again, line 2 of the function triangle being a


comment, Python ignores it. Next, lines 3–6 are
executed in sequence. On completing execution of the
function triangle, the control is transferred to the
statement immediately following the one that called the
function triangle, i.e. at line 18 that prints a blank
line. In line 20, we call the function square. On
execution of the body of function square, the control
returns to main function (line 21). As there are no more
statements to be executed in the main, the control now
moves to the line following the statement that invoked
the main function, i.e., call to print function at line 24
in the global frame, which now executes, and the
program comes to an end.
triangle

square

in v okin g th e fu n ction triangle

in v okin g th e fu n ction square

We would like to emphasize that a function definition


appears in a program as a provision to do something and
can come into action only when invoked (called). So,
defining a function has no effect until it is invoked, for
example, the function triangle in Fig. 2.7 will produce
no output as the function triangle has only been
defined and not invoked.

a fu n ction defin ition h a s n o effect u n less it is in v oked

Unlike the scripts picture (Fig. 2.5) and picture1


(Fig. 2.6), often, the caller and the called functions need
to share some information between themselves. To
demonstrate this, we develop a program to print the area
of a rectangle that takes length and breadth of the
rectangle as inputs from the user.
Fig. 2.7 Th e scr ipt sh ow s th a t fu n ction triangle is n ot bein g
in v oked

We can describe this task of computing area of a


rectangle as a sequence of three steps:

1. take length and breadth of the


rectangle as inputs

2. compute the area of the rectangle

3. print the area of the rectangle

Such an informal description of a program (to be


developed) is called a pseudocode. It serves as the basis
of the program to be developed. When solving a complex
problem, a pseudocode serves as the first hand
description of the solution strategy. In the above
description, we have omitted how to compute the area of
a rectangle. Let us now refine step 2 for the computing
area of a rectangle using the following pseudocode. To
compute the area of a rectangle, we develop a function
that accepts length and breadth as arguments, computes
the area, and outputs it as return value. We may
describe this using the following pseudocode:

areaRectangle:

inputs: length, breadth

output: area

computations:

area <- length * breadth

The above mentioned process is known as stepwise


refinement process, for example, in the above
description, we refined step 2 of the pseudocode. In this
book, we have described the solution strategy in detail as
part of the text. So, we have avoided giving a formal
pseudocode while solving the programming problems.
Let us now develop a function areaRectangle to
compute the area of a rectangle. To compute the area of
a rectangle, this function would need to know the
length and breadth of the rectangle. The main
function will communicate this information to function
areaRectangle at the time of invoking it. Further, the
function areaRectangle (Fig. 2.8) would need to
communicate to the caller function main, the area
computed by it.

com pu tin g a r ea of a r ecta n g le


Fig. 2.8 Fu n ction areaRectangle

Line 1 of the function definition includes the name of


the function (i.e., areaRectangle). The names
length and breadth within parenthesis in the function
are called parameters. Lines 2–6 constitute a docstring
describing the function. Line 3 describes the overall
objective of the function. Line 4 describes each of the
inputs to the function and the type of value it takes. Line
5 indicates that the function would return the area of a
rectangle to the calling function. Area of the rectangle is
computed in line 7. Finally, line 8 is a return statement
that returns the area computed in line 7 to the caller
function main. In general, the return statement
returns the value of the expression following the
keyword return to the caller function. If there is no
return statement in a function, the function returns the
value None to the caller function on the execution of the
last statement of the function. The value being returned
may be assigned to a variable.

return sta tem en t r etu r n s th e v a lu e of ex pr ession follow in g


th e return key w or d in th e a bsen ce of th e return sta tem en t,
defa u lt v a lu e None is r etu r n ed

In Fig. 2.9, we give the complete script to compute the


area of a rectangle that takes length and breadth of the
rectangle as inputs from the user. The variables and
expressions whose values are passed to the called
function are called arguments. At the point of call to
function areaRectangle in line 19, values of
arguments lengthRect and breadthRect are passed
to parameters length and breadth, respectively. These
values are used inside the function areaRectangle, for
computing area. While the parameters length and
breadth are called formal parameters, or dummy
arguments, lengthRect and breadthRect used for
invoking the function areaRectangle are called actual
parameters, or arguments. The arguments in call to the
function must appear in the same order as that of
parameters in the function definition.

a r g u m en ts: v a r ia bles/ex pr ession s w h ose v a lu es a r e pa ssed to


ca lled fu n ction pa r a m eter s: v a r ia bles/ex pr ession s in fu n ction
defin ition w h ich r eceiv es v a lu e w h en th e fu n ction is in v oked

Suppose values entered by the user for variables


lengthRect and breadthRect are 5 and 4,
respectively.

a r g u m en ts m u st a ppea r in th e sa m e or der a s th a t of
pa r a m eter s
Fig. 2.9 Pr og r a m to fin d a r ea of a r ecta n g le (area.py)

Enter the following values for rectangle:

Length : integer value: 5

Breadth : integer value: 4

Area of rectangle is 20

End of program

Figure 2.10 shows how the values of the arguments


lengthRect and breadthRect are passed to the
parameters length and breadth at the point of call to
function areaRectangle. The figure showing the
correspondence between arguments and parameters is
sometimes called a memory map.
We could have used length and breadth in both the
functions areaRectangle and main to denote length
and breadth of the rectangle. On returning the value of
area to the function main in line 8, the function
areaRectangle terminates, and the control returns to
line 19 in the script and the value returned by the
function areaRectangle is assigned to the variable
areaRect.

Fig. 2.10 Ca ll to fu n ction areaRectangle

cor r espon den ce betw een a r g u m en ts a n d pa r a m eter s

Next, suppose we wish to compute the area of a


square. To do this, we may use the function
areaRectangle defined above as follows:

areaRectangle(side, side)
u se of fu n ction areaRectangle for com pu tin g a r ea of th e
squ a r e

However, while using function areaRectangle to find


the area of a square, we assume that the user is aware of
the fact that square is a rectangle with equal length and
breadth. A better way to do this would be to define a
function areaSquare that accepts side of the square as
an input parameter. The user interface for the function
areaSquare makes no assumption about the
relationship between areaSquare and
areaRectangle. However, there is nothing wrong in
using the function areaRectangle in the body of the
function areaSquare (Fig. 2.11). Indeed, this illustrates
a software engineering principle of reusing the already
developed functions.

Fig. 2.11 Fu n ction squareArea

In light of above discussion, we present a complete script


for computing the area of a rectangle and a square (Fig.
2.12).
Fig. 2.12 Pr og r a m to fin d a r ea of squ a r e a n d r ecta n g le (area.py)

Fruitful Functions vs Void Functions


A function that returns a value is often called a fruitful
function, for example, the built-in function sin, and
abs, and the functions areaRectangle, and
areaSquare defined earlier in the chapter. A function
that does not return a value is called a void function, for
example, the built-in function print, and the functions
triangle, and square, defined earlier in the chapter.

Function help

Recall that function help can be used to provide a


description of built in functions. Function help can also
be used to provide description of the function defined by
user. All one needs to do is to add a multi-line comment.
Function help works by retrieving the contents specified
using multi-line comments. For example, consider the
function given in Fig. 2.12.

help on u ser defin ed fu n ction s

On executing the command


help(areaRectangle), contents specified using
multi-line comment will be retrieved.

>>> help(areaRectangle)

Help on function areaRectangle in module


__main__:

areaRectangle(length, breadth)

Objective: To compute area of rectangle

Input Parameters: length, breadth -


numeric value

Return Value: area - numeric value

fu n ction help r etr iev es fir st m u lti-lin e com m en t fr om th e


fu n ction defin ition
If there are more than one multi-line comments, only
the first multi-line comment is displayed.

Default Parameter Values

The function parameters may be assigned initial values


also called default values as shown in Fig. 2.13. When
the function areaRectangle is called without
specifying the second argument breadth, default value
1 is assumed for it, for example:

>>> areaRectangle(5)

Fig. 2.13 Defa u lt pa r a m eter v a lu es

However, if the default parameters are specified in a


function call, the default values are ignored, for
example:

fu n ction ca ll u ses defa u lt v a lu e if v a lu e for a pa r a m eter is n ot


pr ov ided
>>> areaRectangle(5,2)

10

It is important to mention that the default parameters


must not be followed by non-default parameters, for
example:

n on -defa u lt a r g u m en ts sh ou ld n ot follow defa u lt a r g u m en ts


in a fu n ction defin ition

>>> def areaRectangle(length = 10,


breadth):

return length * breadth

SyntaxError: non-default argument follows


default argument

Keyword Arguments

In the programs developed so far, the order of


arguments always matched the parameters in the
function definition. However, Python allows us to specify
arguments in an arbitrary order in a function call, by
including the parameter names along with arguments.
The arguments specified as

parameter_name = value

sy n ta x for key w or d a r g u m en ts

are known as keyword arguments. For example, in the


following call to the function areaRectangle, the
order of arguments is different from the one in the
function definition.

areaRect = areaRectangle(breadth = 2,
length = 5)

Indeed, in situations involving a large number of


parameters, several of which may have default values,
keyword arguments can be of great help, for example:

>>> def f(a = 2, b =3, c = 4, d =5, e = 6,


f = 7, g = 8, h = 9):

return a + b + c + d + e + f + g + h

>>> f(c = 10, g = 20)

62

2.3 IMPORTING USER-DEFINED MODULE

Recall from Section 2.1 that to access functions such as


floor, ceil, and log given in Table 2.1, we need to
import math module that includes the definitions of
these functions. Similarly, to access a function from a
user-defined module (also known as program or script
that may comprise functions, classes, and variables), we
need to import it from that module. To ensure that the
module is accessible to the script, we are currently
working on, we append to the system's path, the path to
the folder containing the module. Once this is done, we
can import the module by using an instruction like:

specify in g sy stem pa th

import name-of-the-module

sy n ta x for im por tin g a m odu le

Once this is done, we can access all the functions defined


in it by using the following notation: module name,
followed by a dot, followed by the function name as
shown in line 14 in Fig. 2.14.
Fig. 2.14 Pr og r a m to fin d a r ea of floor (floorArea.py)

The script in Fig. 2.14 may be used from IDLE as


follows:

Enter the following values for floor:

Length: 500
Width: 400

200000

2.4 ASSERT STATEMENT

The assert statement is used for error checking.


Suppose, we want to compute the percentage of marks
obtained in a subject. It may happen that value of
variables maxMarks and marks entered by the user may
not be in proper range, for example, marks may be
negative or greater than the maxMarks. Hence, we need
to make sure that inputs provided by the user are in the
correct range. For this purpose, we make use of an
assert statement (Fig. 2.15, lines 18 and 20) that has
the following form:

u se of assert sta tem en t for er r or ch eckin g

assert condition
Fig. 2.15 Pr og r a m to fin d per cen ta g e (percent.py)

If the assertions in lines 18 and 20 hold, the function


displays percentage as the output. However, if these
assertions fail to hold the system responds with an
assertion error, for example:

Enter maximum marks: 150

Enter marks obtained: 155

Traceback (most recent call last):

File "F:/PythonCode/Ch02/percent.py",
line 25,

in <module>

main()

File "F:/PythonCode/Ch02/percent.py",
line 20,
in main

assert marks >=0 and marks <=maxMarks

AssertionError
!
2.5 COMMAND LINE ARGUMENTS

Let us now revisit the program to find area of the


rectangle. So far, we have executed the Python programs
in Python IDLE. However, we may choose to run the
Python script from the command line interface. For
example, the script area (Fig. 2.9) may be run from the
command prompt by executing the following steps:

1 . open th e dir ector y (sa y , F:\PythonCode\Ch02)


con ta in in g th e file area.py
2 . open com m a n d pr om pt w in dow u sin g a n option in
con tex t m en u (open ed u sin g shift+right click)
3 . ex ecu te th e com m a n d: python area.py

F:\PythonCode\Ch02>python area.py

Enter the following values for rectangle:

Length : integer value: 20

Breadth : integer value: 10

Area of rectangle is 200

End of program

So far, we have been taking inputs from the user in an


interactive manner. However, we may also take the
inputs as command line arguments while executing a
script from the command prompt as follows:

F:\PythonCode\Ch02>python area1.py 20 10

Area of rectangle is 200

End of program

In above command, 20 and 10 serve as inputs for the


script area1. Whenever, we execute a script from
command line, it takes name of the script as the first
argument followed by other input arguments (if any) in
string form and stores them in the list (discussed later)
sys.argv. We access the arguments stored in argv
using indexes argv[0], argv[1], argv[2], etc.
Examine the script area1 (Fig. 2.16). Since, the number
of arguments including the script name should be three,
we ensure this using condition len(sys.argv) == 3.
We also assume that in the command

u su a lly w h itespa ce(s) a r e u sed for sepa r a tin g th e com m a n d


lin e a r g u m en ts fr om ea ch oth er

python area1.py 20 10

command line arguments length and breadth that follow


the script name (area1.py) are stored in argv[1] and
argv[2] respectively.
Fig. 2.16 Pr og r a m to com pu te a r ea of r ecta n g le u sin g com m a n d
lin e in pu ts (a r ea 1 .py )

SUMMARY

1 . Fu n ction s pr ov ide a sy stem a tic w a y of pr oblem solv in g


by div idin g th e g iv en pr oblem in to sev er a l su b-
pr oblem s a n d fin din g th eir in div idu a l solu tion s.
2 . Bu ilt-in fu n ction s a r e pr edefin ed fu n ction s th a t a r e
pr ov ided by th e Py th on en v ir on m en t.
1 . input fu n ction en a bles u s to a ccept a n in pu t
str in g fr om th e u ser w ith ou t ev a lu a tin g its
v a lu e.
2 . print fu n ction en a bles u s to pr odu ce ou tpu t in
Py th on .
3 . eval fu n ction is u sed to ev a lu a te th e v a lu e of a
str in g .
4 . type fu n ction tells u s th e ty pe of v a lu e.
5 . round fu n ction r ou n ds a n u m ber u p to a
specified n u m ber of decim a l pla ces.
6 . int fu n ction ca n be u sed to con v er t a v a lu e to its
cor r espon din g in teg er .
7 . str fu n ction ca n be u sed to con v er t a v a lu e to its
cor r espon din g str in g .
8 . max a n d min fu n ction s a r e u sed for fin din g
m a x im u m a n d m in im u m ou t of sev er a l v a lu es,
r espectiv ely .
9 . pow fu n ction is u sed to fin d som e pow er of a
n u m ber .
1 0. random fu n ction of th e m odu le random is u sed for
g en er a tin g a r a n dom n u m ber in th e r a n g e
[0,1).
1 1 . randint(1,n) fu n ction of th e m odu le random is
u sed for g en er a tin g a r a n dom n u m ber in th e
r a n g e [1, n].
1 2 . math m odu le con ta in s sev er a l m a th em a tica l
fu n ction s su ch a s log, ceil, a n d sin.
3. A com m en t is a n on -ex ecu ta ble tex t in th e pr og r a m
th a t is ig n or ed by th e Py th on in ter pr eter a s if is n ot
pr esen t. Th e com m en ts a r e u sed to m a ke th e in ten t of
Py th on code clea r to th e r ea der . A sin g le-lin e com m en t
sta r ts w ith ch a r a cter #, w h er ea s a m u lti-lin e com m en t
m a y be specified u sin g docstr in g .
4. Th e code follow in g colon m u st be in den ted i.e. sh ifted to
th e r ig h t.
5. Th e v a r ia bles th a t a ppea r in fu n ction defin ition
en closed in pa r en th eses im m edia tely follow in g th e
n a m e of th e fu n ction a r e ca lled for m a l pa r a m eter s or
du m m y pa r a m eter s. Wh en th e fu n ction is ca lled, th ey
a r e r epla ced by th e v a lu es ca lled a r g u m en ts. Th e
a r g u m en ts in ca ll to th e fu n ction m u st a ppea r in th e
sa m e or der a s th a t of th e pa r a m eter s in th e fu n ction
defin ition .
6. A u ser -defin ed m odu le is a lso kn ow n a s pr og r a m or
scr ipt th a t m a y com pr ise fu n ction s, cla sses, a n d
v a r ia bles.
7. Th e fu n ction pa r a m eter s m a y be a ssig n ed in itia l
v a lu es, ca lled defa u lt v a lu es. A ll n on -defa u lt
pa r a m eter s m u st a ppea r befor e th e defa u lt
pa r a m eter s.
8. Py th on a llow s u s to specify a r g u m en ts in a n a r bitr a r y
or der in a fu n ction ca ll, by in clu din g th e pa r a m eter
n a m es a lon g w ith a r g u m en ts. A n a r g u m en t specified
as
parameter_name = value
is kn ow n a s key w or d a r g u m en t.
9. import sta tem en t is u sed for im por tin g a m odu le th a t
m a y be u ser -defin ed or bu ilt-in .
1 0. assert sta tem en t is u sed for er r or ch eckin g . If th e
con dition specified in a n assert sta tem en t fa ils to h old,
Py th on r espon ds w ith a n a sser tion er r or .

EXERCISES

1 . Wh a t w ill be th e ou tpu t pr odu ced by ea ch of th e


follow in g fu n ction ca lls:
math.ceil(65.65) math.ceil(65.47)

math.fabs(-67.58) math.fabs(3)

math.exp(2.7) math.log(45,2)

math.log10(1000) math.pow(4,1/2)

math.sqrt(121) math.radians(30)

math.degrees(math.pi/2)

2 . Giv e th e r a n g e in w h ich v a lu e of v a r ia ble x m a y lie on


ex ecu tion of th e follow in g sta tem en ts:
import random
x = random.random() + 5
3 . Ev a lu a te th e follow in g ex pr ession s u sin g Py th on sh ell.
A ssu m e th a t A SCII codin g sch em e is u sed for ch a r a cter
da ta .

abs(-5.4) abs(15) chr(72)

round(-24.9) float(57) complex('1+2j')

divmod(5,2) float(57) pow(9,2)

max(97, 88, 60) min(55, 29, 99)

max('a', 'b', 'AB')

4 . Dev elop Py th on fu n ction s to pr odu ce th e follow in g


ou tpu ts:

1.
2.

5 . Con sider th e follow in g fu n ction :


def nMultiple(a = 0, num = 1):
return a * num
Wh a t w ill be th e ou tpu t pr odu ced w h en th e follow in g
ca lls a r e m a de:
1 . nMultiple(5)
2 . nMultiple(5, 6)
3 . nMultiple(num = 7)
4 . nMultiple(num = 6, a = 5)
5 . nMultiple(5, num = 6)
6 . Stu dy th e pr og r a m seg m en ts g iv en below . Giv e th e
ou tpu t pr odu ced, if a n y .
1 . def test(a, b):
a = a+b
b = a-b
a = a-b
print('a = ', a)
print('b = ', b)
test(5,8)
2 . def func():
pass
a = func()
print(a)
7 . Wr ite a fu n ction areaTriangle th a t ta kes th e len g th s
of th r ee sides: side1, side2, and side3 of th e
tr ia n g le a s th e in pu t pa r a m eter s a n d r etu r n s th e a r ea
of th e tr ia n g le a s th e ou tpu t. A lso, assert th a t su m of
th e len g th of a n y tw o sides is g r ea ter th a n th e th ir d
side. Wr ite a fu n ction main th a t a ccepts in pu ts fr om
th e u ser in ter a ctiv ely a n d com pu tes th e a r ea of th e
tr ia n g le u sin g th e fu n ction areaTriangle.
8 . Cr ea te th e follow in g scr ipts importedModule (Fig .
2 .1 7 ) a n d mainModule (Fig . 2 .1 8 ) in th e w or kin g
dir ector y , ex ecu te th e scr ipt mainModule a n d ju stify
th e ou tpu t.
F ig . 2.17 (importedModule.py)

F ig . 2.18 (mainModule.py)

9 . Rew r ite th e code in qu estion 7 so th a t it ta kes in pu ts a s


com m a n d lin e a r g u m en ts.
!
Th is section m a y be skipped on fir st r ea din g w ith ou t loss of
con tin u ity .
CHAPTER 3
CONTROL STRUCTURES

CHAPTER OUTLINE
3 .1 if Con dition a l Sta tem en t

3 .2 Iter a tion (for a n d while Sta tem en ts)

The functions that we have developed so far had the


property that each instruction in a function was
executed exactly once. Further, the instructions in these
functions were executed in the order in which they
appeared in the functions. Such functions are called
straight line functions. However, real life problems
would usually require non-sequential and repetitive
execution of instructions. Python provides various
control structures for this purpose. In this chapter, we
will study the following control structures with suitable
examples: if, for, and while.

con tr ol str u ctu r es a r e u sed for n on -sequ en tia l a n d r epetitiv e


ex ecu tion of in str u ction s

3.1 IF CONDITIONAL STATEMENT

Suppose a teacher grades the students on a scale of 100


marks. To pass the examination, a student must secure
pass marks (say, 40). Before announcing the results, the
teacher decides to moderate the results by giving
maximum of two grace marks. Thus, if the student has
scored 38 or 39 marks, he or she would be declared to
have scored 40 marks. Let us see how script moderate
(Fig. 3.1) achieves this.

First, we set passMarks equal to 40 in the function


main (Fig. 3.1). The next statement prompts the user to
enter the marks obtained by a student. As marks entered
by the user is of type str, we transform it to an integer
quantity intMarks using the function int. In line 23,
we invoke the function moderate defined in lines 1–12
with the arguments intMarks and passMarks. Inside
the function moderate (line 10), we check whether the
value of the input parameter marks is less than
passMarks by one or two using the condition marks
== passMarks-1 or marks == passMarks-2.
The assignment statement in line 11 gets executed only if
the condition evaluates to True. Next, the function
moderate returns marks (possibly modified) to the
main function. The value returned by the function
moderate is assigned to the variable moderatedMarks
(line 23). Finally, we print moderatedMarks in line 24.
If we run the script in Fig. 3.1, the system responds by
asking the marks and displays moderatedMarks.
Fig. 3.1 Pr og r a m to m oder a te th e r esu lts by g iv in g m a x im u m of
tw o g r a ce m a r ks (moderate.py)

marks to be u pda ted to passMarks ba sed on a con dition

>>>

Enter marks: 38

Moderated marks: 40

>>>

Enter marks: 39

Moderated marks: 40

>>>

Enter marks: 40

Moderated marks: 40
In Fig. 3.2, we give a representation of the function
moderate using a flowchart.

Fig. 3.2 Flow dia g r a m of fu n ction moderate

m oder a te marks on ly if th e stu den t is 1 or 2 m a r ks sh or t of


passMarks

General Form of if Conditional Statement

The general form of if conditional statement is as


follows:

sy n ta x for if con dition a l sta tem en t

if < condition >:

< Sequence S of statements to be


executed >
Here, condition is a Boolean expression, which is
evaluated when the if statement is executed. If this
condition evaluates to True, then the sequence S of
statements is executed, and the control is transferred to
the statement following the if statement. However, if
the Boolean expression evaluates to False, the sequence
S of statements is ignored, and the control is
immediately transferred to the statement following the
if statement. The flow diagram for execution of the if
statement has been shown in Fig. 3.3.

sta tem en ts follow in g if cla u se a r e ex ecu ted on ly if th e


con dition in th e cla u se ev a lu a tes to True

Note that <Sequence S of statements to be


executed> following the colon is indented (i.e., shifted
right). Next, suppose we want to restrict the use of a
system. To keep the things simple, all the valid users are
assigned a common password and password validation is
the only task this program performs. We can verify the
password entered by a user against the password stored
in the system using an if statement. If both the
passwords match, the program prints a welcome
message, else an error message indicating password
mismatch is displayed. Let us see how the script in Fig.
3.4 achieves this.

flow -dia g r a m of if sta tem en t


Fig. 3.3 Flow dia g r a m of if sta tem en t
Fig. 3.4 Pr og r a m to a u th en tica te u ser a n d a llow a ccess to sy stem
(authenticate.py)

The function main in Fig. 3.4 prompts the user to


enter the password, which is stored in the variable
password. Next, the function authenticateUser
beginning line 1 is called in line 22 with the argument
password. Inside the function authenticateUser,
the value of this input parameter is matched against the
password 'magic' (already known to the system),
using the condition password == 'magic' (line 7).
The assignment statement in line 8 gets executed only if
the condition holds True. Similarly, if the condition
specified in line 9 holds True, the assignment statement
in line number 10 gets executed. String value returned
by the function authenticateUser (line 11) is
assigned to the variable message in line 22. Finally, we
print a message indicating whether the user is
authorized to use the system in line 23.

pa ssw or d v a lida tion


If we run the script in Fig. 3.4, the system responds by
asking for the password and displays a suitable message
indicating successful or unsuccessful login attempt.

LOGIN SYSTEM

==============================

Enter Password: hello

Password mismatch !!

LOGIN SYSTEM

==============================

Enter Password: magic

Login Successful !!

Welcome to system.

In Fig. 3.5, we represent the function


authenticateUser using a flowchart:

flow ch a r t to v a lida te th e pa ssw or d en ter ed by th e u ser


Fig. 3.5 Flow dia g r a m of fu n ction authenticateUser

Y ou must have noted in the previous program that


there were two if statements for checking the
correctness and incorrectness of the password entered
by a user. However, it is obvious that if password is not
correct, it must be incorrect. Indeed, Python provides an
if-else statement to handle such situations. Let us
have a look at the modified script given in Fig. 3.6.
Fig. 3.6 Pr og r a m to a u th en tica te u ser a n d a llow a ccess to sy stem
(authenticate.py)

If the condition in line 7 holds True, the statement in


line number 8 (body of if statement) gets executed. If
the condition in line 7 fails to hold, control is transferred
to the assignment statement in line 10 (body of the else
part). In Fig. 3.7, we illustrate the if-else statement
with the help of a flowchart.

Conditional Expression

Python allows us to write conditional expressions of the


form given below:

u se of if-else con dition a l sta tem en t to v a lida te th e


pa ssw or d en ter ed by th e u ser

Fig. 3.7 Flow dia g r a m of if-else sta tem en t in th e fu n ction


authenticateUser

<expression1> if <condition> else < expression2>

If the condition holds True, the conditional


expression yields the value of expression1, otherwise,
it yields the value of expression2. For example, the
following piece of code

if password == 'magic':

message = ' Login Successful !!\n '

else:
message = ' Password mismatch !!\n '

may be replaced by

message = ' Login Successful !!\n ' if


password == 'magic' else ' Password
mismatch !!\n '

u se of con dition a l ex pr ession for pa ssw or d v a lida tion

When there is more than one way of doing a thing, one


should prefer the one which enhances the readability of
the program. As you might have noted that the use of an
if-else statement is more readable as compared to a
conditional expression. Although a conditional
expression happens to be more concise, we discourage
the use of conditional expressions for the beginners.

General Form of if-else Conditional Statement

The general forms of if-else statement is as follows:

sy n ta x of if-else con dition a l sta tem en t

if < condition >:

< Sequence S1 of statements to be


executed >

else:

< Sequence S2 of statements to be


executed >

Here, condition is a Boolean expression. If this


condition evaluates to True, then the sequence S1 of
statements is executed, else sequence of statements S2
gets executed. Subsequently, the control is transferred to
the statement following the if-else statement. The
execution of if-else statement is illustrated in Fig. 3.8.
Fig. 3.8 Flow dia g r a m of if-else str u ctu r e

flow dia g r a m of if-else con dition a l sta tem en t

In the next problem, we want to assign a grade to a


student on the basis of marks obtained as per the criteria
mentioned in Table 3.1.
T a bl e 3.1 Cr iter ia for a ssig n in g g r a des

con v er sion of g r a des to m a r ks

The script grade (Fig. 3.9) takes marks of a student as


input from the user and assigns a grade on the bases of
marks obtained using if-elif-else statement. In Fig.
3.10, we illustrate the if-elif-else statement with
the help of a flowchart.
Fig. 3.9 Pr og r a m to a ssig n g r a de on th e ba sis of m a r ks obta in ed
(grade.py)
Fig. 3.10 Flow dia g r a m of if-elif-else sta tem en t in th e
fu n ction assignGrade

con v er sion of m a r ks to g r a des

General Form of if-elif-else Conditional Statement

The general form of if-elif-else statement is as


follows:

if < condition1 >:

< Sequence S1 of statements to be


executed >
elif < condition2 >:

< Sequence S2 of statements to be


executed >

elif < condition3 >:

< Sequence S3 of statements to be


executed >

else:

< Sequence Sn of statements to be


executed >

sy n ta x of if-elif-else con dition a l sta tem en t

elif a n d else cla u ses a r e option a l in a con dition a l sta tem en t

In the above description, elif is an abbreviation used in


Python for else if. By now, it must be clear that the
clauses elif and else of the if statement are optional,
and that the sequence of statements defined under a
clause is executed in a sequence. As the physical
alignment of statements determines which statements
form a block of code, one needs to be very careful about
indentation while writing Python programs.

Nested if-elif-else Conditional Statement

Sometimes, we need a control structure within another


control structure. Such a mechanism is called nesting.
For example, the function maximum3 (Fig. 3.12) finds
the maximum of three numbers using nested structure.
Here, an if clause has been used within another if
clause. First, we test whether n1 is greater than n2. If so,
the condition n1 > n3 is evaluated, and if True, n1 is
declared as the maximum number. The other cases are
dealt with similarly. This is illustrated with the help of
flow diagram in Fig. 3.11.

Fig. 3.11 Flow dia g r a m of if sta tem en t in th e fu n ction maximum

to fin d m a x im u m of th r ee n u m ber s
Fig. 3.12 Pr og r a m to fin d th e m a x im u m of th r ee n u m ber s
(maximum.py)

On executing the script given in Fig. 3.12, Python


prompts the user to enter three numbers and responds
by displaying the maximum number.

>>>

Enter first number: 78

Enter second number: 65

Enter third number: 89


Maximum number is 89

We can simplify the above program using nested


function approach (Fig. 3.13). We define a function
max2 that takes two numbers as an input and computes
their maximum. Next, we make use of max2 to define
the function max3 that finds the maximum of three
numbers. We say that the function max2 is nested within
the function max3. The functions max2 and max3 are
known as inner function and outer function,
respectively.

n ested fu n ction a ppr oa ch to fin d m a x im u m of th r ee n u m ber s


Fig. 3.13 Pr og r a m to fin d m a x im u m of th r ee n u m ber s
(maximum3.py)

3.2 ITERATION (FOR AND WHILE STATEMENTS)

Suppose we wish to read and add 100 numbers. Using


the method discussed so far, we will have to include 100
statements for reading and an equal number of
statements for addition. If the numbers to be read and
added were 10,000 instead of 100, we can well imagine
the gigantic appearance of the program that would run
into well over a hundred pages. Surely, we cannot think
of doing that. The process of repetitive execution of a
statement or a sequence of statements is called a loop.
Using loops, we need to write only once the sequence of
statements to be repeatedly executed. Execution of a
sequence of statements in a loop is known as an iteration
of the loop.

loop: r epetitiv e ex ecu tion of in str u ction s

iter a tion of a loop

The for statement in Python provides a mechanism


to keep count of the number of times a sequence of
statements has been executed. Sometimes, we say that
the for statement loops over a sequence of statements
and as such is also called for loop. At times, there may
be a situation where the number of times, a sequence of
statements has to be processed is not known in advance,
but depends on the fulfillment of some condition. In
such situations, we use a while loop.

3.2.1 for Loop

The control statement for is used when we want to


execute a sequence of statements (indented to the right
of keyword for) a fixed number of times. Suppose, we
wish to find the sum of first few (say n) positive integers.
Further, assume that the user provides the value of n.
For this purpose, we need a counting mechanism to
count from 1 to n and keep adding the current value of
count to the old value of total (which is initially set to
zero). This is achieved using the control statement for
(Fig. 3.14).
Fig. 3.14 Pr og r a m to fin d su m of fir st n positiv e in teg er s
(sum.py)

for loop: u sed to ex ecu te a sequ en ce of in str u ction s a fix ed


n u m ber of tim es

On executing the script (Fig. 3.14), Python prompts


the user to enter the value of n and responds with the
sum of first n positive integers:

Enter number of terms: 5

Sum of first 5 positive integers: 15

In the function summation (script sum, Fig. 3.14), the


variable total is initialized to zero. Next, for loop is
executed. The function call range(1,n + 1) produces
a sequence of numbers from 1 to n. This sequence of
numbers is used to keep count of the iterations. In
general,

range(start, end, increment)


range fu n ction g en er a tes a sequ en ce of in teg er s

returns an object that produces a sequence of integers


from start up to end (but not including end) in steps
of increment. If the third argument is not specified, it
is assumed to be 1. If the first argument is also not
specified, it is assumed to be 0. Values of start, end,
and increment should be of type integer. Any other
type of value will result in error. Next, we give some
examples of the use of range function:

Function Sequence of values produced

range(1,11) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

range(11) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

range(1,11,2) 1, 3, 5, 7, 9

range(30, -4, 30, 27, 24, 21, 18, 15, 12, 9, 6,


-3) 3, 0, -3

In the script sum, the variable count takes a value from


the sequence 1, 2, …, n, one by one, and the
statement

total += count

is executed for every value of count. On completion of


the loop, the function summation returns the sum of
first n positive numbers stored in the variable total
(line 10). The value returned is displayed using print
function in line 21.

Next, we develop a program to read and add the


marks entered by the user in n subjects, and
subsequently use the total marks so obtained to compute
the overall percentage of marks (Fig. 3.15). The
number of subjects n is taken as the input from the user.
The variable totalMarks is initialized to zero in line 8
before the for loop. The sequence of statements at lines
11, 12, and 13 forms the body of the loop and is executed
n times, once for each value of i. We say that the loop
iterates for each value of i in the sequence 1, 2, …,
n. Once the execution of the loop completes,
percentage is computed.

Fig. 3.15 Pr og r a m to com pu te per cen ta g e (percentage.py)

On executing the script percentage (Fig. 3.15),


Python prompts the user to enter the number of subjects
and the marks, and responds by displaying the
percentage.
Number of subjects: 5

Enter marks

Subject 1: 75

Subject 2: 80

Subject 3: 85

Subject 4: 90

Subject 5: 95

Percentage is: 85.0

General Format of for Statement

The general form of for structure is as follows:

for variable in sequence:

<block S of statements>

for loop sy n ta x

Here, variable refers to the control variable used for


counting, which is set in the beginning to the first value
in a sequence of values (e.g., range(10), 'abcdef').
Subsequently, in each iteration of the loop, the value of
the control variable is replaced by the successor value
in the sequence. The process of executing the sequence S
and replacing the current value of control variable by its
successor in sequence is repeated until the entire
sequence is exhaused.

Next, we wish to develop a function to print a


multiplication table for a given number. For example,
the multiplication table for 4 should appear as follows:

4 * 1 = 4

4 * 2 = 8
4 * 3 = 12

4 * 4 = 16

4 * 5 = 20

4 * 6 = 24

4 * 7 = 28

4 * 8 = 32

4 * 9 = 36

4 * 10 = 40

By now you must have noted that Python output is


aligned on the left-hand side, for example:

>>> print(7)

>>> print(100)

100

By defa u lt, Py th on a lig n s th e ou tpu t on LHS

However, the numeric output looks good, if aligned on


the right-hand side. For this purpose, we need to specify
how many places we would like to reserve for printing a
value, for example, the format string '%5d' may be
used to indicate that at least five positions are to be
reserved for an integer value.

>>> '%5d'% 45

' 45'

>>> print('%5d'% 45)

45
>>> print('%5d'% 12345)

12345

for m a tted ou tpu t u sin g for m a t str in g

To develop multiplication table for a given number, we


would require two parameters: number (say, num)
whose multiplication table is to be printed, and the
number of multiples (say, nMultiples) of the number.
In this exercise, we need to print nMultiples (= 10).
The following code segment does this job (Fig. 3.16). In
Fig. 3.17, we present a complete script to print the
multiplication table of a given number.

Fig. 3.16 Loop for pr in tin g m u ltiplica tion ta ble


Fig. 3.17 Pr og r a m to pr in t m u ltiplica tion ta ble of a n u m ber

3.2.2 while Loop

The while loop is used for executing a sequence of


statements again and again on the basis of some test
condition. If the test condition holds True, the body of
the loop is executed, otherwise the control moves to the
statement immediately following the while loop.
Suppose, we wish to find the sum of all the numbers
entered by a user until a null string (empty string: '') is
entered as input. As we do not know in advance the
count of numbers that the user will enter before entering
a null string, we make use of a while loop in the script
sumNumbers (Fig. 3.18). Every time the user enters a
string, its integer value is added to the old value of
total (initialized to zero before the beginning of the
loop). The process continues until the user enters a null
string as input. On encountering a null string, the test
condition in line 10 becomes False, the while loop
terminates, and the control moves to line 13, where we
display the value of total.

while loop: to r epea t ex ecu tion of a n in str u ction sequ en ce a s


lon g a s a con dition h olds

em pty str in g is a lso kn ow n a s n u ll str in g

Fig. 3.18 Pr og r a m to com pu te su m of n u m ber s (sumNumbers.py)


On executing the script sumNumbers (Fig. 3.18),
Python prompts for numbers until the user enters null
string as an input.

>>>

Enter a number: 2

Enter a number: 18

Enter a number: 15

Enter a number: 15

Enter a number:

Sum of all input numbers is 50

Next, we show the working of the while loop in the


context of the foregoing example (Fig. 3.19).

Fig 3.19 Flow dia g r a m of if sta tem en t in scr ipt sumNumbers


General Format of while Statement

The general form of while statement is as follows:

while <test condition>:

<Sequence of statements S>

sy n ta x for while loop

Here, test condition is a Boolean expression, which


is evaluated at the beginning of the loop. If the test
condition evaluates to True, the sequence S of
statements is executed, and the control moves to the
evaluation of test condition once again. The process
is repeated until test condition evaluates to False.
The execution of the while loop is illustrated in Fig.
3.20.

Fig. 3.20 Flow dia g r a m of while str u ctu r e

flow dia g r a m of while loop

Infinite Loops

Sometimes we want a while loop to continue


indefinitely until an enabling event takes place, for
example, the screen of a laptop may remain off until a
key is pressed. For this purpose, we make use of a while
loop based on a condition that always evaluates to
True. Such a loop is known as an infinite loop, for
example:

in fin ite loop: loop w ith a con dition w h ich a lw a y s ev a lu a tes to


True

import time

while True:

try:

print('Loop processing....')

print('Use ctrl+c to break')

time.sleep(1)

except KeyboardInterrupt:

print('User interrupted the loop...


exiting...')

break

in th e a bsen ce of a key boa r d in ter r u pt, th e while loop w ill


ex ecu te in fin itely .

3.2.3 while Statement vs. for Statement

Having learned the use of while statement, let us use a


while statement to rewrite the following piece of code:

for count in range(1, n + 1):

total += count

The revised code is given below:

count = 1
while count < n+1:

total += count

count += 1

n ot a w ise idea : r ew r itin g for loop u sin g while

Note that for computing the sum of first few natural


numbers, the use of for loop is more elegant and easy
as compared to the while loop. Out of several control
structures which may be used at a place, it is the
discretion of the programmer to choose the simple and
elegant one.

3.2.4 Example: To Print Some Pictures

Next, we develop a program that prints a right triangle


or an inverted triangle (shown in Fig. 3.21) depending on
user's choice. Further, the number of rows in the triangle
is also to be taken as input from the user. Let us examine
the script triangle (Fig. 3.22) that serves this purpose.
In this program, the user needs to enter his/her choice of
figure 1 or 2 depending on whether he or she wants to
print a right triangle or an inverted triangle. The
assertion in line 11 is used to check whether the input
choice is a valid choice, i.e., 1 or 2. Subsequently in line
12, the number of rows in the figure is taken as input.
Next, we develop the functions to print right triangle and
inverted triangle. To print a right triangle having a
number of rows (equal to nRows), we have to generate
as many rows of output. Outline of the Python code for
this purpose is given below:

for i in range(1, nRows + 1):

{Generate one row of output for right


triangle}
Fig. 3.21 (a ) Rig h t tr ia n g le a n d (b) in v er ted tr ia n g le
Fig 3.22 main fu n ction to pr in t r ig h t tr ia n g le a n d in v er ted
tr ia n g le (triangle.py)

We note that in the first row, one '*' is to be output, in


the second row two '*'s are to be output, and so on. So,
in general, the ith row will have i '*'s. With these
remarks, we modify the outline of the code given above:

for i in range(1, nRows + 1):

print('*' * i)

for loop for pr in tin g a r ig h t tr ia n g le

Similarly, to print an inverted triangle comprising the


number of rows (equal to nRows), we have to generate
as many rows of output. The Python code may be
outlined as follows:

for i in range(0, nRows):

{Generate one row of output for inverted


triangle}

Let nSpaces denotes the number of leading spaces in a


row. We note that there are no leading spaces in the first
row. So, we set

nSpaces = 0

For every subsequent row, the number of leading spaces


nSpaces increases by one in each row. Next, let
nStars denote the number of stars to be printed in a
row. We note that in the first row, the number of stars to
be printed is 2 * nRows – 1. So, we set

nStars = 2 * nRows - 1
We also note that the number of stars to be printed
decreases by two for every subsequent row. With these
remarks, we modify the outline of the above piece of
code as follows:

nSpaces = 0

nStars = 2 * nRows - 1

for i in range(1, nRows+1):

print(' ' * nSpaces + '*' * nStars)

nStars -= 2

nSpaces += 1

for loop for pr in tin g in v er ted tr ia n g le

In light of the above discussion, we give the complete


script in Fig. 3.23:
Fig. 3.23 Pr og r a m to pr in t r ig h t tr ia n g le a n d in v er ted tr ia n g le
(triangle.py)

In the above script, the figures right triangle and


inverted triangle comprise '*' only. However, we may
make the above program more general by printing the
figures made using a character provided by the user. For
this purpose, the function rightTriangle may be
modified as follows (Fig. 3.24):
Fig. 3.24 Fu n ction rightTriangle

The reader is encouraged to modify the


invertedTriangle and main functions in a similar
manner and experiment with different figures.

3.2.5 Nested Loops

Suppose we wish to develop a function to print


multiplication tables, one for each of the first few (say
10), natural numbers. Further, in the table, multiples of
a number are to be arranged vertically in a column. The
output should appear as shown in Fig. 3.25.

n ested loop: a loop in side a n oth er loop

n estin g m a y con tin u e u p to a n y lev el


Fig. 3.25 Mu ltiplica tion ta ble

In order that the output of the program appears


nicely, we would like that each number be printed using
at least the number of positions specified in the format
string. This may be done as follows (5 digits are reserved
for each number which is left padded with spaces):

>>> for i in range(1,4):

print('{0: >5}'.format(i*9))

18

27

by defa u lt, print fu n ction in ser ts n ew lin e a fter pr in tin g a


lin e

Also, we would like that the output of several calls to


print function may be printed on the same line. For
this purpose, we we need to use empty string ('') in
place of the default newline. This can be achieved using
keyword argument end. For example,

>>> for i in range(1,4):

print('{0: >5}'.format(i*9), end = '')

9 18 27

u sin g em pty str in g a s th e ter m in a tor in print fu n ction by


ch a n g in g th e defa u lt v a lu e of key w or d a r g u m en t end

Indeed, the code segment

>>> for i in range(1,4):

print('{0: >5}'.format(i*9))

is equivalent to:

>>> for i in range(1,4):

print('{0: >5}'.format(i*9), end = '\n')

To develop such a function, we would require two


parameters: the number of tables, (say, nTables) to be
printed, and the number of multiples (say,
nMultiples) of each number to be printed. The
skeleton of a function for this purpose is given in Fig.
3.26.
Fig. 3.26 Skeleton of fu n ction printTable

To print the multiplication table, we need to print


nMultiples (=10) rows, one for each multiple of the
number num. Skeleton of the code segment for printing
multiplication table is given below:

for multiple in range(1, nMultiples + 1):

# Print a row of multiples of each


number num

Next, to print one row of a multiple of all numbers i.e.


multiples of num in the range (1, nTables+1), we
may iterate over num using a for loop as follows:

for num in range(1, nTables + 1):

print('{0: >2}'.format(num),'*',\

'{0: >2}'.format(multiple),'=', \
'{0: >3}'.format(num*multiple),'\t',

end = '')

print()

for loop to pr in t on e r ow of m u ltiples of n u m ber s

Note the use of the keyword argument end in the print


function under the for loop, as we want the output of
the entire loop to appear on the same line. Finally, when
the for loop completes, invoking the print function
moves the control to the next line for printing the next
row of the multiplication table. The character backslash
(\) used at the end of second and third line is a line
continuation character that can be used for wrapping
long lines i.e. if we wish to extend a statement over
multiple lines. The complete script to print multiplication
table is shown in Fig. 3.27.

lin e con tin u a tion ch a r a cter ba cksla sh (\)


Fig. 3.27 Pr og r a m to pr in t m u ltiplica tion ta ble (table.py)

The control structures for and while may be nested


up to any level as required. For example, see Fig. 3.28.
Fig. 3.28 Ex a m ples of n ested con tr ol str u ctu r es

3.2.6 break, continue, and pass Statements

Sometimes, we need to alter the normal flow of a loop in


response to the occurrence of an event. In such a
situation, we may either want to exit the loop or
continue with the next iteration of the loop skipping the
remaining statements in the loop. The break statement
enables us to exit the loop and transfer the control to the
statement following the body of the loop. The continue
statement is used to transfer the control to next iteration
of the loop. When the continue statement is executed,
the code that occurs in the body of the loop after the
continue statement is skipped.

u se break sta tem en t to ex it th e loop

u se continue sta tem en t to tr a n sfer th e con tr ol to n ex t


iter a tion of th e loop

To illustrate the use of break statement, we examine


the function printSquares (Fig. 3.29) intended to
print squares of the integers entered by the user until a
null string is encountered. This function uses a while
loop. The condition in the while loop has been set as
True. If the user enters a null string, the control exits
the loop and moves to the statement following the
while loop, i.e. line 14. Thus, the function terminates
with the message 'End of input!!'. In the other
case, when the user input is not null, the input string is
converted to an integer (line 12) and the square of the
integer so obtained is printed (line 13).
Fig. 3.29 Fu n ction to pr in t squ a r es of positiv e n u m ber s
(square.py)

In the script percentage1 (Fig. 3.30), we wish to


compute the overall percentage of marks obtained by a
student. As the number of subjects on which
examination was conducted is not known beforehand,
we use a while loop. When the while loop is executed,
the user is prompted to enter the marks obtained in
different subjects. If the user responds with a null string,
the break statement is executed which results in
termination of the loop, and the control moves to line 19
for computation of percentage. However, if marks
entered by the user are outside the range [0,100], the
user is prompted again to enter marks. Thus in the case
of invalid marks, the use of continue statement makes
it possible to skip the statements (lines 17 and 18) that
appear after the continue statement in the while loop
and continue with the next iteration of the loop for
taking the next input from the user. Sample output on
executing the script percentage is given below:
Fig. 3.30 Pr og r a m to pr in t per cen ta g e a n d tota l m a r ks
(percentage1.py)

Marks for subject 1: 60

Marks for subject 2: 80

Marks for subject 3: 280

INVALID MARKS !!

Marks for subject 3: 70

Marks for subject 4: 800

INVALID MARKS !!

Marks for subject 4: 80

Marks for subject 5:

Total marks: 290

Number of Subjects: 4

Percentage: 72.5

Sometimes we may want to leave out the details of the


computation in a function body, to be filled in at a later
point in time. The pass statement lets the program go
through this piece of code without executing any code. It
is just like a null operation. Often pass statement is used
as a reminder for some code, to be filled in later. For
example, let us think of a merchant wanting to sell
clothes, who is thinking of allowing some discounts, but
not as of now. So, as of now, he does not want his IT
team to develop the code for discounting. In the script
sellingPrice, we develop the function
sellingPrice (Fig. 3.31) that invokes the function
discount. As the code for the function discount just
comprises a pass statement, it produces None as the
return value. Accordingly, the function sellingPrice
ignores the value None returned by the function
discount (lines 16–17) and returns price (that was
passed on to it as an argument) as the selling price.

pass sta tem en t: ex ecu te n o code


Fig. 3.31 Pr og r a m to com pu te sellin g pr ice (sellingPrice.py)

3.2.7 Example: To Compute sin(x)

The value of sin (x) may be computed as the sum of the


following series:

In the above series, the first term is x/1. The second


term
2
can be computed by multiplying the first term by -
x /(2*3). Similarly, the third term in the series can be
computed
2
by multiplying the second term by -
x /(4*5), and so on. In general, we can obtain a new
term
2
of the series by multiplying the previous term by -
x and dividing this product by the product of the next
two terms in the sequence 1, 2, 3, 4, 5, 6, …. Thus, we
can write first few terms of the series as follows:

x/1
2 3
x/1*(-x )/(2*3) = -x /3!
3 2 5
-x /3!*(-x )/(4*5) = x /5!

2
2
To code the above idea, we set multBy equal to -x and
initialize nxtInSeq (used to compute divBy) equal to
2. We compute divBy = nxtInSeq*(nxtInSeq+1).
Every time we compute a new term, we increment the
value of nxtInSeq by 2. Table 3.1 illustrates these
computations:

T a bl e 3.1 Sin e ter m s com pu ta tion s

Since the given series is an infinite one, and we can do


only finite computations on a computer, we need to
decide when to stop. We keep on adding more terms
until the absolute value of term becomes smaller than a
predefined value, say, epsilon. In Fig. 3.32, we present
the complete function mySine that computes sine(x)
as sum of the above series.
Fig. 3.32 Fu n ction mySine (sine.py)

3.2.8 else Statement

The else clause is useful in such situations where we


may want to perform a task only on successful execution
of a for loop or a while loop. The statements specified
in else clause are executed on normal termination of
the loop. However, if the loop is terminated forcibly
using break statement, then the else clause is skipped.
We demonstrate the use of the else clause for testing
whether a given number is prime. Recall that a number
is said to be prime if and only if it has no divisor other
than one and itself. Given a number n, we need to check
for each number in the range(2, n)whether it is a
divisor of n. If the entire sequence is exhausted and no
divisor of n is found, it is a prime number. In the
function prime (Fig. 3.33) if n is 1, flag is set equal to
False indicating that the number n is not prime. Inside
the for loop, if we find a divisor i of n in the range(2,
n), the condition n % i == 0 becomes True,
indicating that the number n is not a prime number. So
we set flag equal to False and exit the for loop.
However, if the for loop executes smoothly (not on the
execution of break statement), flag is set equal to
True indicating that the number n is prime. Finally,
flag is returned as the value of the function.

else cla u se: to ex ecu te a ta sk on ly on su ccessfu l com pletion of


th e loop
Fig. 3.33 Pr og r a m to ch eck if a n u m ber is pr im e n u m ber or n ot
(prime.py)
SUMMARY

1 . Con tr ol sta tem en ts (a lso ca lled con tr ol str u ctu r es) a r e


u sed to con tr ol th e flow of pr og r a m ex ecu tion by
a llow in g n on -sequ en tia l or r epetitiv e ex ecu tion of
in str u ction s. Py th on su ppor ts if, for, a n d while
con tr ol str u ctu r es. In a con tr ol sta tem en t, th e Py th on
code follow in g th e colon (:) is in den ted.
2 . if sta tem en t a llow s n on -sequ en tia l ex ecu tion
depen din g u pon w h eth er th e condition is sa tisfied.
Th e g en er a l for m of if con dition a l sta tem en t is a s
follow s:

if < condition >:


< Sequence S of statements to be executed >

Her e, condition is a Boolea n ex pr ession w h ich is


ev a lu a ted a t th e beg in n in g of th e if sta tem en t. If
condition ev a lu a tes to True, th en th e sequ en ce S of
sta tem en ts is ex ecu ted, a n d th e con tr ol is tr a n sfer r ed to
th e sta tem en t follow in g if sta tem en t. How ev er , if
condition ev a lu a tes to False, th en th e sequ en ce S of
sta tem en ts is ig n or ed, a n d th e con tr ol is im m edia tely
tr a n sfer r ed to th e sta tem en t follow in g if sta tem en t.
Th e g en er a l for m of if-else sta tem en t is a s follow s:

if < condition >:


< Sequence S1 of statements to be executed >
else:
< Sequence S2 of statements to be executed >

Her e, condition is a Boolea n ex pr ession . If condition


ev a lu a tes to True, th en th e sequ en ce S1 of sta tem en ts
g ets ex ecu ted, oth er w ise, th e sequ en ce S2 of sta tem en ts
g ets ex ecu ted.
Th e g en er a l for m of if-elif-else sta tem en t is a s
follow s:

if < condition1 >:


< Sequence S1 of statements to be executed >
elif < condition2 >:
< Sequence S2 of statements to be executed >
elif < condition3 >:
< Sequence S3 of statements to be executed >
.
.
.
else:
< Sequence Sn of statements to be executed >

Th e cla u ses elif a n d else of if con tr ol str u ctu r e a r e


option a l.
3 . Wh en a con tr ol str u ctu r e is specified w ith in a n oth er
con tr ol str u ctu r e, it is ca lled n estin g of con tr ol
str u ctu r es.
4 . Th e pr ocess of r epetitiv e ex ecu tion of a sta tem en t or a
sequ en ce of sta tem en ts is ca lled a loop. Ex ecu tion of a
sequ en ce of sta tem en ts in a loop is kn ow n a s a n
iter a tion of th e loop.
5 . Th e con tr ol sta tem en t for is u sed w h en w e w a n t to
ex ecu te a sequ en ce of sta tem en ts a fix ed n u m ber of
tim es. Th e g en er a l for m of for sta tem en t is a s follow s:

for variable in sequence:


{Sequence S of statements}

Her e, variable r efer s to th e con tr ol v a r ia ble. Th e


sequ en ce S of sta tem en ts is ex ecu ted for ea ch v a lu e in
sequence.
6 . Th e fu n ction ca ll range(1,n + 1) g en er a tes a
sequ en ce of n u m ber s fr om 1 to n. In g en er a l,
range(start, end, increment) pr odu ces a sequ en ce of
n u m ber s fr om start u p to end (bu t n ot in clu din g end)
in steps of increment. If th ir d a r g u m en t is n ot
specified, increment is a ssu m ed to be 1 .
7 . A while loop is u sed for iter a tiv ely ex ecu tin g a
sequ en ce of sta tem en ts a g a in a n d a g a in on th e ba sis of
a test-condition. Th e g en er a l for m of a while loop is
a s follow s:

while <test-condition>:
<Sequence S of statements>

Her e, test-condition is a Boolea n ex pr ession w h ich is


ev a lu a ted a t th e beg in n in g of th e loop. If th e test-
condition ev a lu a tes to True, th e con tr ol flow s th r ou g h
th e Sequence S of statements (i.e., th e body of th e
loop), oth er w ise th e con tr ol m ov es to th e sta tem en t
im m edia tely follow in g th e while loop. On ex ecu tion of
th e body of th e loop, th e test-condition is ev a lu a ted
a g a in , a n d th e pr ocess of ev a lu a tin g th e test-
condition a n d ex ecu tin g th e body of th e loop is
con tin u ed u n til th e test-condition ev a lu a tes to
False.
8. Th e break sta tem en t is u sed for ex itin g fr om th e loop to
th e sta tem en t follow in g th e body of th e loop.
9. Th e continue sta tem en t is u sed to tr a n sfer th e con tr ol
to n ex t iter a tion of th e loop w ith ou t ex ecu tin g r est of
th e body of loop.
1 0. Th e pass sta tem en t lets th e pr og r a m g o th r ou g h th is
piece of code w ith ou t per for m in g a n y a ction .
11. Th e else cla u se ca n be u sed w ith for a n d while loop.
Sta tem en ts specified in else cla u se w ill be ex ecu ted on
sm ooth ter m in a tion of th e loop. How ev er , if th e loop is
ter m in a ted u sin g break sta tem en t, th en th e else
cla u se is skipped.

EXERCISES

1 . Wr ite a n a ssig n m en t sta tem en t u sin g a sin g le


con dition a l ex pr ession for th e follow in g if-else code:
if marks >=70:
remarks = 'good'
else:
remarks = 'Average'
2 . Stu dy th e pr og r a m seg m en ts g iv en below . In ea ch ca se,
g iv e th e ou tpu t pr odu ced, if a n y .
1 . total = 0
count = 20
while count > 5:
total += count
count -= 1
print(total)
2 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, i+1):
total += 1
print(total)
3 . total = 0
N = 10
for i in range(1, N+1):
for j in range(1, N+1):
total += 1
print(total)
4 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, i+1):
total += 1
total -=1
print(total)
5 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, N+1):
total += i
print(total)
6 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, i+1):
total += j
print(total)
7 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, N+1):
total += i + j
print(total)
8 . total = 0
N = 5
for i in range(1, N+1):
for j in range(1, i+1):
for k in range(1, j+1):
total += 1
print(total)
9 . number = 72958476
a, b = 0, 0
while (number > 0):
digit = number % 10
if (digit % 2!= 0):
a += digit
else:
b += digit
number /= 10
print(a, b)
3 . Wr ite a fu n ction to deter m in e w h eth er a g iv en n a tu r a l
n u m ber is a per fect n u m ber . A n a tu r a l n u m ber is sa id
to be a per fect n u m ber if it is th e su m of its div isor s. For
ex a m ple, 6 is a per fect n u m ber beca u se 6=1+2+3, bu t
15 is n ot a per fect n u m ber beca u se 15≠1+3+5.
4 . Wr ite a fu n ction th a t ta kes tw o n u m ber s a s in pu t
pa r a m eter s a n d r etu r n s th eir lea st com m on m u ltiple.
5 . Wr ite a fu n ction th a t ta kes tw o n u m ber s a s in pu t
pa r a m eter s a n d r etu r n s th eir g r ea test com m on
div isor .
6 . Wr ite a fu n ction th a t a ccepts a s a n in pu t pa r a m eter
th e n u m ber of r ow s to be pr in ted a n d pr in ts a fig u r e
like:
7 . Wr ite a fu n ction th a t fin ds th e su m of th e n ter m s of
th e follow in
2 g ser ies: 4 6 n
1 . 1 – x /2! + x /4! – x /6! + … x /n!

2.

8 . Wr ite a fu n ction th a t r etu r n s True or False depen din g


on w h eth er th e g iv en n u m ber is a pa lin dr om e.
9 . Wr ite a fu n ction th a t r etu r n s th e su m of dig its of a
n u m ber , pa ssed to it a s a n a r g u m en t.
1 0. Wr ite a pr og r a m th a t pr in ts A r m str on g n u m ber s in
th e r a n g e 1 to 1 000. A n A r m str on g n u m ber is a
n u m ber w h ose su m of th e cu bes of th e dig 3 its 3
is equ3 a l to
th e n u m ber itself. For ex a m ple, 3 7 0 = 3 + 7 + 0 .
1 1 . Wr ite a fu n ction th a t ta kes tw o n u m ber s a s in pu t
pa r a m eter s a n d r etu r n s Tr u e or Fa lse depen din g on
w h eth er th ey a r e co-pr im es. Tw o n u m ber s a r e sa id to
be co-pr im e if th ey do n ot h a v e a n y com m on div isor
oth er th a n on e.
1 2 . Wr ite a fu n ction sqr t th a t ta kes a n on -n eg a tiv e
n u m ber a s a n in pu t a n d com pu tes its squ a r e r oot. We
ca n solv e th is pr oblem iter a tiv ely . You w ill r eca ll fr om
h ig h sch ool m a th em a tics th a t to fin d th e squ a r e r oot of
a 2n u m ber , sa y 2, w e n eed to solv e th e equ a tion f(x) =
x – 2 = 0. To beg in w ith , ch oose tw o n u m ber s a a n d b so
th2 a t f(a)<0 a n d f(b)>0. Now , for th e equ a tion f(x) =
x – 2 = 0, f(1)<0 a n d f(2)>0. So, th e r oot of th e
equ a tion m u st lie in th e in ter v a l [a,b] (i.e. [1,2]). We
fin d th e m idpoin t, sa y , mid of th e in ter v a l [a,b]. If
f(a)<0 a n d f(mid)>0, w e kn ow th a t th e r oot of th e
equ a tion f(x)=0 lies in th e in ter v a l [a,mid]. How ev er ,
in th e oth er ca se, (f(mid)<0 a n d f(mid)>0), th e r oot of
th e equ a tion f(x)=0 m u st lie in th e in ter v a l [mid,b].
Th u s, for th e n ex t iter a tion , w e h a v e r edu ced th e
sea r ch in ter v a l for th e r oot of th e equ a tion to h a lf, i.e.
fr om [a,b] to [a,mid] or [mid,b]. Pr oceedin g in th is
w a y , w e fin d a g ood a ppr ox im a tion to th e r oot of th e
equ a tion w h en th e len g th of th e sea r ch in ter v a l
becom es su fficien tly sm a ll, sa y , 0.01. Th e follow in g
ta ble depicts th e steps for com pu tin g squ a r e r oot
a ppr ox im a tion for th e n u m ber 2.
a b mid = (a + b)/2 f(a) f(b) f(mid)

1 2 1.5 −1 2 0.25

1 1.5 1.25 −1 0.25 −0.4375

1.25 1.5 1.375 −0.4375 0.25 −0.1093

1.375 1.5 1.4375 −0.1093 0.25 0.0664

1.375 1.4375 1.4062 −0.1093 0.0664 −0.0226

1.4062 1.4375 1.4218 −0.0226 0.0664 0.0215

1.4062 1.4218 1.4140 −0.0226 0.0215 −0.0006

1.4140 1.4218 – −0.0006 0.0215 –

1 3 . Wr ite a fu n ction to m u ltiply tw o n on -n eg a tiv e


n u m ber s by r epea ted a ddition , for ex a m ple, 7*5 = 7 +
7 + 7+ 7 + 7.
CHAPTER 4
DEBUGGING

CHAPTER OUTLINE
4 .1 Testin g

4 .2 Debu g g in g

When a program fails to yield the desirable result, we say


that it contains a bug. The bug could be an error such as
division by zero, invalid type conversion, using a variable
not defined, wrong initialization, or some other
unintended operation being performed. The process of
discovering the bugs and making the program bug-free
is called debugging. In this chapter, we discuss some
debugging techniques.

debu g g in g : m a kin g th e pr og r a m er r or fr ee

4.1 TESTING

Program testing aims to expose the presence of bugs in


the programs. To find the bugs in a program, we test it
on various inputs. We correct the errors found in this
process and feel confident that the program will run
smoothly.

An Example: Finding Maximum of Three Numbers

Let us examine the script max3 (Fig. 4.1) intended to


find the maximum of three numbers. The function max3
is intended to return the maximum of three numbers.
Since the input numbers can be either positive or
negative, we may have test cases containing various
combinations of positive and negative numbers. Further,
given a set of numbers, we will need to test the code for
all possible 6 (= 3!) permutations of three numbers as
enumerated below:
1. n1 > n2 a n d n2 > n3 : Ma x im u m : n1
2. n1 > n2 a n d n2 < n3 a n d n1 > n3 : Ma x im u m : n1
3. n1 > n2 a n d n2 < n3 a n d n1 < n3 : Ma x im u m : n3
4. n1 < n2 a n d n2 > n3 a n d n1 > n3 : Ma x im u m : n2
5. n1 < n2 a n d n2 > n3 a n d n1 < n3 : Ma x im u m : n2
6. n1 < n2 a n d n2 < n3 : Ma x im u m : n3

test ca ses for fin din g m a x im u m of th r ee n u m ber s

We test this script on various permutations of the inputs:


10, 20, 30, namely:

1. 30, 20, 10
2. 30, 10, 20
3. 20, 10, 30
4. 20, 30, 10
5. 10, 30, 20
6. 10, 20, 30
Fig. 4.1 Pr og r a m to fin d th e m a x im u m of th r ee n u m ber s
(max3.py)

It so turns out that the result obtained is correct for all


input permutations, except for the permutations 20,
10, and 30:

in cor r ect ou tpu t in dica tes bu g in th e pr og r a m

>>>

Enter first number: 20

Enter second number: 10

Enter third number: 30

Maximum number is 0

Thus, a bug persists in the program that needs to be


detected and removed.

4.2 DEBUGGING
There are various Python debugging tools such as pdb,
pudb, pydb, and pydbgr. In this section, we will discuss
Python's built-in debugger pdb, which is an interactive
tool that helps in examining the code execution step by
step. It allows us to stop the execution of a program at a
chosen instruction called a break point, and evaluate the
various expressions in the current context. The debugger
also allows us to examine the current vicinity of the
code, as well as the status of various objects in the
current function being executed which collectively
constitute the stack frame corresponding to that
function.

pdb: py th on debu g g er

In order to debug a program in Python shell, we need


to import the module pdb as well as the script to be
debugged.

>>> import pdb

>>> import max3

>>> pdb.run('max3.main()')

> <string>(1)<module>()->None

(Pdb)

im por tin g pdb m odu le

(pdb): pr om pt to in dica te th a t pr og r a m is ex ecu tin g in


debu g g in g m odu le

Python debugger uses the prompt (Pdb) to indicate that


the program is executing in the debugging mode.
Another way to execute a program in debugging mode is
by including the following two lines in the script:

import pdb
pdb.set_trace()

Note that including above two lines at the beginning of


the program in Fig. 4.1 will increase every line number
by two. By invoking the function set_trace() at the
very beginning, the program would run in debugging
mode right from the first instruction to be executed.
However, since we know that the bug exists in the
function max3, we may invoke set_trace() within
the function body. Before proceeding further, let us have
a look at debugging commands (Table 4.1).

in v oke th e fu n ction set_trace() a t r ig h t pla ce

T a bl e 4.1 Debu g g in g com m a n ds


com m a n ds for debu g g in g

Execution of the program in Fig. 4.1 in debugging mode


for the inputs 20, 10, and 30 is shown in Figs. 4.2 (a),
(b1), and (b2).
Fig. 4.2(a ) Ex ecu tion of pr og r a m max3.py

In Fig. 4.2 (a), line 2 (beginning with greater than


sign) shows the script being executed. Line 3 begins with
an arrow and marks the next line to be executed. Now,
Python enters into debugging mode (line 4), and we see
the Pdb prompt. Command h displays all the available
commands (lines 4–20). Command h s displays the
description of the step command (lines 24–28).
Command w has been used to inspect the current
position in the stack frame and it displays the stack trace
with the statement to be executed next at the bottom
(lines 29–38). Command l (line 39) lists 11 lines in the
vicinity of the current statement (lines 40–50). Next, to
execute lines of code, we use s command. Execution of s
command in line 51 yields the definition of function
max3 for future use. Similarly, execution of s command
in line 54 yields the definition of function main for
future use. Now, line 56 shows that the step to be
executed next is the if statement in the script. On
execution of s command (line 57), the conditional
expression yields True, and the control moves to the
next statement that invokes the function main (line 59).
Execution of s command (line 60) moves the control to
the beginning of the function main (line 63):
h: h elp on a debu g g in g com m a n d

w: deter m in e cu r r en t position in th e sta ck fr a m e

l: displa y 1 1 lin es in th e v icin ity of th e cu r r en t lin e of code

s: ex ecu te th e cu r r en t sta tem en t a n d m ov e th e con tr ol to th e


n ex t sta tem en t (possibly in th e fu n ction bein g in v oked)

def main():

Now execution of s command moves the control to the


next statement (line 66).

n1 = int(input('Enter first number: '))

At this stage, when s command is executed (line 67), the


control steps into the function input. But we are not
interested in the detailed execution of this function.
Instead, we would like to execute the function input as
a single unit. So, we need to move one level up in the
stack frame. For this purpose, we execute the command
u (line 72). Subsequently, we execute command n to
execute the current line as a single unit. Thus, user
inputs are entered on the execution of n commands
(lines 75–86). At this stage, we display (n1, n2, n3)
(lines 87–88). As we move to the execution of the
function max3, we show the details in a separate figure
(Fig. 4.2 (b1)).

u: m ov e on e lev el u p in th e sta ck fr a m e

n: ex ecu te th e cu r r en t sta tem en t/fu n ction com pletely a n d


m ov e th e con tr ol to th e n ex t sta tem en t
Fig 4 2 (b1) Ex ecu tion of pr og r a m m a x 3 py
Fig. 4.2 (b1) Ex ecu tion of pr og r a m m a x 3 .py

In Fig. 4.2 (b1), using l command in line 1, we inspect


the next statement to be executed. The arrow in line 7
marks the next line to be executed in the code, i.e. line
28. To completely execute the function max3 with the
input numbers, we use the command n. Now, the
control moves to line 29 in the script. On executing the
command n once more, the value of maximum is
displayed which being 0 (line 25) is incorrect. Note that
main function is now completely executed and the
control returns to the point following line 32 in the script
which invoked the function main. Now we have
reached the end of the script as indicated by the response
of the debugger:

f:\pythoncode\ch04\max3.py(32)<module>()-
>None

Since there are no further statements to be executed, we


use q command to quit from the debugger.

q: qu it th e debu g g er

Although we know that a bug exists in the function


max3, we have still not found it. To find the bug, we
need to step into the function max3 instead of executing
it completely in one go using command n. This has been
shown in Fig. 4.2 (b2). At line 13, on the execution of the
command s, the control transfers to the statement:

def max3(n1, n2, n3):

On executing command s once again, the arguments


are passed to the function parameters and the control
moves to the statement maxNumber = 0 (line 19). We
verify the argument values passed from main function
using the command a (line 20), which displays the
following output:

n1 = 20

n2 = 10
n3 = 30

a: pr in t a r g u m en ts a n d th eir v a lu es for cu r r en t fu n ction

We then use command s to execute the current


statement that assigns value 0 to variable maxNumber
and the control steps to the next line (conditional
statement) in execution. By default, if no command is
specified, and enter key is pressed, pdb repeats execution
of the most recent pdb command i.e. command s in this
case (line 27). Since condition n1 > n2 yields True,
control is transferred to statement if n1 > n3:.
However, since the condition n1 > n3 turned out to be
False, the control is transferred to return statement.
This reminds us that we need to include an else clause
associated with the statement if n1 > n3: which
assigns n3 to variable maxNumber if the condition n1 >
n3 yields False. Anyway, let us complete the execution
of the code as it would illustrate some more points. Now,
the execution of s command brings the control back to
the main function. Finally, the value of maxNumber is
printed (lines 43) on using next command n. We exit out
of the debugging mode by using command quit (line
51).
Fig. 4.2 (b2) Ex ecu tion of pr og r a m m a x 3 .py

Often it is convenient to set some breakpoints and


execute the code as usual up to a breakpoint. In the
example at hand, we set the breakpoint using the
command b max3. Using the command c, execution
of the code continues until the breakpoint (function max)
is reached (Fig. 4.3). Now the debugging process can be
continued as before.

b: set th e br ea kpoin t

c: con tin u e th e ex ecu tion till th e br ea kpoin t


Fig. 4.3 Ex ecu tion of pr og r a m maximum.py

SUMMARY

1 . Debu g g in g is th e pr ocess of ex a m in in g th e sou r ce code


fr om th e poin t of deter m in in g bu g s a n d elim in a tin g
th em to m a ke th e pr og r a m bu g -fr ee.
2 . Py th on debu g g er pdb is a n in ter a ctiv e debu g g er for
debu g g in g Py th on pr og r a m s. Th e m odu le pdb con ta in s
th e cla ss pdb. Th e debu g g er h elps in debu g g in g th e
code step by step, a llow s settin g of br ea kpoin ts,
pr in tin g som e lin es in th e v icin ity of th e cu r r en t lin e of
th e code, su ppor ts ev a lu a tin g a n d pr in tin g th e r esu lt of
ev a lu a tin g a n ex pr ession in th e cu r r en t con tex t, a n d
ex a m in in g th e sta ck fr a m e
3 . Fu n ction set_trace of m odu le pdb is u sed to tell th e
sta r tin g poin t of debu g g in g w h en th e pr og r a m is
n or m a lly r u n . By m en tion in g th is sta tem en t in th e
v er y beg in n in g , w e in ten d to specify th a t th e pr og r a m
sh ou ld sta r t r u n n in g in debu g g in g m ode fr om th e
sta r tin g poin t of its ex ecu tion .
4 . Py th on debu g g er pdb su ppor ts th e follow in g
com m a n ds:
Command Explanation

In t h e ab senc e of any ar gu ment , i t l i st s al l t h e


h or
av ai l ab l e c ommands. W i t h an ar gu ment , i t p r i nt s t h e
help
desc r i p t i on ab ou t t h at c ommand.

Pr i nt s t h e st ac k t r ac e (sequ enc e of f u nc t i on c al l s
w or c u r r ent l y i n ex ec u t i on, most r ec ent f u nc t i on c al l
where b ei ng at t h e b egi nni ng). A l so sh ow s t h e st at ement t o b e
ex ec u t ed nex t .

u or Mov es t o t h e st ac k f r ame one l ev el u p i n t h e st ac k


up t r ac e.

d or Mov es t o t h e st ac k f r ame one l ev el dow n i n t h e st ac k


down t r ac e.

Ex ec u t es t h e c u r r ent st at ement and mov es t h e c ont r ol


s or
t o ei t h er nex t st at ement or t h e f u nc t i on t h at i s b ei ng
step
i nv ok ed i n c u r r ent st at ement .

Ex ec u t es t h e c u r r ent st at ement and mov es t h e c ont r ol


n or t o t h e nex t st at ement . U nl i k e st ep c ommand, i f a
next f u nc t i on i s b ei ng i nv ok ed i n t h e c u r r ent st at ement ,
t h e i nv ok ed f u nc t i on get s ex ec u t ed c omp l et el y .

r or
Cont i nu e ex ec u t i on u nt i l t h e c u r r ent f u nc t i on
retur
r et u r ns.
n

j(ump
) Ju mp s t o t h e gi v en l i ne nu mb er f or t h e nex t st at ement
linen t o b e ex ec u t ed.
o

l or
Li st 1 1 l i nes i n t h e v i c i ni t y of t h e c u r r ent st at ement .
list

b or
Set s t h e b r eak p oi nt at t h e l i ne sp ec i f i ed (name of f i l e
break
op t i onal ). If t h e ar gu ment func sp ec i f y i ng f u nc t i on
[[fil
name i s p r ov i ded, b r eak p oi nt i s set at t h e f i r st
e:]li
ex ec u t ab l e st at ement of t h e f u nc t i on. Th e sec ond
ne|fu
ar gu ment may b e u sed t o denot e a c ondi t i on w h i c h
nc[,c
mu st ev al u at e t o True f or set t i ng t h e b r eak p oi nt .
ond]]

tbrea
k
[[fil Si mi l ar t o break c ommand. How ev er , b r eak p oi nt s
e:]li b ei ng set ar e au t omat i c al l y r emov ed onc e t h ey ar e
ne|fu r eac h ed.
nc[,c
ond]]

cl or Cl ear s t h e sp ec i f i ed b r eak p oi nt . In t h e ab senc e of any


clear ar gu ment , i s c l ear s al l t h e b r eak p oi nt s.
[[fil
e:]li
ne|fu
nc[,c
ond]]

c or
conti Cont i nu e ex ec u t i on u nt i l t h e b r eak p oi nt i s r eac h ed.
nue

a or Pr i nt s t h e ar gu ment l i st of t h e c u r r ent f u nc t i on al ong


args w i t h t h ei r v al u es.

p or
print
Pr i nt s t h e v al u e of t h e sp ec i f i ed ex p r essi on i n t h e
(expr
c u r r ent c ont ex t .
essio
n)

q or
Qu i t s f r om t h e Py t h on deb u gger .
quit

EXERCISES

1 . Con sider th e follow in g Py th on code in ten ded to


com pu te th e su m of n n a tu r a l n u m ber s. Du r in g
testin g , it w a s fou n d th a t su m pr in ted by pr og r a m
a lw a y s ex clu des th e la st n u m ber . Debu g th e scr ipt (Fig .
4 .4 ) u sin g th e debu g g er discu ssed in th e ch a pter .

F ig . 4.4 Pr ogr am t o c omp u t e t h e su m of n nat u r al nu mb er s

2 . Con sider th e follow in g Py th on code (Fig . 4 .5 ) in ten ded


to pr in t in v er se r ig h t tr ia n g le for g iv en n u m ber of
r ow s nRows. For ex a m ple, for nRows = 5 , th e follow in g
in v er ted tr ia n g le sh ou ld be pr in ted:
*****
****
***
**
*
Du r in g testin g , it w a s fou n d th a t pr og r a m does n ot
pr odu ce ev en th e sin g le lin e of ou tpu t. Debu g th e
follow in g scr ipt (Fig . 4 .5 ) u sin g th e debu g g er discu ssed
in th e ch a pter .
3 . Con sider th e Py th on scr ipt g iv en in Fig . 4 .6 in ten ded to
com pu te th e per cen ta g e. Du r in g testin g , it w a s fou n d
th a t per cen ta g e com pu ted w a s n ot a ccu r a te r a th er
r ou n ded to low er bou n d in teg er v a lu e. Debu g th e scr ipt
(Fig . 4 .6 ) u sin g th e debu g g er discu ssed in th e ch a pter .
4 . Con sider th e Py th on scr ipt in Fig . 4 .7 , in ten ded to
deter m in e w h eth er th e g iv en y ea r is a lea p y ea r .
Du r in g testin g , it w a s fou n d th a t a n y ea r su ch a s 1 8 00
or 2 1 00, despite bein g n on -lea p y ea r , w a s a lso
displa y ed a s a lea p-y ea r . Debu g th e fu n ction
isLeapYear (Fig . 4 .7 ) u sin g th e debu g g er discu ssed in
th e ch a pter .

F ig . 4.5 Pr ogr am t o p r i nt i nv er se r i gh t t r i angl e


F ig . 4.6 Pr ogr am t o c omp u t e p er c ent age

F ig . 4.7 Pr ogr am t o det er mi ne w h et h er t h e gi v en y ear i s a l eap y ear

5 . Con sider th e Py th on scr ipt (Fig . 4 .8 ), in ten ded to fin d


HCF. Du r in g testin g , it w a s fou n d th a t pr og r a m y ields
a n er r or for n u m ber s h a v in g n o com m on fa ctor oth er
th a n 1 . Debu g th e scr ipt (Fig . 4 .8 ) u sin g th e debu g g er
discu ssed in th e ch a pter .

F ig . 4.8 Pr ogr am t o f i nd HCF


CHAPTER 5
SCOPE

CHAPTER OUTLINE
5 .1 Objects a n d Object IDs

5 .2 Scope of Objects a n d Na m es

In this chapter, we will review the objects and their


mapping to names, the scope of names and parameter
passing mechanisms in Python. Recall that in Python,
the terms name and variable are used as synonyms.

5.1 OBJECTS AND OBJECT IDS

Each object in Python is assigned a unique identifier that


can be accessed using the function id.

ea ch Py th on object h a s a u n iqu e iden tifier


Fig. 5.1 Pr og r a m to illu str a te objects a n d th eir ids
(objectId.py)

On an execution of the above script (Fig. 5.1), it


produced the following output:

v a r ia bles a a n d b r efer to th e sa m e object 5 a n d th u s h a v e


sa m e id

a = 5 id(a): 10538176

b = 5 id(b): 10538176

a = 7 id(a): 10538240

b = 5 id(b): 10538176

Recall that when the script objectId is executed,


Python makes a note of the definition of the function
main in the global frame. Next, on encountering the if
statement, Python checks whether the name of the
current module is __main__. This being true, the
expression __ name__ == '__main__' evaluates as
True, and the function main gets invoked. Next, the
statements in the main function are executed in a
sequence. Line 2 being a comment is ignored by Python.
Execution of line 3 creates an int object 5 and assigns it
the name a. This object has a unique object id but can
have multiple names as the execution of the script
proceeds. For example, execution of the statement

b = 3 + 2

in line 5 does not generate a new object, it only


associates the name b to the int object 5 created earlier.
Now, a and b have the same object id. However,
execution of line 7 creates an int object 7 and associates
it with the name a. The name b continues to be
associated with int object 5 created earlier. It is
important to emphasize that different object ids may be
generated when a script is executed again.

Py th on Tu tor : tool for v isu a lizin g ex ecu tion of Py th on code

It comes as good news that there are some open


source tools available online that can be used to visualize
the execution of Python code. For example, the following
link

http://www.pythontutor.com/visualize.html#mode=
display

opens a user interface for visualizing Python code.


Figure 5.2 shows this interface. We select the language
Python 3.6 and copy the code in Fig. 5.1 in the box.
Fig. 5.2 Py th on tu tor in ter fa ce

We can see the line numbers appearing on the left of


each line of code. If we want to discuss our code with a
friend, we can start a shared session by clicking on the
icon Start shared session. This would open a chat box
and generate a link that we can send to our friend. Once
he/she copies it in the browser, we are ready for an
interactive session, and each of us can see actions
performed by the other person. For our discussion in this
section, we have chosen the following options:

sh a r ed session
Once we have learned to use the visualizer, we can play
with other options. Finally, to visualize the execution of
code, we click the icon Visualize Execution, and a bar
showing the progress of program execution appears.
Clicking somewhere on this bar would execute a fraction
of the code. Alternatively, we can use the forward and
back buttons. To begin with, we prefer the latter option.
Anytime, we want to modify the code, we can click on
Edit code.

v isu a l ize execu t ion

To start visualization, we click <Forward >. On


encountering the main function definition, the global
frame lists the identifier main as shown in Fig. 5.3. On
the screen, we notice two arrows, a red arrow (shown as
dark grey in the figure) and a green arrow (shown as
light grey in the figure). The red arrow marks the next
line to be executed, and the green arrow marks the line
just executed. Now clicking <Forward>, executes the
if statement. Clicking <Forward> again executes the
call to the function main and the visualizer shows the
frame for the main function. Clicking <Forward>
next, moves the next line pointer to line 3, and its
execution shows the creation of int object 5 having
name a. Next, clicking <Forward> shows the output of
the execution of line 4 in <Print output> box (Fig.
5.4). Next click executes line 5. Now, the name b is
mapped to the int object 5 created earlier. Further click
executes line 6 and the output appears in the <Print
output> box. This is shown in Fig. 5.5.

<For wa r d> bu tton : Mov e a step for w a r d du r in g pr og r a m


ex ecu tion
<Ba ck> bu tton : Mov e a step ba ckw a r d du r in g pr og r a m
ex ecu tion
Fig. 5.3 V isu a liza tion in Py th on tu tor
Fig. 5.4 V isu a liza tion in Py th on tu tor
Fig. 5.5 V isu a liza tion in Py th on tu tor
Fig. 5.6 V isu a liza tion in Py th on tu tor

Next, clicking <Forward> executes line 7, resulting


in creation of a new int object 7 and its mapping to a.
Further clicks execute lines 8 and 9 and the output
appears in the <Print output> box (Fig. 5.6). Next
click shows return value None associated with the
function main as it does not return any value. A further
click brings us to the end of the program. The final
response of the visualizer is shown in Fig. 5.7. If we
choose the option <Use text labels for pointers>, the
visualizer will show the object ids as id1, id2, etc.
Fig. 5.7 V isu a liza tion in Py th on tu tor

We noted above that Python created an int object 5


on execution of line 3. However, only a reference to that
object was created on execution of line 5. The general
principle is expressed by saying that Python caches or
interns small integer objects (typically, up to 100) for
future use. But, the same may not hold for other forms
of data. For example, examine the following Python
shell output:

>>> print(id(2.4))
46078432

>>> print(id(2.4))

47619216

>>> print(id(2.4))

47619024

>>> print(id(2.4))

46078432

>>> print(id(2.4))

47619024

>>> print(id(2.4))

47619216

differ en t iden tifier s for th e sa m e v a lu e

Note that the first three instructions create new objects.


However, subsequent instructions sometimes used the
objects created earlier. The del operator makes a name
(i.e. the association between the name and the object)
undefined, for example, examine, the following sequence
of statements:

>>> a = 5

>>> b = 5

>>> print(id(a), id(b))

10538176 10538176

>>> del a

>>> print(a)
File "<pyshell#26>", line 1, in <module>

print(a)

NameError: name 'a' is not defined

>>> print(b)

>>> del b

>>> print(b)

Traceback (most recent call last):

File "<pyshell#29>", line 1, in <module>

print(b)

NameError: name 'b' is not defined

a ccessin g a n u n defin ed n a m e lea ds to er r or

v a r ia ble b con tin u es to r efer to object 5

The first statement creates an int object 5 and binds it


to name a. The second statement does not create a new
object. Instead, it binds the same object to name b and
thus creates another reference to int object a. Figure
5.8 illustrates this.
Fig. 5.8 V isu a liza tion in Py th on tu tor

Python keeps a count of the number of references to an


object. When the statement

r efer en ce cou n t: th e n u m ber of r efer en ces (n a m es) a ssocia ted


w ith a n object

del a
is executed, it reduces the reference count of int object
5 from 2 to 1 and removes the binding of name a to int
object 5 as shown in Fig. 5.9. Therefore, an attempt to
access a now yields an error. However, the name b
continues to refer to int object 5 created on execution of
the statement

v a r ia ble a n o m or e r efer s object 5 . r efer en ce cou n t of object 5


decr ea ses by 1

b = 5

When the statement

del b
Fig. 5.9 V isu a liza tion in Py th on tu tor
Fig. 5.10 V isu a liza tion in Py th on tu tor

is executed, it reduces the reference count of int object


5 from 1 to 0 (Fig. 5.10), and removes the binding of
name b to int object 5. Therefore, an attempt to access
b now yields an error. We conclude this section by giving
another example of a Python program (Fig. 5.11). We
execute the script as shown in Fig. 5.12. In this figure,
we see a progress bar indicating what fraction of the
script we have executed so far. Below the progress bar
we see the following line:

pr og r ess ba r m a r ks pa r t of th e scr ipt ex ecu ted so fa r


Fig. 5.11 Pr og r a m to com pu te per cen ta g e (per cen ta g e.py )
Fig. 5.12 V isu a liza tion in Py th on tu tor

Step 1 of 5

It means that we are about to execute the first of the five


steps in the script. These five steps are as follows:

1. Defin ition of fu n ction percent(marks, maxMarks)


2. Defin ition of fu n ction main()
3. if sta tem en t
4. In v okin g th e fu n ction main()
5. Ex ecu tion of fu n ction main()

On clicking <Forward>, step 1 is executed and we see


the function percent in the global frame. On execution
of next step, the function main is also shown in the
global frame. When step 3 is executed, the condition if
__name__=='__main__' evaluates as True. Therefore,
in step 4 the function main is invoked (Fig. 5.13). Next
click executes the call to function main and the
visualizer shows the function main among frames. Next
click moves the next line pointer to line 13, and its
execution (shown on the right hand side) yields a
message that prompts the user to enter total marks in
<Input Box> and hit the Submit button (Fig. 5.14).
This input message along with the values entered as
input are also shown in <Print output>. At this stage,
we enter 500 as total marks, and click Submit. Now
execution of line 13 is complete, resulting in creation of
an instance of float object 500.0. This object is named
as maxMarks. Next click executes line 14, again
prompting for marks obtained (say, 450). As before, an
instance of float object 450.0 is created, and named
as marks. The control moves the next line pointer to line
15 (Fig. 5.15).

<In pu t Box>

<Pr in t Ou t pu t > box


Fig. 5.13 V isu a liza tion in Py th on tu tor
Fig. 5.14 V isu a liza tion in Py th on tu tor
Fig. 5.15 V isu a liza tion in Py th on tu tor
Fig. 5.16 V isu a liza tion in Py th on tu tor

Next, clicking <Forward> executes the call to the


function percent and the visualizer shows the function
percent among frames (Fig. 5.16). Note that the
parameters marks and maxMarks are mapped to float
objects created earlier. Next, clicking <Forward>,
moves the line pointer to line 7. Another click executes it
and creates the float object percentage having value
90.0. In the visualizer, execution of return statement at
line 8 requires two clicks. On first click, Python creates a
return value i.e. the float object (to be returned to the
main function) 90.0 which was created earlier as
shown in Fig. 5.17. The second click returns the value
90.0 from the function percent by associating it with
the variable percentage of function main (line 15).
This completes the execution of line 15 (Fig. 5.18). Now,
the control moves to line 16. Note that the variable
percentage of the function main now maps to the
float object 90.0 (Return value returned by
function percent). Further, since we had opted to show
exited frames, visualizer is still showing the lightly
highlighted frame for the function percent. Next click
shows the output on execution of line 16 in <Print
output> box (Fig. 5.19) and moves the line pointer to
line 17. It also shows return value None associated with
the function main() as it does not return any value. A
further click brings us to the end of the program. The
final response of the visualizer is shown in Fig. 5.20.
Fig. 5.17 V isu a liza tion in Py th on tu tor
Fig. 5.18 V isu a liza tion in Py th on tu tor
Fig. 5.19 V isu a liza tion in Py th on tu tor
Fig. 5.20 V isu a liza tion in Py th on tu tor

5.2 SCOPE OF OBJECTS AND NAMES

5.2.1 Namespaces

As the term suggests, a namespace is a space that holds


some names. A namespace defines a mapping of names
to the associated objects. In Python, a module, class, or
function defines a namespace. Names that appear in
global frame (usually outside of the definition of classes,
functions, and objects) are called global names and
collectively they define the namespace called global
namespace. The names introduced in a class or function
are said to be local to it. The region in a script in which a
name is accessible is called its scope. Thus, the scope of a
name is resolved in the context of the namespace in
which it is defined. For example, each of the functions
f1 and f2 defined in a script may have the name x.
Indeed, the variable x defined in function f1 may refer
to an object of type different from that of the object
associated with variable x in the function f2. A
namespace maps names to objects. Being an object-
oriented language, definitions of functions and classes
are also examples of objects.

n a m espa ce h olds n a m es a n d th eir object bin din g s

g loba l n a m es: u su a lly a ppea r ou tside of th e defin ition of a ll


cla sses, fu n ction s, a n d objects

scope of a n a m e: th e r eg ion of th e code in w h ich it is a ccessible

5.2.2 Scope

LEGB Rule

The scope rules for names in Python are often


summarized as LEGB rule. LEGB stands for local,
enclosing, global, and built in. All names defined within
the body of a function are local to it. Function
parameters are also considered local. If a name is not
locally found, Python recursively searches for its
definition in an enclosing scope. Names defined in the
Python script but usually outside of any function or class
definition are called global. Python defines some built-in
names such as len and abs, which can be accessed
from anywhere in a program.
LEGB r u le for scope: Loca l, En closin g , Globa l, Bu ilt-in

In light of the above discussion, the scope of a name in


the context of a function, say f, may be described as
follows:

A ll n a m es in tr odu ced loca lly in fu n ction f ca n be a ccessed


w ith in it.

If a n a m e is n ot defin ed loca lly in fu n ction f, bu t is defin ed in


a fu n ction g, th a t en closes it, th en it is a ccessible in th e
fu n ction f. If th e n a m e bein g a ccessed is n ot defin ed in th e
fu n ction g th a t im m edia tely en closes f, th en Py th on looks
for it in a fu n ction th a t en closes g, a n d so on .

If a n a m e is n ot defin ed in a n y en closin g fu n ction , Py th on


looks for it ou tside of a ll fu n ction s a n d if fou n d, it is a ccessible
in fu n ction f.

We will illustrate the notion of scope and namespaces


with the help of several examples.

Example 5.1

On executing the script scope1 (Fig. 5.21), Python


responds with the following output:

a ccess to g loba l v a r ia ble a

global a: 4

Note that as the variable a has global scope, it is


accessible in function f.
Fig. 5.21 Pr og r a m to illu str a te scope of v a r ia bles (scope1.py)

Example 5.2

On executing the script scope2 (Fig. 5.22), Python


responds with the following output:

a (lin e 4 ): Fou n d loca lly in fu n ction f


a (lin e 6 ): g loba l defin ition u sed

local a: 5

global a: 4.2

Note that the name a introduced in line 3 in the function


f is local to it and has associated value 5. Thus defining
the value of name a in the function f, does not affect
the value of the global name a.
Fig. 5.22 Pr og r a m to illu str a te scope of v a r ia bles (scope2.py)

Example 5.3

On executing the script scope3 (Fig. 5.23), Python


responds with the following output:

inside function g, b: 5

In this example, during execution of function g, when


the variable a is to be accessed, Python looks for it in the
local scope of function g, as it is not defined in the body
of function g, it is searched in the next enclosing scope,
i.e., the scope of function f, where the variable a is
indeed defined, and therefore the value 5 of the variable
a in function f gets bound to the occurrence of variable
a in the function g.

a: sea r ch ed loca lly in fu n ction g , fa iled


: sea r ch ed loca lly in fu n ction f a n d fou n d
Fig. 5.23 Pr og r a m to illu str a te scope of v a r ia bles (scope3.py)

Example 5.4

On executing the script scope4 (Fig. 5.24), Python


responds with the following output:

a loca l v a r ia ble defin ed in a n ested scope is n ot v isible ou tside


it

in outer function g, a =

Traceback (most recent call last):

File "F:/PythonCode/Ch05/scope4.py",
line 6, in <module>

f()

File "F:/PythonCode/Ch05/scope4.py",
line 5,

in f

print('in outer function g, a =', a)


NameError: global name 'a' is not defined

In this example, the variable a is defined in the body of


inner function g. When we attempt to access the name a
in line 5 of the outer function f, Python looks for its
definition first inside the body of function f, as there is
no definition of a in the function f, it looks for definition
of a in the next available enclosing scope, which is the
global scope. Again, there is no definition of the name a
in global name space, and hence the error message is
printed.

Fig. 5.24 Pr og r a m to illu str a te scope of v a r ia bles (scope4.py)

Example 5.5

On executing the script scope5 (Fig. 5.25), Python


responds with the following output:

loca l v a r ia ble sh ou ld n ot be r efer en ced befor e a ssig n m en t

Traceback (most recent call last):

File "F:/PythonCode/Ch05/scope5.py",
line 9,

in <module>
f()

File "F:/PythonCode/Ch05/scope5.py",
line 8,

in f

g()

File "F:/PythonCode/Ch05/scope5.py",
line 5,

in g

b = a

UnboundLocalError: local variable 'a'


referenced before assignment

In this example, while executing line 5 in function g,


when the variable a is accessed, Python looks for local
definition of a in the function g. Indeed, it does find a
definition of a in g at line 7, but that definition occurs
only after line 5, where it is used. Hence, the system
generates the error message: UnboundLocalError:
local variable 'a' referenced before
assignment. Here, we would like to emphasize that
while accessing a global name in a function nested at
any level is fine, assignment to a global name within a
function yields a new local variable.
Fig. 5.25 Pr og r a m to illu str a te scope of v a r ia bles (scope5.py)

Example 5.6

On executing the script scope6 (Fig. 5.26), Python


responds with the following output:

inside f, before calling g, a = 5

inside g, before modifying a, a = 5

inside g, after modifying a, a = 10

inside f, after calling g, a = 10

after calling f, a = 4

Python allows us to access a variable in an enclosing


scope. Thus in the script scope3, we could access the
value the local variable a defined in the enclosing
function f in the nested function g. Similarly, in the
script scope6, local definition of variable a in function
f (line 3) is visible inside the nested function g.
However, in order to modify the value of a local variable
in the enclosing scope, Python provides the keyword
nonlocal. In line 5, using the keyword nonlocal, we
tell Python that the name a being used in function g
refers to the same object as the one associated with
name a defined in function f because the function f is
enclosing the function g. Thus, the assignment
statement in line 7 modifies the variable a defined in
function f, the new value being 10.

m odify in g th e v a r ia ble in en closin g scope u sin g th e key w or d


nonlocal

Fig. 5.26 Pr og r a m to illu str a te scope of v a r ia bles (scope6.py)

Example 5.7

On executing the script scope7 (Fig. 5.27), Python


responds with the following output:
m odify in g a g loba l v a r ia ble

inside function g, global a = 4

inside function f, local a = 5

outside of all function definitions a = 4

In this example, in line 4, we tell Python that the


variable a used in the scope of function g is from the
global scope by using the keyword global. Thus, the
assignment statement in line 5 modifies the global
variable a, the new value being 4. However, in line 8, as
the variable a is locally available, no attempt is made to
search it in the global scope. The value 5 is assigned to
local variable a. Of course, this assignment of value 5 to
local variable in function f does not affect the value of
global variable which remains unaltered i.e. 4.
Fig. 5.27 Pr og r a m to illu str a te scope of v a r ia bles (scope7.py)

Example 5.8

On executing the script scope8 (Fig. 5.28), Python


responds with the following output:

>>>

in global namespace: id(f): 40585712

global f

before re-definition of f, id(f): 40585712

after re-definition of f: , id(f):


40686704

inner f

in global namespace: id(f): 40686704

global f
inside h: id(f): 40686704

inner f

Traceback (most recent call last):

File "F:/PythonCode/Ch05/scope8.py",
line 27,

in <module>

main()

File "F:/PythonCode/Ch05/scope8.py",
line 24,

in main

h()

File "F:/PythonCode/Ch05/scope8.py",
line 15,

in h

fprime()

NameError: global name 'fprime' is not


defined

In this example, we demonstrate that the same rules


apply to resolve the names of function objects and
numeric objects. On execution of line 18, id(f) is
printed for the global function f. Next, the function f is
assigned to the name fprime. On invoking the function
f, line 2 is executed. During execution of function g, the
execution of line 6 prints the id(f) for the global
function f. Subsequently, the global function f is
redefined in the function g, and the execution of line 9
prints the id of this modified function f. However, it does
not affect the definition of function fprime. Thus,
execution of line 23 invokes the function fprime,
thereby, line 2 is executed
illu str a tion of scope r u les for fu n ction objects
Fig. 5.28 Pr og r a m to illu str a te scope of v a r ia bles (scope8.py)

Subsequently, the function h is invoked, that further


invokes functions f and fprime. As the definition of
global function f has been modified, the execution of
line 8 prints inner f. However, when we attempt to
invoke function fprime (line 15), Python first looks for
its definition within function h, and when it does not find
the definition of function fprime locally, it looks for the
definition in the next outer scope, i.e., the global
namespace. But no definition of fprime is found even in
the global namespace. Hence the system flags the error
message NameError: global name 'fprime' is
not defined.

SUMMARY

1 . Py th on v isu a lizer is a n on lin e tool for v isu a lizin g th e


ex ecu tion of Py th on code.
2 . A n a m espa ce defin es a m a ppin g of n a m es to th e
a ssocia ted objects.
3 . Na m es th a t a ppea r in g loba l fr a m e ou tside of th e
defin ition of cla sses, fu n ction s, a n d objects a r e ca lled
g loba l n a m es, a n d collectiv ely th ey defin e th e
n a m espa ce ca lled g loba l n a m espa ce.
4 . Th e n a m es in tr odu ced in a cla ss, or fu n ction a r e sa id to
be loca l to it.
5 . Th e r eg ion in a scr ipt in w h ich a n a m e is a ccessible is
ca lled its scope.
6 . Th e scope r u les for n a m es in Py th on a r e often
su m m a r ized a s LEGB r u le. LEGB sta n ds for loca l,
en closin g , g loba l a n d bu ilt in .
7 . If a n a m e is n ot loca lly defin ed, Py th on r ecu r siv ely
sea r ch es for its defin ition in a n en closin g scope.
8 . Py th on defin es som e bu ilt-in n a m es su ch a s len a n d
abs w h ich ca n be a ccessed fr om a n y w h er e in a
pr og r a m .

EXERCISES

1 . Stu dy th e pr og r a m seg m en ts g iv en below . Giv e th e


ou tpu t pr odu ced, if a n y .
1 . globalVar = 10
def test():
localVar = 20
print('Inside function test :
globalVar =', globalVar)
print('Inside function test : localVar
=', localVar)
test()
print('Outside function test : globalVar
=', globalVar)
print('Outside function test : localVar
=', localVar)
2. globalVar = 10
def test():
localVar = 20
globalVar = 30
print('Inside function test :
globalVar =', globalVar)
print('Inside function test : localVar
=', localVar)
test()
print('Outside function test : globalVar
=', globalVar)
3. globalVar = 10
def test():
global globalVar
localVar = 20
globalVar = 30
print('Inside function test :
globalVar =', globalVar)
print('Inside function test : localVar
=', localVar)
test()
print('Outside function test : globalVar
=', globalVar)
4. def test1():
test1.a = 10
def test2():
test1.a = 8
print('Inside function test2: ',
test1.a)
test2()
print('Outside function test2 ',
test1.a)
test1()
5. a = 4
def f():
a = 5
def g():
nonlocal a
a = 10
print('inside function g,', 'a = ',
a)
def h():
nonlocal a
a = 20
print('inside function h,', 'a = ',
a)
h()
g()
print('inside function f,', 'a = ', a)
f()
6. x = 2
def test():
x = x + 1
print(x)
print(x)
7. x = 2
def test():
global x
x = x + 1
print(x)
print(x)
CHAPTER 6
STRING

CHAPTER OUTLINE
6 .1 Str in g s

6 .2 Str in g Pr ocessin g Ex a m ples

6 .3 Pa tter n Ma tch in g

Elementary forms of data such as numeric and Boolean


are called scalar data types. Several applications require
more complex forms of data. For example, the name of
a person, or an SMS may be expressed in the form of a
string. We have already been dealing with strings. In this
chapter, we shall discuss more about strings

6.1 STRINGS

As mentioned earlier, a string is a sequence of


characters. A string may be specified by placing the
member characters of the sequence within quotes
(single, double or triple). Triple quotes are typically used
for strings that span multiple lines. The following
assignment statement assigns the string 'Hello Gita'
to the variable message. We may also say that the
string 'Hello Gita' has been bound to the name
message.

a str in g is a sequ en ce of ch a r a cter s en closed w ith in qu otes

>>> message = 'Hello Gita'

Python function len finds the length of a string. Thus,

>>> len(message)

10
Individual characters within a string are accessed using
a technique known as indexing. In Fig. 6.1, we illustrate
the notion of indexing with the help of the string 'Hello
Gita'.

Fig. 6.1 In dex in g for v a r ia ble message

Note that the indices start with 0 (index for accessing


the first character from the left) and end with one less
than the length of the string (index for accessing the last
character). The following instructions illustrate how to
access individual characters in a string via indices. An
index is specified within the sqaure brackets, for
example:

in dex in g for a ccessin g in div idu a l ch a r a cter s in a str in g

Py th on a llow s n eg a tiv e a s w ell a s n on n eg a tiv e in dex es

>>> message[0]

'H'

>>> message[6]

'G'

>>> index = len(message)-1


>>> message[index]

'a'

The expression message[0] yields character 'H' since


'H' is stored at index 0. Similarly, the value of
len(message) being 10, when index is set equal to
len(message)-1, message[index] yields the last
character of the string message at index 9, i.e. 'a'.
Sometimes it is more convenient to access the elements
of a string from the right end. For this purpose, Python
provides negative indices. The negative indices range
from - (length of the string) to -1. For the string
message, the negative indices would range from -10 to
-1. Thus, the entire range of valid indices would be
{-10, -9, …, -1, 0, 1, …, 9}. Consequently,
message[-1] would yield 'a' and message[-index]
would yield 'e':

n eg a tiv e in dex es: u sed to a ccess th e str in g fr om th e r ig h t en d

>>> message[-1]

'a'

>>> message[-index]

'e'

If we try to access an index which is not in the valid


index range of a string, IndexError will be generated:

a ttem pt to a ccess a n in v a lid in dex y ields er r or

>>> message[15]

Traceback (most recent call last):

File "<pyshell#1>", line 1, in <module>

message[15]
IndexError: string index out of range

Strings in Python are immutable, i.e., a component of a


string cannot be altered, and an attempt to do so would
lead to an error:

Py th on str in g s a r e im m u ta ble

>>> message[6] = 'S'

Traceback (most recent call last):

File "<pyshell#2>", line 1, in <module>

message[6] = 'S'

TypeError: 'str' object does not support


item assignment

As mentioned earlier, strings can be concatenated using


concatenation operator + and can be repeated a multiple
number of times using the operator *.

str in g con ca ten a tion a n d r epetition

>>> 'Computer' + ' Science'

'Computer Science'

>>> 'Hi' * 3

'HiHiHi'

Strings may also be compared using relational operators


mentioned in chapter 1. Also, recall that the functions
max and min may be used to find maximum and
minimum respectively of several values, for example:

max(): to fin d th e la r g est v a lu e


min(): to fin d th e sm a llest v a lu e

>>> max('AZ', 'C', 'BD', 'BT')

'C'

>>> min('BD', 'AZ', 'C')

'AZ'

>>> max('hello', 'How', 'Are', 'You',


'sir')

' sir'

6.1.1 Slicing

Sometimes, we need to retrieve a substring, also called a


slice, from a string. This can be done by specifying an
index range. For example, to extract the substring
comprising the character sequence having indices from
start to end-1, we specify the range in the form
start:end as illustrated below:

slicin g for r etr iev in g a su bstr in g

>>> message = 'Hello Sita'

>>> message[0:5]

'Hello'

>>> message[-10:-5]

'Hello'

If the value of start or end is not specified, Python


assumes 0 as the default value of start, and length of
the string as the default value of end, for example:
for a slice of str in g s, defa u lt start in dex is:
0 or -(len(s)) defa u lt en d in dex is:
len(s)-1 or -1

>>> message[:5]

'Hello'

>>> message[5:]

' Sita'

>>> message[:]

'Hello Sita'

>>> message[:5] + message[5:]

'Hello Sita'

>>> message[:15]

'Hello Sita'

>>> message[15:]

''

>>> message[:15] + message[15:]

'Hello Sita'

Note that message[:n] + message[n:] always


yields message, irrespective of the value of n being
negative, positive, or even out of range. Indeed, values
used for defining a slice may be arbitrary integers or
even None, for example:

>>> message[8:20]

'ta'

>>> message[6:None]

'Sita'
Apart from extracting a consecutive subsequence of
characters from a string, Python also allows us to extract
a subsequence of the form start:end:inc. This
subsequence will include every incth element of the
sequence in the range start to end-1, for example:

>>> message[0:len(message):2]

'HloSt'

>>> message[0:len(message):3]

'HlSa'

We have already mentioned that a string is a sequence of


characters. The slicing operation discussed above can
also be applied to other sequences such as lists and
tuples, to be discussed later.

6.1.2 Membership

Python also allows us to check for membership of the


individual characters or substrings in strings using in
operator. Thus, the expression s in str1 yields True or
False depending on whether s is a substring of str1,
for example:

deter m in in g w h eth er a str in g is a su bstr in g of a n oth er str in g

>>> 'h' in 'hello'

True

>>> 'ell' in 'hello'

True

>>> 'h' in 'Hello'

False

In Python, we use a for loop to iterate over each


element in a sequence. In the following example, we
construct the string 'h e l l o ' from the string 'hello'
by iterating over each element of the string:

iter a tin g ov er a str in g

>>> helloSpaced = ''

>>> for ch in 'hello':

helloSpaced = helloSpaced + ch + ' '

>>> helloSpaced

'h e l l o'

6.1.3 Built-in Functions on Strings

Next, we examine some built-in functions that can be


applied on strings.

Function count

Suppose, we wish to find the number of occurrences of


character 'c' in the string 'Encyclopedia'. To
achieve this, we apply the function count with
argument 'c' to the string 'Encyclopedia':

count(): to cou n t occu r r en ces of a str in g in a n oth er str in g

>>> 'Encyclopedia'.count('c')

As an application of the function count, examine the


following code intended to find the count of all the
vowels in the string 'Encyclopedia:':

>>> vowels = 'aeiou'

>>> vowelCount = 0

>>> for ch in vowels:


vowelCount += 'Encyclopedia'.count(ch)

>>> vowelCount

The system responds with 4 as the value of the


vowelCount, even though the number of vowels in the
search string 'Encyclopedia' is 5. As the character
'E' was not included in the string vowels, it was not
included in counting too. To include the count of
uppercase vowels also, we just need to include vowels in
uppercase also in the string vowels:

vowels = 'AEIOUaeiou'

Rest of the code remains the same.

Functions find and rfind

Examine the string colors. Suppose we wish to find out


whether 'red' is present as a substring in the string
colors. We can do so by using the function find that
returns the index of the first occurrence of string
argument 'red' in colors:

fin din g in dex of fir st occu r r en ce of a str in g in a n oth er str in g

>>> colors = 'green, red, blue, red, red,


green'

>>> colors.find('red')

To find the last occurrence of a string, we use the


function rfind that scans the string in reversed order
from the right end of the string to the beginning:

fin din g in dex of th e la st occu r r en ce of a str in g in a n oth er


str in g
>>> colors.rfind('red')

23

If the function find fails to find the desired substring, it


returns -1:

>>> colors.find('orange')

-1

Functions capitalize, title, lower, upper,


and swapcase

Python provides several functions that enable us to


manipulate the case of strings. For example, the function
capitalize can be used for converting the first letter
of a string to uppercase character and converting the
remaining letters in the string to lowercase (if not
already so).

tr a n sfor m in g a str in g to sen ten ce ca se

>>> 'python IS a Language'.capitalize()

'Python is a language'

Python function title can be used to capitalize the first


letter of each word in a string and change the remaining
letters to lowercase (if not already so):

>>> 'python IS a PROGRAMMING


Language'.title()

'Python Is A Programming Language'

Python functions lower and upper are used to convert


all letters in a string to lowercase and uppercase,
respectively. Suppose we want to check for the
equivalence of a pair of email ids. Since email ids are not
casesensitive, we convert both email ids to either
uppercase or lowercase before testing for equality:
>>> emailId1 = 'geek@gmail.com'

>>> emailId2 = 'Geek@gmail.com'

>>> emailId1 == emailId2

False

>>> emailId1.lower() == emailId2.lower()

True

>>> emailId1.upper() == emailId2.upper()

True

Python function swapcase may be used to convert


lowercase letters in a string to uppercase letters and vice
versa, for example:

>>> 'pYTHON IS PROGRAMMING


LANGUAGE'.swapcase()

'Python is programming language'

Functions islower, isupper, and istitle

The functions islower and isupper can be used to


check if all letters in a string are in lowercase or
uppercase, respectively, for example:

ch eckin g ca se (low er / u pper ) of a str in g

>>> 'python'.islower()

True

>>> 'Python'.isupper()

False

The function istitle returns True if a string S


(comprising atleast one alphabet) is in title case, for
example:

ch eckin g w h eth er th e str in g is in title ca se

>>> 'Basic Python Programming'.istitle()

True

>>> 'Basic PYTHON Programming'.istitle()

False

>>> '123'.istitle()

False

>>> 'Book 123'.istitle()

True

Function replace

The function replace allows to replace part of a string


by another string. It takes two arguments as inputs. The
first argument is used to specify the substring that is to
be replaced. The second argument is used to specify the
string that replaces the first string. For example:

r epla cin g a su bstr in g w ith a n oth er str in g

>>> message = 'Amey my friend, Amey my


guide'

>>> message.replace('Amey', 'Vihan')

'Vihan my friend, Vihan my guide'

Functions strip, lstrip, and rstrip


The functions lstrip and rstrip remove whitespaces
from the beginning and end, respectively. The function
strip removes whitespaces from the beginning as well
as the end of a string. We may choose to remove any
other character(s) from the begining or end by explicitly
passing the character(s) as an argument to the function.
The following examples illustrate the use of the functions
lstrip, rstrip, and strip:

r em ov in g w h itespa ce fr om th e beg in n in g / en d of a str in g

>>> ' Hello How are you! '.lstrip()

'Hello How are you! '

>>> ' Hello How are you! '.rstrip()

' Hello How are you!'

>>> ' Hello How are you! '.strip()

'Hello How are you!'

Functions split and partition

The function split enables us to split a string into a list


of strings based on a delimiter. For example:

splittin g a str in g in to su bstr in g s

>>> colors = 'Red, Green, Blue, Orange,


Yellow, Cyan'

>>> colors.split(',')

['Red', ' Green', ' Blue', ' Orange', '


Yellow', ' Cyan']

Note that the function split outputs a sequence of


strings enclosed in square brackets. A sequence of objects
enclosed in square brackets defines a list. We shall
discuss more about lists in the next chapter.
If no delimiter is specified, Python uses whitespace as
the default delimiter:

>>> colors.split()

['Red,', 'Green,', 'Blue,', 'Orange,',


'Yellow,', 'Cyan']

The function partition divides a string S into two


parts based on a delimiter and returns a tuple (discussed
in the next chapter) comprising string before the
delimiter, the delimiter itself, and the string after the
delimiter, for example:

partition(): pa r tition in g a str in g in to tw o pa r ts

>>> 'Hello. How are you?'.partition('.')

('Hello', '.', ' How are you?')

Function join

Python function join returns a string comprising


elements of a sequence separated by the specified
delimiter. For example,

join in g a sequ en ce of str in g s

>>> ' > '.join(['I', 'am', 'ok'])

'I > am > ok'

>>> ' '.join(('I', 'am', 'ok'))

'I am ok'

>>> ' > '.join("'I', 'am', 'ok'")

"' > I > ' > , > > ' > a > m > ' > , > > '
> o > k > '"
In the first example, the sequence comprises three
elements, namely, 'I', 'am', and 'ok', which are
combined to form the string 'I > am > ok'. In the
second example, we use space as a delimiter instead of
>. In the third example, each character in the string
"'I > am > ok'" is an element of the sequence of
characters in "'I > am > ok'".

Functions isspace, isalpha, isdigit, and


isalnum

The functions isspace, isalpha, isdigit, and


isalnum enable us to check whether a value is of the
desire type. For example, we can check whether the
name entered by a user contains only alphabets as
follows:

Does a str in g com pr ises a lph a bets, dig its, or w h itespa ces
on ly ?

>>> name = input('Enter your name : ')

Enter your name : Nikhil

>>> name.isalpha()

True

>>> name = input('Enter your name : ')

Enter your name : Nikhil Kumar

>>> name.isalpha()

False

Note that the blank character is not an alphabet.


Similarly, to check the validity of a mobile number, we
may want it to be a string of length 10 comprising of
digits only. This can be achieved using functions
isdigit and len:

>>> mobileN = input('Enter mobile no : ')


Enter mobile no : 1234567890

>>> mobileN.isdigit() and len(mobileN)

== 10

True

Python function isspace is used to check if the string


comprises of all whitespaces:

ch eck for a w h ite spa ce on ly str in g

>>> ' \n\t '.isspace()

True

The function isalnum checks whether a string


comprises of alphabets and digits only. For example, if
the password is allowed to comprise of only alphabets
and digits, we may use the function isalnum to ensure
this constraint for a user specified password:

ch eck for a n a lph a n u m er ic str in g

>>> password = input('Enter password : ')

Enter password : Kailash107Ganga

>>> password.isalnum()

True

>>> password = input('Enter password : ')

Enter password : Kailash 107 Ganga

>>> password.isalnum()

False
Function startswith and endswith

Suppose we want to check if the last name of a person is


Talwar. We can do this using Python function
endswith as follows:

ch eckin g w h eth er a str in g sta r ts or en ds w ith a pa r ticu la r


str in g

>>> name = 'Ankita Narain Talwar'

>>> name.endswith('Talwar')

True

Similarly, to find whether a person's name begins with


Dr. we can use the function startswith as follows:

>>> name = 'Dr. Vihan Garg'

>>> name.startswith('Dr. ')

True

>>> name = ' Dr. Amey Gupta'

>>> name.startswith('Dr. ')

False

Functions encode and decode

Sometimes, we need to transform data from one format


to another for the sake of compatibility. Thus, we use,
Python function encode that returns the encoded
version of a string, based on the given encoding scheme.
Another function decode (reverse of function encode)
returns the decoded string, for example:

en codin g a n d decodin g a str in g

>>> str1 = 'message'.encode('utf32')


>>> str1

b'\xff\xfe\x00\x00m\x00\x00\x00e\x00\x00\x
00s\x00\x00\x00s\x00\x00\x00a\x00\x00\x00g
\x00\x00\x00e\x00\x00\x00'

>>> str1.decode('utf32')

'message'

One may also use alternative coding schemes such as


utf8 and utf16.

List of Functions

The functions described above are listed in Table 6.1.


Note that the original string S remains unchanged in
each case.
T a bl e 6.1 Str in g fu n ction s
6.2 STRING PROCESSING EXAMPLES

In this section, we will study several examples that


illustrate the use of string processing functions described
in the previous section.

6.2.1 Counting the Number of Matching Characters in a Pair


of Strings

Given two strings str1 and str2 of alphabets, we


wish to find the count of characters in str1 that match
a character in str2, ignoring any difference in case
(lowercase or uppercase). If a character, say, ch1, in
str1 appears more often than once in str2, every
occurrence of ch1 in str2 should be counted. For this
purpose, we develop the function nMatchedChar (Fig.
6.2).
Fig. 6.2 Pr og r a m to fin d n u m ber of m a tch ed ch a r a cter s in tw o
str in g s (matchChar.py)

As we do not wish to distinguish among alphabets


based on the case (lower or upper), we convert the input
arguments to lowercase. To keep a count of the matched
characters, we initialize the variable count to 0. The
outer loop works by picking up a character ch1 from
temp1 and comparing it against every character ch2 in
temp2 in the nested loop. For each matched pair, the
variable count is incremented by one. At the end of the
function, the value of count is returned. Let us examine
an example:

> >> name1 = 'Ram Rahim'

>>> name2 = 'SAMARTH RAHI'

>>> nMatchedChar(name1, name2)

16

Note that the first 'R' in string 'Ram Rahim' matches


'R' in 'SAMARTH RAHI' at indices 4 and 8, first 'a' in
string 'Ram Rahim' matches 'A' in 'SAMARTH
RAHI' at indices 1, 3, and 9, first 'm' in string 'Ram
Rahim' matches 'M' in 'SAMARTH RAHI' at index 2,
first space character ' ' in string 'Ram Rahim'
matches ' ' in 'SAMARTH RAHI' in at index 7, the
second 'R' in string 'Ram Rahim' again matches 'R'
in 'SAMARTH RAHI' at indices 4 and 8, and so on.

6.2.2 Counting the Number of Common Characters in a Pair


of Strings

To count the number of common characters in two


strings, say, str1 and str2, we execute the inner
loop, only if that character has not been encountered
earlier. Also, we terminate the inner loop using break
statement as soon as a character in str1 matches a
character in str2 (Fig. 6.3).
Fig. 6.3 Fu n ction to fin d th e n u m ber of com m on ch a r a cter s in
tw o str in g s (matchChar.py)

6.2.3 Reversing a String

Next, we wish to find the reverse of a given string. For


example, on reversing the string 'abcddb' we obtain
the string 'bddcba'. To find reversed string of a given
string str1, we begin with an empty string
reverseStr. In case, the input string is a null string,
the reversed string reverseStr will also be a null
string. In the case of a non-null string, for each
character in the given string, we concatenate by
appending it with the reverseStr built so far. The
complete function reverse is given in Fig. 6.4.

Next, we present a recursive function for reversing a


string. Note that it is comparatively easier to visualize
the recursive solution. In the recursive approach (Fig.
6.5), we concatenate the reverse of the string left after
removing first character i.e. str1[1:], with the first
character of the string str1, recursively, until empty
string is left. In Chapters 8 and 16, we will discuss
recursion in detail and give several examples of the use
of recursion.
Fig. 6.4 Fu n ction to fin d r ev er se of a str in g (reverseStr.py)

Fig. 6.5 Pr og r a m to fin d r ev er se of a str in g (reverse2.py)

6.3 PATTERN MATCHING


Sometimes we are interested in strings that conform to a
pattern, for example, we may be interested in words that
terminate in ing. Patterns are defined using regular
expressions, described below:

6.3.1 Some Important Definitions

Alphabet: An alphabet is a non-empty set of symbols,


denoted by ∑.

String: A string is a finite sequence of symbols chosen


from the alphabet ∑. An empty string '' containing no
symbols is called null string and is often denoted by λ or
ε. The length of a string is defined as the number of
symbols in the string. The length of the null string is
defined to be zero.

Language: It is the set of strings (words) defined over


the alphabet ∑ that conforms to some predefined
pattern, or rule(s). In this section, we discuss a class of
languages called regular languages. A regular language
is described by a regular expression, described below. We
shall use the terms regular expression and pattern
interchangeably.

r eg u la r ex pr ession s: u sed to defin e r eg u la r la n g u a g es

Each symbol of the alphabet defines a regular


language, comprising the symbol itself. Thus, for the
alphabet ∑ = {0,1}, 0 is a regular expression denoting
the language {0}. Similarly, 1 is a regular expression
denoting the language {1}. In general, if r is regular
expression, L(r) denotes the language described by r.

λ or ε is a regular expression that denotes the language


comprising the null string only. Thus, L(ε) = {''}.
The language containing no word, not even λ is called
null or empty language {}, and is denoted by the regular
expression φ.
em pty la n g u a g e

If r and s are regular expressions, r|s is also a


regular expression and denotes the language L(r|s) =
L(r) U L(s). The operator | is called the union
operator. Thus, the regular expression 0|1 denotes the
language L(0|1) = L(0) U L(1) = {0} U {1} =
{0,1}.

If is r is a regular expression, so is (r), denoting the


same language, i.e. L(r) = L((r)). Parentheses are
used to enforce precedence of operators in the regular
expressions.

The regular expression rs denotes the language


L(rs) = L(r) L(s), i.e., the language formed by
concatenating every string of the language L(r) by
every string of language L(s). The regular expression
(0|1)1 denotes the language L((0|1)1) =
L((0|1))L(1) = {0,1} {1} = {01,11}. It is easy
to see that the regular expressions 1(0|1) and
(0|1)1 denote different languages. Thus,
concatenation is not commutative. Concatenation has
higher precedence than the union operator |. Thus, the
regular expression 0|11 would denote the language
L(0|11) = L(0) U L(11) = {0} U {11} =
{0,11}.

If r is a regular expression, r* is also a regular


expression, that defines the language comprising the
concatenation of an arbitrary number of strings that
match the pattern r, i.e. belong to the language L(r).
Thus, * denotes zero or more occurrences of the
preceding pattern r. By definition, the null string also
belongs to L(r*). As an example, 0* defined over
alphabet ∑ = {0, 1} defines the language, L = {λ,
0,00, 000, 0000, …}. Similarly, L(((0|1)1)*) =
{01,11}* = { λ, 01,11, 0101, 0111,
1101,1111, 010101,011101, 111101, 110101,
…}.
Given a pattern r, r+ denotes the language
comprising one or more occurrences of strings that
match the pattern r. Formally, L(r+) = {w ε ∑*: w
has one or more occurrences of strings that match the
regular expression r}. Now L(((0|1)1)+) =
{01,11, 0101, 0111, 1101, 1111,
010101,011101, 111101, 110101, …}.

In Table 6.2, we describe the use of some important


symbols used in regular expressions. In Table 6.3, we
give examples of several regular expressions and the
languages they denote.

For dealing with a regular expression in Python, we


need to import the module re, which contains functions
for handling the regular expressions. The function
search of this module is used for matching a regular
expression in the given string. It looks for the first
location of a match in the given string. If the search is
successful, it returns the matchObject instance
matching the regular expression pattern, otherwise it
returns None. The function group of matchObject
instance returns the substring that matches the regular
expression. In Table 6.4, we give some examples that
illustrate the use of search function.

m odu le r e dea ls w ith pa tter n m a tch in g search(): u sed for


pa tter n m a tch in g
T a bl e 6.2 Sy m bols u sed in r eg u la r ex pr ession s
T a bl e 6.3 Ex a m ples of r eg u la r ex pr ession s a n d th e cor r espon din g
la n g u a g es
T a bl e 6.4 Py th on ex a m ples of r eg u la r ex pr ession s
Next, we wish to find email ids from a string. A simple
email id such as pranav.gupta@cs.iitd.ac.in can be
expressed as a sequence of patterns:

den oted by
a sequ en ce of a lph a n u m er ic ch a r a cter s
[a-z0-9]+

den oted by
a r epea tin g (0 or m or e tim es) sequ en ce of
(\.[a-z0-
dots follow ed by a lph a n u m er ic ch a r a cter s
9]+)*

@ den oted by @

den oted by
sequ en ce of a lph a betic ch a r a cter s
[a-z]+

r epea tin g (1 or m or e tim es) sequ en ce of dot den oted by


follow ed by a lph a betic ch a r a cter s (\.[a-z]+)+

Thus, an email id may be represented using the


regular expression [a-z0-9]+(\.[a-z0-9]+)*@[a-
z]+(\.[a-z]+)+. Generally, a regular expression is
preceded with r to denote a raw string. Use of a raw
string as a regular expression avoids any confusion with
some characters that have special meaning in regular
expressions. Examine the following instructions:

r eg u la r ex pr ession for em a il-id

>>> match = re.search(r'[a-z0-9]+(\.[a-z0-


9]+)*@
[a-z]+(\.[a-z]+)+', 'ram@gmail.com,
pranav.gupta@cs.iitd.ac.in, nik@yahoo.com,
raman@gmail.com')

>>> match.group()

'ram@gmail'

When several substrings of a given string match the


regular expression, the function group returns the first
substring matching the regular expression. However, if
we wish to retrieve list of all substrings matching the
regular expression, we may use the function finditer:
r etr iev in g a ll su bstr in g s m a tch in g a r eg u la r ex pr ession

>>> for i in re.finditer(r'[a-z0-9]+(\.[a-


z0-9]+)*@[a-z]+(\.[a-z]+)+',
'ram@gmail.com,
pranav.gupta@cs.iitd.ac.in, nik@yahoo.com,
raman@gmail.com'):

print(i.group())

ram@gmail.com

pranav.gupta@cs.iitd.ac.in

nik@yahoo.com

raman@gmail.com

Note that the null string matches the pattern


r'(a(b|c))*'. Next, let us find all words ending with
'ing' in a string. Again, we can use the function
finditer for this purpose.

sea r ch in g for w or ds en din g w ith ing in a str in g

>>> for i in re.finditer(r'[A-Za-z]+ing',


'Walking down the road, he was thinking
about the coming years.'):

print(i.group())

Walking

thinking

coming

Another function findall enables us to retrieve a list of


all the substrings matching a regular expression, for
example:
r etr iev in g a ll m a tch in g pa tter n s

>>> re.findall(r'[A-Za-z]+ing', 'Walking


down the road, he was thinking about the
coming years.')

['Walking', 'thinking', 'coming']

Next, we use the function findall to determine the


number of words in a string as follows:

>>> message = 'Python:Python is an


interactive language. It is developed by
Guido Van Rossum'

>>> words = re.findall('\w+', message)

>>> len(words)

13

Next, we use the function findall to match the email


ids.

>>> re.findall(r'([a-z0-9]+(\.[a-z0-
9]+)*@[a-z]+(\.[a-z]+)+)', 'ram@gmail.com,
pranav.gupta@cs.iitd.ac.in, nik@yahoo.com,
raman@gmail.com')

[('ram@gmail.com', '', '.com'),


('pranav.gupta@cs.iitd.ac.in', '.gupta',
'.in'), ('nik@yahoo.com', '', '.com'),
('raman@gmail.com', '', '.com')]

Note that findall returns a list of matched patterns


within the parenthesis only if the entire regular
expression matches.

Next, given a snippet of Python code, we wish to


extract all the single line comments contained in it. As a
single line comment begins with # and terminates with
an end of line character, it can be represented using the
regular expression #.*.

ex tr a ctin g com m en ts

>>> pythonCode = '''

"""

Python code to add two numbers.

"""

a = 5 #number1

b = 5 #number2

#Compute addition of two numbers

c = a + b

'''

>>> for i in re.finditer(r'(#.*)',


pythonCode):

print(i.group())

#number1

#number2

#Compute addition of two numbers

Next, we wish to extract multi-line comments, enclosed


in triple quotes ("""). Such a comment may be
represented using the regular expression: """.*?""".
Recall that a dot in a regular expression includes any
character except end of line. However, if we include
re.DOTALL as the third argument in the function
finditer, dot matches newline character also. For
example:
>>> for i in re.finditer(r'(""".*?""")',
pythonCode, re.DOTALL):

print(i.group())

"""

Python code to add two numbers.

"""

As our final example of regular expressions, we wish to


extract names of students from a string comprising
comma separated names, using the split function:

>>> re.split(r',', 'Mira,Ronit,Vivek')

['Mira', 'Ronit', 'Vivek']

However, if the string to be searched for names is a


multi-line string, either of the two symbols, comma and
end of line character, would serve as a separator:

r e . split (): r etu r n s a list of th e su bstr in g s delim ited


by th e r eg u la r ex pr ession pr ov ided

>>> re.split(r',|\n', '''Mira,Rohit,Vivek

Aiysha,Renuka,Robin

Sneha,Ravi''')

['Mira', 'Rohit', 'Vivek', 'Aiysha',


'Renuka', 'Robin', 'Sneha', 'Ravi']

SUMMARY

1 . A str in g is a sequ en ce of ch a r a cter s en closed in qu otes


(sin g le, dou ble, or tr iple).
2 . Str in g s in Py th on a r e im m u ta ble, i.e. a com pon en t of a
str in g ca n n ot be a lter ed.
3 . In dex in g is u sed for a ccessin g in div idu a l ch a r a cter s
w ith in th e str in g .
4 . Th e n on -n eg a tiv e in dices sta r t w ith 0 (in dex for
a ccessin g th e fir st ch a r a cter ) a n d en d w ith on e less
th a n th e len g th of th e str in g (in dex for a ccessin g th e
la st ch a r a cter ). Th e n eg a tiv e in dices r a n g e fr om -
(length of the string) to -1. A n a ttem pt to a ccess
a com pon en t of a str in g ou tside its v a lid in dex r a n g e
w ill g en er a te in dex out of range error.
5 . Retr iev in g a su bstr in g fr om a str in g is ca lled slicin g .
Th is ca n be don e by specify in g a n in dex r a n g e.
6 . Mem ber sh ip of in div idu a l ch a r a cter s or su bstr in g s in a
str in g ca n be ch ecked u sin g in oper a tor .
7 . Som e of th e im por ta n t fu n ction s a pplied on str in g s a r e
listed in th e follow in g ta ble:
F unct
Explanation
ions

S.cou
Cou nt s nu mb er of t i mes st r i ng str oc c u r s i n t h e st r i ng
nt(st
S.
r)

S.fin Ret u r ns i ndex of t h e f i r st oc c u r r enc e of t h e st r i ng str


d(str i n st r i ng S, and r et u r ns -1 i f str i s not p r esent i n
) st r i ng S.

S.rfi
Ret u r ns i ndex of t h e l ast oc c u r r enc e of st r i ng str i n
nd(st
st r i ng S, and r et u r ns -1 i f str i s not p r esent i n st r i ng S.
r)

S.cap
Ret u r ns a st r i ng t h at h as f i r st l et t er of t h e st r i ng S i n
itali
u p p er c ase and r est of t h e l et t er s i n l ow er c ase.
ze()

Ret u r ns a st r i ng t h at h as f i r st l et t er of ev er y w or d i n
S.tit
t h e st r i ng S i n u p p er c ase and r est of t h e l et t er s i n
le()
l ow er c ase.

Ret u r ns a st r i ng t h at h as al l u p p er c ase l et t er s i n
S.low
st r i ng S c onv er t ed i nt o c or r esp ondi ng l ow er c ase
er()
l et t er s.

Ret u r ns a st r i ng t h at h as al l l ow er c ase l et t er s i n
S.upp
st r i ng S c onv er t ed i nt o c or r esp ondi ng u p p er c ase
er()
l et t er s.

S.swa Ret u r ns a st r i ng t h at h as al l l ow er c ase l et t er s i n


pcase st r i ng S c onv er t ed i nt o u p p er c ase l et t er s and v i c e
() v er sa.

S.isl
Ret u r ns True i f al l al p h ab et s i n st r i ng S ar e i n
ower(
l ow er c ase, el se False.
)

S.isu
Ret u r ns True i f al l al p h ab et s i n st r i ng S ar e i n
pper(
u p p er c ase, el se False.
)

S.ist Ret u r ns True i f st r i ng S i s i n t i t l e c ase, i .e. f i r st l et t er


itle( of eac h w or d i s c ap i t al i zed and t h e st r i ng S c ont ai ns at
) l east one al p h ab et .

S.rep
lace( Ret u r ns a st r i ng t h at h as ev er y oc c u r r enc e of st r i ng
str1, str1 i n S r ep l ac ed w i t h an oc c u r r enc e of st r i ng str2.
str2)

S.str Ret u r ns a st r i ng t h at h as w h i t esp ac es i n S r emov ed


ip() f r om t h e b egi nni ng and t h e end.

S.lst Ret u r ns a st r i ng t h at h as w h i t esp ac es i n S r emov ed


rip() f r om t h e b egi nni ng.

S.rst Ret u r ns a st r i ng t h at h as w h i t esp ac es i n S r emov ed


rip() f r om t h e end.

S.spl Ret u r ns a l i st f or med b y sp l i t t i ng t h e st r i ng S i nt o


it(de su b st r i ngs. Th e delimiter i s u sed t o mar k t h e sp l i t
limit p oi nt s.
er)

S.par
Par t i t i ons t h e st r i ng S i nt o t h r ee p ar t s b ased on
titio
delimiter and r et u r ns a t u p l e c omp r i si ng t h e st r i ng
n(del
b ef or e delimiter, delimiter i t sel f and t h e st r i ng af t er
imite
delimiter.
r)

S.joi
n(seq Ret u r ns a st r i ng c omp r i si ng el ement s of t h e sequence
uence sep ar at ed b y del i mi t er S.
)

S.iss Ret u r ns True i f al l c h ar ac t er s i n st r i ng S c omp r i se


pace( w h i t esp ac e c h ar ac t er s onl y , i .e. ' ', '\n', and '\t' el se
) False.

S.isa
Ret u r ns True i f al l c h ar ac t er s i n st r i ng S c omp r i se
lpha(
al p h ab et s onl y , and False ot h er w i se.
)

S.isd
Ret u r ns True i f al l c h ar ac t er s i n st r i ng S c omp r i se
igit(
di gi t s onl y , and False ot h er w i se.
)

S.isa
Ret u r ns True i f al l c h ar ac t er s i n st r i ng S c omp r i se
lnum(
al p h ab et s and di gi t s onl y , and False ot h er w i se.
)

S.sta
rtswi Ret u r ns True i f st r i ng S st ar t s w i t h st r i ng str, and
th(st False ot h er w i se.
r)

S.end
Ret u r ns True i f st r i ng S ends w i t h st r i ng str, and False
swith
ot h er w i se.
(str)

S.enc
ode(e Ret u r ns S i n an enc oded f or mat , b ased on t h e gi v en
ncodi encoding sc h eme.
ng)

S.dec
ode(e Ret u r ns t h e dec oded st r i ng S, b ased on t h e gi v en
ncodi encoding sc h eme.
ng)

8 . A r eg u la r ex pr ession defin es a pa tter n . It is u sed for


ex tr a ctin g sequ en ces of ch a r a cter s in a str in g th a t
m a tch th e pa tter n . A r eg u la r ex pr ession in v olv es
sy m bols su ch a s sy m bols fr om th e a lph a bet of th e
la n g u a g e, n u ll str in g , pa r en th esis, * (sta r ), a n d +
(plu s).
9 . We n eed to im por t th e re m odu le for w or kin g w ith
r eg u la r ex pr ession s.
1 0. Th e fu n ction search of th e Py th on m odu le re is u sed
for m a tch in g a r eg u la r ex pr ession in a g iv en str in g . It
sea r ch es for th e fir st loca tion of a m a tch a n d r etu r n s
th e matchObject in sta n ce m a tch in g th e r eg u la r
ex pr ession , a n d None oth er w ise.

EXERCISES

1 . Wr ite a fu n ction th a t ta kes a str in g a s a pa r a m eter a n d


r etu r n s a str in g w ith ev er y su ccessiv e r epetitiv e
ch a r a cter r epla ced w ith a sta r (*). For ex a m ple,
'balloon' is r etu r n ed a s 'bal*o*n'.
2 . Wr ite a fu n ction th a t ta kes tw o str in g s a n d r etu r n s
True if th ey a r e a n a g r a m s a n d False oth er w ise. A pa ir
of str in g s is a n a g r a m s if th e letter s in on e w or d ca n be
a r r a n g ed to for m th e secon d on e.
3 . Wr ite a fu n ction th a t ta kes a sen ten ce a s a n in pu t
pa r a m eter a n d displa y s th e n u m ber of w or ds in th e
sen ten ce.
4 . Wr ite a fu n ction th a t ta kes a sen ten ce a s a n in pu t
pa r a m eter a n d r epla ces th e fir st letter of ev er y w or d
w ith th e cor r espon din g u pper ca se letter a n d r est of th e
letter s in th e w or d by cor r espon din g letter s in
low er ca se w ith ou t u sin g bu ilt-in fu n ction .
5 . Wr ite a fu n ction th a t ta kes a str in g a s a n in pu t a n d
deter m in es th e cou n t of th e n u m ber of w or ds w ith ou t
u sin g r eg u la r ex pr ession .
6 . Wh a t w ill be th e ou tpu t on ex ecu tin g ea ch of th e
sta tem en ts, follow in g th e a ssig n m en t sta tem en t:
address = 'B-6, Lodhi road, Delhi'
1 . len(address)
2 . address[17:-1]
3 . address[-len(address): len(address)]
4 . address[:-12] + address[-12:]
5 . address.find('delhi')
6 . address.swapcase()
7 . address.split(',')
8 . address.isalpha()
7 . Ex a m in e th e follow in g str in g :
greeting = 'Good Morning. Have a Good Day!!'
Wh a t w ill be th e ou tpu t for th e follow in g fu n ction ca lls:
1 . greeting.count('Good')
2 . greeting.find('a')
3 . greeting.rfind('a')
4 . greeting.capitalize()
5 . greeting.lower()
6 . greeting.upper()
7 . greeting.swapcase()
8 . greeting.istitle()
9 . greeting.replace('Good', 'Sweet')
1 0. greeting.strip()
1 1 . greeting.split()
1 2 . greeting.partition('.')
1 3 . greeting.startswith('good')
1 4 . greeting.endswith('!!')
8 . Deter m in e th e pa tter n s ex tr a cted by th e follow in g
r eg u la r ex pr ession s.
1 . string1 = 'Python Programming Language'
1 . match1 = re.search('......m?',
string1)
print(match1.group())
2 . match2 = re.search('......m{1,2}',
string1)
print(match2.group())
3 . match3 = re.search('.*Language$',
string1)
print(match3.group())
4 . match4 = re.search('\w*\s\w*',
string1)
print(match4.group())
5 . match5 = re.search('.*', string1)
print(match5.group())
2 . string2 = 'Car Number DL5645'
1 . match1 = re.search('\w\w?\d{1,4}',
string2)
print(match1.group())
2 . match2 = re.search('.*5', string2)
print(match2.group())
3 . match3 = re.search('.*5?', string2)
print(match3.group())
4 . match4 = re.search('\d{3}',
string2)
print(match4.group())
5 . match5 = re.search('^C.*5$',
string2)
print(match5.group())
3. string3 = 'cdcccdcddd343344aabb'
1 . match1 = re.search('(c|d)*\d*(a|b)*', string3)
print(match1.group())
2. match2 = re.search('(cd)*d', string3)
print(match2.group())
3. match3 = re.search('(cc|cd)*(3|4)*(aa|bb)',
string3)
print(match3.group())
4. match4 = re.search('(cc|cd|dd)*(3|4)*(aa|bb)',
string3)
print(match4.group())
5. match5 = re.search('(cc|cd|dd)*(3|4)*(aa|bb)*',
string3)
print(match5.group())
CHAPTER 7
MUTABLE AND IMMUTABLE OBJECTS

CHAPTER OUTLINE
7 .1 Lists

7 .2 Sets

7 .3 Tu ples

7 .4 Diction a r y

Elementary forms of data such as numeric and Boolean


are called scalar data types. Several applications require
more complex forms of data, for example, the name of a
person, coordinates of a point, a set of objects, or a list of
personal records of individuals. In the previous chapter,
we discussed about strings (type str – an immutable
structure). In this chapter, we will discuss some other
mutable and immutable objects, namely, lists, tuples,
sets, and dictionaries.

7.1 LISTS

A list is an ordered sequence of values. It is a non-scalar


type. Values stored in a list can be of any type such as
string, integer, float, or list, for example, a list may be
used to store the names of subjects:

list: a com m a sepa r a ted or der ed sequ en ce of v a lu es, en closed


in squ a r e br a ckets

>>> subjects=['Hindi', 'English', 'Maths',


'History']

Note that the elements of a list are enclosed in square


brackets, separated by commas. Elements of a list are
arranged in a sequence beginning index 0, just like
characters in a string. In Fig. 7.1, we show the
representation of the list subjects as in PythonTutor.
in dex in g in a list

Fig. 7.1 Repr esen ta tion of list subjects

To understand the lists better, let us invoke the function


id that returns object identifier for the list object
subjects:

>>> id(subjects)

57135752

Next, examine the following statements:

differ en t v a r ia bles m a y r efer to th e sa m e list object

>>> temporary = subjects

>>> id(temporary)

57135752

Note that each of the names subjects and temporary


is associated with the same list object having object id
57135752. PythonTutor representation of the lists
subjects and temporary, at this point, is shown in
Fig. 7.2.
Fig. 7.2 Repr esen ta tion of th e lists subjects a n d temporary

This method of accessing an object by different names is


known as aliasing. Unlike strings, lists are mutable, and
therefore, one may modify individual elements of a list.
However, modifying an element of a list does not alter its
object id, for example:

a lia sin g : to a ccess objects u sin g differ en t n a m es

lists a r e m u ta ble

>>> temporary[0] = 'Sanskrit'

>>> print(temporary)

['Sanskrit', 'English', 'Math', 'History']

>>> print(subjects)

['Sanskrit', 'English', 'Math', 'History']

>>> print(id(subjects), id(temporary))

57135752 57135752

As each of the two names temporary and subjects


refers to the same list, on modifying the component
temporary[0] of the list temporary, the change is
reflected in subjects[0] as shown as shown in Fig.
7.3.
Next, we create a list of subjects and their
corresponding subject codes. For this purpose, we
represent each pair of subject and subject code as a list,
and form a list of such lists:

tw o-dim en sion a l list: list of lists

>>> subjectCodes = [['Sanskrit', 43],


['English', 85] , ['Maths', 65],
['History', 36]]

Fig. 7.3 Repr esen ta tion of lists subjects a n d temporary

A list of lists such as subjectCodes, each of whose


elements itself is a list, is called a two-dimensional list.
Thus, subjectCodes[1] being a list, its components
may be accessed as subjectCodes[1][0] and
subjectCodes[1][1]:

>>> subjectCodes[1]

['English', 85]

>>> print(subjectCodes[1]
[0],subjectCodes[1][1])

English 85

As expected, subjectCodes[1] yields the list


['English', 85], i.e. element at index 1 of the list
subjectCodes. As subjectCodes[1] is itself a list,
subjectCodes[1][0] and subjectCodes[1][1]
yield elements of the list subjectCodes[1] at indices 0
and 1, i.e. 'English' and 85, respectively. In general,
when we write subjectCodes[i][j], the first index i
yields the list subjectCodes[i] in subjectCodes,
and the second index j yields the element
subjectCodes[i][j] within the list
subjectCodes[i].

As seen above, values contained in a list may be of


different types. As another example, we may like to store
name, address, and mobile number of a person in the list
details:

h eter og en eou s list: list w ith v a lu es of differ en t ty pes

>>> details = ['Megha Verma', 'C-55, Raj


Nagar, Pitam Pura, Delhi - 110034',
9876543210]

Often times, we need to take a list as an input from the


user. For this purpose, we use the function input for
taking the input from the user, and subsequently apply
the function eval for transforming the raw string to a
list:

u se of eval for con v er tin g r a w str in g to a list

>>> details = eval(input('Enter details of


Megha: '))

Enter details of Megha: ['Megha Verma',


'C-55, Raj Nagar,Pitam Pura, Delhi -
110034', 9876543210]

>>> details

['Megha Verma', 'C-55, Raj Nagar,Pitam


Pura, Delhi - 110034', 9876543210]

7.1.1 Summary of List Operations


In Table 7.1, we describe some functions and operations
on lists with the help of the following lists:

>>> list1 = ['Red', 'Green']

>>> list2 = [10, 20, 30]


T a bl e 7.1 Su m m a r y of oper a tion s th a t ca n be a pplied on lists

The membership operator in may be used in a for loop


for sequentially iterating over each element in the list,
for example:

iter a tin g ov er th e elem en ts of a list

>>> students = ['Ram', 'Shyam', 'Gita',


'Sita']

>>> for name in students:

print(name)

Ram

Shyam

Gita

Sita

As another example, given a list of marks in a subject, let


us find the number of students who have obtained
marks >= 75.

>>> marksList = [78, 32, 89, 99, 56]

>>> count = 0

>>> for marks in marksList:

if marks >= 75:

count += 1

>>> count

7.1.2 Function list

The function list takes a sequence as an argument and


returns a list. For example, given a string of vowels
'aeiou', we can convert it to the list of vowels for
further use as follows:
con v er tin g a sequ en ce to a list

>>> vowels = 'aeiou'

>>> list(vowels)

['a', 'e', 'i', 'o', 'u']

7.1.3 Functions append, extend, count, remove,


index, pop, and insert

append: The function append insert the object passed


to it at the end of the list, for example:

in ser tin g a n object a t th e en d of a list

>>> a = [10, 20, 30, 40]

>>> a.append(35)

>>> a

[10, 20, 30, 40, 35]

extend: The function extend accepts a sequence as an


argument and puts the elements of the sequence at the
end of the list, for example:

in ser tin g a sequ en ce of objects a t th e en d of a list

>>> a = [10, 20, 30]

>>> a.extend([35,40])

>>> a

[10, 20, 30, 35, 40]

>>> a.extend('abc')
>>> a

[10, 20, 30, 35, 40, 'a', 'b', 'c']

count: The function count returns the count of the


number of times the object passed as an argument
appears in the list, for example:

cou n tin g th e n u m ber of occu r r en ces of a n object in a list

>>> a = [10, 20, 30, 10, 50, 20, 60, 20,


30, 55]

>>> a.count(20)

pop: The function pop returns the element from the list
whose index is passed as an argument, while removing it
from the list, for example:

r em ov in g a n d r etu r n in g th e elem en t w ith th e g iv en in dex

>>> a = [10, 20, 30, 10, 50, 20, 60, 20,


30, 55]

>>> a.pop(3)

10

>>> a.pop(3)

50

>>> a

[10, 20, 30, 20, 60, 20, 30, 55]

remove: The function remove takes the value to be


removed from the list as an argument, and removes the
first occurrence of that value from the list, for example:
r em ov in g th e g iv en elem en t fr om th e list

>>> a.remove(20)

>>> a

[10, 30, 20, 60, 20, 30, 55]

Next, suppose we have two lists, names – the list of the


names of students and rollNums – the list of
corresponding roll numbers:

>>> names = ['Ram', 'Shyam', 'Sita',


'Gita', 'Sita']

>>> rollNums = [1, 2, 3, 4, 5]

To remove a student, 'Shyam' from the lists, we cannot


apply the function remove as we do not know the roll
number of 'Shyam'. However, since there is a
correspondence between student names and their roll
numbers, knowing the index of a student in the list
names will solve the problem. Python function index
can be used for finding the index of a given value in the
list.

index(): to deter m in e in dex of a n elem en t

>>> rollNums.pop(names.index('Shyam'))

>>> names.remove('Shyam')

>>> print(names, rollNums)

['Ram', 'Sita', 'Gita', 'Sita'] [1, 3, 4,


5]

del: The del operator is used to remove a subsequence


of elements (start:end:increment) from a list, for
example:

deletin g elem en ts in th e g iv en in dex r a n g e

deletin g a n object

>>> a = [10, 20, 30, 20, 60, 20, 30, 55]

>>> del a[2:6:3]

>>> a

[10, 20, 20, 60, 30, 55]

>>> del a

>>> a

Traceback (most recent call last):

File "<pyshell#14>", line 1, in <module>

NameError: name 'a' is not defined

Note that on execution of statement del a, name a no


more refers to the list object. Informally, we may say
that the object a has been deleted or a has been deleted.

a ttem pt to a ccess a deleted object lea ds to a n er r or

7.1.4 Function insert

The insert function can be used to insert an object at a


specified index. This function takes two arguments: the
index where an object is to be inserted and the object
itself, for example:
in ser tin g a n object a t th e specified in dex

>>> names = ['Ram', 'Sita', 'Gita',


'Sita']

>>> names.insert(2, 'Shyam')

>>> names

['Ram', 'Sita', 'Shyam', 'Gita', 'Sita']

7.1.5 Function reverse

The function reverse reverses the order of the elements


in a list, for example:

r ev er sin g th e or der of elem en ts in th e list

>>> names = ['Ram', 'Sita', 'Sita',


'Anya']

>>> names.reverse()

>>> names

['Anya', 'Sita', 'Sita', 'Ram']

7.1.6 Functions sort and reverse

The function sort can be used to arrange the elements


in a list in ascending order. For example, the names of
students in the list names can be arranged in an
ascending order using the function sort:

sor tin g th e elem en ts of th e list

>>> names = ['Ram', 'Sita', 'Sita',


'Anya']

>>> names.sort()
>>> names

['Anya', 'Ram', 'Sita', 'Sita']

If we wish to sort the list of names in descending order,


we may use the argument reverse = True while
invoking the function sort:

u se key w or d a r g u m en t reverse = True for sor tin g th e


elem en ts of a list in descen din g or der

>>> names =['Ram', 'Sita', 'Sita', 'Anya']

>>> names.sort(reverse = True)

>>> names

['Sita', 'Sita', 'Ram', 'Anya']

Sometimes, we need to sort objects in a list based on key


values obtained by applying a function to the objects in
the list. For example, we may like to sort the strings in a
list, based on their length. To achieve this, we need to
provide an argument of the form key = function as
illustrated below:

sor tin g th e list a ccor din g to th e specific cr iter ia

>>> names = ['Ram', 'Sita', 'Purushottam',


'Shyam']

>>> names.sort(key = len)

>>> names

['Ram', 'Sita', 'Shyam', 'Purushottam']

7.1.7 List Functions

In Table 7.2, we list some important built-in functions


that can be applied to lists. Many of these functions such
as append, reverse, sort, extend, pop, remove,
and insert modify the list. Functions such as count
and index do not modify the list. The function dir can
be used to output the list of all the attributes including
the functions that can be applied to a particular type. For
example, dir(list) outputs the list including all the
functions that can be applied to objects of the type list.
Similarly, dir(str) outputs the list including all the
functions that can be applied to objects of the type str.

fu n ction s count a n d index do n ot m odify th e list

T a bl e 7.2 List fu n ction s

7.1.8 List Comprehension


List comprehension provides a shorthand notation for
creating lists. Suppose we want to create a list that
contains cubes of numbers ranging from 1 to 10. To do
this, we may create an empty list, and use a for-loop to
append the elements to this list:

>>> cubes =[]

>>> end = 10

>>> for i in range(1, end + 1):

cubes.append(i ** 3)

>>> cubes

[1, 8, 27, 64, 125, 216, 343, 512, 729,


1000]

Alternatively, a simple one line statement can be used for


achieving the same task.

sh or th a n d n ota tion for cr ea tin g a list of cu bes

>>> cubes = [x**3 for x in range(1, end +


1)]

The expression [x**3 for x in range(1, end +


1)] creates a list containing cube of each element in the
range (1, end + 1). Next, suppose we have a list
comprising information about names and heights of the
students. The name of each student is followed by the
height of the corresponding student in centimetres. We
wish to create a list comprising the students in the list
lst whose height exceed or equal a threshold:

>>> lst = [['Rama', 160], ['Anya', 159],


['Mira',158], ['Sona', 161]]

>>> threshold = 160

The desired list can be easily created using


comprehensions:
>>> tall = [x for x in lst if x[1] >=
threshold]

>>> tall

[['Rama', 160], ['Sona', 161]]

Next, given a list s1 of alphabets and another list s2 of


numbers, we wish to create a cross product of s1 and
s2. Each element of the list crossProduct is a two-
element list of the type [alphabet, number]. This is easily
achieved using comprehensions:

list com pr eh en sion for com pu tin g cr oss pr odu ct of tw o lists

>>> s1 = ['a', 'b', 'c']

>>> s2 = [3, 5]

>>> crossProduct = [[x, y] for x in s1 for


y in s2]

>>> crossProduct

[['a', 3], ['a', 5], ['b', 3], ['b', 5],


['c', 3], ['c', 5]]

7.1.9 Lists as Arguments

Let us examine the script in Fig. 7.4. The function


listUpdate updates the list a (line 10) by replacing the
object a[i] by value. The main function invokes the
function listUpdate with the arguments lst, 1, and
15 corresponding to the formal parameters a, i, and
value. As arguments are passed by reference, during
execution of the function listUpdate, an access to the
formal parameter a means access to the list lst created
in the main function. Consequently, when we update the
list a in the function listUpdate, it results in the
corresponding update of the list lst, as visualized in
PythonTutor (Fig. 7.5). Thus, the value at index 1 of the
list lst gets updated to the value 15.
a r g u m en ts a r e pa ssed by r efer en ce
Fig. 7.4 List pa ssed a s a n a r g u m en t
Fig. 7.5 List lst befor e a n d a fter th e ca ll to th e fu n ction
listUpdate

7.1.10 Copying List Objects

In the beginning of the chapter, we mentioned that a list


is a sequence of values. To be more precise, a list
comprises a sequence of references to values (objects).
We have seen earlier that if the name list1 refers to a
list, the assignment of list1 to another name, say,
list2 does not create a new list

a ssig n in g a list to a n oth er n a m e does n ot cr ea te a n oth er copy


of th e list, in stea d it cr ea tes a n oth er r efer en ce

>>> list1 = [10, 20, [30, 40]]

>>> list2 = list1


As the names list1 and list2 refer to the same list
object (Fig. 7.6), any changes made in the list will relate
to both the names list1 and list2, for example (Fig.
7.7):
Fig. 7.6 list1 a n d list2 r efer to th e sa m e list
Fig. 7.7 list1 a n d list2 r efer to th e sa m e list

>>> list1[1] = 22

>>> list1

[10, 22, [30, 40]]

>>> list2

[10, 22, [30, 40]]

However, sometimes we need to create a copy of the list


as a distinct object. To create another instance of the list
object having different storage, we need to import the
copy module and invoke the function copy.copy():

copy(): to cr ea te a copy of th e list elem en ts ex clu din g th e


n ested objects

>>> import copy

>>> list1 = [10, 20, [30, 40]]

>>> list3 = copy.copy(list1)

Note that the copy function creates a new copy list3


of the list1. Consequently, on modifying list1[1],
list3[1] remains unaltered:
Fig. 7.8 list1 a n d list3 r efer to th e differ en t lists

>>> list1[1] = 25

>>> list1

[10, 25, [30, 40]]

>>> list3

[10, 20, [30, 40]]


However, the copy function creates a shallow copy i.e. it
does not create copies of the nested objects. Thus, the
two lists share the same nested objects. Thus, list1[2]
and list3[2] refer to the same nested list [30, 40].
Next, let us modify list1[2][0] in sub-list list1[2]
of list list1 to value 35.

>>> list1[2][0] = 35

>>> list1

[10, 25, [35, 40]]

>>> list3

[10, 20, [35, 40]]

As discussed above, since list1[2] and list3[2]


refer to the same sub-list at index 2 (Fig. 7.9), when we
modify the list list1[2], the modification is also visible
in the list list3[2].
Fig. 7.9 list1 a n d list3 r efer to th e differ en t lists

If we wish to create a copy of a list object so that the


nested objects (at all levels) get copied to new objects, we
use the function deepcopy of the copy module:
deepcopy(): to cr ea te a copy of a list in clu din g copies of th e
n ested objects a t a ll lev el

>>> import copy

>>> list1 = [10, 20, [30, 40]]

>>> list4 = copy.deepcopy(list1)

Note that list1 and list4 are distinct objects (Fig.


7.10), having the nested lists list1[2] and list4[2]
as distinct objects. Thus, modifying the value of
list1[2][0] to 35 does not affect the object
list4[2] [0] of list4 which remains unaltered as
shown in Fig. 7.11.

>>> list1[2][0] = 35

>>> list1

[10, 20, [35, 40]]

>>> list4

[10, 20, [30, 40]]


Fig. 7.10 list1 a n d list4 r efer to th e differ en t lists a t a ll lev els
of n estin g
Fig. 7.11 list1 a n d list4 r efer to th e differ en t lists a t a ll lev els
of n estin g

7.1.11 map, reduce, and filter


!
Operations on a
Sequence

Python provides several built-in functions based on


expressions, which work faster than loop-based user
defined code.
The function map is used for transforming every value
in a given sequence by applying a function to it. It takes
two input arguments: the iterable object (i.e. object
which can be iterated upon) to be processed and the
function to be applied, and returns the map object
obtained by applying the function to the list as follows:

m a ppin g ea ch v a lu e in th e sequ en ce by a pply in g th e fu n ction

result = map(function, iterable object)

The function to be applied may have been defined


already, or it may be defined using a lambda expression
which returns a function object.. A lambda expression
consists of the lambda keyword followed by a comma-
separated list of arguments and the expression to be
evaluated using the list of arguments in the following
format:

la m bda ex pr ession : u sed to defin e th e ex pr ession to be be


ev a lu a ted u sin g th e a r g u m en ts

lambda arguments: expression

For example, let us define a lambda function that takes a


number x as an input parameter and returns the cube of
it. The following statement defines a lambda function
and assigns it the name cube. The function cube can
now be used as usual:

la m bda ex pr ession to com pu te th e cu be of a n u m ber

>>> cube = lambda x: x ** 3

>>> cube(3)

27

Similarly, the function sum2Cubes may be used to


compute the sum of cubes of two numbers:
la m bda ex pr ession to com pu te th e su m of cu bes of tw o
n u m ber s

>>> sum2Cubes = lambda x, y: x**3 + y**3

>>> sum2Cubes(2, 3)

35

Next, suppose we wish to compute the cubes of all values


in the list lst. The following statements use the map
function to map every value in the list lst to its cube.
Since the function map returns a map object, we have
used the function list to convert it to list.

m a ppin g ev er y v a lu e in th e sequ en ce to its cu be

>>> lst = [1, 2, 3, 4, 5]

>>> list(map(lambda x: x ** 3, lst))

[1, 8, 27, 64, 125]

>>> list(map(cube, lst))

[1, 8, 27, 64, 125]

We may also use any system defined or user-defined


function as an argument of the map function, for
example:

>>> list(map(abs, [-1, 2, -3, 4, 5]))

[1, 2, 3, 4, 5]

Suppose we wish to compute the sum of cubes of all


elements in a list. Note that adding elements of the list is
a repetitive procedure of adding two elements at a time.
The function reduce, available in functools module,
may be used for this purpose. It takes two arguments: a
function, and a iterable object, and applies the function
on the iterable object to produce a single value:
com pu tin g su m of cu bes of a ll elem en ts in th e list

>>> lstCubes = list(map(lambda x: x ** 3,


lst))

>>> import functools

>>> sumCubes = functools.reduce(lambda x,


y: x + y, lstCubes)

>>> sumCubes

225

Thus, in the above example, we are able to compute the


sum of all the elements of the list lstCubes. In a
parallel environment, the sum may be computed by
adding two values at a time, and then summing over the
sums obtained in the first step, and so on. Thus, the sum
of the elements of the list [1, 2, 3, 4, 5, 6, 7, 8] may be
computed as (((1+2) + (3+4)) + ((5+6) + (7+8))).

Next, we compute the sum of cubes of only those


elements in the list lstCubes that are even. Thus, we
need to filter the even elements from the list lstCubes
and before applying the function reduce. Python
provides the function filter that takes a function and
a iterable object as the input parameters and returns
only those elements from the iterable object for which
function returns True. In the following statement, the
filter function returns an iterable object of even
elements of the list lstCubes, which is assigned to
variable evenCubes. Since the function filter returns
a filter object, we have used the function list to
convert it to list.

filter in g elem en ts fr om a list sa tisfy in g th e g iv en con dition

>>> evenCubes = list(filter(lambda x: x%2


== 0, lstCubes))
>>> evenCubes

[8, 64]

>>> sumEvenCubes = functools.reduce(lambda


x, y: x + y, evenCubes)

>>> sumEvenCubes

72

Alternatively, the sum of odd cubes may be computed as


follows:

>>> sumEvenCubes = functools.reduce(lambda


x, y: x + y, filter(lambda x: x%2 == 0,
lstCubes))

>>> sumEvenCubes

72

The functions map, reduce, and filter are often used


to exploit the parallelism of the system to distribute
computation to several processors. However, details of
the parallel programming are beyond the scope of the
book.

7.2 SETS

A set in Mathematics refers to an unordered collection of


objects without any duplicates. An object of type set may
be created by enclosing the elements of the set within
curly brackets. The set objects may also be created by
applying the set function to lists, strings, and tuples.
Next, we give some examples of sets:

set: a com m a sepa r a ted u n or der ed sequ en ce of v a lu es


en closed w ith in cu r ly br a ces

set(): to con v er t a sequ en ce to a set


>>> {1,2,3}

{1, 2, 3}

>>> vowels = set('aeiou')

>>> vowels

{'e', 'a', 'o', 'u', 'i'}

>>> vehicles = set(['Bike', 'Car',


'Bicycle', 'Scooter'])

>>> vehicles

{'Scooter', 'Car', 'Bike', 'Bicycle'}

>>> digits = set((0, 1, 2, 3, 4, 5, 6, 7,


8, 9))

>>> digits

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

The elements of a set are required to be immutable


objects. Therefore, whereas objects of types such as int,
float, tuple, and str can be members of a set, a list
cannot be a member of a set. Unlike lists, we cannot
access elements of a set through indexing or slicing. Also,
we cannot apply + and * operators on sets. However,
using the membership operator in, we can iterate over
elements of a set:

elem en ts of a set m u st be im m u ta ble

set ty pe does n ot su ppor t in dex in g , slicin g , + oper a tor , a n d *


oper a tor

iter a tin g ov er elem en ts of th e set


>>> for v in vowels:

print(v, end = ' ')

e a o u i

The functions min, max, sum, and len work for sets in
the same manner as defined for lists.

a pply in g min(), max(), sum(), a n d len() fu n ction s to sets

>>> min(digits)

>>> max(digits)

>>> sum(digits)

45

>>> len(vehicles)

The membership operator in checks whether an object


is in the set.

>>> 'Bike' in vehicles

True

7.2.1 Set Functions add, update, remove, pop,


and clear

Suppose we wish to add an element 'Bus' to the set


vehicles. It can be done using the function add. To
include new elements in a set, we use update function.
The input argument to the update function may be an
object such as list, set, range, or tuple, for example:
a ddin g elem en ts to a set

>>> vehicles.add('Bus')

>>> vehicles

{'Car', 'Bike', 'Bicycle', 'Bus',


'Scooter'}

>>> vehicles.update(['Truck', 'Rickshaw',


'Bike'])

>>> vehicles

{'Car', 'Bike', 'Bicycle', 'Rickshaw',


'Bus', 'Truck', 'Scooter'}

It is important to point out that an attempt to add a


duplicate value ('Bike' in the above case) is just
ignored by Python. Next, we define the set
heavyVehicles as follows:

du plica te elim in a tion

>>> heavyVehicles = {'Truck', 'Bus',


'Crane'}

An element may be removed from a set using the


function remove, for example:

r em ov in g a n elem en t fr om th e set

>>> heavyVehicles.remove('Crane')

>>> heavyVehicles

{'Bus', 'Truck'}

>>> heavyVehicles.remove('Car')
Traceback (most recent call last):

File "<pyshell#432>", line 1

heavyVehicles.remove('Car')

KeyError: 'Car'

Note that an attempt to remove an element from a set,


which is not a member of the set, yields an error.
Although the function pop is defined for objects of type
set, the element removed by the function pop is
unpredictable.

elem en t r em ov ed u sin g pop fu n ction is u n pr edicta ble

>>> heavyVehicles = {'Truck', 'Bus',


'Crane'}

>>> heavyVehicles.pop()

'Bus'

To remove all the elements of a set, without deleting the


set object, we use the clear function:

r em ov in g a ll elem en ts of a set

>>> heavyVehicles.clear()

>>> heavyVehicles

set()

7.2.2 Set Functions union, intersection,


difference, and symmetric_difference

Python provides functions union, intersection,


and symmetric_difference to carry out these
mathematical operations. We define two sets fruits
and vegetables:
>>> fruits = {'Apple', 'Orange', 'Tomato',
'Cucumber', 'Watermelon'}

>>> vegetables = {'Cucumber', 'Potato',


'Tomato', 'Watermelon', 'Cauliflower'}

Now, to determine all eatables whether fruits or


vegetables, we take union of the above two sets.

u n ion of tw o sets

>>> eatables = fruits.union(vegetables)

>>> eatables

{'Orange', 'Tomato', 'Cucumber',


'Watermelon', 'Cauliflower', 'Apple',
'Potato'}

Alternatively, we may use the union operator | for


achieving the same result:

>>> eatables = fruits | vegetables

>>> eatables

{'Orange', 'Tomato', 'Cucumber',


'Watermelon', 'Cauliflower', 'Apple',
'Potato'}

Next, to determine those eatables which are both


fruits and vegetables, we take intersection of sets
fruits and vegetables using either the function
intersection or the intersection operator & as
follows:

in ter section of tw o sets

>>> fruitsAndVegetables =
fruits.intersection(vegetables)
>>> fruitsAndVegetables

{'Tomato', 'Cucumber', 'Watermelon'}

>>> fruitsAndVegetables = fruits &


vegetables

>>> fruitsAndVegetables

{'Tomato', 'Cucumber', 'Watermelon'}

Next, we find the fruits which are not vegetables


by taking difference of the two sets, either using the
function difference or using the difference operator:

set differ en ce

>>> onlyFruits =
fruits.difference(vegetables)

>>> onlyFruits

{'Orange', 'Apple'}

>>> onlyFruits = fruits - vegetables

>>> onlyFruits

{'Orange', 'Apple'}

Similarly, we can determine vegetables which are not


fruits as follows:

>>> onlyVegetables =
vegetables.difference(fruits)

>>> onlyVegetables

{'Cauliflower', 'Potato'}

>>> onlyVegetables = vegetables - fruits


>>> onlyVegetables

{'Cauliflower', 'Potato'}

Next, to determine eatables which are either only


fruits or only vegetables, we may take union of the
sets onlyFruits and onlyVegetables:

>>> fruitsXORVegs = onlyFruits |


onlyVegetables

>>> fruitsXORVegs

{'Orange', 'Apple', 'Cauliflower',


'Potato'}

Alternatively, we may use the function


symmetric_difference, which determines the
elements that are in one of the either sets but not in
both:

sy m m etr ic differ en ce

>>> fruitsXORVegs =
fruits.symmetric_difference(vegetables)

>>> fruitsXORVegs

{'Orange', 'Apple', 'Cauliflower',


'Potato'}

The functions set.intersection, set.union, and


set.difference can be applied to two or more sets to
carry out intersection, union, and difference
operations on sets:

>>> digits1 = {0, 1, 2, 3}

>>> digits2 = {2, 4, 5, 6}

>>> digits3 = {0, 7, 8, 9, 2}

>>> set.union(digits1, digits2, digits3)


{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

>>> set.intersection(digits1, digits2,


digits3)

{2}

>>> set.difference(digits1, digits2,


digits3)

{1, 3}

The function set.difference works by taking the


union of all sets except the first one and subtracting the
union from the first set.

7.2.3 Function copy

We make use of the function copy to create a separate


copy of a set so that changes in one copy are not
reflected in the other:

copy in g th e elem en ts of a set

>>> digits = {0, 1, 2, 3, 7, 8, 9}

>>> digits2 = digits.copy()

>>> digits.update({4, 5, 6})

>>> digits

{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

>>> digits2

{0, 1, 2, 3, 7, 8, 9}

7.2.4 Subset and Superset Test

To check whether a given set is the subset or superset of


another set, we use the operators <= and >=,
respectively. For example, let the sets multiples2 and
multiples4 comprise multiples of 2 and 4,
respectively. We can check whether multiples2 is a
subset or superset of multiples4 using these operators:

su bset a n d su per set oper a tion s

>>> multiples2 = {2, 4, 6, 8, 10, 12, 14}

>>> multiples4 = {4, 8, 12}

>>> isSubset = multiples4 <= multiples2

>>> isSubset

True

>>> isSuperset = multiples2 >= multiples4

>>> isSuperset

True

The functions issubset and issuperset can also be


used for the same purpose.

7.2.5 List of Functions

In Table 7.3, we list some important built-in functions


that can be applied to sets.
T a bl e 7.3 Set fu n ction s

7.2.6 Finding Common Factors

Suppose, given two numbers n1 and n2, we wish to find


their common factors. To check whether a number i is a
factor of another number, say num, we only need to find
the remainder num % i. If the remainder is zero, then i
is a factor of num, otherwise, i is not a factor of num. We
represent the collection of common factors as a set. We
also note that a common factor cannot exceed smaller of
the two numbers, say n1 and n2. To build a set of
common factors, we make use of comprehensions. For
each number i in range(1, min(n1,n2) + 1), we
include it in the set if it is a factor of each of n1 and n2.
Thus, our code comprises just one line:
set com pr eh en sion : a pplied to fin d com m on fa ctor s

commonFactors = {i for i in range(1,


min(n1+1, n2+1)) if n1%i == 0 and n2%i ==
0}

7.2.7 Union and Intersection Operation on Lists

Given a list lst1 of people who like basketball and


another list lst2 of individuals who like badminton;
suppose, we wish to construct the following lists:

A list of in div idu a ls w h o like eith er ba sketba ll or ba dm in ton ,


i.e. u n ion of lists lst1 | lst2.

A list of people w h o like both ba sketba ll a n d ba dm in ton , i.e.,


th e in ter section of lists lst1 & lst2.

A list of in div idu a ls w h o like ba sketba ll bu t n ot ba dm in ton ,


i.e. th e differ en ce lst1 - lst2.

A lth ou g h Py th on does n ot su ppor t su ch oper a tor s on lists, w e


ca n con v er t lists in to sets, a pply th e n ecessa r y oper a tion s on
sets, a n d fin a lly con v er t th e sets ba ck in to lists. It is
im por ta n t to em ph a size th a t a list sh ou ld be con v er ted to sets
on ly w h en th e or der of elem en ts in th e list is n ot im por ta n t.
A lso, tr a n sfor m in g a list in to th e set w ill r em ov e r epea tin g
elem en ts. In Fig . 7 .1 2 , w e defin e th e fu n ction s union,
intersection, a n d difference for lists.
Fig. 7.12 Fu n ction s to fin d u n ion , in ter section , a n d differ en ce of
lists (lists.py)
7.3 TUPLES

A tuple is a non-scalar type defined in Python. Just like a


list, a tuple is an ordered sequence of objects. However,
unlike lists, tuples are immutable, i.e. elements of a tuple
cannot be overwritten. A tuple may be specified by
enclosing in the parentheses, the elements of the tuple
(possibly of heterogeneous types), separated by commas,
for example, the tuple t1 comprises five objects:

tu ple: a com m a sepa r a ted or der ed sequ en ce of v a lu es en closed


in pa r en th esis

>>> t1 = (4, 6, [2, 8], 'abc', {3, 4})

>>> type(t1)

<class 'tuple'>

If a tuple comprises a single element, the element should


be followed by a comma to distinguish a tuple from a
parenthesized expression, for example:

sin g leton tu ple: com m a r equ ir ed a fter th e elem en t

>>> (2)

>>> (2,)

(2,)

A tuple having a single element is also known as


singleton tuple. Another notation for tuples is just to list
the elements of a tuple, separated by commas:

>>> 2, 4, 6

(2, 4, 6)

Tuples being immutable, an attempt to modify an


element of a tuple yields an error:
tu ples a r e im m u ta ble

>>> t1[1] = 3

Traceback (most recent call last):

File "<pyshell#61>", line 1, in <module>

t1[1] = 3

TypeError: 'tuple' object does not support


item assignment

However, an element of a tuple may be an object that is


mutable, for example:

elem en ts of a tu ple m a y be m u ta ble

>>> t1 = (1, 2, [3, 4])

>>> t1[2][1] = 5

>>> t1

(1, 2, [3, 5])

7.3.1 Summary of Tuple Operations

In Table 7.4, we summarize the operations on tuples and


use the following tuples t1 and t2 for the purpose of
illustration:

>>> t1 = ('Monday', 'Tuesday')

>>> t2 = (10, 20, 30)


T a bl e 7.4 Su m m a r y of oper a tion s th a t ca n be a pplied on tu ples
7.3.2 Functions tuple and zip

The function tuple can be used to convert a sequence


to a tuple, for example:

con v er tin g a sequ en ce to a tu ple

>>> vowels = 'aeiou'

>>> tuple(vowels)

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


>>> tuple([4,10,20])

(4, 10, 20)

>>> tuple(range(5))

(0, 1, 2, 3, 4)

The function zip is used to produces a zip object


(iterable object), whose ith element is a tuple containing
ith element from each iterable object passed as argument
to the zip function. We have applied list function to
convert the zip object to a list of tuples. For example,

pr odu cin g a list of tu ples con ta in in g cor r espon din g elem en t


fr om ea ch iter a ble object

>>> colors = ('red', 'yellow', 'orange')

>>> fruits = ['cherry', 'banana',


'orange']

>>> quantity = ('1 kg', 12, '2 kg')

>>> fruitColor = list(zip(colors, fruits))

>>> fruitColor

[('red', 'cherry'),('yellow', 'banana'),


('orange', 'orange')]

>>> fruitColorQuantity =
list(zip(fruitColor, quantity))

>>> fruitColorQuantity

[(('red', 'cherry'), '1 kg'), (('yellow',


'banana'), 12), (('orange', 'orange'), '2
kg')]

>>> list(zip(colors, fruits, quantity))


[('red', 'cherry', '1 kg'), ('yellow',
'banana', 12), ('orange', 'orange', '2
kg')]

7.3.3 Functions count and index

The function count is used to find the number of


occurrences of a value in a tuple, for example:

cou n tin g n u m ber of occu r r en ces of a v a lu e in a tu ple

>>> age = (20, 18, 17, 19, 18, 18)

>>> age.count(18)

The function index is used to find the index of the first


occurrence of a particular element in a tuple, for
example:

fin din g in dex of th e fir st occu r r en ce of a n elem en t in th e


tu ple

>>> age.index(18)

These functions are summarized in Table 7.5:

T a bl e 7.5 Tu ple fu n ction s


7.4 DICTIONARY

Unlike lists, tuples, and strings, a dictionary is an


unordered sequence of key-value pairs. Indices in a
dictionary can be of any immutable type and are called
keys. Beginning with an empty dictionary, we create a
dictionary of month_number-month_name pairs as
follows:

diction a r y : a com m a sepa r a ted u n or der ed sequ en ce of key -


v a lu e pa ir s en closed in cu r ly br a ces

>>> month = {}

>>> month[1] = 'Jan'

>>> month[2] = 'Feb'

>>> month[3] = 'Mar'

>>> month[4] = 'Apr'

>>> month

{1: 'Jan', 2: 'Feb', 3: 'Mar', 4: 'Apr'}

>>> type(month)

<class 'dict'>

Key and value in a key-value pair in a dictionary are


separated by a colon. Further, the key:value pairs in a
dictionary are separated by commas and are enclosed
between curly parentheses. Next, we define another
dictionary comprising vegetable-price pairs:

deter m in in g v a lu e cor r espon din g to a key

>>> price = {'tomato':40, 'cucumber':30,


'potato':20, 'cauliflower':70,
'cabbage':50, 'lettuce':40, 'raddish':30,
'carrot':20, 'peas':80}
>>> price['potato']

20

>>> price['carrot']

20

>>> price.keys()

dict_keys(['tomato', 'cucumber', 'potato',


'cauliflower', 'cabbage', 'lettuce',
'raddish', 'carrot', 'peas'])

>>> price.values()

dict_values([40, 30, 20, 70, 50, 40, 30,


20, 80])

>>> price.items()

dict_items([('tomato', 40), ('cucumber',


30), ('potato', 20), ('cauliflower', 70),
('cabbage', 50), ('lettuce', 40),
('raddish', 30), ('carrot', 20), ('peas',
80)])

Note that the search in a dictionary is based on the key.


Therefore, in a dictionary, the keys are required to be
unique. However, the same value may be associated
with multiple keys. In particular, in the dictionary
price of vegetable-price pairs, we have already noted
that whereas the names of vegetables are unique
throughout the dictionary, the prices may be duplicated
(price['potato'] == price['carrot'] and
price['tomato'] == price['lettuce']). The
functions keys, values, and items return objects
comprising of keys, values, and key-value tuples in the
dictionary respectively. If required, a function such as
list or tuple may be applied to the output of the
functions keys, values, and items to obtain a list or
tuple of keys, values, or key-value tuples. As keys in a
dictionary are immutable, lists cannot be used as keys.
However, values associated with keys can be mutable
objects and thus, may be changed at will, for example:

key s: m u st be u n iqu e v a lu es: m a y be du plica ted

keys(): r etu r n a n object of key s


values(): r etu r n a n object of v a lu es
items(): r etu r n a n object of key -v a lu e tu ples

key s a r e im m u ta ble

>>> price['tomato'] = 25

Keys in a dictionary may be of heterogeneous types, for


example:

>>> counting = {1:'one', 'one':1, 2:'two',


'two':2}

7.4.1 Dictionary Operations

Table 7.6 gives some operations that can be applied to a


dictionary and illustrate these operations using a
dictionary of digit-name pairs:

digits = {0:'Zero', 1:'One', 2:'Two',


3:'Three', 4:'Four', 5:'Five', 6:'Six', 7:
'Seven', 8:'Eight', 9:'Nine'}
T a bl e 7.6 Su m m a r y of oper a tion s th a t ca n be a pplied on
diction a r ies

Next, consider a dictionary of winter months:

>>> winter = {11:'November ', 12:


'December', 1:'January', 2:'February'}

Membership operation in, and functions min, max and


sum apply only to the keys in a dictionary. Thus,
applying these operations on the dictionary winter is
equivalent to applying them on winter.keys() as
shown below:
min, max, sum, a n d in a pply to key s in a diction a r y

>>> 2 in winter, min(winter), max(winter),


sum(winter)

(True, 1, 12, 26)

>>> 2 in winter.keys(),
min(winter.keys()), max(winter.keys()),
sum(winter.keys())

(True, 1, 12, 26)

7.4.2 Deletion

We may remove a key-value pair from a dictionary


using del operator, for example:

r em ov in g a key -v a lu e pa ir

>>> del winter[11]

>>> winter

{12: 'December', 1: 'January', 2:


'February'}

To delete a dictionary, we use del operator:

deletin g a n en tir e diction a r y

>>> del winter

To remove all the key–value pairs in a dictionary, we use


the clear function. Note that while assigning an empty
dictionary {} creates a new object, the function clear
removes all key-value pairs from an existing
dictionary:

clear(): to r em ov e a ll key -v a lu e pa ir s
>>> winter = {11:'November ', 12:
'December', 1:'January', 2:'February'}

>>> months = winter

>>> months.clear()

>>> months, winter

({}, {})

Note that as the names winter and months refer to the


same dictionary object, on applying clear function to
months, the dictionary winter also becomes empty.

7.4.3 Function get

The function get is used to extract the value


corresponding to a given key, for example:

r etr iev in g v a lu e cor r espon din g to a key

>>> passwords = {'Ram':'ak@607',


'Shyam':'rou.589', 'Gita':'yam@694'}

>>> passwords.get('Ram',-1)

'ak@607'

The first parameter is used to specify the key and the


second parameter is used to specify the value to be
returned in case the key is not found in the dictionary. In
case, the second parameter is not specified, the system
returns None, for example:

get() r etu r n s secon d a r g u m en t if th e key is n ot pr esen t in


th e diction a r y

>>> passwords.get('Raman', -1)

-1
>>> print(passwords.get('Raman'))

None

7.4.4 Function update

The function update is used to insert in a dictionary, all


the key–value pairs of another dictionary, for example:

in ser tin g key -v a lu e pa ir s

>>> morePasswords = {'Raman':'vi97@4',


'Kishore':'23@0jsk'}

>>> passwords.update(morePasswords)

>>> passwords

{'Ram': 'ak@607', 'Shyam': 'rou.589',


'Gita': 'yam@694', 'Raman': 'vi97@4',
'Kishore': '23@0jsk'}

7.4.5 Function copy

To create a shallow copy of a dictionary object, we make


use of the copy function, for example:

cr ea tin g sh a llow copy of a diction a r y

>>> newPasswords = morePasswords.copy()

>>> id(newPasswords), id(morePasswords)

(54782832, 54781104)

7.4.6 List of Functions

In Table 7.7, we list some of the built-in functions that


can be applied to objects of dict type. Whereas many of
these functions such as update and clear modify a
dictionary, functions such as items, keys, values, and
get do not alter a dictionary.
T a bl e 7.7 Diction a r y fu n ction s

7.4.7 Inverted Dictionary

Suppose we are maintaining a dictionary of words and


their meanings of the form word:meaning. For
simplicity, we assume that each word has a single
meaning. Even so, there might be a few words that may
have shared meaning. Given this dictionary, we wish to
find synonyms of a word, i.e. given a word, we wish to
find the list of words that have the same meaning. For
this purpose, we would like to build an inverted
dictionary invDict of meaning:list-of-words. In
the function buildInvDict, we begin with an empty
dictionary invDict that uses meaning as the key. For
every key-value pair of word:meaning in the
dictionary dict1, if it is the first occurrence meaning,
then meaning:[word] is entered in the inverted
dictionary. If the key meaning already exists in the
inverted dictionary, then word is appended to the list
invDict[meaning]. Finally, we use comprehensions
to drop the words having only one meaning:

diction a r y com pr eh en sion for fin din g sy n on y m s in a


diction a r y

{meaning: invDict[x] for x in invDict if


len(invDict[x])>1}

The complete program appears in Fig. 7.13.

We conclude this section with a sample run of the


program invDict (Fig. 7.13).

>>>

Enter word meaning dictionary:


{'dubious':'doubtful',
'hilarious':'amusing',
'suspicious':'doubtful',
'comical':'amusing', 'hello':'hi'}

Inverted Dictionary:

{'doubtful': ['dubious', 'suspicious'],


'amusing': ['hilarious', 'comical']}
Fig. 7.13 Pr og r a m to con str u ct in v er ted diction a r y
(invDict.py)

SUMMARY

1 . Th e list is a n on -sca la r ty pe. It is a n or der ed sequ en ce of


v a lu es specified w ith in squ a r e br a ckets. V a lu es in a list
m a y be of a n y ty pe su ch a s str, int, float, or list.
2 . In dex in g is u sed for a ccessin g elem en ts of a list.
3 . Un like str in g s, lists a r e m u ta ble, i.e. on e m a y m odify
in div idu a l elem en ts of a list.
4 . A list of lists is ca lled a tw o-dim en sion a l list.
5 . Th e follow in g ta ble lists oper a tion s th a t ca n be a pplied
on th e list:

>>> list1 = ['Red', 'Green']


>>> list2 = [10, 20, 30]
Ope ration Example

>>> list2 * 2
Mu l t i p l i c at i on op er at or *
[10, 20, 30, 10, 20, 30]

>>> list1 = list1 + ['Blue']


Conc at enat i on op er at or + >>> list1
['Red', 'Green', 'Blue']

>>> len(list1)
Lengt h op er at or l en
3

>>> list2[-1]
Index i ng
30

>>> list2[0:2]
Sl i c i ng [10, 20]
Sy nt ax : start:end:inc >>> list2[0:3:2]
[10, 30]

>>> min(list2)
Fu nc t i on min
10

>>> max(list1)
Fu nc t i on max
'Red'

Fu nc t i on sum >>> sum(list2)


(not def i ned on st r i ngs) 60

>>> 40 in list2
Memb er sh i p op er at or in
False

6 . Th e follow in g ta ble lists som e im por ta n t bu ilt-in


fu n ction s th a t ca n be a pplied to lists:
F unctio
Explanation
n

L.append
Inser t s t h e el ement e at t h e end of t h e l i st L.
(e)

L.extend Inser t s t h e i t ems i n t h e sequ enc e L2 at t h e end of t h e


(L2) el ement s of t h e l i st L.

L.remove Remov es t h e f i r st oc c u r r enc e of t h e el ement e f r om


(e) t h e l i st L.

L.pop(i) Remov es t h e el ement at i ndex i f r om t h e l i st L.

L.count( Ret u r ns c ou nt of oc c u r r enc es of ob jec t e i n t h e l i st


e) L.

L.index( Ret u r ns i ndex of t h e f i r st oc c u r r enc e of t h e ob jec t


e) e, i f p r esent i n t h e l i st L.

L.insert
Inser t s el ement e at i ndex i i n t h e l i st L.
(i,e)

L.sort() Sor t s t h e el ement s of t h e l i st L.

L.revers
Rev er ses t h e or der of el ement s i n t h e l i st L.
e()

7 . Com pr eh en sion pr ov ides a n ea sy sh or th a n d n ota tion


for cr ea tin g lists, sets, a n d diction a r ies. For ex a m ple,
th e ex pr ession [x**3 for x in range(1, end)]
cr ea tes a list con ta in in g cu be of ea ch elem en t in th e
r a n g e (1, end).
8 . A ssig n m en t of a list to a n oth er v a r ia ble does n ot cr ea te
a n ew list. In stea d, th e n ew v a r ia ble r efer en ces th e
ex istin g list th a t a ppea r s on th e r ig h t-h a n d side of th e =
oper a tor .
9 . To cr ea te a n oth er in sta n ce of a n object of ty pes su ch a s
list, set, a n d dict, w e n eed to im por t th e copy
m odu le a n d in v oke th e fu n ction copy.copy().
How ev er , to cr ea te a copy of a list object, so th a t
em bedded objects (a t a ll lev els) g et copied, th e fu n ction
deepcopy of th e copy m odu le sh ou ld be u sed.
1 0. Th e fu n ction m a p is u sed for tr a n sfor m in g ev er y v a lu e
in a g iv en iter a ble object by a pply in g a fu n ction to it.
1 1 . Th e fu n ction filter th a t ta kes a fu n ction a n d a iter a ble
object a s th e in pu t pa r a m eter s a n d r etu r n s on ly th ose
elem en ts fr om th e iter a ble object for w h ich th e
fu n ction r etu r n s Tr u e.
1 2 . Th e fu n ction reduce, a v a ila ble in functools m odu le
ta kes tw o a r g u m en ts: a fu n ction , a n d a n iter a ble
object, a n d a pplies th e fu n ction on th e iter a ble object to
pr odu ce a sin g le v a lu e.
1 3 . A set is a n u n or der ed collection of objects w ith ou t a n y
du plica tes. A n object of ty pe set m a y be cr ea ted by
en closin g w ith in cu r ly br a ckets th e elem en ts of th e set.
A set object m a y a lso be cr ea ted by a pply in g th e set
fu n ction to a list, str in g or tu ple.
1 4 . Th e follow in g ta ble lists som e im por ta n t bu ilt-in
fu n ction s th a t ca n be a pplied to sets:

F unction De scription

S.add(e) A dds t h e el ement e t o t h e set S.

S1.update(L1) A dds t h e i t ems i n ob jec t L1 t o t h e set S1 .

S.remove(e) Remov es t h e el ement e f r om t h e set S.

S.pop() Remov es an el ement f r om t h e set S.

S.clear() Remov es al l el ement s f r om t h e set S.

S.copy() Cr eat es a c op y of t h e set S.

S1.union(S2) Ret u r ns u ni on of set s S1 and S2.

S1.intersecti Ret u r ns a set c ont ai ni ng el ement s c ommon i n


on(S2) t h e set s S1 and S2.

S1.difference Ret u r ns a set c ont ai ni ng el ement s i n t h e set


(S2) S1 b u t not i n t h e set S2.

S 1 . Ret u r ns a set c ont ai ni ng el ement s w h i c h ar e


symmetric_dif i n one of t h e t w o set s S1 and S2, b u t not i n
ference(S2 b ot h .

1 5 . Th e oper a tor s <=, ==, a n d >= m a y be u sed to ch eck


w h eth er a g iv en set is a su bset, equ a l, or su per set of
a n oth er set.
1 6 . A tu ple is a n on -sca la r ty pe. It is a n or der ed sequ en ce of
elem en ts. Un like lists, tu ples a r e im m u ta ble, i.e.
elem en ts of a tu ple ca n n ot be ov er w r itten .
1 7 . A tu ple w ith a sin g le elem en t is a lso kn ow n a s sin g leton
tu ple. Py th on a llow s v a lu es con ta in ed in a tu ple to be of
v a r ied ty pes.
1 8 . If a com pon en t of a tu ple con ta in s a n object th a t itself is
m odifia ble, th a t object ca n be m odified.
1 9 . Th e follow in g ta ble lists oper a tion s th a t ca n be a pplied
on tu ples:

>>> t1 = ('Monday', 'Tuesday')


>>> t2 = (10, 20, 30)
Ope ration Example

>>> t1 * 2
Mu l t i p l i c at i on
('Monday', 'Tuesday', 'Monday',
op er at or *
'Tuesday')

>>> t3 = t1 + ('Wednesday',)
Conc at enat i on
>>> t3
op er at or +
('Monday', 'Tuesday', 'Wednesday')

>>> len(t1)
Lengt h op er at or len
2

>>> t2[-2]
Index i ng
20

Sl i c i ng
>>> t1[1:2]
Sy nt ax :
'Tuesday'
start:end:inc

>>> min(t2)
Fu nc t i on min
10

>>> max(t2)
Fu nc t i on max
30

Fu nc t i on sum
>>> sum(t2)
(not def i ned on
60
st r i ngs)

Memb er sh i p >>> 'Friday' in t1


op er at or in False

2 0. Th e fu n ction tuple is u sed to con v er t a sequ en ce to a


tu ple.
2 1 . Th e fu n ction zip is u sed to pr odu ce a list, w h ose ith
elem en t is a tu ple con ta in in g ith elem en t fr om a ll th e
sequ en ces in th e ca ll to th e zip fu n ction .
2 2 . Th e follow in g ta ble lists tw o bu ilt-in fu n ction s th a t ca n
be a pplied on tu ples.

F unction Explanation

T.count(e Ret u r ns c ou nt of oc c u r r enc es of el ement e i n


) t u p l e L.

T.index(e
Ret u r ns i ndex of t h e el ement e f r om t u p l e L.
)

2 3 . A diction a r y is a n on -sca la r ty pe. It is a n u n or der ed


collection of key-value pa ir s. A diction a r y m a y be
specified by in clu din g th e key-value pa ir s w ith in
cu r ly br a ces. A key a n d its a ssocia ted v a lu e a r e colon -
sepa r a ted. Ea ch key u n iqu ely iden tifies th e v a lu e
a ssocia ted w ith it, a n d a lso, a cts a s a n in dex . A s key s in
a diction a r y a r e im m u ta ble, lists ca n n ot be u sed a s
key s.
2 4 . Th e follow in g ta ble lists th e oper a tion s th a t ca n be
a pplied on th e diction a r y of dig it–n a m e pa ir s:
digits = {0:'Zero', 1:'One', 2:'Two',
3:'Three', 4:'Four', 5:'Five', 6:'Six',
7:'Seven', 8:'Eight', 9:'Nine'}
2 5 . A key-value pa ir ca n be r em ov ed fr om a diction a r y
u sin g del oper a tor .
2 6 . Th e follow in g ta ble lists som e of th e bu ilt-in fu n ction s
th a t ca n be a pplied on th e ty pe dict:

F uncti
De scription
on

D.item Ret u r n an ob jec t c omp r i si ng of t u p l es of key-value


s() p ai r s p r esent i n di c t i onar y D. .

D.keys Ret u r n an ob jec t c omp r i si ng of al l k ey s of di c t i onar y


() D.

D.valu
es() Ret u r n an ob jec t c omp r i si ng of al l v al u es of
di c t i onar y D.
D.clea Remov es al l k ey –v al u e p ai r s f r om di c t i onar y D.
r()

D.get( For t h e sp ec i f i ed key, t h e f u nc t i on r et u r ns t h e


key,de assoc i at ed v al u e. Ret u r ns t h e default v al u e i n c ase of
fault) ab senc e of key i n di c t i onar y D.

D.copy
Cr eat es a sh al l ow c op y of di c t i onar y D.
()

D1.upd
A dds t h e k ey –v al u e p ai r s of di c t i onar y D2 i n
ate(D2
di c t i onar y D1.
)

EXERCISES

1 . Wr ite a fu n ction th a t ta kes a list of v a lu es a s in pu t


pa r a m eter a n d r etu r n s a n oth er list w ith ou t a n y
du plica tes.
2 . Wr ite a fu n ction th a t ta kes a list of n u m ber s a s in pu t
fr om th e u ser a n d pr odu ces th e cor r espon din g
cu m u la tiv e list w h er e ea ch elem en t in th e list a t in dex
i is th e su m of elem en ts a t in dex j <= i.
3 . Wr ite a pr og r a m th a t ta kes a sen ten ce a s in pu t fr om
th e u ser a n d com pu tes th e fr equ en cy of ea ch letter . Use
a v a r ia ble of diction a r y ty pe to m a in ta in th e cou n t.
4 . Iden tify th e ou tpu t pr odu ced w h en th e follow in g
fu n ction s a r e in v oked.
1 . def func():
l1 = list()
l2 = list()
for i in range(0,5):
l1.append(i)
l2.append(i+3)
print(l1)
print(l2)
2 . def func():
l1 = list()
l2 = list()
for i in range(0,5):
l1.append(i)
l2.append(i+3)
l1, l2 = l2, l1
print(l1)
print(l2)
5. Deter m in e th e ou tpu t of th e follow in g code sn ippets:
1 . c = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = 0
for i in range(0, 10):
if (c[i]%2 == 0):
result += c[i]
print(result)
2 . c = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = 0
for i in range(0, 10):
if (c[i]%2 != 0):
result += c[i]
print(result)
3 . subject = 'computer'
subject = list(subject)
ch = subject[0]
for i in range(0, len(subject)-1):
subject[i] = subject[i+1]
subject[len(subject)-1]=ch
print(''.join(subject))
4 . quantity = [15, 30, 12, 34, 56, 99]
total = 0
for i in range(0, len(quantity)):
if (quantity[i] > 15):
total += quantity[i]
print(total)
5 . x = [1, 2, 4, 6, 9, 10, 14, 15, 17]
for i in range(0, len(x)):
if (x[i]%2 == 0):
x[i] = 4*i
elif (x[i]%3 == 0):
x[i] = 9*i
else:
x[i] *= 2
print(x)
6. Wr ite a fu n ction th a t ta kes n a s a n in pu t a n d cr ea tes a
list of n lists su ch th a t ith list con ta in s fir st fiv e
m u ltiples of i.
7. Wr ite a fu n ction th a t ta kes a n u m ber a s a n in pu t
pa r a m eter a n d r etu r n s th e cor r espon d tex t in w or ds,
for ex a m ple, on in pu t 4 5 2 , th e fu n ction sh ou ld r etu r n
'Four Five Two'. Use a diction a r y for m a ppin g dig its
to th eir str in g r epr esen ta tion .
8. Giv en th e follow in g in pu ts, in dica te in ea ch ca se (a ) to
(x ), w h eth er th e sta tem en ts w ill ex ecu te su ccessfu lly .
If, so, g iv e w h a t w ill be th e ou tcom e of ex ecu tion ? A lso
g iv e th e ou tpu t of pr in t sta tem en ts (w h er e a pplica ble):
address = 'B-6, Lodhi road, Delhi'
list1 = [1, 2, 3]
list2 = ['a', 1, 'z', 26, 'd', 4]
tuple1 = ('a', 'e', 'i', 'o', 'u')
tuple2 = ([2,4,6,8], [3,6,9], [4,8], 5)
dict1 = {'apple': 'red', 'mango': 'yellow',
'orange': 'orange'}
dict2 = {'X': ['eng', 'hindi', 'maths',
'science'], 'XII': ['english', 'physics',
'chemistry', 'maths']}
1 . list1[3] = 4
2 . print(list1 * 2)
3 . print(min(list2))
4 . print(max(list1))
5 . print(list(address))
6 . list2.extend(['e', 5])
print(list2)
7 . list2.append(['e', 5])
print(list2)
8 . names = ['rohan', 'mohan', 'gita']
names.sort(key= len)
print(names)
9 . list3 = [(x * 2) for x in range(1, 11)]
print(list3)
1 0. del list3[1:]
print(list3)
1 1 . list4 = [ x+y for x in range(1,5) for y
in range(1,5)]
print(list4)
1 2 . tuple2[3] = 6
1 3 . tuple2.append(5)
1 4 . t1 = tuple2 +(5)
1 5 . ','.join(tuple1)
1 6 . list(zip(['apple', 'orange'], ('red',
'orange')))
1 7 . dict2['XII']
1 8 . dict2['XII'].append('computer science'),
dict2
1 9 . 'red' in dict1
2 0. list(dict1.items())
2 1 . list(dict2.keys())
2 2 . dict2.get('XI', 'None')
2 3 . dict1.update({'kiwi':'green'})
print(dict1)

9 . Con sider th e follow in g th r ee sets, n a m ely vehicles,


heavyVehicles, a n d lightVehicles:
>>>vehicles = {'Bicycle', 'Scooter', 'Car',
'Bike', 'Truck', 'Bus', 'Rickshaw'}
>>> heavyVehicles = {'Truck', 'Bus'}
>>> lightVehicles = {'Rickshaw', 'Scooter',
'Bike', 'Bicycle'}
Deter m in e th e ou tpu t on ex ecu tin g th e follow in g
sta tem en ts:
1 . lytVehicles = vehicles – heavyVehicles
print(lytVehicles)
2 . hvyVehicles = vehicles – lightVehicles
print(hvyVehicles)
3 . averageWeightVehicles = lytVehicles &
hvyVehicles
print(averageWeightVehicles)
4 . transport = lightVehicles |
heavyVehicles
print(transport)
5 . transport.add('Car')
print(transport)
6 . for i in vehicles:
print(i)
7 . len(vehicles)
8 . min(vehicles)
9 . set.union(vehicles, lightVehicles,
heavyVehicles)
!
Th is section m a y be skipped on fir st r ea din g w ith ou t loss of
con tin u ity
CHAPTER 8
RECURTION

CHAPTER OUTLINE
8 .1 Recu r siv e Solu tion s for Pr oblem s on Nu m er ic Da ta

8 .2 Recu r siv e Solu tion s for Pr oblem s on Str in g s

8 .3 Recu r siv e Solu tion s for Pr oblem s on Lists

8 .4 Pr oblem of Tow er of Ha n oi

In the previous chapters, we have used functions for


various programming tasks. When computation in a
function is described in terms of the function itself, it is
called a recursive function. Python allows a function to
call itself, possibly with new arguments.

Recursion aims to solve a problem by providing a


solution in terms of the simpler version of the same
problem. A recursive function definition comprises two
parts. The first part is the base part, which is the solution
of the simplest version of the problem, often termed
stopping or termination criterion. The second part is the
inductive part, which is the recursive part of the problem
that reduces the complexity of the problem by redefining
the problem in terms of simpler version(s) of the original
problem itself.

A r ecu r siv e solu tion com pr ises:


ba se pa r t a n d in du ctiv e pa r t

8.1 RECURSIVE SOLUTIONS FOR PROBLEMS ON NUMERIC DATA

8.1.1 Factorial

Suppose we wish to find the factorial of a non-negative


number n. To do this, we have to multiply numbers 1 to
n:
n! = n * (n-1) * (n-2) * (n-3) * … * 2 * 1

Factorial of 0 is of course defined to be 1. We will first


discuss the iterative approach, thus, providing an insight
into how space is allocated on system stack when a
function is invoked. This is followed by the recursive
approach for computing factorial.

Iterative Approach

Factorial of a number n can be computed by using a


loop that iterates over elements in the range(1, n +
1). An iterative function for computing the factorial of a
number is given in Fig. 8.1.
Fig. 8.1 Pr og r a m to com pu te fa ctor ia l of a n u m ber
(factorial1.py)

Recursive Approach

Next, we rewrite the function factorial to compute


factorial of a number using recursive approach. Recall
that n! = n * (n-1) * (n-2) * (n-3) * … * 2
* 1. Alternatively, we may write the definition of n! as

or equivalently as

factorial(n) = 1 if n==0 or 1

= n * factorial(n-1) if n > 1

r ecu r siv e defin ition of fa ctor ia l

Thus, the problem of computing factorial(n) – a


problem of size n – has been expressed in terms of a
problem of size (n – 1), i.e. to compute
factorial(n), we multiply by n the result of
computing factorial(n-1). Now factorial(n-1)
can be computed using the same technique, i.e. to
compute factorial(n-1), we multiply by n-1 the
result of computing factorial(n-2). Thus, we solve a
problem of size (n – 1) in terms of a problem of size
(n – 2), and so on until we arrive at the problem of
size 1, which is a trivial task. Thus, the factorial of a
number, say 3, it may be computed as follows:

factorial(3) = 3 * factorial(2)

= 3 * (2 * factorial(1))

= 3 * (2 * 1))

= 3 * 2

= 6

Now, we are ready to present a recursive function to


compute factorial(n) (Fig. 8.2):
Fig. 8.2 Pr og r a m to com pu te fa ctor ia l of a n u m ber
(factorialRecur.py)

Let us examine the recursive function factorial to


compute the factorial of a number, say 3. The script
factorialRecur (Fig. 8.2) invokes the function main
in line 24 which further invokes the function
factorial in line 20. Whenever a function is called in
a program, the program must remember the point of
call, so that the control can be returned appropriately
when the function is completely executed. Also, it should
save the current state, i.e. binding of variables. For every
call to a function, an entry in a stack, called stack frame
or activation record, is created. In this entry, temporary
storage is allocated to parameters, local variables, and
return address. Like any other stack, the objects in the
activation stack leave in the reverse order of their arrival.
ca ll to a fu n ction cr ea tes a n en tr y in th e sta ck fr a m e/
a ctiv a tion r ecor dl

sta ck fr a m e stor es pa r a m eter s, loca l v a r ia bles, a n d r etu r n


a ddr ess

Figure 8.3 shows stack frames created and exited


during the execution of the script in Fig. 8.2. Note that
the exited frames (border lines as well as the content) are
shown in light grey color. To begin with, when Python
encounters the definitions of factorial and main
functions in the program, an entry is created for
factorial and main functions in the global frame
(Fig. 8.3(a)). When the condition if
__name__=='__main__' evaluates to True, the
function main is invoked and a new frame is created. On
entering 3 as the input value for n (line 19), the variable
binding for it is created (Fig. 8.3(b)). On invoking the
function factorial (line 20, Fig. 8.2) with the
argument 3, a new frame is created containing a binding
for the input parameter n (Fig. 8.3(c)). Further, since the
value of n is greater than l, during execution of line 11, a
recursive call is made to the function factorial with 2
as the input argument. This creates another stack frame
as shown in Fig. 8.3(d). Note that the parameter n is
now bound to value 2. This recursive call further invokes
function factorial with input argument l (Fig.
8.3(e)). In this frame, the parameter n is bound to value
1. As the value associated with variable n is now 1, the
condition in line 8 becomes True. So, this instance of
function call creates the returns value 1 (Fig. 8.3(f)). On
completion of the execution of this instance of the
function factorial, the frame for the function call
that has just terminated is removed from the stack, and
the control is returned to the previous frame (Fig. 8.3(g))
at the point of call (line 11), i.e. frame for function
factorial, where parameter n is bound to value 2.
This instance of function call now creates the returns
value 2 as shown in Fig. 8.3(g). The function returns
value 2 on execution of line 11. This value 2 is returned
in line 11 (variable n is now bound to value 3, Fig.
8.3(h)). This instance of function call now creates the
returns value 6 as shown in Fig. 8.3(h). Execution of line
11 returns value 6 to the main function (Fig. 8.3(i)). In
the main function, the just returned value 6 gets bound
to the variable result (Fig. 8.3(i)). When the main
function completes, it returns value None associated
with it (Fig. 8.3(j)), and the control is returned to the
global frame from the frame main function (Fig.
8.3(k)).

Note that the stack is growing in the downward


direction. The value of any variable can be found in the
current state of the program by looking at the most
recent stack frame (highlighted frame in the visualizer).
Fig. 8.3 Recu r siv e ca lls to fu n ction factorial

Next, we rewrite the function factorial with a


slight change:

def factorial(n):

'''

Objective: To compute factorial of a


positive number

Input Parameter: n – numeric value

Return Value: factorial of n - numeric


value

'''

assert n >= 0

if n == 0 or n == 1:

return 1

return n * factorial(n-1)
a lter n a tiv e defin ition for fu n ction fa ctor ia l

If the base condition (n == 0 or n == 1) evaluates


to True, control is automatically returned from the
function with value 1. However, failure of the base
condition leads to the execution of the line return n *
factorial(n-1). Note that in case n has value 0 or 1,
this statement will not be executed as the control would
have already returned to the caller function i.e. main(),
in this example.

8.1.2 Fibonacci Sequence

Fibonacci sequence is a sequence of integers. The first


and the second numbers in the sequence are 0 and 1. A
subsequent term in the sequence is computed as the sum
of immediately preceding two terms. Thus, we get the
Fibonacci sequence as follows:

0, 1, 1, 2, 3, 5, 8, 13, 21, …

Suppose, we want to find out the nth term in the


Fibonacci sequence. It may be computed as follows:

Iterative Approach

In this section, we develop a function to compute the nth


term of the Fibonacci sequence. If the value of n is 1 or
2, the function just needs to return 0 or 1, respectively.
However, if n>2, the nth term is computed using a loop
with iterator i that iterates over elements in the range
(3, n+1), and for each element in the range(3,n+1),
the new value is computed by taking the sum of the
previous two terms that we call secondLast and last.
Iterative function for finding the nth term of the
Fibonacci sequence is given in Fig. 8.4.
Fig. 8.4 Pr og r a m to deter m in e n th Fibon a cci ter m (fibo1.py)

Recursive Approach

In this section, we compute nth Fibonacci term using


recursive approach. As mentioned earlier, nth term in
the Fibonacci sequence may be computed as follows:

r ecu r siv e defin ition of n th fibon a cci ter m

where fibo(n) denotes nth term of Fibonacci series.

We call the problem of computing fibo(n), a problem


of size n. In the above formulation, we have expressed
the problem of computing fibo(n) – a problem of size
n, in terms of two problems:

a pr oblem of com pu tin g fibo(n-1) – pr oblem of size n –1


and
a pr oblem of com pu tin g fibo(n-2) – pr oblem of size n – 2

These problems of sizes smaller than that of the original


problem can be further expressed in terms of problems of
even smaller sizes, and so on until we reach a problem of
size 1 or 2 – a trivial problem to solve. For example, 4th
term of Fibonacci sequence may be computed as follows:

fibo(4) = fibo(3) + fibo(2)

= (fibo(2) + fibo(1)) + fibo(2)

= (1 + fibo(1)) + fibo(2)

= (1 + 0) + fibo(2)
= 1 + fibo(2)

= 1 + 1

= 2

In light of the above discussion, we present a recursive


function to compute nth term in the Fibonacci sequence
(Fig. 8.5).

Note that during each call to function Fibonacci, a


new stack frame will be allocated, and variable bindings
will be created, allocating storage space for new values.
Also, the program remembers the point of call to the
function, so as to return control back to the point of call
when the function completes. Suppose we wish to
determine 4th Fibonacci term. Determining 4th
Fibonacci number involves computing 3rd and 2nd
Fibonacci terms. Figures 8.6(a) and (b) show the
contents of the run-time stack as visualized in Python
Tutor for computation of the 3rd and 2nd Fibonacci
terms. Subsequently, 4th term is computed using these
two values as shown in Fig. 8.6(c).
Fig. 8.5 Pr og r a m to deter m in e nth ter m in th e Fibon a cci
sequ en ce (fiboRecur.py)

Note that computation of 4th term in the Fibonacci


sequence involves repetitive computations of second
Fibonacci term. In general, computing nth term in the
Fibonacci sequence in a recursive manner involves
repetitive computations that add to space and time
requirements of the problem. Thus, use of recursion
should be best avoided whenever we can conceive of a
simple iterative alternative solution. However, to learn
recursion as a programming technique, we will begin
with recursive solutions to the simple problems for
which iterative solutions may be more efficient.
Subsequently, we will give several examples of problems
for which it is extremely hard, if not impossible, to
conceive iterative solutions. The problems like tower of
Hanoi, permutation generation, 8-queen's problem,
Knight's tour problem, and the problem of creating
patterns within pattern using fractals fall under this
category.

a r ecu r siv e solu tion m a y a dd to spa ce a n d tim e r equ ir em en ts

pr efer iter a tiv e solu tion ov er r ecu r siv e if iter a tiv e solu tion is
sim pler to con ceiv e

8.2 RECURSIVE SOLUTIONS FOR PROBLEMS ON STRINGS

In this section, we will solve some problems related to


strings using recursion.
8.2.1 Length of a String

Let us begin with the problem of computing length of a


string. Although Python provides a function len for
computing the length of a string, we will develop our
function length for this purpose using the concept of
slicing. Let us first examine the base case when the
string is an empty string. In this case, the length of the
string is 0. However, if the string is non-empty, its length
may be computed as 1 plus the length of the string
excluding the first character. Thus, the length of the
string can be expressed using recursion as follows:

r ecu r siv e defin ition for len g th of a str in g


Fig. 8.6 Recu r siv e ca lls to fu n ction fibo

Thus, a problem of size n (n > 0) has been expressed in


terms of a problem of size (n – 1). A recursive
function to do this is given in Fig. 8.7. Suppose we need
to compute the length of the string 'Zero'. We may do
so using the function length as follows:

length('Zero') = 1 + length('ero')

= 1 + (1 + length('ro'))

= 1 + (1 + (1 + length('o')))

= 1 + (1 + (1 + (1 + length(''))))

= 1 + (1 + (1 + (1 + 0)))

= 1 + (1 + (1 + 1))

= 1 + (1 + 2)

= 1 + 3

= 4
Fig. 8.7 Pr og r a m to deter m in e len g th of th e str in g (lenStr.py)
Figure 8.8 gives stack frames created and exited on the
execution of the script lenStr with 'Zero' as an input
value for str1, as visualized in Python Tutor.

8.2.2 Reversing a String

A string is said to be a reversed string of another string if


the first character in the reversed string is the last
character of the given string, the second character in the
reversed string is the second last character of the given
string, and so on. To reverse a given string, the trivial
base case is the case when the string is an empty string,
in which case, the reverse of the given string is the
empty string itself. However, if the string is non-empty,
reversed string can be obtained as the last character of
the string concatenated with the reverse of string
obtained from the original string by dropping the last
character:

r ecu r siv e defin ition for r ev er se of a str in g

Thus, a problem of size n has been expressed as the


problem of size (n – 1). A recursive function to
compute reverse string of a given string is given in Fig.
8.9. Suppose we need to reverse the string 'Zero', it may
be done as follows:

reverse('Zero') = 'o' + reverse('Zer')

= 'o' + ('r' + reverse('Ze'))

= 'o' + ('r' + ('e' + reverse('Z')))

= 'o' + ('r' + ('e' + ('Z' +


reverse(''))))

= 'o' + ('r' + ('e'+ ('Z'+ '')))

= 'o' + ('r' + ('e' + 'Z'))


= 'o' + ('r' + 'eZ')

= 'o' + 'reZ'

= 'oreZ'
Fig. 8.8 Recu r siv e ca lls to fu n ction length
Fig. 8.9 Pr og r a m to r ev er se th e str in g (reverse.py)

In Fig. 8.10, we present stack frames created and


exited on the execution of script reverse in Python
Tutor on the input string 'Zero'.

8.2.3 Palindrome

A string is said to be a palindrome if the reverse of a


string is equal to the string itself. Next, we examine how
to check whether a given string is a palindrome. A string
can be tested for being palindrome by comparing the
characters in the string from the two extreme ends.
Thus, we compare the character at index 0 with the
character at index −1, the character at index 1 with the
character at index −2, and so on, till we reach the middle
of the string. In case, a mismatch is found on the way,
given string is not a palindrome, and we return False;
otherwise, it is a palindrome, and we return True. This
approach can be easily expressed using recursion. The
trivial base case is the case where the string is an empty
string and as such a palindrome. However, if the string is
non-empty, a string can be declared as palindrome if the
following two conditions hold:

Fir st a n d la st ch a r a cter s of th e g iv en str in g m a tch .


Th e r em a in in g str in g , obta in ed by dr oppin g th e fir st a n d
la st ch a r a cter s of th e or ig in a l str in g is a pa lin dr om e.
Fig. 8.10 Recu r siv e ca lls to fu n ction reverse

Thus, the problem of checking whether a string is a


palindrome can be expressed using the recursion as
follows:
is g iv en str in g is a pa lin dr om e?

To begin with the base case, an empty string is trivially a


palindrome. However, if the given string is not an empty
string, we can express the problem of testing whether a
string of size n is a palindrome in terms of a problem of
size (n – 2). Next, we apply the above method to test
whether the string 'noon' is a palindrome as follows:

isPalindrome('noon') = str1[0]==str1[-1]
and isPalindrome('oo')

= True and isPalindrome('oo')

= True and (str1[0]==str1[-1] and


isPalindrome(''))

= True and (True and isPalindrome(''))

= True and (True and (True))

= True and (True)

= True

In light of the above discussion, we present a recursive


function to determine whether a string is a palindrome
(Fig. 8.11).
Fig. 8.11 Pr og r a m to deter m in e w h eth er a str in g is a pa lin dr om e
(palindrome.py)
In Fig. 8.12, we present stack frames created and
exited on the execution of script palindrome when
'noon' is entered as an input value for str1.

Fig. 8.12 Recu r siv e ca lls to fu n ction isPalindrome

8.3 RECURSIVE SOLUTIONS FOR PROBLEMS ON LISTS


8.3.1 Flatten a List

Let us examine the problem of flattening the list. Given a


list of lists, the nesting of lists may occur up to any
arbitrary level. By flattening a list, we mean to create a
list of all data values in the given list. The data values in
the flattened list appear in the left to right order of their
appearance in the original list, ignoring the nested
structure of the list. Thus, the list

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


12], 13], 14, [[15,16]], 17]

will be flattened to obtain the following list:

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


13, 14, 15, 16, 17]

To create the flattened list, say lst2, for a given list


lst1, we initialize list lst2 as an empty list and append
the data values in the list lst1 to the list lst2, one by
one. The overall approach to flatten a list can be
summarized as follows:

for every element i in list lst1

if i is not a list

append it to list lst2

otherwise,

flatten list i

A recursive function to flatten a list is given in Fig. 8.13.

Let us examine the recursive program to flatten the list


[1, [2, 3]]. As Python Tutor does not support the
eval function, we will fix the value of the variable lst1
in the program to be [1, [2, 3]]. This style of
programming where values of the variables or
parameters cannot be changed without modifying the
program is called hard-coding and is strongly
discouraged for all practical purposes. Anyway, while
executing the program in Fig. 8.13 in the Python Tutor,
we replace line 20 in Fig. 8.13 by the assignment
statement:

lst1 = [1, [2, 3]]

Py th on Tu tor does n ot su ppor t eval fu n ction

h a r d-codin g th e v a lu es of v a r ia bles
Fig. 8.13 Pr og r a m to fla tten a list (flatten.py)

As discussed before, during each call to function


flatten, a new stack frame will be allocated, and the
variable bindings will be created allocating storage space
for new values. In Fig. 8.14, we show stack frames
created and exited during the execution of the script
flatten. To begin with, when Python encounters the
definitions of flatten and main functions in the
program, an entry is created for flatten and main
functions in the global frame (Fig. 8.14 (a)). When the
condition if __name__=='__main__' evaluates to
True, function main is invoked and a new frame is
created. On assigning [1, [2, 3]] as the value
associated with list lst1, variable binding for it is
created as shown in Fig. 8.14(b). On execution of line 21
in Fig. 8.14, the function flatten gets invoked, and a
new frame is created containing bindings for input
parameters lst1 and lst2 (Fig. 8.14(c)). Now lst1
refers to the list to be flattened and lst2 refers to the
flattened list being created (currently empty). Iterating
over the list lst1, element is initialized to lst1[0],
i.e. 1 (Fig. 8.14(d)). Since the type of this value is not a
list, there is no need to flatten it further. Thus, line 9 is
executed, and 1 is appended to the list lst2 (Fig.
8.14(e)). In the next iteration, element takes the value
[2,3] (Fig. 8.14(f)). Since the value of the element is a
list, it needs to be flattened further. The execution of line
11 recursively invokes function flatten with the list
[2,3] as the first argument (the list to be flattened) and
the list lst2 as the second argument (flattened list being
produced). This leads to the creation of new stack frame
with respective input parameters, lst1 pointing to
[2,3] and lst2 pointing to list [1] as shown in Fig.
8.14(g). Iterating through this new list lst1 yields 2
and 3 as values which need no flattening. Thus,
resultant list lst2 will contain [1,2,3] as shown in
Fig. 8.14(k). Now the function returns [1,2,3] as the
list lst2 (Fig. 8.14(l)). As the current instance of
function flatten has been completely executed, the
control returns to the previous frame (Fig. 8.14(m)) at
the point of call (line 11). Since the list lst1 [1,
[2,3]] is now exhausted, the function returns the
flattened list lst2 to the main function. The flattened
list is received in the main function in the variable
result (Fig. 8.14(n)). Thus, we see the new binding of
the local variable result in the main frame with the
list [1,2,3] returned by the function flatten. When
the main function completes, it returns the value None
associated with it, as it does not return any value (Fig.
8.14(n)), and the control is returned to the global frame
from the frame main function (Fig. 8.14(o)).
Fig. 8.14 Recu r siv e ca lls to fu n ction flatten

8.3.2 Copy

In this section, we develop a function for creating a copy


of a list. As mentioned earlier, simply assigning a list
object to another name does not create a copy of the list;
instead, both the names refer to the same list object. So,
to create a copy of a source list, say lst1, we begin with
an empty destination list, say lst2, and append every
element of list lst1 to list lst2 recursively. The trivial
base case is the case when the list lst1 is an empty list,
implying that the destination list lst2 will also be
empty. However, if the list lst1 is non-empty, a copy of
a list can be created by appending the first element of list
lst1 to list lst2, and invoking the copy function for
the remaining list lst1 (i.e., excluding the first
element). This way of copying a sequence is also known
as shallow copy. Thus, a problem of size n has been
expressed in terms of a problem of size (n – 1). Based
on this discussion, we present the complete program that
accepts a list from the user, creates a copy of the list and
prints it (Fig. 8.15).

copy in g a list
Fig. 8.15 Pr og r a m to cr ea te copy of a list (copy.py)

Let us examine the recursive function to create a copy of


the list [1, [2, 3]]. As discussed before, a new stack
frame will be allocated, and the variable bindings will be
created, allocating storage space for new values. Also,
the program remembers the point of call of the function,
so as to return control back to the point of call when the
function completes. Figure 8.16 shows the stack frames
created and exited on execution of the script as visualized
in Python Tutor with [1, [2, 3]] being the value of
the list lst1.

8.3.3 Deep Copy

As mentioned earlier, in a shallow copy operation the


embedded objects such as nested list are not copied,
instead they are shared between the two lists. If we wish
to copy the entire list, including embedded objects, such
a copy is called deep copy.

deep copy : copy in g th e en tir e list in clu din g em bedded objects


Fig. 8.16 Recu r siv e ca lls to fu n ction copy

A deep copy of a list can be created in a manner


similar to creating a shallow copy of the list. However,
an element of list lst1 is appended to list lst2 only if it
is not a list. In case the element itself is a list object, the
deepCopy function is invoked for that element. The
trivial base case is the case when the list lst1 is an
empty list, in which case the resulting list lst2 is also
an empty list. However, if the list lst1 is non-empty, a
deep copy of the list is created. Based on this discussion,
we present the complete program that accepts a list from
the user, creates a deep copy of the list and prints it (Fig.
8.17). Figure 8.18 shows stack frames created and exited
on execution of script in Fig. 8.17 as visualized in Python
Tutor with [1,[2,3]] as the value of the list lst1.

8.3.4 Permutation

An arrangement of the elements of a list is called a


permutation. For example, the list [1, 2, 3] will have
the following six permutations:

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


1], [3, 1, 2], [3, 2, 1]
Fig. 8.17 Pr og r a m to cr ea te deep copy of a list (deepCopy.py)

In this section, we will develop a function to generate all


permutations of a list. In general, a list with n elements
will have n! permutations.

To understand the mechanism for generating the


permutations, suppose we already have a permutation
perm of two numbers: [1, 2]. To generate a
permutation of three numbers {1, 2, 3} from this list, we
apply the following procedure:

for each position pos in the list perm:

insert 3 at pos

print perm

remove 3 from perm at pos (To get back the


original permutation [1,2])

g en er a tin g per m u ta tion s of [1 , 2 , 3 ] fr om [1 , 2 ] by in ser tin g


elem en t 3 a t differ en t position s
Thus, on inserting 3 at position 0, 1, and 2, we get the
permutations [3, 1, 2], [1, 3, 2], and [1, 2,
3], respectively.
Fig. 8.18 Recu r siv e ca lls to fu n ction deepCopy

A recursive function to generate permutations of a list


is given in Fig. 8.19. The function is based on the
assumption that the elements at index 0 through k-1 of
list lst1 are already in the permutation list lst2. Thus,
the problem at hand is to insert the element lst1[k] in
the current permutation list, i.e. lst2, at every possible
position one by one. On inserting lst1[k], if the length
of the permutation lst2 becomes equal to len(lst1),
we print the permutation. Otherwise, we build up the
permutation further by invoking the function permute
once again, with the objective of inserting lst1[k+1]
in the list lst2. Note that the element lst1[k] that
was inserted at position pos in the permutation list lst2
(line 10) is removed from there (line 19), so as to
generate other possible permutations (line 23). Initially,
the function permute is invoked with the list lst1 as
an argument. The other parameters are set to default
values.
Fig. 8.19 Pr og r a m to cr ea te copy of a list (permute.py)

We have executed the script permute (Fig. 8.19) to


generate permutations of the list [1, 2, 3]. In Fig.
8.20, we show the contents of the run-time stack as
visualized in Python Tutor, for first three calls to the
function permute.

8.4 PROBLEM OF TOWER OF HANOI

In this section, we will discuss how to use recursion to


solve the problem of Tower of Hanoi. First, let us
describe the problem. There are three poles numbered 1,
2, and 3. In the first pole, n disks have been inserted.
These disks are placed one above the other in a
decreasing order of the diameter. The problem is to
transfer all the disks from pole 1 to pole 3 using pole 2 as
a spare pole, moving one disk at a time, and always
keeping in mind that a disk with larger diameter is not to
be placed over a disk with smaller diameter. See Fig. 8.21
for the case n = 3.
Fig. 8.20 Gen er a tin g th e fir st per m u ta tion u sin g fu n ction
permute

Fig. 8.21 Tow er of Ha n oi for n = 3

Before solving the problem in general, let us consider


some simple cases.

n = 1

The solution is trivial. Just move the disk from pole 1 to


pole 3.
n = 2

Tow er of Ha n oi h a v in g on e disk

Move the smaller disk at pole 1 to the spare pole 2. Now,


the bigger disk at pole 1 can be moved to pole 3. Finally,
move the smaller disk from the spare pole 2 to pole 3.
This completes the task.

n = 3

Tow er of Ha n oi h a v in g tw o disks

When the largest disk is transferred to pole 3, it must be


empty. Therefore, the first task we have to do is to
transfer two disks to pole 2 using pole 3 as a spare pole.
We have already seen above, how to transfer two disks
from one pole to another using a spare pole. The only
difference being that in the example above, pole 1, pole 2,
and pole 3 were used as the source, spare, and
destination poles, respectively, and currently pole 1, pole
3, and pole 2 are to be used as source, spare, and
destination poles, respectively. The following steps will
achieve this task:

Tow er of Ha n oi h a v in g th r ee disks

Move a disk from pole 1 to pole 3

Move a disk from pole 1 to pole 2

Move a disk from pole 3 to pole 2


Now, the largest disk can be moved from pole 1 to
pole 3.

Two disks in pole 2 are yet to be transferred to pole 3


using pole 1, which is currently empty as the spare pole.
Since each disk in pole 2 is of a smaller diameter than
the disk in pole 3, any of them can be shifted to pole 3.
The following steps will achieve the transfer of two disks
from pole 2 to pole 3.

Move a disk from pole 2 to pole 1

Move a disk from pole 2 to pole 3

Move a disk from pole 1 to pole 3

The task is now complete for n = 3.

In general, if there are n disks to be transferred from


pole 1 to pole 3, using pole 2 as the spare pole, the task
can be accomplished as follows:

Transfer (n – 1) disks from pole 1 to pole


2 using pole 3 as the spare pole.

Transfer one disk from pole 1 to pole 3

Transfer (n -1) disks from pole 2 to pole


3 using pole 1 as the spare pole.

pseu do-code for solv in g Tow er of Ha n oi pr oblem

Thus, a problem of size n has been expressed in terms of


two problems of size (n – 1), each of which can be
solved using the same technique, i.e., by expressing each
problem of size (n – 1) in terms of two problems of
size (n – 2), and so on until only one disk is to be
transferred, which is a trivial task. These ideas have been
coded in the form of function hanoi (Fig. 8.22).
Fig. 8.22 Pr og r a m to solv e pr oblem of Ha n oi(h a n oi.py )

SUMMARY

1 . Py th on a llow s a fu n ction to ca ll itself, possibly w ith


n ew pa r a m eter v a lu es. Th is tech n iqu e is ca lled
r ecu r sion .
2 . Recu r sion is a tech n iqu e, w h ich a im s to solv e a pr oblem
by pr ov idin g a solu tion in ter m s of th e sm a ller
v er sion (s) of th e sa m e pr oblem . A r ecu r siv e fu n ction
defin ition com pr ises tw o pa r ts. Th e fir st pa r t is th e ba se
pa r t w h ich is th e sim plest v er sion of th e pr oblem , often
ter m ed stoppin g or ter m in a tion cr iter ion . Th e secon d
pa r t is th e in du ctiv e pa r t w h ich is th e r ecu r siv e pa r t of
th e pr oblem th a t r edu ces th e com plex ity of th e
pr oblem by defin in g a sim pler v er sion of th e or ig in a l
pr oblem itself.
3 . Fa ctor ia l of a n u m ber ca n be r ecu r siv ely ex pr essed a s
follow s:

4 . n th ter m of th e Fibon a cci sequ en ce ca n be r ecu r siv ely


ex pr essed a s follow s:

5 . Len g th of a str in g ca n be r ecu r siv ely ex pr essed a s


follow s:

6 . Rev er se of a str in g ca n be r ecu r siv ely ex pr essed a s


follow s:
7 . Ch eckin g w h eth er a str in g is a pa lin dr om e ca n be
r ecu r siv ely ex pr essed a s follow s:

8 . Th e a ppr oa ch to fla tten a list r ecu r siv ely ca n be


ex pr essed a s follow s:
for every element i in list lst1
if i is not a list
append it to list lst2
otherwise,
flatten list i
9 . In Tow er of Ha n oi pr oblem , if th er e a r e n disks to be
tr a n sfer r ed fr om pole 1 to pole 3 , u sin g pole 2 a s th e
spa r e pole, th e ta sk ca n be a ccom plish ed a s follow s:
if n == 1
transfer one disk from pole 1 to pole 3.
else
transfer (n – 1) disks from pole 1 to pole 2 using pole 3 as
the spare pole
transfer one disk from pole 1 to pole 3
transfer (n – 1) disks from pole 2 to pole 3 using pole 1 as
the spare pole

EXERCISES

1 . Wr ite a r ecu r siv e fu n ction th a t m u ltiplies tw o positiv e


n u m ber s a a n d b, a n d r etu r n s th e r esu lt.
Mu ltiplica tion is to be a ch iev ed a s a + a + a (b tim es).
2 . Wr ite a r ecu r siv e fu n ction th a t ta kes n u m ber n a s a n
in pu t pa r a m eter a n d pr in ts n-dig it str ictly in cr ea sin g
n u m ber s.
3 . Wr ite a r ecu r siv e fu n ction th a t g en er a tes a ll bin a r y
str in g s of n-bit len g th .
4 . Wr ite a r ecu r siv e fu n ction th a t ta kes tw o str in g s a s
in pu t pa r a m eter s a n d pr in ts a ll in ter lea v in g str in g s of
th e g iv en tw o str in g s pr eser v in g th eir or der of
occu r r en ce. For ex a m ple, in ter lea v in g of str in g s ‘A B’
a n d ‘CD’ w ill g en er a te th e str in g s: ‘A BCD’, ‘A CBD’,
‘A CDB’, ‘CDA B’, ‘CA DB’ a n d ‘CA BD’.
5 . Wr ite a r ecu r siv e fu n ction th a t in ser ts th e elem en t x a t
ev er y kth position in th e g iv en list, a n d r etu r n s th e
m odified list. For ex a m ple, if w e w ish to in ser t elem en t
5 0 a t ev er y 3 r d position (cou n tin g 0, 1 , 2 , 3 ) in th e list
[1 , 2 , 3 , 4 , 5 , 6 , 7 ], th e ou tpu t list w ill be [1 , 2 , 3 , 5 0,
4 , 5 , 6 , 5 0, 7 ].
6 . Wr ite a r ecu r siv e fu n ction th a t deletes ev er y kth
elem en t, a n d r etu r n s th e m odified list. For ex a m ple, if
w e w ish to delete ev er y 3 r d elem en t fr om th e list [1 , 2 ,
3 , 4 , 5 , 6 , 7 , 8 , 9 , 1 0, 1 1 ], th e ou tpu t list w ill be [1 , 2 ,
4 , 5 , 7 , 8 , 1 0, 1 1 ].
7 . Wr ite a r ecu r siv e fu n ction th a t r ecu r siv ely r em ov es
a dja cen t du plica tes fr om a g iv en list, a n d r etu r n s th e
m odified list. For ex a m ple, r em ov in g a dja cen t
du plica tes r ecu r siv ely fr om th e list [1 , 2 , 4 , 4 , 5 , 7 , 7 ,
7 , 8 , 8 , 9 , 7 ] w ill y ield list [1 , 2 , 5 , 9 , 7 ].
8 . Wr ite a r ecu r siv e fu n ction th a t ta kes tw o n u m ber s a s
in pu t pa r a m eter s a n d com pu tes th eir g r ea test com m on
div isor .
9 . In Fig . 8 .1 7 , a fter lin e 2 5 , in clu de th e follow in g
sta tem en t, ex ecu te th e code a g a in a n d ju stify th e
ou tpu t:
lst2 = deepCopy(lst1)
CHAPTER 9
FILES AND EXCEPTIONS

CHAPER OUTLINE
9 .1 File Ha n dlin g

9 .2 Wr itin g Str u ctu r es to a File

9 .3 Er r or s a n d Ex ception s

9 .4 Ha n dlin g Ex ception s u sin g try…except

9 .5 File Pr ocessin g Ex a m ple

Programs that we have developed so far take data from


the user in an interactive manner. Such data remain in
memory only during the lifetime of the program. Often
we want to store data permanently, in the form of files
that usually reside on disks, so that it is available as and
when required. For example, for login application, we
would like to validate the user name and password
entered by a user against the names and passwords of
valid users stored permanently in a file. By default,
Python provides a standard input file and a standard
output file to deal with the transitory data. The standard
input file is read from the keyboard, and the standard
output file is displayed on the screen. Apart from these
standard input/output files, we can also create files on
disks that store data permanently for subsequent use. In
this chapter, we will study file handling in detail.
Moreover, programs necessarily have to deal with
exception situations like unavailability of a file we want
to read from or an error like division by zero. Therefore,
in this chapter, we will also discuss how to deal with
such situations smoothly.

files pr ov ide a m ea n s to stor e da ta per m a n en tly


9.1 FILE HANDLING

Files provide a means of communication between the


program and the outside world. A file is nothing but a
stream of bytes, comprising data of interest. Files can be
used in any application where data is required to be
stored permanently. Before performing a read or write
operation in a file, we need to open the file. Built-in
function open() is used for this purpose. This function
takes the name of the file as the first argument. The
second argument indicates the mode for accessing the
file. A file may be opened in any of the three modes: r
(read), w (write), and a (append). Read mode is used
when an existing file is to be read. Write mode is used
when a file is to be accessed for writing data in it. While
opening a file in the read mode, if the specified file does
not exist, it would lead to an error. As opposed to this,
while opening a file in write mode, if the specified file
does not exist, Python will create a new file. However,
while opening a file in write mode, if the specified file
already exists, this file gets overwritten. As the name
suggests, append mode allows us to write into a file by
appending contents at the end of the specified file.
However, if the specified file does not exist, a new file is
created. The absence of the second argument in the
open function sets it to default value 'r' (read mode).
Successful execution of open function returns a file
object. Failure in opening the file results in error. A file
may be opened using the following syntax:

file is a str ea m of by tes

open(): to open a file

m odes for open in g a file:


r ea d(r ): to r ea d th e file
w r ite(w ): to w r ite to th e file
a ppen d(a ): to w r ite a t th e en d of th e file

open in g a n on -ex isten t file in w or a m ode cr ea tes a n ew file


w ith th e g iv en n a m e
f = open(file_name, access_mode)

by defa u lt, a file is open ed in r ea d m ode

In the following statement, the file object returned by


the function open has been named f and we will be
using this name for writing the contents into the file:

>>> f = open('PYTHON','w')

By default, the system creates a file in the default


working directory. Instead of this relative path name,
absolute (full) path name such as
F:\PythonCode\Ch09 could also be specified. The
functions read and write are used for reading from
and writing into the file respectively. To use
read/write function, we use the following notation:
name of the file object, followed by the dot operator (.),
followed by the name of the function. For example, in
the following statement, we use write() function to
write some text in the file PYTHON.

read(): to r ea d a file

write(): to w r ite in to a file

>>> f.write('''Python:

Python is an interactive programming


language.

Simple syntax of the language makes Python


programs easy to read and write.''')

130

Note that apart from writing the given data into a file,
the function write also returns the number of
characters written into the file (130 in the above
example). Since the file is opened in write mode, Python
disallows read operation on it by flagging an error as
shown below:

write fu n ction r etu r n s th e n u m ber of ch a r a cter s w r itten in


th e file

r ea din g a file open ed for w r itin g y ields a n er r or

>>> f.read()

Traceback (most recent call last):

File "<pyshell#0>", line 1, in <module>

f.read()

io.UnsupportedOperation: not readable

When a file is no longer required for reading or writing,


it should be closed by invoking the function close as
shown below:

close(): sa v es a n d closes th e open ed file

>>> f.close()

The function close also saves a file, which was opened


for writing. Once a file is closed, it cannot be read or
written any further unless it is opened again and an
attempt to access the file results in an I/O
(input/output) error:

a ttem pt to r ea d/w r ite a closed file r esu lts in a n er r or


>>> f.write('Python was developed by Guido
Van Rossum in 1991.')

Traceback (most recent call last):

File "<pyshell#21>", line 1, in <module>

f.write('Python was developed by Guido


Van Rossum in 1991.')

ValueError: I/O operation on closed file.

To read the contents of the file f, we open the file again,


but this time in read mode. Once the file has been
opened in read mode, its contents can be read using
read function:

>>> f = open('PYTHON', 'r')

>>> f.read()

'Python:\nPython is an interactive
programming language.\nSimple syntax of
the language makes Python programs easy to
read and write.'

>>> f.close()

While writing to the file, we entered a multiline string


comprising three lines. When the file is read, the newline
character marks the end of each line. Of course, we
could have displayed the string using the print function
as shown below:

>>> f = open('PYTHON', 'r')

>>> print(f.read())

Python:

Python is an interactive programming


language.
Simple syntax of the language makes Python
programs easy to read and write.

>>> f.close()

As seen above, the read() function retrieves the


contents of the entire file. More often, we need to read
data in smaller chunks. As an alternative, we can read a
fixed number of bytes from the file by specifying the
number of bytes as the argument to read function. For
example, reading only first 4 bytes will return Pyth as
output.

fu n ction read r etr iev es th e con ten t of th e en tir e file

r ea din g fix ed n u m ber of by tes

>>> f = open('PYTHON','r')

>>> f.tell()

>>> f.read(4)

'Pyth'

>>> f.tell()

We have used the function tell to know the current


position while reading the file object f. Initially, the
current position of file object f is set at 0, i.e., position of
the first byte. A subsequent read operation will read the
file f from the current position of the file object.

tell(): to fin d cu r r en t position of th e file object


>>> f.read(4)

'on:\n'

>>> f.tell()

Note that so far we have read only eight bytes from the
input file. However, the function f.tell() shows 9 as
the current position in the file. This is because the end of
line character '\n' is stored by WINDOWS operating
system as a pair of characters, namely, carriage return
character (CR) to transfer control to beginning of line
and line feed character (LF) to transfer control to the 1
next line. However, if we are using a linux/UNIX®
based systems, the function tell would return the
position 8 as shown below:

readline(): to r ea d on e lin e a t a tim e fr om th e file

>>> f.tell()

>>> f.read(4)

'on:\n'

>>> f.tell()

Another way of reading from a file is reading one line at


a time, Python function readline() is used for this
purpose:

>>> f.readline()

'Python is an interactive programming


language.\n'
Note that the readline function reads a stream of
bytes beginning the current position until a newline
character is encountered. On reading a sequence of four
bytes from the file twice, the current file position was set
at the beginning of the second line. That is why, on
invoking the function readline, the system returns the
second line of text. Once we are done with reading this
line, the next read operation will take place beginning
the next line.

>>> f.readline()

'Simple syntax of the language makes


Python programs easy to read and write.'

>>> f.readline()

''

Note that, when all the contents of a file have been read,
a further read operation on it will return a null string.
One way to read from a particular position in a file is to
use the function seek(). For example, for reading from
the beginning of the file, we may invoke the seek
function with the argument 0 as shown below:

r ea din g th e file th a t h a s been r ea d en tir ely r etu r n s a n u ll


str in g

seek(): to r ea ch desir ed position in a file

>>> f.seek(0)

The function seek returns the new absolute position.


The function readlines()returns all the remaining
lines of the file in the form of a list:

readlines(): r ea ds a n d r etu r n s a list of lin es r ea d fr om a file


>>> f.readlines()

['Python:\n', 'Python is an interactive


programming language.\n', 'Simple syntax
of the language makes Python programs easy
to read and write.']

As each string in the list returned by the function


readlines comprises one line, it terminates with the
newline character. Just like the readlines function
discussed above, the function writelines takes a list of
lines to be written in the file as an argument.

writelines(): w r ites a list of lin es to a file

>>> f = open('PYTHON', 'w')

>>> description = ['Python:\n', 'Python is


an interactive programming language.\n']

>>> f.writelines(description)

>>> f.close()

>>> f = open('PYTHON', 'r')

>>> f.read()

'Python:\nPython is an interactive
programming language.\n'

>>> f.close()

Suppose if we wish to copy the contents of a text file, say,


PYTHON in another file PythonCopy. For this purpose,
we open the source file PYTHON in read mode and the
output file PythonCopy (yet to be created) in write
mode, read the data from the file PYTHON, and write it
into the file PythonCopy as follows:

>>> f1 = open('PYTHON', 'r')


>>> f2 = open('PythonCopy', 'w')

>>> data = f1.read()

>>> f2.write(data)

55

>>> f1.close()

>>> f2.close()

Note that if an application requires the file to be opened


in both read and write mode, 'r+' mode can be used
while opening it. If we wish to put the new content at
the end of previously existing contents in a file, we need
to open the file in append ('a') mode as shown below:

u se r+ m ode for open in g a file both for r ea din g a n d w r itin g

open in g a file in w r ite m ode deletes its pr ev iou sly ex istin g


con ten ts

>>> f = open('PYTHON', 'a')

>>> f.write('Simple syntax of the language


')

31

>>> f.write('makes Python programs easy to


read and write')

44

>>> f.close()

>>> f = open('PYTHON', 'r')

>>> f.read()
'Python:\nPython is an interactive
programming language.\nSimple syntax of
the language makes Python programs easy to
read and write'

>>> f.close()

To ensure that the contents written to a file have been


saved on the disk, it must be closed. While we are still
working on a file, its contents may be saved anytime
using the flush function.

9.2 WRITING STRUCTURES TO A FILE

If we wish to write a structure such as a list or a


dictionary to a file and read it subsequently, we may use
the Python module pickle. Pickling refers to the
process of converting the structure to a byte stream
before writing to the file. While reading the contents of
the file, a reverse process called unpickling is used to
convert the byte stream back to the original structure. In
the script fileStructure (Fig. 9.1), we will
demonstrate how to write a list and a dictionary to a file.
To begin with, we import the module pickle. In lines 9
and 10, we write a list and a dictionary respectively to
file f, using the function dump of the pickle module
which performs pickling. This function takes two
arguments: the first argument is the structure to be
written to the file, and the second argument is a file
object. In lines 14 and 15, we read a list and a dictionary
from the file using the load function of the pickle
module that performs unpickling. This function takes file
object as an argument and returns an object such as a
list or a dictionary. In Python 3.x versions, binary mode
is used for reading or writing pickled data. So, a file that
involves reading or writing pickled data should be
opened in binary mode by specifying b as the mode for
opening it.
Fig. 9.1 Pr og r a m to r ea d a n d w r ite a str u ctu r e to th e file
(fileStructure.py)
dump(): to con v er t a str u ctu r e to by te str ea m a n d w r ite it to
a file

load(): to r ea d a by te str ea m fr om a file a n d con v er t it ba ck


to th e or ig in a l str u ctu r e

On executing script in Fig. 9.1, Python responds with


the following output:

['hello', 'world'] {1: 'one', 2: 'two'}

9.3 ERRORS AND EXCEPTIONS

Errors occur when something goes wrong. We have


encountered several errors in our program such as index
out of bound, division by zero, and invalid cast
operation. The errors in Python programming may be
categorized as syntax errors and exceptions. A syntax
error occurs when a rule of Python grammar is violated,
for example, a syntax error occurs in the following call
to print function because of missing quote mark at the
end of the string. Similarly, missing colon in the for
statement results in a syntax error.

sy n ta x er r or : v iola tion of Py th on g r a m m a r r u le

>>> print('Hello)

SyntaxError: EOL while scanning string


literal

>>> for i in range(0, 10)

SyntaxError: invalid syntax

Another common error in Python programming is


caused by incorrect indentation. Often it leads to a
syntax error, but incorrect indentation may sometimes
lead to a logical error that alters the intended meaning of
the program that is difficult to locate.

In den ta tion er r or

In contrast to a syntax error, an exception occurs


because of some mistake in the program that the system
cannot detect before executing the code as there is
nothing wrong in terms of the syntax, but leads to a
situation during the program execution that the system
cannot handle. For example, opening a non-existent file
for reading, attempting to access value of a variable
without assigning a value to it, and dividing a number
by zero. These errors disrupt the flow of the program at a
run-time by terminating the execution at the point of
occurrence of the error. We have noticed that whenever
an exception occurs, a Traceback object is displayed
which includes error name, its description, and the point
of occurrence of the error such as line number. Now we
describe some commonly encountered exceptions:

exceptions: er r or s th a t occu r a t ex ecu tion tim e

1 . NameError
Th is ex ception occu r s w h en ev er a n a m e th a t a ppea r s
in a sta tem en t is n ot fou n d g loba lly . For ex a m ple, in
th e follow in g sta tem en t, w e in ten d to ta ke m a r ks a s a n
in pu t fr om th e u ser . For doin g so, w e in ten ded to u se
fu n ction input bu t in stea d ty ped Input. Py th on bein g
ca se-sen sitiv e fa ils to r ecog n ize th e fu n ction input a n d
th e sy stem r espon ds w ith th e er r or m essa g e
NameError: name 'Input' is not defined. Th is
m essa g e beg in s w ith th e n a m e of th e ex ception . Note
th a t th e follow in g Traceback object descr ibes th a t
er r or occu r r ed in lin e 1 in Py th on sh ell, in th e m ost
r ecen t ca ll:

name not f ou nd gl ob al l y

>>> marks = Input('Enter your marks')


Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
marks = Input('Enter your marks')
NameError: name 'Input' is not defined
Note th a t th e a bov e er r or cou ld n ot h a v e been detected
a s a sy n ta x er r or a s it is per fectly fin e to defin e a
fu n ction Input a s sh ow n below :

>>> def Input():


return input('Enter your marks: ')
>>> marks = Input()
Enter your marks: 78
>>> marks
'78'

Sim ila r ly , a ccessin g th e v a lu e of a v a r ia ble befor e


defin in g it r a ises a n ex ception :

>>> print(price)
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
print(price)
NameError: name 'price' is not defined

2 . TypeError
Th is ex ception occu r s w h en a n oper a tion or fu n ction is
a pplied to a n object of in a ppr opr ia te ty pe. For ex a m ple,
th e ex pr ession 'sum of 2 and 3 is ' + 5 in v olv es
a ddin g a n u m ber to a str in g w h ich is n ot a v a lid
oper a tion r esu ltin g in a n ex ception .

Inv al i d t y p e of op er ands f or t h e op er at i on

>>> 'sum of 2 and 3 is ' + 5


Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
'sum of 2 and 3 is ' + 5
TypeError: must be str, not int

3 . ValueError
Th is ex ception occu r s w h en ev er a n in a ppr opr ia te
a r g u m en t v a lu e, ev en th ou g h of cor r ect ty pe, is u sed
in a fu n ction ca ll, for ex a m ple:

Inv al i d ar gu ment v al u e

>>> int('Hello')
Traceback (most recent call last):
File "<pyshell#5>", line 1, in <module>
int('Hello')
ValueError: invalid literal for int() with
base 10: 'Hello'

Note th a t in th e a bov e ex a m ple, th e fu n ction int h a s


been in v oked w ith a v a lid ty pe of a r g u m en t, i.e. str,
bu t its v a lu e, i.e., 'Hello', ca n n ot be con v er ted to a n
in teg er . Hen ce th e ValueError.
4 . ZeroDivisionError
Th is ex ception occu r s w h en w e tr y to per for m n u m er ic
div ision in w h ich th e den om in a tor h a ppen s to be zer o,
for ex a m ple:

at t emp t t o di v i de b y zer o

>>> 78/(2+3-5)
Traceback (most recent call last):
File "<pyshell#13>", line 1, in <module>
78/(2+3-5)
ZeroDivisionError: division by zero

5 . OSError
Th is ex ception occu r s w h en ev er th er e is a sy stem
r ela ted er r or su ch a s disk fu ll or a n er r or r ela ted to
in pu t/ou tpu t, for ex a m ple, open in g a n on -ex isten t file
for r ea din g or r ea din g a file open ed in w r ite m ode:

sy st em r el at ed er r or

>>> f = open('passwordFile.txt')
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
f = open('passwordFile.txt')
FileNotFoundError: [Errno 2] No such file or
directory: 'passwordFile.txt'

6 . IndexError
Th is ex ception occu r s w h en ev er w e tr y to a ccess a n
in dex th a t is ou t of a v a lid r a n g e. For ex a m ple, let u s
n a m e th e list of color s ['red', 'green', 'blue'], a s
colors. Now th e v a lid r a n g e of in dex es for colors is
[-3, -2, -1, 0, 1, 2] a n d th e v a lid in dex r a n g e of
in dex es for th e str in g colors[2] is [-4, -3, -2, -1,
0, 1, 2, 3]. A ccessin g a n in dex ou tside a v a lid r a n g e
w ill ca u se IndexError exception to occu r :

ac c essi ng an i nv al i d i ndex

>>> colors = ['red', 'green', 'blue']


>>> colors[4]
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
colors[4]
IndexError: list index out of range
>>> colors[2][4]
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
colors[2][4]
IndexError: string index out of range

9.4 HANDLING EXCEPTIONS USING TRY…EXCEPT

We have seen several examples of exceptions that would


result in abrupt termination of program execution. Such
exceptions are known as unhandled exceptions. To
prevent a program from terminating abruptly when an
exception is raised, we need to handle it by catching it
and taking appropriate action using the try…except
clause.

Whereas a try block comprises statements that have


the potential to raise an exception, except block
describes the action to be taken when an exception is
raised. In the except clause, we may specify a list of
exceptions and the common action to be taken on
occurrence of any of these exceptions. Alternatively, a
specific action may be provided for each of the
exceptions separately. We can also specify a finally
block in the try…except clause, which is executed
irrespective of whether an exception is raised.

try block: sta tem en ts h a v in g poten tia l to r a ise a n ex ception

except block: a ction to be per for m ed w h en ex ception is r a ised

In the script try_except1 (Fig. 9.2), line 10 (within


except block) will be executed only when any input–
output related error is raised in line 8 that lies within the
try block. While executing this script, an attempt to
open a non-existent file will cause the IOError
exception and will yield the following output:

finally block: ex ecu ted ir r espectiv e of w h eth er a n ex ception


is r a ised
Fig. 9.2 Pr og r a m to open n on -ex isten t file (try_except1.py)

Problem with Input Output...

Program continues smoothly beyond


try...except block

Note that as IOError exception raised in line 8 had


been handled (lines 9–10), the program did not
terminate abruptly and continued smoothly to execute
line 11 after the exception was handled.

We can access the description of the Traceback


notice directly. For this purpose, the name of the
exception such as IOError is followed by the keyword
as, which is followed by a user-defined name such as
err in the except clause (Fig. 9.3). So, when IOError
exception is raised during execution of the open function
(line 9), the exception information is assigned to the
variable err and the message [Errno 2] No such
file or directory: 'Temporary_File' is
displayed (line 11). It is also possible to track the
exception raised by Python using the expression
sys.exc_info(), which yield the details of the
exception as a tuple comprising the type of exception,
and description of the exception, a reference to the
exception object, for example, on executing the script
try_except2 (Fig. 9.3), the system responds as
follows:

tr a ckin g r a ised ex ception


Fig. 9.3 Pr og r a m to open n on -ex isten t file (try_except2.py)

Problem with Input Output...

[Errno 2] No such file or directory:


'Temporary_File'

(<class 'FileNotFoundError'>,
FileNotFoundError(2, 'No such file or
directory'), <traceback object at
0x02EB2530>)

Program continues smoothly beyond


try...except block
There may be situations when a sequence of statements
that appear in a try block can potentially throw more
than one exceptions. We can deal with such situations in
different ways: the first option is to enumerate all
possible exceptions in the except clause in the form of a
list, the second option is to define an except clause for
handling each exception separately, and yet another
option is to go for a defensive approach by placing the
targeted group of statements in try block and specify an
empty except clause. Such an except clause is capable
of catching all possible errors.

a n em pty except cla u se ca tch es a ll possible ex ception s

In the script pricePerUnit1 (Fig. 9.4), we wish to


compute the price per unit weight of an item. For this
purpose, we define a function main that takes price
and weight as inputs and computes the price per unit.
Note that ValueError and TypeError exceptions may
be raised while converting an argument to a float
value (lines 12 and 14) and ZeroDivisionError
exception may be raised while dividing price by
weight (line 16). For handling these exceptions, we
include all of them in the except clause (line 17). An
optional else clause (line 20) may also be specified in
the try…except clause, which will be executed only if
no exception is raised.
Fig. 9.4 Pr og r a m to com pu te pr ice per u n it w eig h t of a n item
(pricePerUnit1.py)

On executing the script pricePerUnit1 (Fig. 9.4),


the system prompts the user to enter values of price
and weight:

> >>

Enter price of item purchased: 400

Enter weight of item purchased: 0


Invalid input provided by user

(<class 'ZeroDivisionError'>,
ZeroDivisionError('float division by
zero',), <traceback object at 0x039BD2B0>)

As we have specified a common action to be taken on


each of the exceptions ValueError, TypeError, and
ZeroDivisionError, we could have replaced the
except clause:

com m on a ction s for th e ex ception s

except (ValueError, TypeError,


ZeroDivisionError):

by the empty except clause:

except:

However, it is often preferable to handle different


exceptions separately as shown in the script
pricePerUnit2 (Fig. 9.5). Also, we make use of the
assert statement in line 13 to ensure that price and
weight are positive values. An empty except clause is
used (line 21) to catch all other exceptions (for example,
invalid range).

It is pr efer a ble to h a n dle differ en t ex ception s sepa r a tely


Fig. 9.5 Pr og r a m to com pu te pr ice per u n it w eig h t of a n item
(pricePerUnit2.py)

Next, we present the system response on execution of


the script pricePerUnit2.py on different inputs:

Enter price of item purchased: 20


Enter weight of item purchased: x

Invalid inputs: ValueError

Enter price of item purchased: -20

Enter weight of item purchased: 10

(<class 'AssertionError'>,
AssertionError(), <traceback object at
0x0356D328>)

Enter price of item purchased: 20

Enter weight of item purchased: 0

Invalid inputs: (ZeroDivisionError)

Enter price of item purchased: 20

Enter weight of item purchased:

Invalid inputs: TypeError

Enter price of item purchased: -20

Enter weight of item purchased: 0

(<class 'AssertionError'>,
AssertionError(), <traceback object at
0x03B42508>)

When we enter the inputs -20 and 0, each of the


assert statement (line 15) and division operation (line
16) can raise exceptions. However, as the assert
statement is encountered before the division operation,
in the try…except clause, AssertionError exception
is raised. As none of the exceptions specified in lines 17,
19, and 21 matches the AssertionError exception, the
empty except block (lines 23–24) got executed. Thus,
line 16 got skipped.

A segment of the script that handles an exception is


called a handler. In the above script, the exceptions were
raised and handled within a try…except block.
However, if an exception is raised in a try block, but the
script does not include the corresponding handler in that
block, then search for a handler is continued in the outer
try…except block, and so on. We illustrate this in the
script pricePerUnit3 (Fig. 9.6) – a slightly modified
version of the script pricePerUnit2 (Fig. 9.5). In this
version, each of the lines 13 and 18 is placed under a
separate try…except block, which catches only
ValueError exception. So, when TypeError is raised
in line 13 or line 18, Python does not find any matching
except clause in the inner try…except block and the
search for the corresponding handler continues in the
outer try…except block, where we find the required
handler and the function main prints the string
Invalid inputs: TypeError'.

If th er e is n o h a n dler for th e ex ception r a ised in tr y block,


sea r ch for h a n dler ta kes pla ce in ou ter tr y ...ex cept block
Fig. 9.6 Pr og r a m to com pu te pr ice per u n it w eig h t of a n item
(pricePerUnit3.py)

If we wish to execute some action(s) irrespective of


whether an exception is raised, such action(s) may be
specified in the finally clause. Further, an exception
may be raised explicitly using the keyword raise,
followed by the name of the exception, followed by the
string (enclosed in parentheses) to be displayed when the
exception is raised. For example, in the script
raiseFinally1 (Fig. 9.7, line10), if the value of the
variable marks is out of the valid range, i.e. marks < 0
or marks > 100, the exception
ValueError('Marks out of range') is thrown.
As the exception is not handled using an except clause,
the program terminates by throwing the unhandled
exception on invoking the print function in the
finally clause.

u se raise key w or d for ex plicitly r a isin g a n ex ception

a n u n h a n dled ex ception lea ds to pr og r a m ter m in a tion

>>>
Bye

Traceback (most recent call last):

File "F:/PythonCode/Ch09/except.py", line


16

main()

File "F:/PythonCode/Ch09/except.py", line


10, in main

raise ValueError('Marks out of range')

ValueError: Marks out of range


Fig. 9.7 To illu str a te th e u se of r a ise a n d fin a lly cla u ses
(raiseFinally1.py)

Next, we modify the script raiseFinally1 by


including an except clause (Fig. 9.8) so that the
program continues smoothly after the exception is
raised.

> >>

Bye

Program continues after handling exception


Fig. 9.8 To illu str a te th e u se of r a ise a n d fin a lly cla u ses
(raiseFinally2.py)

9.5 FILE PROCESSING EXAMPLE

In this section, we will develop a program to moderate


the results in an examination. We are given a file named
studentMarks. This file contains the student data that
includes roll number (rollNo), name (name), and
marks (marks) for each student. The data about each
student is stored in a separate line and the individual
pieces of information rollNo, name, and marks are
separated by commas. Further, data about each student
is stored in a separate line. Sample data in the file is
shown below:

sa m ple da ta for file studentMarks

4001,Nitin Negi,75

4002,Kishalaya Sen,98

4003,Kunal Dua,80

4004,Prashant Sharma,60

4005,Saurav Sharma,88

We define addPerCent as the percentage of maxMarks


that should be added to the marks obtained to get the
moderated marks, subject to the upper limit of
maxMarks. To carry out the moderation, we prompt the
user to enter the moderation percentage (addPerCent)
and produce another file moderatedMarks containing
moderated marks of the students. Next, we describe this
task in the form of a pseudocode (Fig. 9.9).
Fig. 9.9 Pseu docode for pr odu cin g file moderatedMarks

As we need to ensure throughout the program that the


file operations are being performed smoothly without
any errors, we must perform checks on error conditions.
The revised pseudocode is shown in Fig. 9.10.

ch eck for possible ex ception s


Fig. 9.10 Pseu docode for pr odu cin g file moderatedMarks

The complete script is given in Fig. 9.11. When we


execute the program in Fig. 9.11 and enter 3 as value of
addPercent, the system outputs the contents of the file
moderatedMarks as follows:

con ten t of file moderatedMarks

4001,Nitin Negi,78.0

4002,Kishalaya Sen,100

4003,Kunal Dua,83.0

4004,Prashant Sharma,63.0

4005,Saurav Sharma,91.0
Fig. 9.11 Pr og r a m to com pu te m oder a ted m a r ks
(moderatedMarks.py)

In our next program, we wish to compute monthly


wages to be paid to employees in an organization. The
input data has been provided to us in two files named
empMaster and empMonthly. The first file empMaster
contains permanent data about employees (also called
master data) that include employee id (empID),
employee name (empName), and hourly wages
(hrlyWages). Individual elements of the data are
separated by commas. Further, the data about each
employee is stored in a separate line. Sample data in the
file is shown below:

sa m ple da ta for file empMaster

1001,Vinay Kumar,30

1002,Rohit Sen,35

1003,Vinita Sharma,28

1004,Bijoy Dutta,35

The second file empMonthly contains monthly


information (often called transaction data) about
employees. It stores two pieces of information about
each employee, namely, employee id (tEmpID) and the
number of hours worked (hrsWorked). Data in this file
is also comma separated. Data about each employee is
stored in a separate line. We assume that information
about the employees is stored in each file in the
ascending order of employee id. Further, we assume that
the file empMonthly contains information about each
employee even if he/she worked for zero hours. Sample
data in this file is shown below:

sa m ple da ta for file empMonthly

1001,245

1002,0

1003,0

1004,240
To compute the monthly wages of all employees, we
need to read the files employeeMaster and
empMonthly and produce a third file monthlyWages
containing monthly wages of the employees. We
describe this task in the form of a pseudocode (Fig. 9.12).

Fig. 9.12 Pseu docode to com pu te con ten ts for file monthlyWages

As we need to ensure throughout the program that file


operations are being performed smoothly without any
errors, we must perform checks on error conditions. The
revised pseudocode is shown in Fig. 9.13.

ch eck for possible ex ception s

The complete script is given in Fig. 9.14. Instead of


invoking the exit function in line 13, we could have
executed a return statement to return the control to
main function and ask the user to enter the name of the
file again. On the execution of the program in Fig. 9.14,
the system creates an output file monthlyWages with
the following content:

1001,7350

1002,0

1003,0

1004,8400

Fig. 9.13 Pseu docode to com pu te con ten ts for file monthlyWages
Fig. 9.14 Pr og r a m to g en er a te sa la r y (salaryGen.py)
In the above program, we assume that the information
about each employee in empMaster is available in
empMonthly. Suppose, the file empMonthly does not
contain an entry for employees for whom hrlyWorked
is equal to 0. Sample data in this file is shown below:

1001,245

1004,240

Next, we present a pseudocode for computing monthly


wages of all employees (Fig. 9.15).
Fig. 9.15 Pseu docode to com pu te con ten ts for file monthlyWages

The complete script is given in Fig. 9.16. On the


execution of the above program, the system outputs the
contents of the file monthlyWages as follows:

1001,7350

1002,0

1003,0

1004,8400
Fig. 9.16 Pr og r a m to g en er a te sa la r y (salaryGen.py)

SUMMARY

1 . A file is a str ea m of by tes, com pr isin g da ta of in ter est.


2 . Bu ilt-in fu n ction open() is u sed for open in g a file. It
r etu r n s a file object. Th is fu n ction ta kes th e n a m e of
th e file a s th e fir st a r g u m en t. Th e secon d a r g u m en t
in dica tes m ode for a ccessin g th e file.
3 . A file m a y be open ed in a n y of th r ee m odes: r (r ea d), w
(w r ite), a n d a (a ppen d). Rea d m ode is u sed w h en a n
ex istin g file is to be r ea d. Wr ite m ode is u sed w h en a file
is to be a ccessed for w r itin g da ta in it. A ppen d m ode
a llow s on e to w r ite in to a file by a ppen din g con ten ts a t
th e en d. If th e specified file does n ot ex ist, a file is
cr ea ted.
4 . Th e a bsen ce of th e secon d a r g u m en t in open fu n ction
sets it to defa u lt v a lu e 'r' (r ea d m ode).
5 . Wh en a n ex istin g file is open ed in w r ite m ode, pr ev iou s
con ten ts of th e file g et er a sed.
6 . Th e fu n ction s read a n d write a r e u sed for r ea din g
fr om a n d w r itin g in to th e file, r espectiv ely . To u se
read/write fu n ction , w e u se th e follow in g n ota tion :
n a m e of th e file object, follow ed by th e dot oper a tor (.),
a n d follow ed by th e n a m e of th e fu n ction .
7 . Fu n ction close is u sed for closin g th e file. Th e fu n ction
close a lso sa v es a file, w h ich w a s open ed for w r itin g .
On ce a file is closed, it ca n n ot be r ea d or w r itten a n y
fu r th er u n less it is open ed a g a in a n d a n a ttem pt to
a ccess th e file r esu lts in a n I/O (in pu t/ou tpu t) er r or .
8 . Fu n ction tell y ields cu r r en t position in th e file.
9 . Th e readline fu n ction r ea ds a str ea m of by tes
beg in n in g th e cu r r en t position u n til a n ew lin e
ch a r a cter is en cou n ter ed.
1 0. Rea d oper a tion on a file w h ose a ll th e con ten ts h a v e
been r ea d w ill r etu r n a n u ll str in g .
1 1 . Fu n ction seek()is u sed for a ccessin g th e file fr om a
pa r ticu la r position .
1 2 . Fu n ction readlines() r etu r n s a ll th e r em a in in g lin es
of th e file in th e for m of a list of str in g s. Ea ch str in g
ter m in a tes w ith a n ew lin e ch a r a cter .
1 3 . Fu n ction writelines ta kes a list of lin es to be w r itten
to th e file a s a n a r g u m en t.
1 4 . Picklin g r efer s to th e pr ocess of con v er tin g a str u ctu r e
to a by te str ea m befor e w r itin g to th e file. Th e r ev er se
pr ocess of con v er tin g a str ea m of by tes in to a str u ctu r e
is kn ow n a s u n picklin g .
1 5 . Py th on m odu le pickle is u sed for w r itin g a n object
su ch a s list or diction a r y to a file a n d r ea din g it
su bsequ en tly . Fu n ction dump of th e pickle m odu le
per for m s picklin g . Fu n ction load of th e pickle m odu le
per for m s u n picklin g .
1 6 . A sy n ta x er r or occu r s w h en a r u le of Py th on g r a m m a r
is v iola ted.
1 7 . Th e ex ception occu r s beca u se of som e m ista ke in th e
pr og r a m th a t th e sy stem ca n n ot detect befor e
ex ecu tin g th e code a s th er e is n oth in g w r on g in ter m s
of th e sy n ta x , bu t lea ds to a situ a tion du r in g th e
pr og r a m ex ecu tion th a t th e sy stem ca n n ot h a n dle.
Th ese er r or s disr u pt th e flow of th e pr og r a m a t a r u n -
tim e by ter m in a tin g th e ex ecu tion a t th e poin t of
occu r r en ce of th e er r or .
1 8 . NameError ex ception occu r s w h en ev er a n a m e specified
in th e sta tem en t is n ot fou n d g loba lly .
1 9 . TypeError ex ception occu r s w h en a n oper a tion in a n
ex pr ession is in com pa tible w ith th e ty pe of oper a n ds.
2 0. ValueError ex ception occu r s w h en ev er a n in v a lid
a r g u m en t is u sed in a fu n ction ca ll.
2 1 . ZeroDivisionError ex ception occu r s w h en w e tr y to
per for m n u m er ic div ision in w h ich den om in a tor
h a ppen s to be zer o.
2 2 . IOError ex ception occu r s w h en ev er th er e is a n y er r or
r ela ted to in pu t or ou tpu t.
2 3 . IndexError ex ception occu r s w h en ev er w e tr y to
a ccess a n in dex ou t of th e v a lid r a n g e.
2 4 . try…except cla u se is u sed for h a n dlin g th e ex ception .
Wh er ea s a try block com pr ises sta tem en ts, w h ich h a v e
th e poten tia l to r a ise a n ex ception , except block
descr ibes th e a ction to be ta ken w h en ex ception is
r a ised. In th e except cla u se, w e m a y specify a list of
ex ception s a n d th e a ction to be ta ken on occu r r en ce of
ea ch ex ception .
2 5 . finally block is a ssocia ted w ith try…except cla u se
a n d is ex ecu ted ir r espectiv e of w h eth er a n ex ception is
r a ised.
2 6 . Deta ils of th e ex ception r a ised by Py th on ca n be
a ccessed fr om th e object: sys.exc_info().

EXERCISES

1 . Wr ite a fu n ction th a t ta kes tw o file n a m es, file1 a n d


file2 a s in pu t. Th e fu n ction sh ou ld r ea d th e con ten ts
of th e file file1 lin e by lin e a n d sh ou ld w r ite th em to
a n oth er file file2 a fter a ddin g a n ew lin e a t th e en d of
ea ch lin e.
2 . Wr ite a fu n ction th a t r ea ds a file file1 a n d displa y s
th e n u m ber of w or ds a n d th e n u m ber of v ow els in th e
file.
3 . Wr ite a fu n ction th a t ta kes da ta to be stor ed in th e file
file1 a s in ter a ctiv e in pu t fr om th e u ser u n til h e
r espon ds w ith n oth in g a s in pu t. Ea ch lin e (or
pa r a g r a ph ) ta ken a s in pu t fr om th e u ser sh ou ld be
ca pita lized, a n d stor ed in th e file file1.
4 . Wr ite a fu n ction th a t r ea ds th e file file1 a n d copies
on ly a lter n a tiv e lin es to a n oth er file file2.
A lter n a tiv e lin es copied sh ou ld be th e odd n u m ber ed
lin es. Ha n dle a ll ex ception s th a t ca n be r a ised.
5 . Wr ite a fu n ction th a t ta kes tw o files of equ a l size a s
in pu t fr om th e u ser . Th e fir st file con ta in s w eig h ts of
item s a n d th e secon d file con ta in s cor r espon din g pr ices.
Cr ea te a n oth er file th a t sh ou ld con ta in pr ice per u n it
w eig h t for ea ch item .
6 . Wr ite a fu n ction th a t r ea ds th e con ten ts of th e file
Poem.txt a n d cou n ts th e n u m ber of a lph a bets, bla n k
spa ces, low er ca se letter s a n d u pper ca se letter s, th e
n u m ber of w or ds sta r tin g w ith a v ow el, a n d th e
n u m ber of occu r r en ces of w or d 'beautiful' in th e file.
7 . Wh a t w ill be th e ou tpu t pr odu ced on ex ecu tin g
fu n ction inverse1 w h en th e follow in g in pu t is en ter ed
a s th e v a lu e of v a r ia ble num:
(a )5 (b)0 (c)2 .0 (d)x (e)Non e
def inverse1():
try:
num = input('Enter the number: ')
num = float(num)
inverse = 1.0 / num
except ValueError:
print('ValueError')
except TypeError:
print('TypeError')
except ZeroDivisionError:
print('ZeroDivisionError')
except:
print('Any other Error')
else:
print(inverse)
finally:
print('Function inverse completed')
8 . Ex a m in e th e follow in g fu n ction per cen ta g e:
def percentage(marks, total):
try:
percent = (marks / total) * 100
except ValueError:
print('ValueError')
except TypeError:
print('TypeError')
except ZeroDivisionError:
print('ZeroDivisionError')
except:
print('Any other Error')
else:
print(percent)
finally:
print('Function percentage completed')
Deter m in e th e ou tpu t for th e follow in g fu n ction ca lls:
1 . percentage(150.0, 200.0)
2 . percentage(150.0, 0.0)
3 . percentage('150.0', '200.0')
9 . Iden tify tw o ex ception s th a t m a y be r a ised w h ile
ex ecu tin g th e follow in g sta tem en t:
result = a + b
1 0. Wh a t w ill be th e ou tpu t for th e follow in g code sn ippets
if th e file bein g open ed does n ot ex ist:
1 . try:
f = open('file1.txt', 'r')
except IOError:
print('Problem with Input
Output...\n')
else:
print('No Problem with Input
Output...\n')
2 . try:
f = open('file1.txt', 'w')
except IOError:
print('Problem with Input
Output...\n')
else:
print('No Problem with Input
Output...\n')
1
UNIX® is a r eg ister ed tr a dem a r k of Th e Open Gr ou p
CHAPTER 10
CLASSES I

CHAPER OUTLINE
1 0.1 Cla sses a n d Objects

1 0.2 Per son : A n Ex a m ple of Cla ss

1 0.3 Cla ss a s A bstr a ct Da ta Ty pe

1 0.4 Da te Cla ss

We have already studied basic building blocks of Python


language such as variables for naming the data objects,
control structures for control flow, and functions for
providing a systematic way of problem solving by
dividing the given problem into several sub-problems. A
program of moderate size would comprise several groups
of related information. Keeping track of them in an ad-
hoc manner would be a challenging task. Packaging
together related code and data in the form of classes
would make our job easier. A class is a template that
provides a logical grouping of data and methods that
operate on them. Instances of a class are called objects.

cla ss: log ica l g r ou pin g of r ela ted da ta a n d m eth ods th a t


oper a te on th em

Variables used so far took values of types (also called


classes) string (str), integer (int), floating point
(float), Boolean (bool), list, tuple, or dictionary
(dict). As these classes are already available in Python,
they are called built-in classes. Python also allows us to
define new classes (i.e., types), called user-defined
classes. Data and methods associated with a class are
collectively known as class attributes.
cla ss a ttr ibu tes: da ta a n d m eth ods a ssocia ted w ith a cla ss

10.1 CLASSES AND OBJECTS

We begin our study of classes with the built-in class str.


The strings 'Raman', 'CBSE', and 'Jan 11 2014'
are instances of class str. The following assignment
statement assigns the object 'Raman' of class str to the
variable name:

th e v a r ia ble n a m e r efer s to object of cla ss str

fu n ction s of a cla ss a r e kn ow n a s m eth ods

>>> name = 'Raman'

A class would usually have several functions (called


methods in the context of classes), which can act on
objects of the class. We have already seen several
methods that can be applied to objects of the class str.
For example, the method lower returns an str object
that has all uppercase letters in the given string object
replaced by lowercase letters:

>>> name.lower()

'raman'

Here, the method lower defined in class str has been


invoked for the object name. To specify an attribute of a
class (or class instance), we write the name of the class
(or class instance) followed by a dot, followed by the
name of that attribute. In the above example, name –
an instance of class str is followed by a dot (.), followed
by lower() – the attribute of interest. The method
lower may also be invoked as follows:

specify in g a ttr ibu te of a cla ss


>>> str.lower(name)

'raman'

In this format, we specify the name of the class (str),


followed by the dot operator (.), followed by the name of
the method (lower), followed by an object (name).
The object name being an argument is enclosed in
parentheses.

10.2 PERSON: AN EXAMPLE OF CLASS

In this section, we shall discuss the concept of class with


the help of an example. To keep the matter simple, we
shall describe a person using three attributes, viz., name,
DOB (date of birth), and address, each of which takes
values of type str. In Fig. 10.1, we define the class
Person that describes a person with the above-
mentioned attributes name, DOB, and address.

da ta a ttr ibu tes of cla ss Person: name, DOB, a n d address


Fig. 10.1 Cla ss Per son (person.py)

A class definition begins with the keyword class


followed by the name of the class, and a colon. By
convention, the first letter of the class name is
capitalized. The syntax for class definition is as follows:

sy n ta x for cla ss defin ition

class ClassName:

classBody

In the docstring in line 2, we describe the purpose of the


class. In line 3, we introduce the class variable count
and initialize it to 0. It is used to keep count of the
number of Person objects created. The class variables
are also called static variables. The__init__ method is
used to initialize data for the instance of the class being
constructed and is called class initializer or class
constructor. However, for the sake of completeness, we
would like to mention that there may be a class not
having any __init__ method. Such a class would use
the default constructor of Python. Names of the special
methods begin and end with a double underscore. The
__init__ method is called automatically when an
object of the class is created, for example, the following
instruction creates an object named p1:

cla ss v a r ia bles a r e a lso ca lled sta tic v a r ia bles

__init__(): to in itia lize da ta for a n in sta n ce of th e cla ss

n a m es of specia l m eth ods beg in a n d en d w ith dou ble


u n der scor e

cr ea tin g a n object of cla ss Person

>>> p1 = Person('Amir','24-10-1990',
'38/4, IIT Delhi 110016')
The execution of the above statement does three things:

1 . Cr ea tes a n in sta n ce of cla ss Person


2 . In itia lizes it by in v okin g th e m eth od __init__ defin ed
in lin es 4 –1 7
3 . Retu r n s a r efer en ce to it, so th e n a m e p1 n ow r efer s to
th e in sta n ce of th e cla ss Person th a t h a s ju st been
cr ea ted

Execution of statements in lines 14, 15, and 16 sets data


members name, DOB, and address of the object p1 equal
to parameter values 'Amir', '24-10-1990', and
'38/4, IIT Delhi 110016' respectively with which
the method __init__ was invoked. Execution of the
assignment statement in line 17 increments the class
variable count, which now holds value 1. Note that all
instances of a class Person share this attributes. A
reference to count may be made using either the class
name or a specific object of the class Person.

a cla ss a ttr ibu te is sh a r ed a m on g a ll in sta n ces of th e cla ss

a cla ss a ttr ibu te ca n be r efer en ced u sin g th e n a m e of th e cla ss


or a n object of th e cla ss

Note that while creating an object (such as p1) of


class Person, although we mention only three
arguments to be used by method __init__, in effect
four arguments are used for initializing an instance of
Person. By default, Python passes object itself (such as
p1) as the first argument to the method __init__. In
the formal parameter list for the method __init__, it
appears by the name self. Although being a formal
parameter, any other name (like me) would do equally
well, there is a strong convention to use self as the first
parameter. Indeed, when we execute the statement:

by defa u lt, th e object itself is pa ssed a s th e fir st pa r a m eter to


th e m eth od __init__
p1 = Person('Amir','24-10-1990','38/4, IIT
Delhi 110016')

Python invokes the method Person.__init__ with p1


(the object being created) as the first parameter. Note
that while the name, DOB, and address mentioned in
line 4 are formal parameters for the method __init__,
variables self.name, self.DOB, and self.address
used in lines 14, 15, and 16 are associated with the
specific instance, such as p1, of the object being created.
Next, we create another object of class Person:

>>> p2 = Person('Riya','11-10-1992','C-
3,Vivek Vihar, Delhi-92')

Execution of the above statement creates an object


named p2 of class Person and initializes it by invoking
the method __init__. Execution of statements in lines
14, 15, and 16 sets data members name, DOB, and
address of object p2 equal to parameters 'Riya',
'11-10-1992', and 'C-3, Vivek Vihar, Delhi-92'
respectively. Execution of the assignment statement in
line 17 increments the class variable count, which now
holds value 2.

Data members and methods associated with an


instance of a class are called attributes of the object. The
set of attributes that are associated with an object forms
its namespace. Figure 10.2 shows Python tutor
visualization of objects p1 and p2 along with the class
attributes. The data members of the object p1 are
referred to as p1.name, p1.DOB, p1.address, and the
methods of the object p1 are referred to as p1.getName,
p1.getDOB, p1.getAddress, p1.setName, p1.
setDOB, p1.setAddress, p1.getCount, and
p1.__str__. We refer to the attributes of the object p2
in a similar manner.

object a ttr ibu tes: da ta m em ber s a n d m eth ods a ssocia ted w ith
a n in sta n ce of a cla ss
Fig. 10.2 Py th on Tu tor v isu a liza tion of objects p1 a n d p2, a n d
cla ss a ttr ibu tes

To execute the script person and generate some


objects, let us include the following two statements in the
script:

p1 = Person('Amir','24-10-1990','38/4, IIT
Delhi 110016')

p2 = Person('Riya','11-10-1992','C-3,Vivek
Vihar, Delhi-92')

Before we go ahead to execute the modified script


person in Python Tutor, it is important to know that
currently, Python Tutor does not allow modification of
the value of a class variable. So, if we wish to execute the
modified script person in Python Tutor, we need to delete
line 17 that modifies the value of the class variable
count. Indeed, Fig. 10.2 is a manually edited version of
the figure produced by the Python Tutor.

It is important to know that whereas each instance of


a class has its copy of data members, the class variables
and methods are shared. In summary, operations
supported by classes may be categorized as follows:

1 . In sta n tia tion : It r efer s to th e cr ea tion of a n object, i.e.


a n in sta n ce of th e cla ss.
2 . A ttr ibu te r efer en ces: Meth ods a n d da ta m em ber s of a n
object of a cla ss a r e a ccessed u sin g th e n ota tion : n a m e
of th e object, follow ed by dot oper a tor , follow ed by th e
m em ber n a m e.

oper a tion s su ppor ted by a cla ss: in sta n tia tion a n d a ttr ibu te
r efer en ces

For the system-defined classes like int, str, list, and


tuple, Python provides built-in method attribute
__str__ that transforms internal representation of the
object to a printable string as illustrated below:

__str__(): to tr a n sfor m in ter n a l r epr esen ta tion of th e object


to a pr in ta ble str in g

>>> hasattr(7, '__str__')

True

>>> hasattr(int, '__str__')

True

>>> hasattr(list, '__str__')

True

>>> int.__str__(7)

'7'

>>> print(int.__str__(7))

The method hasattr(obj, attr ) returns True if


instance obj contains the attribute attr, and False
otherwise. Note that the method __str__ when applied
to int object 7 indeed returns equivalent str value '7'.
Thus, the statement

hasattr(): does a n object possess th e g iv en a ttr ibu te?

print(7)

is effectively equivalent to each of the following


statements:
print(int.__str__(7))

print(str(7))

When the print function is called to print an object,


Python invokes __str__ method of the corresponding
class to obtain a string representation of the object. So, to
print the values of data attributes of an object of type
Person, we define the method __str__ (lines 79–86,
Fig. 10.1) for this class. This method takes an object of
class Person as the parameter and returns a string
describing the data attributes: name, DOB, and address
associated with the object. Thus, execution of statement

__str__ m eth od is a u tom a tica lly in v oked w h en print


fu n ction is in v oked to pr in t a n object

p1.__str__()

would yield the string:

'Name:Amir\nDOB:24-10-1990\nAddress:38/4,
IIT Delhi 110016'

and

print(p1.__str__())

would yield the output:

Name:Amir

DOB:24-10-1990

Address:38/4, IIT Delhi 110016

Execution of the following statement also yields the


same output as shown above:

>>> print(p1)

In Fig. 10.1, we have defined methods getName,


getDOB, and getAddress, which are responsible for
returning the name, DOB, and address associated with
an object. We have also defined methods setName,
setDOB, and setAddress for updating name, date of
birth, and address, respectively. For example, suppose,
DOB for person p1, needs to be modified to '24-10-
1991'. To achieve this, we invoke the method setDOB
associated with the object p1.

m eth ods of th e cla ss Person

>>> p1.setDOB('24-10-1991')

>>> print(p1)

Name:Amir

DOB:24-10-1991

Address:38/4, IIT Delhi 110016

10.2.1 Destructor

When an object is no more required, we use the del


statement. However, an object may be referenced by
multiple names. Execution of the del statement reduces
the reference count by one. When the reference count
becomes zero, the __del__ method is invoked. Next, we
define the __del__ method for the class Person. As the
number of Person objects reduces by one on execution
of the destructor, we decrement Person.count by one
(line 9, Fig. 10.3).
Fig. 10.3 Per son cla ss m eth od __del__

The use of del statement is illustrated below:

>>> p1 = Person('Amir','24-10-1990','38/4,
IIT Delhi 110016')

>>> p2 = Person('Riya','11-10-1992','C-
3,Vivek Vihar, Delhi-92')

>>> p3 = p2

>>> print(Person.count)

>>> del p1

Deleted !!

>>> print(p1)

Traceback (most recent call last):


File "<pyshell#23>", line 1, in <module>

print(p1)

NameError: name 'p1' is not defined

>>> print(Person.count)

>>> del p2

>>> print(Person.count)

>>> del p3

Deleted !!

>>> print(Person.count)

th e m eth od __del__ is in v oked befor e destr oy in g th e in sta n ce


object, w h en a ll th e r efer en ces to th e g iv en in sta n ce h a v e
been r em ov ed

Note that we created two Person objects p1 and p2.


Name p3 refers to the same object as p2 and is just
another reference for the object p2 created earlier, and
the reference count of the object p2 as well as that of p3
is 2. Execution of the instruction del p1 invokes
__del__ method defined in the class Person, the object
p1 gets deleted, Person.count gets decremented by
one, and the message 'Deleted !!' is printed.
However, the instruction del p2 does not delete the
object p2 as the name p3 still refers to it. It only
dissociates the name p2 from the object.

10.3 CLASS AS ABSTRACT DATA TYPE

Oxford dictionary describes abstract as follows:


ex istin g in th ou g h t or idea bu t n ot h a v in g a ph y sica l or
con cr ete ex isten ce,
th e qu a lity of dea lin g w ith idea s r a th er th a n ev en ts,
fr eedom fr om r epr esen ta tion a l qu a lities,
th e pr ocess of con sider in g som eth in g in depen den tly of
its a ssocia tion s or a ttr ibu tes.

a bstr a ct da ta ty pe

Indeed, a class in Python introduces an abstract data


type in the sense mentioned above. A class definition
provides a framework for creating objects. Objects of a
class can be created, modified, and destroyed in the
program.

objects ca n be cr ea ted, m odified, a n d destr oy ed

Once a class is defined, it can be saved as an


independent module that can be imported for use in any
module. For example, let us save the above class
definition in the file person.py in the directory
F:\PythonCode\Ch10. We illustrate the use of the
class Person in another script, personEx (Fig. 10.4).
The first step is to include the appropriate directory
(F:\PythonCode\Ch10) in the path (lines 4–6). Next,
in line 7, we import all attributes of class Person from
the module person.py, so that they become available
in the current module personEx.py.

The execution of the first statement in the main


function (line 16) prints the directory of class Person as
shown in Fig. 10.5 (lines 1–8). Note that directory
contains the docstring __doc__, the class variable
count, and the list of methods of the class, but does not
contain the data attributes of the class as they belong to
the class objects and not directly to the class. Also, note
that the directory includes some attributes that we have
not discussed. These are system defined attributes. Once
you are of comfortable with the basic concepts of classes,
you can experiment with them. As expected, use of
print function in line 17 prints the docstring:

dir ector y of a cla ss

The class Person describes a person

associated with the class Person (lines 9–10, Fig. 10.5).


In line 18 (Fig. 10.4), we print the name of the module
that contains the class Person (lines 11–12, Fig. 10.5). In
line 22 (Fig. 10.4), we create an object p1 of the class
Person.
Fig. 10.4 Usin g cla ss Per son (personEx.py)
Fig. 10.5 Ou tpu t of th e scr ipt personEx (Fig . 1 0.4 )

In line 23 (Fig. 10.4), we print the value of class


variable count (lines 13–14, Fig. 10.5). Here, we would
like to mention that to access data attributes of a class
directly outside of the class definition is in violation of
the abstraction principle and it is best avoided. In line 24
(Fig. 10.4), we invoke the method getCount for the
object p1 that fetches the class variable count (lines 15–
16, Fig. 10.5). This is consistent with the abstraction
principle as we are making use of the function
getCount to retrieve the value of count. In lines 25–26
(Fig. 10.4), we print the values of p1.__doc__ and
p1.__module__ (lines 17–20, Fig. 10.5). Note that
p1.getCount(), p1.__doc__, and p1.__module__
yield the same values as Person.count,
Person.__doc__, and Person.__module__,
respectively, because p1 is an object of class Person. In
line 27 (Fig. 10.4), we print the object p1 (see Fig. 10.5,
lines 21–24). The print function invokes the method
Person.__str__() for the object p1. More explicitly,
we may invoke the __str__ method defined in class
Person as follows:

w h ile Person.count ca n a lso be a ccessed u sin g p1 .cou n t, bu t


a ssig n in g a v a lu e to p1.count w ou ld n ot ch a n g e th e v a lu e of
cor r espon din g cla ss v a r ia ble, in stea d it w ill cr ea te a n ew da ta
a ttr ibu te for th e object p1

>>> print(p1.__str__())

Name:Amir

DOB:24-10-1991

Address:38/4, IIT Delhi 110016

The above statement invokes the method __str__ of


the object p1. Here, the object p1 that corresponds to the
formal parameter self is passed to the method __str__
implicitly. In the following call to the print function,
the call to method __str__ of class Person is even
more explicit and matches the syntactic description of
__str__(self). However, in practice, this form is
rarely used.
ex plicit ca ll to m eth od __str__

>>> print(Person.__str__(p1))

Name:Amir

DOB:24-10-1991

Address:38/4, IIT Delhi 110016

In line 28 (Fig. 10.4), we print the directory of the object


p1 (lines 25–33, Fig. 10.5). Note that in addition to
attributes of the class Person that automatically get
associated with the object p1, the directory for object p1
also contains its data attributes: name, DOB, and
address.

In lines 32–39 (Fig. 10.4), we create another object p2


and print Person.count, p2.getCount(),
p1.getCount(), p2.__doc__, p2.__module__, p2,
and dir(p2) (lines 34–57, Fig. 10.5). Note that each of
Person.count, p2.getCount(), and
p1.getCount() yields value 2. Y ou must have noticed
that p1.getCount() yields the value 2 because Python
maintains only one copy of a class variable that gets
associated with all instances of that class. For the same
reason, p1.__doc__ and p2.__doc__ have identical
values as each of them corresponds to the string
Person.__doc__ (Fig. 10.5, lines 9–10, 17–18, 41–42).
Similarly, p1.__module__ and p2.__module__ have
identical values as each of them corresponds to the string
Person.__module__ (Fig. 10.5, lines 11–12, 19–20,
43–44). Indeed, dir(p1) and dir(p2) also have
identical values (Fig. 10.5, lines 25–33, 49–57) as p1
and p2 have the same set of attributes. Further, in
output lines 59–70 (Fig. 10.5) corresponding to lines 41–
51 (Fig. 10.4) of source code, we see that
Person.__module__, p1.__module__, and
p2.__module__ have the same object ids. Similarly,
Person.__doc__, p1.__doc__, and p2.__doc__
have identical object ids.
Py th on m a in ta in s on ly on e copy of cla ss v a r ia ble

In lines 55–57 (Fig. 10.4), we print


Person.__dict__, p1.__dict__, and
p2.__dict__. The object Person.__dict__ is a
dictionary comprising key-value pairs (Fig. 10.5, lines
77–88). A key may either be a class data member or a
method, and the corresponding value would be the value
of the data member or the reference associated with the
class method. Similarly, each of the dictionaries
p1.__dict__ and p2.__dict__ comprises mapping
between data members associated with it and their
values (Fig. 10.5, lines 90–92, 94–96).

__dict__ a ttr ibu te

10.4 DATE CLASS

We often need to deal with date and time in our


programs. Although Python provides a built-in class for
this purpose, in this section, we shall discuss how to
develop our class to deal with dates. We know that the
date comprises the day, month, and year. In the script
date (Fig. 10.6), we define the class MyDate. In this
example we have struggled to ensure that the class
MyDate creates an instance of a valid date only.
However, you may skip the details of validating the date
on first reading.
Fig. 10.6 Defin ition a n d u se of cla ss MyDate(date.py)

The execution of line 77 (Fig. 10.6) creates an object


named today and initializes it to date 03-09-2014 by
invoking the constructor of the class MyDate as
MyDate(3,9,2014). Execution of the lines 20, 25, and
30 in the constructor achieves the desired initialization of
the data members day, month, and year of the object
today of the class MyDate. Execution of the statement
in line 79 creates the object defaultDate. Since no
arguments are provided while creating the object
defaultDate, the method __init__ uses the default
parameter values 01, 01, and 2000 for initializing the
instance variables day, month, and year, respectively.
So, on executing line 80, Python will print:

defa u lt da te

01-01-2000

Note that day, month, and year provided while


invoking the constructor of the class MyDate may be
invalid. For example, the following statement attempts
to create an object of the class MyDate by initializing the
instance variables day, month, and year as 30, 02,
and 2012, respectively:

>>> feb30 = MyDate(30, 2, 2012)

Invalid value for day


Therefore, when we create an object of class MyDate, we
need to ensure that the values of the day, month, and
year passed as arguments to the constructor __init__
constitute a valid date. Firstly, values of data attributes
day, month, and year should be a positive and non-zero
integer. Also, the value of month should not be more
than 12, and the value of day should be valid as per the
month and the specified year. In line 30 (Fig. 10.6), we
invoke the method checkDay (lines 32–51). It first
determines whether the given year is a leap year (line
43) and then assigns the list of days in months of that
year to the variable currentYear. In line 47 of the
method checkDay, we determine whether the day
specified by the user is within correct range: less than or
equal to the maximum number of days in the given
month, and greater than 0. If any of the attributes day,
month, or year provided by the user happens to be
incorrect, the relevant message 'Invalid value for
day', 'Invalid value for month', or 'Invalid
value for year. Year should be greater
than 1900.' is printed and the program terminates.

v a lida tin g da te

As mentioned earlier that the print function in line


78 invokes the method __str__ that returns the string
representation of this object in the dd-mm-yyyy format
to print the value of object today of the class MyDate as
03-09-2014.

SUMMARY

1 . A cla ss is a tem pla te th a t pr ov ides a log ica l g r ou pin g of


da ta a n d m eth ods th a t oper a te on th em . In sta n ces of a
cla ss a r e ca lled objects.
2 . Da ta m em ber s a n d m eth ods a ssocia ted w ith a n
in sta n ce of a cla ss a r e ca lled a ttr ibu tes of th e object.
Th e set of a ttr ibu tes th a t a r e a ssocia ted w ith a n object
for m s its n a m espa ce. To u se a n a ttr ibu te of a cla ss (or
cla ss in sta n ce), w e specify th e n a m e of th e cla ss (or
cla ss in sta n ce) follow ed by a dot oper a tor , follow ed by
th e n a m e of th a t a ttr ibu te.
3 . A cla ss defin ition beg in s w ith th e key w or d class
follow ed by th e n a m e of th e cla ss, a n d a colon . By
con v en tion , th e fir st letter of th e cla ss n a m e is
ca pita lized.
4. Fu n ction s defin ed in a cla ss a r e ca lled m eth ods. By
defa u lt, Py th on pa sses th e object itself a s th e fir st
pa r a m eter to th e m eth od.
5. Specia l m eth ods beg in a n d en d w ith a dou ble
u n der scor e.
6. Th e __init__ m eth od is u sed to in itia lize a n in sta n ce of
a cla ss.
7. Wh en w e w a n t to delete a n object u sin g del sta tem en t,
Py th on specia l m eth od __del__, if defin ed, is in v oked
for th e object.
8. Oper a tion s su ppor ted by cla sses m a y be ca teg or ized a s
follow s:
1 . In sta n tia tion : It r efer s to th e cr ea tion of a n
object, i.e. a n in sta n ce of th e cla ss.
2 . A ttr ibu te r efer en ces: Meth ods a n d da ta m em ber s
of a n object of a cla ss a r e a ccessed u sin g th e
n ota tion : n a m e of th e object, follow ed by dot
oper a tor , follow ed by th e m em ber n a m e.
9. Py th on pr ov ides a bu ilt-in m eth od a ttr ibu te __str__
for tr a n sfor m in g th e in ter n a l r epr esen ta tion of th e
object to a pr in ta ble str in g . Wh en th e pr in t fu n ction is
ex ecu ted to pr in t a n object, Py th on in v okes th e m eth od
__str__ of th e cor r espon din g cla ss to obta in a str in g
r epr esen ta tion of th e object.
1 0. Py th on bu ilt-in da ta m em ber __doc__ stor es docstr in g
of th e cla ss.
11. Py th on bu ilt-in da ta m em ber __dict__ is a diction a r y
com pr isin g key –v a lu e pa ir s. A key m a y eith er be a
da ta m em ber or a m eth od, a n d th e cor r espon din g
v a lu e w ou ld be th e v a lu e of th e da ta m em ber s or th e
r efer en ce a ssocia ted w ith th e cla ss m eth od.
12. Cla ss a ttr ibu tes a r e sh a r ed a m on g a ll in sta n ces of th e
cla ss.

EXERCISES

1 . Defin e a cla ss Rectangle. Th e cla ss sh ou ld con ta in


sides: length a n d breadth of th e r ecta n g le a s th e da ta
m em ber s. It sh ou ld su ppor t th e follow in g m eth ods:
1 . __init__ for in itia lizin g th e da ta m em ber s:
length a n d breadth.
2 . setLength for u pda tin g th e len g th of th e
r ecta n g le.
3 . setBreadth for u pda tin g br ea dth of th e
r ecta n g le.
4 . getLength for r etr iev in g th e len g th of th e
r ecta n g le.
5 . getBreadth for r etr iev in g th e br ea dth of th e
r ecta n g le.
6 . area to fin d th e a r ea of th e r ecta n g le.
7 . perimeter for fin din g per im eter of th e
r ecta n g le.
2 . Defin e th e follow in g m eth ods for MyDate cla ss:
1 . addDays – To a dd n da y s to th e da te.
2 . addMonths – To a dd n m on th s to da te.
3 . addYears – To a dd n y ea r s to da te.
4 . weekday – To r etu r n w eekda y of th e da te.
5 . diffDates – To fin d differ en ce betw een tw o
da tes in ter m s of th e y ea r s, m on th s, a n d da y s.
6 . futureDate – To fin d a fu tu r e da te a fter a g iv en
n u m ber of da y s, m on th s, a n d y ea r s.
7 . pastDate – To fin d a da te in th e pa st befor e a
g iv en n u m ber of da y s, m on th s, a n d y ea r s.
3 . Defin e a cla ss Stu den t th a t keeps tr a ck of a ca dem ic
r ecor d of stu den ts in a sch ool. Th e cla ss sh ou ld con ta in
th e follow in g da ta m em ber s:
rollNum – Roll n u m ber of stu den t
name – Na m e of stu den t
marksList – List of m a r ks in fiv e su bjects
stream – A : A r ts, C: Com m er ce, S: Scien ce
percentage – Per cen ta g e com pu ted u sin g m a r ks
grade – Gr a de in ea ch su bject com pu ted u sin g m a r ks
division – Div ision com pu ted on th e ba sis of ov er a ll
per cen ta g e
Th e cla ss sh ou ld su ppor t th e follow in g m eth ods:
1 . __init__ for in itia lizin g th e da ta m em ber s.
2 . setMarks to ta ke m a r ks for fiv e su bjects a s a n
in pu t fr om th e u ser .
3 . getStream for a ccessin g th e str ea m of th e
stu den t.
4 . percentage for com pu tin g th e ov er a ll
per cen ta g e for th e stu den t.
5 . gradeGen th a t g en er a tes g r a des for ea ch stu den t
in ea ch cou r se on th e ba sis of th e m a r ks
obta in ed. Cr iter ia for com pu tin g th e g r a de is a s
follow s:

Marks Grade

>= 90 A

<90 and >=80 B

<80 and >=65 C

<65 and >=40 D

<40 E

6. division f or c omp u t i ng di v i si on on t h e b asi s of t h e f ol l ow i ng


c r i t er i a b ased on ov er al l p er c ent age of mar k s sc or ed:

Percentage Division

>= 60 I

<60 and >=50 II

<50 and >=35 III

7 . __str__ t h at di sp l ay s st u dent i nf or mat i on.


4 . Defin e a cla ss Bank th a t keeps tr a ck of ba n k cu stom er s.
Th e cla ss sh ou ld con ta in th e follow in g da ta m em ber s:
name – Na m e of th e cu stom er
accountNum – A ccou n t Nu m ber
type – A ccou n t Ty pe (Sa v in g s or Cu r r en t)
amount – a m ou n t deposited in th e ba n k a ccou n t
interest – In ter est ea r n ed by th e cu stom er
Th e cla ss sh ou ld su ppor t th e follow in g m eth ods:
1 . __init__ for in itia lizin g th e da ta m em ber s.
2 . deposit for depositin g m on ey in th e a ccou n t.
3 . withdrawal for w ith dr a w in g m on ey fr om th e
a ccou n t.
4 . findInterest th a t deter m in es th e in ter est on
th e ba sis of a m ou n t in th e a ccou n t:

Amount Interest per annum (%)

>= 5,00,000 8

>= 3,00,000 and < 5,00,000 7

>= 1 ,00,000 and < 3,00,000 5

< 1 ,00,000 3

5 . __str__ th a t displa y s in for m a tion a bou t ba n k


cu stom er .
5 . Defin e a cla ss Item th a t keeps tr a ck of item s a v a ila ble
in th e sh op. Th e cla ss sh ou ld con ta in th e follow in g da ta
m em ber s:
name – Na m e of th e item
price – Pr ice of th e item
quantity – Qu a n tity of th e item a v a ila ble in th e
stock
Th e cla ss sh ou ld su ppor t th e follow in g m eth ods:
1 . __init__ for in itia lizin g th e da ta m em ber s.
2 . purchase for u pda tin g th e qu a n tity a fter a
pu r ch a se m a de by th e cu stom er . Th e m eth od
sh ou ld ta ke th e n u m ber of item s to be pu r ch a sed
a s a n in pu t.
3 . increaseStock for u pda tin g th e qu a n tity of a n
item for w h ich n ew stock h a s a r r iv ed. Th e
m eth od sh ou ld ta ke th e n u m ber of item s to be
a dded a s a n in pu t.
4 . display th a t displa y s in for m a tion a bou t a n
item .
6 . Fill in th e deta ils (Fig . 1 0.7 ) to defin e th e m eth od to
com pu te th e da te on th e follow in g da y of a g iv en da te
for th e cla ss MyDate:

F ig . 10.7 Pr ogr am t o met h od t o c omp u t e t h e dat e on t h e f ol l ow i ng day


of a gi v en dat e
CHAPTER 11
CLASSES II

CHAPER OUTLINE
1 1 .1 Poly m or ph ism

1 1 .2 En ca psu la tion , Da ta Hidin g , a n d Da ta A bstr a ction

1 1 .3 Modifier a n d A ccessor Meth ods

1 1 .4 Sta tic Meth od

1 1 .5 A ddin g Meth ods Dy n a m ica lly

1 1 .6 Com position

1 1 .7 In h er ita n ce

1 1 .8 Bu ilt-in Fu n ction s for Cla sses

We have already studied user-defined data types in the


form of classes. The classes lie at the heart of a
programming methodology called object-oriented
paradigm or Object-oriented Programming (OOP). It
includes several concepts like polymorphism,
encapsulation, data hiding, data abstraction, and
inheritance. In this chapter, we shall study these
concepts.

object-or ien ted pr og r a m m in g

11.1 POLYMORPHISM

Object-oriented programming revolves around the


notion of objects. A method/operator may be applied to
objects of different types (classes). This feature of object-
oriented programming is called polymorphism. We have
already seen that len function operates on various types
of objects such as str, list, and tuple. Based on the
type of object whose length we want to find out, Python
invokes __len__ method of the appropriate class. As
another example, the print function may be used to
print object of any type whether user-defined or pre-
defined. Based on the type (class) of the object to be
printed, Python would invoke __str__ method of the
associated class (pre-defined classes such as str, int,
dict, tuple, or user-defined class such as MyDate).

a pply in g a m eth od/ oper a tor to objects of differ en t ty pes

11.1.1 Operator Overloading

When we add, subtract, multiply, or divide two int or


float objects using operators + - * /, the
corresponding Python special method __add__,
__sub__, __mul__, or __div__ gets invoked for the
class (type) of objects on which the operator is to be
applied. For example, in the expressions 3.5+4.5, 9.7-
5.5, 6.5*2.1, and 11.5/5.5, the methods __add__,
__sub__, __mul__, and __div__ of float class gets
invoked. In the same spirit, in the expressions 3+4,
[1,2]+[3,4], (1,2)+(3,4), and '12' + '34', the
method __add__ of the respective class int, list,
tuple, and str gets invoked, as illustrated in Fig. 11.1.
Use of the same syntactic operator such as + in the
examples shown above for objects of different classes
(types) is called operator overloading.

ov er loa din g + oper a tor


Fig. 11.1 Use of specia l m eth ods

Next, we define a class Point (Fig. 11.2) for


representing 2D points on the plane. The class contains
methods __init__ and __str__ for initializing and
displaying the string representation of Point object
respectively.
Fig. 11.2 Cla ss Point (point.py)
Suppose we wish to add two points to determine co-
ordinates of the new point. For this purpose, we may
overload the special method __add__ by defining an
implementation of addition for objects of type Point. In
Fig. 11.3, we modify the class Point by incorporating
the method __add__ which overloads the operator +.

ov er loa din g + oper a tor for a ddin g tw o poin ts


Fig. 11.3 Cla ss Point (point.py)

Next, we create the objects point1 and point2 of the


class Point, and apply the + operator on these objects as
follows:

>>> point1 = Point(3,6)

>>> point2 = Point(2,1)

>>> print(point1 + point2)

(5,7)

Comparing Dates

In addition to the special methods discussed above,


Python also provides special methods such as __eq__,
__lt__, __le__, __gt__, and __ge__ for
overloading comparison operators ==, <, <=, >, and
>= respectively. Suppose we wish to compare two dates.
Let us define two objects of MyDate class and compare
them as follows:

>>> date1 = MyDate(31,12,2014)

>>> id(date1)

49078096

>>> date2 = MyDate(31,12,2014)


>>> id(date2)

10775792

>>> date1 == date2

False

Note that in spite of two dates being same, the


comparison yields False as the result. It is so because
the default implementation of
__eq__ method compares ids of the two objects. So, we
define our own implementation of the equality operator
== for the class MyDate (Fig. 11.4) that would consider
two dates to be equal if and only if they agree on each of
the day, month, and year components. In line 10 (Fig.
11.4) we invoke the built-in function isinstance to
check whether the second object received as a parameter
is an object of MyDate class. If the condition holds True,
it returns the result of the comparison. Otherwise, it
displays the message 'Type Mismatch' and the
program terminates. The method __ne__ corresponding
to the operator != may be developed on similar lines.
Next, we illustrate the use of the method __eq__

defa u lt im plem en ta tion of __eq__() com pa r es ids of tw o


objects

ov er loa din g oper a tor == for com pa r in g tw o da tes

defin e m eth od __ne__ for ov er loa din g oper a tor !=

if __ne__() is n ot defin ed in a cla ss, th en u su a lly , it r etu r n s


not __eq__()

>>> date1 = MyDate(31,12,2014)

>>> date2 = MyDate(31,12,2014)


>>> date3 = MyDate(1,12,2014)

>>> date1 == date2

True

>>> date1 == date3

False

Fig. 11.4 Cla ss m eth ods __eq__

Next, we present the implementation of __lt__ method


for the MyDate class (see Fig. 11.5). This method may be
used to sort a list of objects of type Date.
ov er loa din g oper a tor < for com pa r in g da te objects

>>> dates = [MyDate(31,12,2014),


MyDate(31,10,2014), MyDate(17,12,2014)]

>>> dates.sort()

>>> for date in dates:

print(date)

31-10-2014

17-12-2014

31-12-2014
Fig. 11.5 Da te cla ss m eth ods __lt__

When we invoke the sort function with a list of


objects of type Date, it makes use of the method
__lt__ defined for the Date class.

11.1.2 Function Overloading

Function overloading provides the ability of writing


different functions having the same name, but with a
different number of parameters, possibly of the various
types. For example, we may like to define two functions
by the name area to compute the area of a circle or
rectangle:
fu n ction ov er loa din g : differ en t fu n ction s h a v in g th e sa m e
n a m e bu t differ en t n u m ber a n d ty pe of pa r a m eter s

def area(radius):

# Computes the area of circle

areaCirc = 3.14 * radius * radius

return areaCirc

def area(length, breadth):

# Computes the area of rectangle

areaRect = length * breadth

return areaRect

When we require a function to behave differently


depending on the number and/or type of parameters, we
like to define separate functions that have the same
name, but can be differentiated by the number and type
of parameters. However, Python does not support
function overloading. Indeed, Python cannot distinguish
between parameters based on their type as the type of a
parameter is inferred implicitly when a function is
invoked with actual arguments. Further, when we define
a number of functions that have the same name, Python
retains only the most recent definition. Thus, whereas
invoking the function area with a single argument
results in error, invoking it with two arguments yields
the expected output as illustrated below:

Py th on does n ot su ppor t fu n ction ov er loa din g

ou t of a ll th e defin ition s in a scope h a v in g th e sa m e fu n ction


n a m e, Py th on r eta in s th e m ost r ecen t defin ition

>>> area(4)
Traceback (most recent call last):

File "<pyshell#3>", line 1, in


<module>

area(4)

TypeError: area() missing 1 required


positional argument: 'breadth'

>>> area(4, 5)

20

Method overloading may be implemented indirectly, via


use of default parameters. Let us assume that we wish
the same function named area to compute the area of
each of the circle and rectangle depending upon the
number of arguments passed. We may define it as given
below:

in dir ect im plem en ta tion of m eth od ov er loa din g

def area(a, b = None):

'''

Objective: To compute area of a circle or


rectangle depending on the number of parameters.

Inputs:

a: radius, in the case of a circle side1, in case


of rectangle

b: None, in the case of a circle side2, in the


case of rectangle
Output: area of circle or rectangle as applicable

'''

if b == None:

# Computes the area of circle

areaCirc = 3.14 * a * a
return areaCirc
else:

# Computes the area of rectangle


areaRect = a * b

return areaRect

Thus, when the function area is invoked with two


arguments, it computes the area of the rectangle, and
when it is invoked with only one argument, it computes
the area of the circle.

11.2 ENCAPSULATION, DATA HIDING, AND DATA ABSTRACTION

Encapsulation enables us to group together related data


and its associated functions under one name. Classes
provide an abstraction where essential features of the
real world are represented in the form of interfaces,
hiding the lower-level complexities of implementation
details. Object-oriented languages such as C++ restrict
access to data attributes of an instance or a class outside
the class. However, Python permits us to do so freely, for
example:

en ca psu la tion : g r ou pin g tog eth er r ela ted da ta a n d its


a ssocia ted fu n ction s u n der on e n a m e

a bstr a ction : r epr esen tin g essen tia l fea tu r es of th e r ea l w or ld,


h idin g low er lev el deta ils

today = MyDate(31,1,2014)

today.day = 15

Note that setting attribute day of the object today is a


violation of the principle of data abstraction, which
states that the data attributes of the instance variables
should only be accessed by the methods of the class.
Python allows us to prevent accidental access to the data
and method attributes from outside the class via the
notion of private members. We can tell Python that an
attribute is a private attribute by prefixing the attribute
name by at least two consecutive underscore characters.
Further, the attribute name should not have more than
one underscore character at the end. This technique of
restricting access to private members from outside the
class is known as name mangling. For example, in the
class MyDate, to indicate that the attributes day, month,
and year are private members of the class, we would
prefix each of these attribute names by two consecutive
underscore characters __, thus replacing the attribute
names day, month, and year by __day, __month, and
__year, respectively. Now, these attributes are not
directly accessible from outside the class, and an attempt
to access them will result in error. For example, an
attempt to access today.__day from outside the scope
of the class MyDate generates an error message
indicating that no attribute with name __day exists:

a ccessin g da ta a n d m eth od a ttr ibu tes ou tside th e cla ss is a


v iola tion of th e pr in ciple of a bstr a ction

n a m e m a n g lin g : a tech n iqu e for defin in g pr iv a te a ttr ibu tes

>>> today = MyDate(3,9,2014)

>>> print(today.__day)

Traceback (most recent call last):

File "<pyshell#1>", line 1, in


<module>

print(today.__day)

AttributeError: 'MyDate' object has no


attribute '__day'
However, access to this attribute within the class will
continue to be allowed using notation self.__day. The
restriction on the use of private variables from outside
the scope of the class may be bypassed using the syntax:

sy n ta x for a ccessin g pr iv a te m em ber s fr om ou tside of th e


cla ss

<instance>._<className><attributeName>

Thus, the attribute __day of the object today may be


accessed as today._MyDate__day. However, in
accordance with the principle of data abstraction, we
suggest that the data attributes of a class should be
accessed only through class methods by defining the
operations on the data attributes in the form of methods.
Next, suppose we wish to add an attribute weekDay to
the namespace of the object today of the class MyDate.
For doing so, we may use the following statement:

a ddin g a n a ttr ibu te to th e n a m espa ce of a n object

today.weekDay = 'Wednesday'

However, the inclusion of the attribute weekDay in the


namespace of today will not affect the namespaces of
other objects of the class MyDate, which might have
been created already or may be created later. Since the
class MyDate does not have any interface to deal with
the new attribute weekDay, all modifications to this
attribute must be applied by the programmer explicitly.
Again, one should normally define all the attributes in
the class definition only. The inclusion of an attribute
such as weekDay for an instance of the class should only
be an exception.

11.3 MODIFIER AND ACCESSOR METHODS


The methods in the class definition that modify the value
of one or more arguments are known as modifiers. For
example, the methods setAddress and setName in the
class Person are modifiers since they change the values
of the data attributes address and name respectively
associated with parameter self. However, methods
such as getAddress and getName of the class MyDate
only access (do not modify) the data attributes address
and name of the object self. Such methods are known
as accessors.

m odifier s: m eth ods th a t m odify th e a r g u m en ts

a ccessor s: on ly a ccess (do n ot m odify ) th e a r g u m en ts

11.4 STATIC METHOD

In the methods discussed so far, the object that invokes


the method is passed as the first implicit argument
(self). These methods are called instance methods. An
instance method typically defines operations on the data
members of an instance of a class. However, there are
situations when we want to define a method for a class
to modify the class data members. Such a method does
not require a class object to be passed as the first
parameter and is called a static method. A static method
is invoked as an attribute of a class. It is usually invoked
as className.staticMethodName.

in sta n ce m eth ods: in v oked for th e pa r ticu la r in sta n ce of th e


cla ss,w h ich is pa ssed a s th e fir st a r g u m en t (cor r espon din g to
self)

sta tic m eth ods: u sed for m odify in g cla ss da ta m em ber s a n d do


n ot r equ ir e pa ssin g object a s th e fir st pa r a m eter
Let us examine the class Person once again. To
maintain uniformity of naming conventions used in this
chapter, we shall rename the variable count as
personCount. Thus, in this class, we use the class
variable personCount in the method __init__ to
keep track of the number of instances of Person.

The value of the variable personCount is


incremented by one every time an instance of Person is
created. However, since the information personCount
is not associated with any specific instance of the class
Person, it should be accessed using a static method
without reference to a specific instance of the class
Person. In the script person (Fig. 11.6), we define two
static methods, namely, incPersonCount and
getPersonCount. The incPersonCount method is
invoked by __init__ and increments personCount by
one whenever an instance of the class is created. The
method getPersonCount (replacement for function
getCount) may be used to retrieve the value of data
member personCount. To tell Python that a method is
a static method, the function decorator
@staticmethod precedes the method definition.

@staticmethod: decor a tor th a t pr ecedes th e defin ition of a


sta tic m eth od
Fig. 11.6 Cla ss Person (person.py)

The following instructions illustrate the use of static


methods:

>>> p1 = Person('Smita', '20 May,1980',


'House-177 Block-10, Shalimar Road,
Delhi')

>>> p2 = Person('Aarushi', '20


April,1990', 'House-175 Block-10, Shalimar
Road, Delhi')
>>> Person.getPersonCount()

11.5 ADDING METHODS DYNAMICALLY

Once all the methods of the class have been defined, one
may realize the need to add another method to the class
or a particular instance of the class. Python allows us to
add methods dynamically to a class using the syntax:

sy n ta x for a ddin g m eth ods dy n a m ica lly to a cla ss

<className>.<newMethodName> =
<existingFunctionName>

For the sake of an illustration, we define a class


Student having only the constructor method
__init__ (Fig. 11.7). The script also includes the
methods percentage and result. However, these
methods do not belong to the class Student. The
following instruction will add the method percentage
to the class.

>>> Student.percentage = percentage


Fig. 11.7 Cla ss Student (student.py)

The method percentage can now be invoked like any


other method of the class Student as shown below:

>>> s1 = Student('Amey', 47, 450)

>>> print(s1.percentage())
90.0

Instead, if we were to associate a method with a


particular instance of a class, we need to import the
function MethodType from the module types (line 1,
Fig. 11.7). Subsequently, we use the following syntax to
add a method to an instance of a class:

sy n ta x for a ddin g m eth ods dy n a m ica lly to a n in sta n ce of a


cla ss

<instance>.
<newMethodName>=MethodType(<existingFuncti
onName>,<instance>)

Now we are ready to add the method result to the


instance s1 of the class Student.

>>> s1.result = MethodType(result, s1)

>>> s1.result()

'pass'

Invoking this method from a class instance to which we


have not added the result method will lead to an error:

>>> s2 = Student('Vihan', 23, 490)

>>> s2.percentage()

98.0

>>> s2.result()

Traceback (most recent call last):

File "<pyshell#99>", line 1, in


<module>

s2.result()
AttributeError: 'Student' object has no
attribute 'result'

11.6 COMPOSITION

In this section, we will refine the class Person,


introduced in the last chapter, that comprised the
instance attributes name, DOB, and address in addition
to the class attribute personCount. While creating
objects of class Person, we used string objects such as
'24-10-1990' as values of the date of birth (DOB). In
the last chapter, we also defined MyDate class
comprising three components day, month, and year.
To use this representation of the date in the class
Person, we only need to import the MyDate class in the
script, and there is no change in the description of class
Person (Fig. 11.8).

Fig. 11.8 Cla ss Person (person.py)

Now we illustrate the use of MyDate class to create


instances of Person class:

>>> dob = MyDate(24,10,1990)

>>> p1 = Person('Rajat Mittal', dob, \ 'B-


23,Malviya Nagar,Delhi')

>>> print(p1)

Name:Rajat Mittal
DOB:24-10-1990

Address:B-23,Malviya Nagar,Delhi

Note that data attribute dob of object p1 is of type


MyDate. Here, we have used an object of another class
MyDate as an attribute of the class Person. The process
of using objects of the other classes as attribute values is
called object composition. It is important to observe that
we have already used this concept subconsciously. While
creating objects of class Person earlier, we used objects
of system-defined class str as values of attributes name,
DOB, and address. We could have, equally well, used
the object MyDate(24,10,1990)directly as an
argument, while invoking the the constructor, instead of
first creating it as dob, as shown below:

u sin g objects of oth er cla sses a s a ttr ibu tes

>> p1 = Person('Rajat Mittal',


MyDate(24,10,1990), 'B-23,Malviya
Nagar,Delhi')

11.7 INHERITANCE

Inheritance is an important feature of object oriented


programming that imparts ability to a class to inherit
properties and behavior of another class. The class
object includes a rich set of special Python functions as
seen below:

in h er itin g pr oper ties a n d beh a v ior of a n oth er cla ss

>>> dir(object)
['__class__', '__delattr__', '__dir__',
'__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__',
'__hash__', '__init__',
'__init_subclass__', '__le__', '__lt__',
'__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__',
'__subclasshook__']

It is interesting to note that various types such as int,


list, tuple, and dict have some common methods
such as __eq__, __lt__, and __str__. These types
have derived these common methods (attributes) from
the object class. The object class serves as the base
class of each of these classes.

object cla ss is th e ba se cla ss of a ll cla sses

Suppose we want to develop a program that deals with


employees in an organization. Data attributes of an
employee may comprise his/her name, address, date of
birth, employee id, and salary. As a first reaction, one
may wish to create class Employee having these
attributes and define all the methods required for this
class. However, notice that every employee is a person,
and we have already done much hard work to develop
the Person class. It makes sense to design the
Employee class as an extension of the Person class. In
this way, all the data and method attributes of the
Person class would be available to Employee class. In
the language of Object-oriented Programming (OOP),
we say that Employee class inherits or derives the data
and method attributes from the Person class. Here,
Person class is called base, super, or parent class, and
Employee class is called derived, sub, or child class.
Thus, the notion of inheritance allows us to express the
parent–child relationship among the classes as shown in
Fig. 11.9.
r ela tion sh ip betw een ba se cla ss a n d der iv ed cla ss

"is a" r ela tion sh ip

Fig. 11.9 Pa r en t a n d ch ild cla ss

11.7.1 Single Inheritance

When inheritance involves a derived class that derives its


properties from a single base class (see Fig. 11.9), it is
called single inheritance. As another example, think of a
manager in a factory. The manager would have all the
attributes of an employee and may have some new
attributes like managerial pay. This relationship is
expressed in Fig. 11.10.

Manager cla ss der iv es pr oper ties fr om th e ba se cla ss Employee

Fig. 11.10 Em ploy ee a n d m a n a g er cla ss


Details of the class Employee appear in Fig. 11.11. As
the Employee class is a derived class of the base class
Person, we import the base class Person from module
person (stored as person.py in the current directory).
Next, we must tell Python that the class Employee is a
derived class of base class Person. We do this by
enclosing the name of base class Person in parenthesis
following the name of derived class Employee (line 3,
Fig. 11.11). Based on the assumption that the Employee
ids begin with 1001, the class attribute nextId is
initialized as 1001 and is incremented by the constructor
method whenever an instance of class Employee is
created.
Fig. 11.11 Cla ss Employee (employee.py)

As the Employee class is a derived class of the base


class Person, all the data and method attributes defined
in the Person class become available to the Employee
class. Recall that we had defined the methods
__init__, __str__, and __del__ in the class
Person. However, we need to redefine these methods in
the derived class Employee. When an object of a derived
class makes a call to a method that is also defined in the
base class, Python invokes the method of derived class.
Thus, the derived class methods override the base class
methods, and this process is known as method
overriding.

m eth od ov er r idin g : r edefin in g a m eth od in th e der iv ed cla ss

The constructor for the Employee class, needs to


initialize the variables of the Person class as well as the
new variables introduced in the Employee class. Recall
that we say that Employee is a Person. Therefore, to
initialize an object of class Employee, we invoke the
constructor of class Person that initializes the Person
class variables for an object of the Employee class. For
this purpose, we pass self (self refers to an object of
Employee class) as an argument while invoking the
Person class constructor. To be more specific, invoking
the constructor of the Person class in the Employee
class constructor does not create a new instance of the
Person class, instead it only initializes the variables of
the Person class for the Employee class object.

Within the definition of the constructor for class


Employee, if we attempt to invoke __init__, it would
lead to a recursive call to itself. So we qualify __init__,
by prefixing the name of the base class, as
Person.__init__. Similarly, in line 65, the method
Person.__str__ of the base class is invoked to return
the string representation for the inherited variables. Note
that invoking the method Person.__init__
increments the class variable personCount of the class
Person.

in v okin g a ba se cla ss m eth od


In the destructor method __del__ of class
Employee, the class variable employeeCount would be
decremented by 1. Recall that the variables of the
Person class for the Employee class object were also
initialized while creating the Employee class object,
thus, when __del__ method of class Employee is
invoked, we invoke the destructor method
Person.__del__ of the base class Person (line 86).
Consequently, the class variable personCount of the
base class Person would also get decremented by 1. This
is illustrated by the following example:

>>> person1 = Person('Shyam Kapoor',


MyDate(24,10,1990), 'B-23, Malviya Nagar,
Delhi')

'B-23,Malviya Nagar,Delhi')

>>> print(Person.personCount)

>>> emp1 = Employee('Rehman',


MyDate(5,6,1970),

'D-9, Vivek Vihar, Delhi', 50000,


MyDate(2,8,2013))

>>> print(Employee.employeeCount)

>>> print(Person.personCount)

>>> del emp1

Deleted!!

>>> print(Employee.employeeCount)
0

>>> print(Person.personCount)

In line 18 (Fig. 11.11), call to the method __init__ is


made using a superclass name and the object instance is
explicitly passed as an argument to the superclass
method. Alternatively, we may use the super function
to access a method of the superclass. Thus, line 18 (Fig.
11.11) can be replaced by the following statement:

u sin g super fu n ction for a ccessin g a m eth od of a ba se cla ss

super(Employee, self).__init__(name, DOB,


address)

or

super().__init__(name, DOB, address)

Similarly, line 86 (Fig. 11.11) can be replaced by the


following statement:

super(Employee, self).__del__()

or

super().__del__()

Scope Rule

To access an instance attribute, Python will first look for


it in the instance's namespace, then in the class
namespace, and then in the superclass namespace
recursively going up in the hierarchy. We illustrate this
in Fig. 11.12.

scope r u le for a ccessin g a n in sta n ce a ttr ibu te


Fig. 11.12 Scope of v a r ia bles (scope.py)

In the script scope, we create the objects ob1 and


ob2 of the classes A and B, respectively (lines 46 and 47,
Fig. 11.12). These objects are displayed using print
functions in lines 48 and 49. Next, we display the
directories of class A, object ob1, class B, and object ob2
(lines 50–53, Fig. 11.12).

ob1:

w:100, x:2, y:10, z:30

ob2:
w:100, x:6, y:10, z:30, v:50

dir(A):

['__class__', '__delattr__', '__dict__',


'__dir__', '__doc__', '__eq__',
'__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__',
'__weakref__', 'z']

dir(ob1):

['__class__', '__delattr__', '__dict__',


'__dir__', '__doc__', '__eq__',
'__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__',
'__weakref__', 'w', 'x', 'y', 'z']

dir(B):

['__class__', '__delattr__', '__dict__',


'__dir__', '__doc__', '__eq__',
'__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__',
'__weakref__', 'x', 'y', 'z']

dir(ob2):
['__class__', '__delattr__', '__dict__',
'__dir__', '__doc__', '__eq__',
'__format__', '__ge__',
'__getattribute__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__',
'__lt__', '__module__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__',
'__str__', '__subclasshook__',
'__weakref__', 'v', 'w', 'x', 'y', 'z']

The values of data attributes of the objects ob1 and ob2


can be read from the namespaces of these objects (Fig.
11.13).
Fig. 11.13 Repr esen ta tion of cla ss A , cla ss B, object ob1, a n d object
ob2

In the expression 'ob1:\n' + str(ob1), when the


__str__ method is invoked, it uses the values of data
attributes x, y, and w directly from the namespace of
object ob1. The data attribute ob1.z is also accessible as
it is defined as a class variable of the class A of which
ob1 is an object. According to scope rule, an attribute is
first searched in object's namespace. Therefore, in the
expression 'ob2:\n' + str(ob2), when the
__str__ method is invoked, it uses the values of data
members x and v directly from the namespace of the
object ob2 and the variables x and v are bound to values
6 and 50, respectively. The attribute y is an instance
attribute inherited from the parent class A and is bound
to value 10. Similarly, the attribute w is an instance
attribute inherited from the superclass A and is bound to
value 100. However, for accessing z, Python first
searches in object ob2's namespace, then in its class B's
namespace, and finally in superclass A's namespace,
where it is found and gets bound to value 30.

We may obtain the name(s) of the class(es) from


which a class inherits properties as follows:
__bases__: u sed to fin d ba se cla ss(es) of a cla ss

>>> str.__bases__

(<class 'object'>,)

>>> B.__bases__

(<class '__main__.A'>,)

>>> B.__bases__[0]

<class '__main__.A'>

Note that class B inherits from only one class, i.e. A.


Therefore, tuple B.__bases__ contains only one class,
i.e. <class '__main__.A'>. Given an object, its class
name may be obtained as shown below:

__name__: u sed to r etr iev e th e n a m e of a cla ss

>>> 'Python'.__class__.__name__

'str'

Extending Scope of int Class Using a User Defined Class

Built-in methods such as __add__, __sub__,


__mult__, and __div__ are already defined for objects
of class int. However, there is no implementation of
method len. We define the length of an integer x to be
the number of digits in abs(x). For this purpose, we
define a class MyInt as a derived class of Python class
int (Fig. 11.14) and define a method len that computes
the length of an integer.

ex ten din g in t cla ss a s MyInt a n d defin in g a m eth od len for it


Fig. 11.14 MyInt cla ss (myint.py)

Next, we illustrate the use of MyInt class to display the


number of digits in an integer:

>>> n1 = MyInt(3456)

>>> n2 = MyInt(-18)

>>> type(n1), type(n2)


(<class '__main__.MyInt'>, <class
'__main__.MyInt'>)

>>> len(n1)

>>> len(n2)

>>> len(MyInt(0))

Note that the methods of the int class such as


__add__, __sub__, __mult__, and __div__ can still
be applied to objects of type MyInt as it inherits all the
attributes of the int class. The following examples
illustrate this:

>>> n1 + n2

3438

>>> n1 - n2

3474

11.7.2 Hierarchical Inheritance

In Section 11.7.1, we discussed the derived classes.


Further, a derived class is like any other class and may
serve as base class for another class derived from it and
so on. Each derived class may define its new attributes.
Thus, inheritance allows us to create a class hierarchy,
also called type hierarchy. When inheritance involves
more than one level of hierarchy such as A -> B -> C,
it is called multilevel inheritance, and inheritance
involving multiple classes deriving from single base class
is known as hierarchical inheritance. For example,
examine the base class Vehicle, having attributes like
registration number, make, model, and color. From this
class, we may derive classes PassengerVehicle and
CommercialVehicle. The class PassengerVehicle
may have additional attributes like maximum passenger
capacity. The class CommercialVehicle, may have
other attributes like maximum load capacity. From the
PassengerVehicle class, we may derive classes Car,
Autorickshaw, and Bus. The Car and Bus may have
attributes like the number of doors, not shared by
Autorickshaw. The Bus may have a Boolean attribute
doubleDecker not shared by Car and Autorickshaw.
Note that every car has all the attributes of a
PassengerVehicle, and every PassengerVehicle
has all the attributes of a Vehicle. So we can say Car is
a PassengerVehicle and PassengerVehicle is a
Vehicle. This relationship between the derived class
and the base class is called is an/is a relationship. The
relationships among Vehicle, PassengerVehicle,
Car, Autorickshaw, and Bus are shown in Fig. 11.15.
The figure demonstrates that several derived classes may
inherit from the same base class, for example, the classes
PassengerVehicle and CommercialVehicle inherit
from the same base class Vehicle, and the classes Car,
Autorickshaw, and Bus inherit from the same base
class PassengerVehicle.

m u ltilev el in h er ita n ce

h ier a r ch ica l in h er ita n ce

"is a" r ela tion sh ip


Fig. 11.15 Ex a m ple of in h er ita n ce h ier a r ch y

As another example of class inheritance, the two classes


Clerk and Manager may be derived from single base
class Employee (Fig. 11.16). Whereas the Clerk class
has an additional class attribute clerkCount, the
Manager class has two additional attributes: a class
attribute managerCount and an instance attribute
managerialPay. The complete definition of these
classes is given in Fig. 11.17. Note that class Manager
defines method getSalary that overrides the superclass
method getSalary and computes the manager's salary
by adding managerialPay to an employee's Salary.

Fig. 11.16 In h er ita n ce r ela tion sh ip betw een Em ploy ee, Cler k, a n d
Ma n a g er

Next, let us study some examples:


>>> clerk1 = Clerk('Arun',
MyDate(5,6,1930),

'D-9, Sarojni Nagar, Delhi', 20000,


MyDate(5,6,1950))

>>> print(clerk1)

Name:Arun

DOB:05-06-1930

Address:D-9, Sarojni Nagar, Delhi

Id:1001

Salary:20000

Date of Joining:05-06-1950
Fig. 11.17 Cla sses Clerk a n d Manager

Since there is no __str__ method in the class Clerk, to


print the object clerk1, __str__ method of the
superclass Employee is invoked. Also, because Arun is
the first employee, Id 1001 is assigned to him. Next, we
create an object of class Manager:
in v okin g a m eth od of a su per cla ss

>>> manager1 = Manager('Rehman',

MyDate(5,6,1970), 'D-9, Vivek Vihar,


Delhi',

50000, MyDate(5,6,1990), 2000)

>>> print(manager1)

Name:Rehman

DOB:05-06-1970

Address:D-9, Vivek Vihar, Delhi

Id:1002

Salary:52000

Date of Joining:05-06-1990

ManagerialPay:2000

As the class Manager has its own __str__ method


(lines 70–78), it will be invoked to print manager1. As
Manager is an employee, the method __str__ of
Manager class concatenates
'\nManagerialPay:'+str(self.managerialPay)
to Employee.__str__(self) to return string
representation of an object of the class Manager. Next,
let us print salary (basicSalary + managerialPay)
of manager1:

>>> print(manager1.getSalary())

52000

As a Manager is also an Employee, the Manager class


method getSalary invokes the method getSalary of
the Employee class to compute the basicSalary of
the Manager and adds managerialPay to compute the
salary of the manager.

11.7.3 Multiple Inheritance

In the case of multiple inheritance, a subclass derives its


attributes from two or more classes. In this section, we
make use of multiple inheritance to schedule
appointments by creating a class Appointment. Since
an appointment will comprise date and time, we may
inherit the classes MyDate and MyTime in the class
Appointment (Fig. 11.18).

a su bcla ss m a y der iv e its pr oper ties fr om tw o or m or e cla sses

th e cla ss Appointment der iv es pr oper ties fr om tw o cla sses:


MyDate a n d MyTime

Fig. 11.18 Cla sses Cler k a n d Ma n a g er

We have already developed the class MyDate. In Fig.


11.19, we give details of the class MyTime having data
attributes hours, minutes, and seconds.
Fig. 11.19 Cla ss MyTime (time1.py)

We may create an object of class MyTime as follows:

>>> currentTime = MyTime(23,50,30)

>>> print(currentTime)

23:50:30

Finally, we present the derived class Appointment (Fig.


11.20).
Fig. 11.20 Cla ss Appointment (appointment.py)

Suppose we wish to create two appointments for the


Principal of a college. The first is a meeting with office
staff regarding admissions scheduled on 15 July 2014 at
10:00 and the second is a meeting with teachers
regarding timetable scheduled on 18 July 2014 at 13:30.
For doing so, we may create two objects as follows:

>>> meetStaff =Appointment(15, 7, 2014,


10,\

0, 0,' Meeting with staff regarding


admissions')

>>> meetTeachers =Appointment(18, 7,


2014,\

13, 30, 0, ' Meeting with teachers


regarding timetable')

Details of an appointment may be printed using the str


representation of an appointment, for example:

>>> print(meetStaff)

15-7-2014, 10:00:00

Meeting with staff regarding admissions


If required, hierarchical inheritance may be combined
with multiple and multilevel inheritance, to yield hybrid
inheritance.

11.7.4 Abstract Methods

An abstract method in a base class identifies the


functionality that should be implemented by all its
subclasses. However, since the implementation of an
abstract method would differ from one subclass to
another, often the method body comprises just a pass
statement. Every subclass of the base class will override
this method with its implementation. A class containing
abstract methods is called abstract class. It is important
to point out that although it is not possible to instantiate
an abstract class, a subclass of an abstract class that
defines the abstract methods may be instantiated as
usual.

a bstr a ct m eth ods a n d a bstr a ct cla sses iden tify fu n ction a lity
th a t sh ou ld be im plem en ted by a ll th e su bcla sses

a bstr a ct cla ss: cla ss con ta in in g a bstr a ct m eth ods

To use Python Abstract Base Classes (ABCs), one


needs to import ABCMeta and abstractmethod from
the abc module. For example, let us examine the class
Shape and its subclasses Rectangle and Circle
defined in the script shape (Fig. 11.21). Each of the
subclasses Rectangle and Circle needs methods for
computing area and perimeter. However, the procedure
for computing area and perimeter would differ for
Rectangle and Circle. Therefore, we define the
classes Rectangle and Circle as subclasses of the
class Shape. We define methods area and perimeter
as abstract methods in the class Shape. The subclasses
Rectangle and Circle override the methods area
and perimeter by defining their implementation as
shown in Fig. 11.21. If the subclasses Rectangle and
Circle fail to override any of the methods area or
perimeter, Python will yield a TypeError while
instantiating them.

a bstr a ct cla sses ca n n ot be in sta n tia ted

abc m odu le: pr ov ides su ppor t for Py th on a bstr a ct ba se cla sses


Fig. 11.21 Cla ss Sh a pe a n d its der iv ed cla sses(shape.py)

We indicate that a method is abstract by preceding its


definition by
@abstractmethod (function decorator). Note that the
definition of an abstract class begins with

@ a b s t r a c t - method: decor a tor for specify in g a n


a bstr a ct m eth od

__metaclass__ = ABCMeta
To illustrate the use of abstract classes, we create an
object rectangle of the class Rectangle having
length and breadth 30 and 15, respectively, and an
object circle of the class Circle having radius 5.
The methods area and perimeter defined in the
subclasses Rectangle and Circle override the
corresponding abstract methods defined in the superclass
Shape. Next, we see some examples of the use of these
methods:

> >> rectangle = Rectangle(30, 15)

>>> rectangle.area()

450

>>> rectangle.perimeter()

90

>>> circle = Circle(5)

>>> circle.area()

78.5

>>> circle.perimeter()

31.4

11.7.5 Attribute Resolution Order for Inheritance

Python classes are categorized as old and new style


classes. Python 3 is purely based on new-style classes. A
new-style class inherits from the built-in class object.
In the new style classes, to access an attribute of an
object, Python typically looks for it in the namespace of
the object itself, then in the namespace of the class, then
in the namespace of the superclasses in the order in
which they are derived and so on. In the script
newStyleClasses (Fig. 11.22), class C inherits from
classes B1 and B2, which further inherit from the class
A. It is important to point out that the class C inherits
from classes B1 and B2 in the order B1 and B2.
However, if the definition of class C were to begin with

n ew -sty le cla sses

a ttr ibu te r esolu tion or der : for a ccessin g a n a ttr ibu te of a n


object

class C(B2, B1):

then the class C would inherit from classes B1 and B2 in


the order B2 and B1.
Fig. 11.22 In h er ita n ce in n ew -sty le cla sses
(newStyleClasses.py)

In Fig. 11.23, the order of resolution would be the


object c1 of class C, class C, class B1, class B2, class A,
class object. On executing the script in Fig. 11.22,
value 50 is printed. When the print function is
executed in the main function (line 21), Python invokes
pre-defined method __str__ where it needs to reference
variable test. Since test is not an instance variable of
the object c1, the search is made in class C, subsequently
followed by a search in superclass B1, and finally in B2
where it is found.
Fig. 11.23 In h er ita n ce h ier a r ch y for cla sses in Fig . 1 1 .2 2

For determining the order in which methods of classes


will be accessed, Python provides the attriibute __mro__
which stands for method resolution order. It returns a
list ordered by the classes in which search for methods is
to take place. For example:
__mro__: fin ds or der in w h ich m eth ods of cla sses w ill be
a ccessed

>>> C.__mro__

(<class '__main__.C'>, <class


'__main__.B1'>, <class '__main__.B2'>,
<class '__main__.A'>, <class 'object'>)

>>> B2.__mro__

(<class '__main__.B2'>, <class


'__main__.A'>, <class 'object'>)

>>> B1.__mro__

(<class '__main__.B1'>, <class


'__main__.A'>, <class 'object'>)

>>> A.__mro__

(<class '__main__.A'>, <class 'object'>)

11.8 BUILT-IN FUNCTIONS FOR CLASSES

Python provides several built-in functions that deal with


classes and their instances. For example, to find whether
a class is a subclass of another class, one may use the
function issubclass that takes two arguments: sub
and super:

issubclass()

issubclass(sub, super)

The function issubclass returns True if sub is the


subclass of class super, and False otherwise. For
example:

>>> issubclass(Appointment, MyDate)

True
To find whether the instance obj is an object of class
class1, we use the function isinstance:

isinstance()

isinstance(obj, class1)

This function returns True if either obj is an instance of


class class1 or it is an instance of a subclass of class
class1, and False otherwise, for example:

>>> isinstance(meetStaff, MyDate)

True

>>> isinstance(manager1, Employee)

True

>>> isinstance(manager1, MyDate)

False

>>>

To find whether an instance obj contains an attribute


attr, we use the function hasattr:

hasattr()

>>> hasattr(obj, attr )

This function returns True if instance obj contains an


attribute attr, and False otherwise, for example:

>>> hasattr(manager1, 'hours')

False
>>> hasattr(manager1, 'DOB')

True

The functions getattr and setattr may be used to


retrieve and set respectively, the value val of an
attribute attr of an instance obj, as illustrated below:

getattr() a n d setattr()

getattr(obj, attr)

setattr(obj, attr, val)

>>> getattr(meetStaff, 'day')

15

>>> setattr(meetStaff, 'day', 23)

>>> print(meetStaff)

23-07-2014, 10:00:00

Meeting with parents regarding admissions

We may delete an attribute attr of instance obj as


follows:

delattr()

delattr(obj, attr)

>>> delattr(meetStaff, 'day')

>>> print(meetStaff)

Traceback (most recent call last):

File "<pyshell#5>", line 1, in


<module>
print(appointment1)

File "F:\PythonCode\Ch11\appointment.py",
line 28, in __str__

+'\n'+self.description

File " F:\PythonCode\Ch11\date.py", line


103, in __str__

if self.day <= 9:

AttributeError: 'Appointment' object has


no attribute 'day'

As we had deleted the day attribute, subsequent


attempts to access it in the print method resulted in
error.

SUMMARY

1 . Cla sses a r e ba sed on a n object-or ien ted pa r a dig m


kn ow n a s Object-or ien ted Pr og r a m m in g (OOP). Object-
or ien ted pr og r a m m in g r ev olv es a r ou n d th e n otion of
objects.
2 . A m eth od/oper a tor m a y be a pplied to objects of
differ en t ty pes (cla sses). Th is fea tu r e of object-or ien ted
pr og r a m m in g is ca lled poly m or ph ism .
3 . In oper a tor ov er loa din g , a sta n da r d oper a tor is
r edefin ed a s per th e r equ ir em en t of a cla ss, for
ex a m ple, th e specia l m eth ods th a t su ppor t oper a tor
ov er loa din g in clu de __add__, __sub__, __mult__,
__div__, __lt__, __le__, __gt__, a n d __ge__.
4 . Wh ile u sin g a bin a r y oper a tor , th e m eth od a ssocia ted
w ith th e object on th e left-hand s ide of th e oper a tor is
in v oked.
5 . Fu n ction ov er loa din g pr ov ides th e a bility of w r itin g
differ en t fu n ction s h a v in g th e sa m e n a m e, bu t w ith a
differ en t n u m ber of pa r a m eter s, possibly of v a r iou s
ty pes. Py th on does n ot su ppor t fu n ction ov er loa din g .
In dir ectly , m eth od ov er loa din g m a y be r ea lized u sin g
defa u lt pa r a m eter s.
6 . Py th on specia l m eth od __del__ is u sed for defin in g th e
cla ss destr u ctor .
7 . En ca psu la tion en a bles u s to g r ou p r ela ted da ta a n d its
a ssocia ted fu n ction s u n der on e n a m e. En ca psu la tion is
r ea lized v ia cla sses. Cla sses pr ov ide a n a bstr a ction
w h er e essen tia l fea tu r es of th e r ea l w or ld a r e
r epr esen ted in th e for m of in ter fa ces, h idin g th e low er
lev el com plex ities of im plem en ta tion deta ils.
8 . Py th on a llow s u s to pr ev en t a cciden ta l a ccess to th e
da ta a n d m eth od a ttr ibu tes fr om ou tside th e cla ss. Th is
is a ch iev ed v ia th e n otion of pr iv a te m em ber s. We ca n
tell Py th on th a t a n a ttr ibu te is a pr iv a te a ttr ibu te by
pr efix in g th e a ttr ibu te n a m e by tw o con secu tiv e
u n der scor e ch a r a cter s __. Fu r th er , n a m e of a pr iv a te
a ttr ibu te sh ou ld n ot h a v e m or e th a n on e u n der scor e
ch a r a cter a t th e en d. Th is tech n iqu e of r estr ictin g
a ccess to pr iv a te m em ber s fr om ou tside th e cla ss is
kn ow n a s name mangling. Th e r estr iction on th e u se of
pr iv a te v a r ia bles fr om ou tside th e scope of th e cla ss,
m a y be by pa ssed u sin g th e sy n ta x :
<instance>._<className><attributeName>
9. Meth ods in th e cla ss defin ition th a t m odify th e v a lu e of
on e or m or e a r g u m en ts a r e kn ow n a s m odifier s.
1 0. Meth ods in th e cla ss defin ition w h ich on ly a ccess (do
n ot m odify ) th e da ta a ttr ibu tes a ssocia ted w ith
a r g u m en ts a r e kn ow n a s a ccessor s.
11. Th e m eth ods in w h ich th e object th a t in v okes th e
m eth od is pa ssed a s th e fir st im plicit pa r a m eter (self)
a r e ca lled in sta n ce m eth ods. A n in sta n ce m eth od
defin es oper a tion s on th e da ta m em ber s of a n in sta n ce
of a cla ss.
12. Th e m eth od th a t does n ot r equ ir e a cla ss object to be
pa ssed a s th e fir st pa r a m eter is ca lled a sta tic m eth od.
Ca ll to th is m eth od sh ou ld be m a de a s
className.staticMethodName, a lth ou g h Py th on
a llow s a sta tic m eth od to be in v oked a s a n a ttr ibu te of
a n object a lso.
13. Py th on a llow s to a dd m eth ods dy n a m ica lly to a cla ss or
a n in sta n ce of a cla ss u sin g th e sy n ta x :
<className>.<newMethodName> =
<existingFunctionName>
1 4. Py th on a lso a llow s to a dd a m eth od to a n in sta n ce of a
cla ss:
<instance>.
<newMethodName>=MethodType(<existingFunction
Name>,<instance>)
15. Th e pr ocess of u sin g objects of oth er cla sses a s a ttr ibu te
v a lu es is ca lled object compos ition.
1 6. In h er ita n ce m a kes it possible to cr ea te a cla ss (a lso
ca lled ty pe) h ier a r ch y . Th e cla ss w h ose pr oper ties a r e
in h er ited is kn ow n a s a ba se cla ss, pa r en t cla ss, or
su per cla ss. Th e cla ss th a t in h er its fr om a n oth er cla ss is
ca lled der iv ed cla ss, ch ild cla ss, or su bcla ss. A der iv ed
cla ss m a y ser v e a s ba se cla ss for a n oth er cla ss der iv ed
fr om it a n d so on . Ea ch der iv ed cla ss m a y defin e its n ew
a ttr ibu tes.
17. Wh en in h er ita n ce in v olv es a der iv ed cla ss th a t der iv es
its pr oper ties fr om a sin g le ba se cla ss (see Fig . 1 1 .9 ), it
is ca lled s ingle inheritance.
1 8. Wh en a n object of a der iv ed cla ss m a kes a ca ll to a
m eth od th a t is a lso defin ed in th e ba se cla ss, it is th e
m eth od of th e der iv ed cla ss th a t is in v oked by Py th on .
Th u s, th e der iv ed cla ss m eth ods ov er r ide th e ba se cla ss
m eth ods, a n d th is pr ocess is kn ow n a s m eth od
overriding.
1 9. Wh en in h er ita n ce in v olv es m or e th a n on e lev el of
h ier a r ch y su ch a s A -> B -> C, it is ca lled m u ltilev el
in h er ita n ce, a n d in h er ita n ce in v olv in g m u ltiple
cla sses der iv in g fr om sin g le ba se cla ss is kn ow n a s
h ier a r ch ica l in h er ita n ce.
2 0. In m u ltiple in h er ita n ce, a su bcla ss der iv es its
a ttr ibu tes fr om tw o or m or e cla sses.
2 1 . A n a bstr a ct m eth od in a ba se cla ss iden tifies th e
fu n ction a lity th a t sh ou ld be im plem en ted by a ll its
su bcla sses. Ev er y su bcla ss of th e ba se cla ss sh ou ld
ov er r ide th is m eth od w ith its im plem en ta tion . A cla ss
con ta in in g a bstr a ct m eth ods is ca lled a bstr a ct cla ss. To
u se Py th on A bstr a ct Ba se Cla sses (A BCs), on e n eeds to
im por t ABCMeta a n d abstractmethod fr om abc
m odu le.
2 2 . A n ew -sty le cla ss in h er its fr om th e bu ilt-in cla ss object.
In th e n ew -sty le cla sses, to a ccess a n a ttr ibu te of a n
object, Py th on fir st looks for it in th e n a m espa ce of th e
object itself, th en in th e n a m espa ce of th e cla ss, th en in
th e n a m espa ce of th e su per cla sses in th e or der in w h ich
th ey a r e der iv ed, a n d so on .
2 3 . Py th on pr ov ides sev er a l bu ilt-in fu n ction s th a t dea l
w ith cla sses a n d th eir in sta n ces:
1 . Th e fu n ction issubclass is u sed to fin d w h eth er
a cla ss is a su bcla ss of a n oth er cla ss.
2 . Th e fu n ction isinstance is u sed to fin d w h eth er
a n object is a n in sta n ce of a cla ss.
3 . Th e fu n ction hasattr is u sed to deter m in e
w h eth er a n in sta n ce con ta in s a pa r ticu la r
a ttr ibu te.
4 . Th e fu n ction s getattr a n d setattr a r e u sed to
r etr iev e or set th e v a lu e of a n a ttr ibu te of a n
in sta n ce r espectiv ely .
5 . Th e fu n ction delattr is u sed to delete a n
a ttr ibu te of a n in sta n ce.

EXERCISES

1 . Wr ite a cla ss Point h a v in g x a n d y coor din a tes a s da ta


m em ber s. Wr ite a n oth er cla ss LineSegment th a t
der iv es th e cla ss Point A lso, list a ppr opr ia te m eth ods.
2 . Defin e th e m eth od __ne__ for th e cla ss MyDate.
3 . Defin e th e m eth od __sub__ (Fig . 1 1 .2 4 ) for th e cla ss
MyDate.
4 . Defin e a cla ss ComplexNumbers. Wr ite oper a tion s for
a ddition , su btr a ction , a n d m u ltiplica tion , u sin g th e
n otion of oper a tor ov er loa din g .
5 . Ex a m in e th e follow in g cla ss Shape:
class Shape:
def __init__(self, shapeType, x, y):
self.shapeType = shapeType
self.length = x
self.width = y
def computeArea():
pass
F ig . 11.24 Met h od __sub__ f or t h e c l ass MyDate

Th e cla ss Shape sh ou ld be in h er ited by th e cla sses


Rectangle and Triangle. Both th e der iv ed cla sses
sh ou ld in v oke th e m eth od __init__ to in itia lize da ta
m em ber s. Note th a t length a n d width cor r espon d to
height a n d base for a tr ia n g le. Th e der iv ed cla sses
sh ou ld ov er r ide th e m eth od computeArea of th e
su per cla ss Shape.
6 . Ex a m in e th e cla ss Person defin ed in th is ch a pter .
Defin e a cla ss Student th a t der iv es th is cla ss a n d
defin es name, rollNum, class, totalMarks, a n d Year
a s th e da ta m em ber s. Th e cla ss sh ou ld con ta in th e
in sta n ce m eth od __init__ a n d th e a bstr a ct m eth od
percentage. Defin e tw o cla sses Grad a n d PostGrad
w h ich in h er it fr om th e ba se cla ss Student. Both th e
cla sses sh ou ld defin e th eir __init__ m eth od a n d
sh ou ld ov er r ide th e a bstr a ct m eth od percentage of th e
su per cla ss. Note th a t totalMarks obta in ed a r e ou t of
6 00 a n d 4 00 for Grad a n d PostGrad cla sses
r espectiv ely .
7 . Defin e a ba se cla ss Vehicle, h a v in g a ttr ibu tes
r eg istr a tion n u m ber , m a ke, m odel, a n d color . A lso,
defin e cla sses PassengerVehicle a n d
CommercialVehicle th a t der iv e fr om th e cla ss
Vehicle. Th e PassengerVehicle cla ss sh ou ld h a v e
a ddition a l a ttr ibu te for m a x im u m pa ssen g er ca pa city .
Th e CommercialVehicle cla ss sh ou ld h a v e a n
a ddition a l a ttr ibu te for m a x im u m loa d ca pa city .
Defin e __init__ m eth od for a ll th ese cla sses. A lso,
defin e g et a n d set m eth ods to r etr iev e a n d set th e v a lu e
of th e da ta a ttr ibu tes.
8 . Defin e cla sses Car, Autorickshaw, a n d Bus w h ich
der iv e fr om th e PassengerVehicle cla ss m en tion ed in
th e pr ev iou s qu estion . Th e Car a n d Bus sh ou ld h a v e
a ttr ibu tes for stor in g in for m a tion a bou t th e n u m ber of
door s, n ot sh a r ed by Autorickshaw. Th e Bus sh ou ld
h a v e Boolea n a ttr ibu te doubleDecker n ot sh a r ed by
Car a n d Autorickshaw. Defin e __init__ m eth od for a ll
th ese cla sses. A lso, defin e g et a n d set m eth ods to
deter m in e a n d set th e v a lu e of th e da ta a ttr ibu tes.
9 . Defin e a cla ss Account, h a v in g a ttr ibu tes a ccou n t
h older 's n a m e, a ccou n t n u m ber , a ccou n t ty pe, th e
a m ou n t deposited a n d m in im u m deposit a m ou n t.
Defin e tw o cla sses, n a m ely Savings a n d Current. Th e
Savings cla ss sh ou ld h a v e a pr oper ty in ter est. Defin e
__init__ m eth od for a ll th ese cla sses. A lso, defin e g et
a n d set m eth ods to deter m in e a n d set th e v a lu e of th e
da ta a ttr ibu tes.
1 0. Usin g Py th on bu ilt-in fu n ction s, w r ite th e sta tem en ts
to
1 . Deter m in e w h eth er A is a su bcla ss of B.
2 . Deter m in e w h eth er a ttr ibu te attr ex ists in th e
n a m espa ce of object ob of cla ss A.
3 . A ssig n v a lu e 70 to a ttr ibu te attr of object ob of
cla ss A.
4 . Delete a n a ttr ibu te attr of object ob of cla ss A.
CHAPTER 12
LIST MANIPULATION

CHAPTER OUTLINE
1 2 .1 Sor tin g

1 2 .2 Sea r ch in g

1 2 .3 A Ca se Stu dy

1 2 .4 Mor e on Sor tin g

In several applications, we need to sort data or search for


some item of interest in the given data. For example, we
may be required to arrange the answer sheets in the
order of roll number, to arrange the student data on the
basis of marks, to search for a phone number in a
telephone directory, or to find an answer sheet with a
given roll number. We already know that given the roll
number of a student, it is easier to find his/her answer
sheet if the answer sheets are arranged according to roll
number. Similarly, it is easier to find how many students
have secured pass marks, if the answer sheets are
arranged according to marks. The process of arranging
data in ascending/descending order is called sorting. In
this chapter, we will study how to sort the data using
several techniques. We will also study searching
techniques for unsorted data as well as for the data that
is already sorted. This chapter concludes with a case
study relating to student data.

sor tin g : th e pr ocess of a r r a n g in g da ta in


a scen din g /descen din g or der

sea r ch in g is m or e efficien t w h en da ta is sor ted

12.1 SORTING
Suppose we need to arrange a list of names in
lexicographic order, i.e., as they appear in a dictionary.
Examine the sample data that appears in the list names
(Fig. 12.1).

Fig. 12.1 Th e list of n a m es a n d th e cor r espon din g in dex es a t


w h ich th ey a ppea r

We have already seen that the strings can be


compared using relational operators <, <=, >, >=, ==,
and !=. So, we shall frequently use the terms such as
less, less than equal to, greater, greater than equal to,
equal to, not equal to, least, smallest, largest, maximum
in the context of strings.

The attribute or property of data that forms the basis


of sorting is called the key. There are several techniques
of sorting the data such as selection sort, bubble sort,
insertion sort, heap sort, merge sort, and quick sort,
which can be studied for their relative efficiency.
However, in this chapter, we shall discuss only first three
techniques. Without any loss of generality, we discuss
how to sort the data in ascending order. The other case
of sorting in descending order follows similarly. We just
need to change the <, <= operators to >, >= operators,
respectively and vice versa.

key : a ttr ibu te th a t for m s th e ba sis of sor tin g

12.1.1 Selection Sort

It is the simplest but not a very efficient method of


sorting. To begin with, we find the lexicographically
smallest value in the list and interchange this entry in
the list with the first value in the list. Next, we find the
entry with the smallest value out of the remaining
entries, and interchange it with the second value in the
list, and proceed in this manner. If there are n values,
only n-1 values need to be placed in order because when
(n-1) values have been put in order, then the nth value
would automatically be in order. This technique of
sorting is called selection sort.

selection sor t: a sim ple m eth od of sor tin g

selection sor t r equ ir es n-1 pa sses of th e en tir e sequ en ce of


v a lu es

Now, we discuss selection sort technique in the context


of sample data in Fig. 12.1. In the first iteration (i=0),
we find the smallest name in the list. To do this, we
begin with the name at index j=0. When we have
examined only the name at index 0, it is also the
smallest of the names examined so far. We keep track of
the index of the smallest name examined so far using the
variable minIndex. Thus, when j=0, minIndex is
equal to 0 (Fig. 12.2). Next, compare value at index j=1
with the value at index minIndex. Since 'Sanvi' is
smaller than 'Vijaya', minIndex will be set equal to
1. Next, consider the next value in the list at index j=2.
We compare it with the value at index minIndex. Since
'Ruby' is smaller than 'Sanvi', we will set minIndex
to 2. When j=3, 'Zafar' will be compared with
'Ruby' (value at minIndex 2). Since 'Zafar' is
greater than 'Ruby', the value of minIndex will
remain unchanged. When j=4, 'Maya' will be
compared with 'Ruby' (value at minIndex 2), and
minIndex will be set to 4 since 'Maya' is smaller than
'Ruby'. Finally, when j=5, 'Anya' is found to be
smaller than 'Maya' (value at minIndex 4). Thus,
after scanning the entire list, minIndex will have value
5.
Now, we need to exchange this smallest name entry
'Anya' at index 5 (minIndex) with the name at index
i=0. This may be accomplished as follows:

pla cin g ith sm a llest v a lu e a t ith in dex in th e sor ted list

lst[i], lst[minIndex] = lst[minIndex],


lst[i]
Fig. 12.2 Steps in th e selection sor t m eth od for fir st iter a tion (i =
0)

At this stage, we have scanned data from index 0 to


index 5, and swapped the name at index 0, with the
smallest name, found at index 5. This completes the first
iteration, and the modified list is shown in Fig. 12.3.

Fig. 12.3 Modified da ta a t th e en d of fir st iter a tion (i = 0)

Now that the smallest name 'Anya' is at the proper


position (index 0), we only have to sort the names in the
updated list from index 1 to 5. For this purpose, we need
to find the index of the second smallest name in the list
(i.e. the smallest name in the index range 1 to 5). In Fig.
12.4, we illustrate this process.
Fig. 12.4 Steps in th e selection sor t m eth od for secon d iter a tion (i
= 1)

Since name 'Maya' at index 4 is the smallest name


across the indexes ranging from 1 to 5, we swap name
at index 4 with the name at index 1. The modified list at
the end of the second iteration is shown in Fig. 12.5.
Fig. 12.5 Modified da ta a t th e en d of secon d iter a tion (i = 2)

In the third iteration, we have to sort names in the


updated list from index 2 to 5. Since the smallest name
in the remaining unsorted list is at minIndex 2, there
will be no change in the relative position of entries in the
third iteration. At the end of the fourth iteration, names
at indexes 3 and 4 will be swapped, and the modified list
is shown in Fig. 12.6.

if th e ith sm a llest elem en t is a lr ea dy a t its position in a n


iter a tion , th er e w ill be n o ch a n g e in r ela tiv e position of
en tr ies

Fig. 12.6 Modified da ta a t th e en d of fou r th iter a tion (i = 3)

In the fifth iteration, we begin the search for the


smallest name from the index 4. Since the name at index
5 is smaller than the name at index 4, the names at
indexes 4 and 5 will be swapped, and the modified list is
shown in Fig. 12.7.

Now that five names (at indexes 0, …, 4) have been


placed in order, the last name at index 5 is automatically
in order. In this manner, we have been able to sort a list
of names (Fig. 12.7).
Fig. 12.7 Modified da ta a t th e en d of fifth iter a tion (i = 4)

We summarize the sorting procedure discussed above in


Fig. 12.8.

Fig. 12.8 Sor tin g pr ocedu r e for selection sor t


(selectionSort.py)

Using the above ideas, we give the complete script


selectionSort (Fig. 12.9).
Fig. 12.9 Pr og r a m for selection sor t (selectionSort.py)

On execution of the script selectionSort (Fig.


12.9), the user is prompted to enter a list (lst). This list
will be passed as an argument to function
selectionSort, which will sort the list. Since a list
(like other objects) is passed by reference in Python, and
the function only modifies the components of the list,
there is no need to return the sorted list. Sample runs of
the script selectionSort are shown below:

Enter a list: ['Vijaya', 'Sanvi', 'Ruby',


'Zafar', 'Maya', 'Anya']

Sorted List

['Anya', 'Maya', 'Ruby', 'Sanvi',


'Vijaya', 'Zafar']

Enter a list: [1001, 1006, 1002, 1005,


1004, 1003]

Sorted List

[1001, 1002, 1003, 1004, 1005, 1006]

th e fu n ction selectionSort w or ks equ a lly w ell on n u m er ic


a n d str in g da ta

12.1.2 Bubble Sort

Just like selection sort, in this method also, the data is


sorted by making several passes (iterations) through the
list. In each pass, we compare values in adjacent
positions and interchange them, if they are out of order.
To begin with, we have a list of n values. The nth value
and (n-1)th value are compared and interchanged if the
nth value is smaller than (n-1)th value, then (n-1)th
value and (n-2)th value are compared and interchanged
if found out of order, and so on. Observe that in the first
pass, the smallest value will move to the front of the list
at index 0; on subsequent passes, it will be ignored. Thus,
in the second iteration, we need to sort the remaining list
of n-1 values excluding the value at index 0. After n-1
iterations, the list will be completely sorted, and the
algorithm will halt. We use the list in Fig. 12.10 to show
the working of the bubble sort procedure:

bu bble sor t: com pa r e key s a t a dja cen t position s


Fig. 12.10 List of n a m es a n d th e cor r espon din g in dex es a t w h ich
th ey a ppea r

In the first iteration of bubble sort, we start at index 5


and keep on comparing adjacent locations in order to
move the smallest name to the beginning of the list.
Steps performed in the first iteration are shown below in
Fig. 12.11:
Fig. 12.11 Steps in th e fir st iter a tion of bu bble sor t (i = 0). Th e
cu r v ed dou ble-h ea ded a r r ow s m a r k th e list elem en ts bein g
sw a pped
The modified list, thus modified, at the end of the first
iteration is shown in Fig. 12.12:

Fig. 12.12 Modified list a t th e en d of fir st iter a tion (i = 0)

Note that at the end of the first iteration, the smallest


name moves to the first position (index 0). Similarly in
the second iteration, above procedure will be performed
on names in the index range 1 to 5 and at the end of it,
the second smallest name will move to index 1 as shown
in Fig. 12.13.
Fig. 12.13 Steps in th e secon d iter a tion of bu bble sor t. Th e cu r v ed
dou ble-h ea ded a r r ow s m a r k th e list elem en ts bein g sw a pped

The modified list after the second iteration is shown in


Fig. 12.14.
Fig. 12.14 Modified list a t th e en d of secon d iter a tion (i=1)

In the third iteration, we consider the names in the index


range 2 to 5 and the modified list at the end of the third
iteration is shown in Fig. 12.15.

Fig. 12.15 Modified list a t th e en d of th ir d iter a tion (i=2 )

In the fourth iteration, we consider the names in the


index range 3 to 5 and the modified list at the end of the
fourth iteration is shown in Fig. 12.16.

Fig. 12.16 Modified list a t th e en d of fou r th iter a tion (i=3)

In the fifth iteration, we consider the names in the index


range 4 to 5. As the names at indexes 4 to 5 are already
in sorted order, the list at the end of the fifth iteration
will be the same as the list at the end of the fourth
iteration (Fig. 12.16). Thus, at the end of the fifth
iteration, all the six names have been arranged in order.
Based on the preceding discussion, we present the
complete script for the bubble sort method (Fig. 12.17).

324
Fig. 12.17 Pr og r a m for bu bble sor t (bubbleSort.py)

Sample runs of the script bubbleSort are shown as


follows:

Enter the list: ['Vijaya', 'Sanvi',


'Ruby', 'Zafar', 'Maya', 'Anya']

Sorted List

['Anya', 'Maya', 'Ruby', 'Sanvi',


'Vijaya', 'Zafar']

Enter the list: [1001, 1006, 1002, 1005,


1004, 1003]

Sorted List

[1001, 1002, 1003, 1004, 1005, 1006]

ex a m ples of in pu t lists a n d th e cor r espon din g sor ted ou tpu t


lists

Next, let us apply bubble sort algorithm on the list in


Fig. 12.18. The modified list at the end of the first,
second, and third iteration is shown in Figs. 12.19, 12.20,
and 12.21, respectively.
Fig. 12.18 List of n a m es a n d th e cor r espon din g in dex es a t w h ich
th ey a ppea r

Fig. 12.19 Modified list a t th e en d of fir st iter a tion (i = 0)

Fig. 12.20 Modified list a t th e en d of secon d iter a tion (i = 1)

325

Fig. 12.21 Modified list a t th e en d of th ir d iter a tion (i = 2)

Note that when we apply bubble sort on the list in Fig.


12.18, the list gets sorted at the end of the second
iteration and no data is swapped in the third iteration.
Indeed, if no data is swapped in an iteration, we
conclude that the list has already been sorted. As such,
the control should break out of the loop, instead of
unnecessarily proceeding with the remaining iterations.
Based on this observation, we modify the script
bubbleSort (see Fig. 12.22).
if n o sw a ppin g ta kes pla ce in a n iter a tion in bu bble sor t, w e
con clu de th a t th e list is n ow sor ted, a n d skip r est of th e
iter a tion s
Fig. 12.22 Pr og r a m for bu bble sor t (bubbleSort1.py)

12.1.3 Insertion Sort

In insertion sort, the list is logically divided into two


parts. Whereas the left part is the sorted part, the right
part is the unsorted part comprising the elements yet to
be arranged in sorted order. In each iteration, we
increase the length of the sorted part by one in the
following manner: insert the first element from the
unsorted part into the sorted part at the correct position.
To find the correct position of the value to be inserted,
we compare it with values in the sorted part (starting
from the rightmost value in the sorted part) and shift
each value to the right by one position, until the correct
position is found. For example, examine the list in Fig.
12.23.

m a in ta in tw o div ision s of th e list: sor ted pa r t a n d u n sor ted


pa r t.

in ea ch iter a tion , in ser t fir st v a lu e fr om th e u n sor ted pa r t


in to th e sor ted pa r t

Fig. 12.23 List of n a m es a n d th e cor r espon din g in dex es


In this example, the left sorted part (grey portion)
comprises elements at indices 0, 1, 2, 3, and the right
unsorted part (white portion) comprises the elements at
indices 4 and 5. As of now, the lengths of the sorted and
unsorted parts are 4 and 2, respectively. So, at the end of
the next iteration, lengths of sorted and unsorted parts
will be 5 and 1, respectively. Our task in this iteration is
to insert the element lst[4] at the correct position. As
'Maya' < 'Zafar', we shift 'Zafar' one position
right, but before we do so, we must save 'Maya' in a
temporary variable, say, temp. The modified list is
shown in Fig. 12.24.

temp = 'Maya'

Fig. 12.24 List of n a m es a n d th e cor r espon din g in dex es

Next, we compare the value of the variable temp, i.e.


'Maya' with lst[2], i.e., 'Vijaya'. As 'Maya' <
'Vijaya', we shift 'Vijaya' one position right. The
modified list is shown in Fig. 12.25.
Fig. 12.25 List of n a m es a n d th e cor r espon din g in dex es

Next, we compare the value of the variable temp, i.e.


'Maya' with lst[1], i.e. 'Sanvi'. As 'Maya' <
'Sanvi', we shift 'Sanvi' one position right. The
modified list is shown in Fig. 12.26.

Fig. 12.26 List of n a m es a n d th e cor r espon din g in dex es

Next, we compare, 'Maya' with lst[0], i.e. 'Anya'.


As 'Maya' > 'Anya', we do not need to shift 'Anya',
and 'Maya' can now be placed at index 1. The modified
list is shown in Fig. 12.27.

Fig. 12.27 List of n a m es a n d th e cor r espon din g in dex es

Recall that the element 'Maya' to be inserted in the


list sorted up to index 3 was at index 4. The following
code achieves the desired effect of shifting 'Maya' to its
correct position at index 1:

i = 4

temp = lst[i]

j = i - 1
while j >= 0 and lst[j] > temp:

lst[j + 1] = lst[j]

j = j-1

lst[j + 1] = temp

code to in ser t v a lu e a t in dex 4 a t cor r ect position in th e list


(sor ted u p to in dex 3 )

Once again, we use the following list to illustrate


insertion sort (Fig. 12.28):

Fig. 12.28 Th e list of n a m es a n d th e cor r espon din g in dex es

in itia lly , th e sor ted list com pr ise v a lu e a t in dex 0, follow ed


by r em a in in g in dex es to be pa r t of u n sor ted list

As shown in Fig. 12.29, in the first iteration, 'Vijaya'


is shifted towards the right by one position and 'Sanvi'
(that appeared at index1 earlier) is inserted at index 0.
Thus, 'Sanvi' now belongs to the sorted part of the list.
Similarly, in the second iteration, names at indices 0 and
1 are shifted towards the right and the name 'Anya' is
placed at index 0 in the left part. This process is
continued till the fifth iteration when the right partition
becomes empty and the left partition contains the sorted
list. On the basis of the foregoing discussion, we present
the complete program for insertion sort (Fig. 12.30).
Fig. 12.29 Steps in in ser tion sor t on th e list in Fig . 1 2 .2 8
Fig. 12.30 Pr og r a m for in ser tion sor t (insertionSort.py)

Sample runs of the script insertionSort are shown


below:

Enter a list: ['Vijaya', 'Sanvi', 'Ruby',


'Zafar', 'Maya', 'Anya']
Sorted List

['Anya', 'Maya', 'Ruby', 'Sanvi',


'Vijaya', 'Zafar']

Enter a list: [1001, 1006, 1002, 1005,


1004, 1003]

Sorted List

[1001, 1002, 1003, 1004, 1005, 1006]

ex a m ples of in pu t lists a n d th e cor r espon din g sor ted ou tpu t


lists

12.2 SEARCHING

In this section, we shall discuss how to find out whether


a data value appears in a list. For example, given a list of
names of students in a class, we wish to find whether a
particular name appears in the list. In the following
sections, we discuss two techniques for searching a value
in a list, namely, linear search, and binary search. While
the former technique scans the list from the beginning
till the data value is found or the list is exhausted, the
latter technique is considerably more efficient in terms of
time complexity but works for sorted lists only.

sea r ch in g for a v a lu e in a list

12.2.1 Linear Search

To search for an element in a list, we scan the list from


the beginning till the required data value is found or the
list is exhausted. This searching technique is known as
linear search as the search process is sequential. For
example, given a list of names of students, to find
whether a particular name appears in the list, we
examine each name in the list starting from the first
position (i.e., index 0). When the target value is found in
the list, we terminate the search. However, if the entire
list is exhausted and the target value is not found, we
conclude that the value being searched is not there in the
list. For example, examine the following list of names of
students (Fig. 12.31):

lin ea r sea r ch : sequ en tia l sea r ch th a t sca n s th e list fr om th e


beg in n in g till th e r equ ir ed da ta v a lu e is fou n d or th e list is
ex h a u sted

Fig. 12.31 List of n a m es of stu den ts

To search for the name 'Shubham' in the list, we look


for this value starting at index 0. After iterating over
values at the indexes 0, 1, 2, and 3, when the value at
index 4 is compared to the target value 'Shubham', we
find that it matches the target value, and the search
terminates successfully. However, if we were searching
for 'Sarthak', the entire list is exhausted without
finding a match. So, we conclude that the name
'Sarthak' is not in the list. The complete script for
linear search appears in Fig. 12.32.
Fig. 12.32 Pr og r a m for lin ea r sea r ch (linearSearch.py)

On executing the script in Fig. 12.32, Python prompts


the user for the list and the value to be searched and will
display the appropriate message indicating presence or
absence of the value, for example:

Enter a list: ['Reena', 'Stuti', 'Monika',


'Deepika']

Enter the value to be searched: 'Monika'

Monika found at index 2

Enter a list: ['Shilpi', 'Ankita',


'Shweta', 'Gaurav', 'Shubham', 'Rashmi']

Enter the value to be searched: 'Sarthak'

Sarthak found at index None

Enter a list: [1001, 1006, 1002, 1005,


1004, 1003]

Enter the value to be searched: 1005


1005 found at index 3

Enter a list: [1001, 1006, 1002, 1005,


1004, 1003]

Enter the value to be searched: 1008

1008 found at index None

ex a m ples of lin ea r sea r ch

12.2.2 Binary Search

If the list to be searched is already sorted, we can use a


faster method, called binary search. For searching a
name, in a list of names that has been sorted in
ascending order, we proceed as follows:

bin a r y sea r ch w or ks on a sor ted sequ en ce of v a lu es

First, we examine the middle name of the list, if it


matches the name that we are looking for, we stop. If
we do not find the name at the middle position, we will
only have to search on the left or right side of the middle
name depending on whether the name at the middle
position is greater or smaller than the name we are
looking for. Based on this idea, we present the
binarySearch function in Fig. 12.33.

cen tr a l idea in bin a r y sea r ch

332
Fig. 12.33 Fu n ction for bin a r y sea r ch

In Fig. 12.34, we present complete script


(binarySearch) for binary search.
Fig. 12.34 Pr og r a m for bin a r y sea r ch (binarySearch.py)

On execution of the script binarySearch, the user is


prompted to enter a sorted list (line 40). In line 41, we
invoke the function isSorted to find out whether the
list entered by the user is sorted. If the list entered by the
user happens to be sorted, the user is asked for the value
to be searched and the control is transferred to the
function binarySearch. In line 10, values of the
variables low and high are set to the first and the last
indexes of the list, respectively. The value of mid is
computed by taking an average of low and high in line
12. If we find lst[mid] == searchValue in line 13,
the search terminates, else we reduce the range to be
searched by modifying either low or high depending on
the searchValue. But, we have yet to consider the case
when the required value is not in the list. As the search
always takes place between indices low and high, the
search should not proceed if low > high. This fact is
used to terminate the search loop in the function
binarySearch.

stoppin g cr iter ia for bin a r y sea r ch : low > high

On executing the script binarySearch (Fig. 12.34),


Python will prompt the user to enter list and the value to
be searched and will display the appropriate message
indicating presence or absence of value, for instance:

Enter a sorted list (ascending order):


['Reena', 'Stuti', 'Monika', 'Deepika']

Given list is not sorted

Enter a sorted list (ascending order):


[1001, 1002, 1003, 1004, 1005]

Enter the value to be searched: 1004

1004 found at index 3

Enter a sorted list (ascending order):


['Ankit', 'Gaurav', 'Nitin', 'Rashmi',
'Shilpi', 'Shubham', 'Shweta']

Enter the value to be searched: 'Gaurav'

Gaurav found at index 1


Enter a sorted list (ascending order):
['Gaurav', 'Nitin', 'Rashmi', 'Shilpi',
'Shubham', 'Shweta']

Enter the value to be searched: 'Shubham'

Shubham found at index 4

ex a m ples of bin a r y sea r ch

Now we study the last example in detail (Fig. 12.35).


In this example, we used binary search to look for the
name 'Shubham' in the list ['Gaurav', 'Nitin',
'Rashmi', 'Shilpi', 'Shubham', 'Shweta']:

Fig. 12.35 List of n a m es of stu den ts

In the first iteration, the variables low and high are


initialized to 0 to 5, respectively. When the name to be
searched is compared against the name at index mid
(=2), the name 'Shubham' is found to be greater than
'Rashmi'. Now the value of low is set to 3 so that the
search can be continued in the index range 3 to 5. In the
second iteration, taking 3 as low and 5 as high, the
name 'Shubham' is compared with the name at index
mid (=4). Since the name 'Shubham' is found at index
4, search terminates by exiting the loop. The search
process has been illustrated in Fig. 12.36.
Fig. 12.36 Steps for bin a r y sea r ch for da ta g iv en in Fig . 1 2 .3 5

Note that binary search on the above-sorted list took


only two steps. However, if the same sorted list were to
be searched for the name 'Shubham' using linear
search, it would have taken five steps. To see how fast
binary search works, we only have to observe that every
time search fails, the search interval is reduced to half.
Thus, in the worst case, we would require no more than
(log2 N) + 1 steps.

bin a r y sea r ch is m or e efficien t th a n lin ea r sea r ch

n u m ber of steps ta ken by bin a r y sea r ch : (log2 N) + 1

!
12.3 A CASE STUDY

In this section, we will discuss how to prepare a merit list


of students who took an examination. For each student,
we store information about roll number, name, and
marks obtained. Sample data is shown in Table 12.1.
deta ils a bou t stu den t da ta

T a bl e 12.1 Sa m ple da ta for stu den t in for m a tion

We define a class Student having a data attribute


rollNo, name, and marks (Fig. 12.37). Note that the
class Student has two methods – constructor
__init__ used for initializing data members of the
class and the special method __str__ for constructing
the string representation of an object of class Student,
to be used later for printing.

Let us introduce another class Section (Fig. 12.38)


having data attribute records that store information
about students in the form of a list of Student objects.
In this class, we define various methods for operations
on the list records. As we have not yet discussed the
implementation of these methods, we use pass
statement as the body of the function.
Fig. 12.37 Cla ss Stu den t (student.py)

337
Fig. 12.38 Cla ss Section (section.py)

We will use an object of class Section, to store the


sample data in Table 12.1 as list records (Fig. 12.39):

As first step, we develop a function textToObject


(Fig. 12.40) that takes the comma-separated student
data as input from a text file (source), converts it to
structured data (objects of class Student), and writes to
another file (destination). We also develop another
function objectToText that takes a file (source) of
objects of class Student as input and outputs the
comma-separated student data as a text file
(destination).
con v er tin g com m a sepa r a ted stu den t da ta to objects of cla ss
Student

con v er tin g objects of cla ss Student to com m a -sepa r a ted


stu den t da ta .

Fig. 12.39 Mem or y r epr esen ta tion r ecor ds of object section


339

Fig. 12.40 Rea din g a n d w r itin g str u ctu r ed da ta to a n d fr om a file


(im pEx pObject.py )

12.3.1 Operations for Class Section


The data about students is stored in an object of the class
Section as a list records of the objects of the class
Student. On this list, we will perform the list
manipulation operations: insert a student in a section,
search for a student in a section, sort a section, delete a
student, and list all students in a section. Next, we
describe various methods for performing these
operations and finally present a complete script for
processing student data.

list m a n ipu la tion oper a tion s on th e list of objects of th e cla ss


Student

1 . __init__()
Th e __init__ m eth od (Fig . 1 2 .4 1 ) in itia lizes a n
in sta n ce of th e Section cla ss by in itia lizin g its list
records (of th e Student cla ss) a s a n em pty list.

i ni t i al i zi ng an i nst anc e of c l ass Section

F ig . 12.41 Met h od __init__

2 . readList(self, source)
Th e readList m eth od (Fig . 1 2 .4 2 ) a ccepts th e n a m e of
th e source file con ta in in g Student objects a s a n in pu t
pa r a m eter a n d a ppen ds th e Student objects r ea d fr om
th e source file to th e list records of th e Section
in sta n ce a t h a n d.

r eadi ng t h e Student ob jec t s f or l i st records f r om source f i l e


F ig . 12.42 Met h od readList

3 . writeList(self, destination)
Th e writeList m eth od (Fig . 1 2 .4 3 ) a ccepts th e n a m e
of th e destination file a s a n in pu t pa r a m eter a n d
w r ites to it on e by on e th e Student objects in th e list
records of th e Section in sta n ce a t h a n d.

w r i t i ng t h e Student ob jec t s i n l i st records t o destination f i l e

F ig . 12.43 Met h od writeList

4 . insertEnd(self, rollNo, name, marks)


For in ser tin g in for m a tion a bou t a n ew stu den t, w e
defin e th e m eth od insertEnd (Fig . 1 2 .4 4 ). Th e m eth od
insertEnd a ccepts rollNo, name, a n d marks a s
pa r a m eter s, cr ea tes a n object student of ty pe Student,
a n d in ser ts it in th e list records. In th is m eth od, w e
fir st ch eck w h eth er th e list records a lr ea dy h a s a n
object w ith th e sa m e r oll n u m ber a s th e object bein g
in ser ted. If so, a n er r or m essa g e in dica tin g du plica te
r oll n u m ber is r etu r n ed, oth er w ise th e r ecor d is
a ppen ded to th e list records a n d a m essa g e in dica tin g
su ccessfu l r ecor d in ser tion is r etu r n ed.
i nser t i ng Student i nst anc e at t h e end of l i st records

F ig . 12.44 Met h od insertEnd

5 . isSorted(self)
If th e list records is a r r a n g ed in a scen din g or der of th e
v a lu es of th e key rollNo, th e m eth od isSorted (Fig .
1 2 .4 5 ) r etu r n s True, oth er w ise it r etu r n s False.

c h ec k i ng w h et h er t h e St u dent ob jec t s ar e sor t ed w i t h r esp ec t t o


r ol l nu mb er s i n l i st r ec or ds

F ig . 12.45 Met h od isSorted

6 . binarySearch(self, rollNo)
Th e binarySearch m eth od (Fig . 1 2 .4 6 ) is a pplica ble if
th e list records is a lr ea dy sor ted. It a ccepts rollNo a s
a n in pu t pa r a m eter . Th e Student objects a r e sea r ch ed
for th e g iv en rollNo in th e list records u sin g th e
bin a r y sea r ch pr ocedu r e descr ibed in th e pr ev iou s
section . If a Student object w ith th e g iv en rollNo is
fou n d in th e list records, th e m eth od r etu r n s th e in dex
of th e m a tch ed object, oth er w ise it r etu r n s None.

sear c h i ng f or t h e r ol l nu mb er of a st u dent i n sor t ed l i st records


F ig . 12.46 Met h od binarySearch

7 . linearSearch(self, rollNo)
Th e linearSearch m eth od (Fig . 1 2 .4 7 ) is u sed if th e
list records is n ot sor ted. It a ccepts rollNo a s a n in pu t
pa r a m eter . Th e Student objects a r e sea r ch ed
sequ en tia lly in th e list records for th e g iv en rollNo in
th e list records u sin g th e lin ea r sea r ch pr ocedu r e
descr ibed in th e pr ev iou s section . If a Student object
w ith th e g iv en rollNo is fou n d in th e list records, th e
m eth od r etu r n s th e in dex of th e m a tch ed object,
oth er w ise it r etu r n s None.

sear c h i ng f or t h e r ol l nu mb er of a st u dent i n t h e u nsor t ed l i st


r ec or ds
F ig . 12.47 Met h od linearSearch

8 . insertionSort(self)
In th e pr ev iou s section , w e discu ssed th r ee tech n iqu es
of sor tin g a list of objects. Now , w e m a ke u se of th e
in ser tion sor t tech n iqu e (Fig . 1 2 .4 8 ) to sor t th e list
records of Student objects, ba sed on rollNo.

sor t i ng l i st records of Student ob jec t s b ased on r ol l nu mb er u si ng


i nser t i on sor t

F ig . 12.48 Met h od insertionSort

9 . delete(self, rollNo)
Th e delete m eth od (Fig . 1 2 .4 9 ) a ccepts rollNo a s th e
in pu t pa r a m eter . It sea r ch es th e en tir e list records
sequ en tia lly for th e Student object h a v in g th e g iv en
rollNo. If th e desir ed Student object is fou n d, it is
r em ov ed fr om th e list records a n d th e m eth od r etu r n s
th e m essa g e 'Record deleted successfully' to
in dica te su ccessfu l ter m in a tion . How ev er , if th e
desir ed Student object h a v in g th e g iv en rollNo is n ot
fou n d, th e m eth od r etu r n s th e m essa g e 'Record not
found'.
del et i ng a Student i nst anc e w i t h t h e gi v en r ol l nu mb er f r om t h e
l i st records

F ig . 12.49 Met h od delete

1 0. sortedInsert(self, rollNo, name, marks)


Th e m eth od a ccepts a s in pu t pa r a m eter s rollNo,
name, a n d marks of th e stu den t for w h om w e w a n t to
in ser t a Student object in th e list records. Th e m eth od
a ssu m es th a t th e list record is a lr ea dy sor ted w ith
r espect to r oll n u m ber s. If th e list is a n em pty list, th e
m eth od a ppen ds th e stu den t in sta n ce to th e em pty list.
Oth er w ise, it fin ds a n a ppr opr ia te in dex a t w h ich
r ecor d is to be in ser ted a n d in ser ts th e r ecor d a t th a t
pla ce. Th e m eth od r ejects a r ecor d if th e r oll n u m ber is
du plica ted. In Fig . 1 2 .5 0, w e defin e th is m eth od.

i nser t i ng Student i nst anc e at ap p r op r i at e p l ac e i n t h e sor t ed l i st


records
F ig . 12.50 Met h od sortedInsert

1 1 . __str__(self)
Th e m eth od __str__ (Fig . 1 2 .5 1 ) of cla ss Section
con str u cts th e str in g r epr esen ta tion for a n in sta n ce of
th e cla ss. It tr a v er ses th e list records in v okin g
__str__ fu n ction for ea ch Student object.

r et u r ni ng st r i ng r ep r esent at i on of ob jec t of t y p e Section


F ig . 12.51 Met h od __str__

Complete Script (Fig. 12.52)

Now we are ready to present a complete script for


processing student data. Before doing any list processing,
we need to read the raw data from a text file and convert
it to a file of objects. Similarly, after the processing, we
need to write the structured data back to a text file. The
script works as follows:

1 . In v oke th e fu n ction textToObject (lin e 1 4 ) fr om th e


m odu le impExpObject for con v er tin g th e stu den t
in for m a tion in a tex t file to a file of Student objects. In
fu tu r e, w e m a y u se th is file of Student objects in stea d
of th e tex t file. Th e da ta in th e tex t file a ppea r s in th e
follow in g for m a t:
1 ,A m it,3 6
5 ,Kr iti,5 0
4 ,A lok,5 0
2 ,Um a n g ,2 7
3 ,Sh w eta ,8 5
w or k i ng of t h e sc r i p t f or p r oc essi ng st u dent dat a
2 . Cr ea te a n in sta n ce section of th e Section cla ss a n d
in itia lize its list records of Student in sta n ces fr om th e
file cr ea ted in step 1 (lin es 1 6 –1 8 ). Th is list of r ecor ds is
u n sor ted a s of n ow .
3 . Sea r ch for a stu den t in th e section u sin g lin ea r sea r ch
(lin es 2 0–2 6 ).
4 . Sor t th e Student objects in th e section ba sed on
rollNo a n d w r ite in a file. In fu tu r e, w e m a y u se th e
sor ted file (lin es 2 8 –3 0).
5 . Rea d th e sor ted file cr ea ted in step 4 to cr ea te a n
in sta n ce section of th e Section cla ss a n d u se bin a r y
sea r ch to look for a rollNo (lin es 3 2 –4 2 ).
6 . Rea d th e sor ted file cr ea ted in step 4 to cr ea te a tex t file
for v iew in g it u sin g a tex t editor (lin e 4 4 ).
Fig. 12.52 Pr og r a m for pr ocessin g stu den t da ta
(listManipulation.py)

Next, we show the working of the above script (Fig.


12.52) with the help of an example:
Enter source file name: student.txt

Enter destination file name:


studentObjects.txt

Roll No: 1, Name: Amit, Marks: 36.0

Roll No: 5, Name: Kriti, Marks: 50.0

Roll No: 4, Name: Alok, Marks: 50.0

Roll No: 2, Name: Umang, Marks: 27.0

Roll No: 3, Name: Shweta, Marks: 85.0

Enter RollNo for record to be searched 3

3 found at index 4

Roll No: 1, Name: Amit, Marks: 36.0

Roll No: 2, Name: Umang, Marks: 27.0

Roll No: 3, Name: Shweta, Marks: 85.0

Roll No: 4, Name: Alok, Marks: 50.0

Roll No: 5, Name: Kriti, Marks: 50.0

Enter RollNo for record to be searched 6

6 not found

Suppose we wish to sort the student data on the basis


of the particular key attribute. For this purpose, we
develop method insertionSort (Fig. 12.53) that takes
the choice as an input parameter and sorts the student
data based on the value of attributes rollNo, name, or
marks depending upon 1, 2, or 3 as the user choice
respectively. This method uses the method key to
retrieve the value of the key attribute based on the user
choice. Recall that the method insertionSort is a
member of class Section. Also, the method key should
be included as a member of the class Student.
Fig. 12.53 Meth ods insertionSort a n d key

12.4 MORE ON SORTING

12.4.1 Merge Sort

The merge sort algorithm is based on the divide and


conquer strategy that takes a list as an input and keeps
on dividing it into two lists until a list of length 1 is
obtained. Notice that when a list of even length is divided
into two lists, each of them will be of the same size, but
in case the original list is of odd length, the two lists
would differ in size by one. It conquers the sorting
problem by merging pairs of length one lists to obtain
lists of length two, merging pairs of lists of length two to
obtain lists of length four, and so on until the final sorted
list of the size of the original list is obtained. It is
important to point out that the lists being merged may
not always be of identical size. It would become clear
when we show the working of the algorithm with the
help of an example.

m er g e sor t is ba sed on div ide a n d con qu er str a teg y

We have provided a function mergeSort (Fig. 12.54)


that takes a list as an input parameter and returns the
sorted list. Note that if the length of a list is 0 or 1, the
function mergeSort returns it as it is (the trivial case as
the list is already sorted). Otherwise, it divides the list
into two parts. When each of these two parts is sorted, it
invokes the function merge that takes two sorted lists
(lst1 and lst2) and merges them into a new single
sorted list sortedLst. The function merge works by
comparing front elements of the two sorted lists and
removing the one with the smaller value, which is placed
in sortedLst. When any of the two lists becomes
empty, the values in the other list are appended to the list
sortedLst.
Fig. 12.54 Pr og r a m for m er g e sor t (mergeSort.py)

The splitting and merging process of merge sort on the


list [15, 12, 14, 17, 13, 11, 12, 16, 14] is
illustrated using Figs. 12.55 and 12.56.
Fig. 12.55 Div idin g th e list u n til sin g leton lists a r e obta in ed

12.4.2 Quick Sort

As compared to merge sort technique, discussed in


previous section, quick sort is more efficient in terms of
the space requirement as it does not need extra space for
sorting. It works by choosing a value called pivot
element, using which we split the list to be sorted in two
parts: the first part comprising elements smaller than or
equal to the pivot element and the second part
comprising elements greater than the pivot element. The
two parts are further sorted using quick sort in a similar
manner until the partitions of length 1 or 0 are left.
Although there are different methods of choosing the
pivot element, for the sake of simplicity, we choose the
last element of the list/partition under consideration as
the pivot element.

qu ick sor t u ses a piv ot elem en t for pa r tition in g th e list


a r ou n d it

We have provided a function quickSort (Fig. 12.57)


that takes a list as an input parameter along with start
and end indexes. If the length of the list is greater than 2,
the function quickSort invokes the function
partition that divides the list to be sorted (list lst
from index start to end) into two parts around the
pivot element, followed by call to function quicksort
for each of the two parts. The function partition
maintains two regions: start to i that keeps track of
elements smaller than or equal to pivot element and the
region from i+1 to j-1 (highlighted region in Fig.
12.58) that keeps track of elements greater than the pivot
element. The function works by comparing every
element lst[j] in the sub-list under consideration with
the pivot element, and if it is less than or equal to the
pivot element, value of index i (initialized to start -
1) is incremented and the element at the incremented
index i is swapped with the element at index j. Thus, we
ensure that elements smaller than or equal to the pivot
element are in the region start to i. Finally, in line 15,
we swap the elements lst[i+1] and lst[end] so that
on the left of the pivot element lie elements smaller or
equal to it and on its right lie the elements larger than it.
For example, examine the execution of function
partition for the list [12, 18, 17, 11, 13, 14]
(Fig. 12.58). Figure 12.58 illustrates how the function
partition works for the first call to the function.
Fig. 12.56 Mer g in g th e sor ted lists to obta in a sin g le sor ted list
Fig. 12.57 Pr og r a m for qu ick sor t (quickSort.py)
Fig. 12.58 Pr og r a m for qu ick sor t (quickSort.py)

SUMMARY
1 . Th e pr ocess of a r r a n g in g da ta in a scen din g /descen din g
or der is ca lled sor tin g . Th e a ttr ibu te th a t for m s th e
ba sis of sor tin g is ca lled key .
2 . In selection sor t, to beg in w ith , w e fin d th e sm a llest
v a lu e in th e list, a n d in ter ch a n g e th is en tr y w ith th e
fir st en tr y in th e list. Nex t, w e fin d th e en tr y w ith th e
sm a llest v a lu e ou t of th e r em a in in g en tr ies, a n d
in ter ch a n g e it w ith th e secon d v a lu e in th e list, a n d
pr oceed in th is m a n n er . If th er e a r e n v a lu es, on ly (n −
1 ) v a lu es n eed to be pla ced in or der beca u se w h en (n −
1 ) v a lu es h a v e been pu t in th e pr oper pla ce, th en th e
nth v a lu e w ou ld a u tom a tica lly be in or der .
3 . In bu bble sor t, in ea ch pa ss, w e com pa r e v a lu es in
a dja cen t position s a n d in ter ch a n g e th em , if th ey a r e
ou t of or der . Su ppose w e h a v e a list of n v a lu es. To
beg in w ith , th e nth a n d (n − 1 )th v a lu es a r e com pa r ed
a n d in ter ch a n g ed if fou n d ou t of or der ; th en (n − 1 )th
a n d (n − 2 )th v a lu es a r e com pa r ed a n d in ter ch a n g ed if
fou n d ou t of or der , a n d so on . Obser v e th a t in th e fir st
pa ss th e sm a llest v a lu e w ill m ov e to th e fr on t of th e list
a t in dex 0; on su bsequ en t pa sses, it w ill be ig n or ed.
A fter n − 1 iter a tion s, th e list w ill be com pletely sor ted
a n d th e a lg or ith m w ill h a lt.
4 . In in ser tion sor t, th e list is log ica lly div ided in to tw o
pa r ts. Wh er ea s th e left pa r t is th e sor ted pa r t, th e r ig h t
pa r t is u n sor ted pa r t com pr isin g th e elem en ts y et to be
a r r a n g ed in sor ted or der . In ea ch iter a tion , w e in cr ea se
th e len g th of th e sor ted pa r t by on e in th e follow in g
m a n n er : in ser t th e fir st elem en t fr om th e u n sor ted
pa r t in th e sor ted pa r t a t th e cor r ecft position . To fin d
th e cor r ect position of th e v a lu e to be in ser ted, w e
com pa r e it w ith v a lu es in sor ted pa r t a n d sh ift ea ch
v a lu e to th e r ig h t by on e position , u n til th e cor r ect
position is fou n d.
5 . Sea r ch in g is th e ta sk of fin din g w h eth er a da ta v a lu e
a ppea r s in a list.
6 . In lin ea r sea r ch of a da ta v a lu e in a list, w e sca n th e list
fr om th e beg in n in g till th e da ta v a lu e is fou n d, or th e
list is ex h a u sted. Th is tech n iqu e is kn ow n a s lin ea r
sea r ch a s th e or der of sea r ch is lin ea r or sequ en tia l in
n a tu r e.
7 . Bin a r y sea r ch is u sed in ca se th e list to be sea r ch ed is
a lr ea dy sor ted. For sea r ch in g a da ta v a lu e in th is list,
w e pr oceed a s follow s: fir st, w e ex a m in e th e m iddle
elem en t of th e list, if it is equ a l to th e da ta v a lu e th a t
w e a r e lookin g for , w e w ill stop. If w e do n ot fin d th e
elem en t a t th e m iddle position , w e w ill on ly h a v e to
sea r ch on th e left or th e r ig h t of th e m iddle elem en t
depen din g on w h eth er th e da ta v a lu e a t th e m iddle
position is g r ea ter or sm a ller th a n th e da ta v a lu e w e
a r e lookin g for .
8 . Mer g e sor t a n d qu ick sor t m eth ods m a ke sig n ifica n tly
less n u m ber of com pa r ison s a s com pa r ed to selection
sor t, in ser tion sor t, a n d bu bble sor t m eth ods.

EXERCISES

1 . Dev elop a pr og r a m to sor t th e em ploy ee da ta on th e


ba sis of pa y of th e em ploy ees u sin g (i) selection sor t, (ii)
bu bble sor t a lg or ith m , a n d (iii) in ser tion sor t. Con sider
a list L con ta in in g objects of cla ss Employee h a v in g
empNum, name, a n d salary.
2 . Wr ite th e r ecu r siv e v er sion of lin ea r sea r ch a n d bin a r y
sea r ch a lg or ith m s, discu ssed in th e tex t.
3 . Rew r ite selection sor t, bu bble sor t a n d in ser tion sor t
fu n ction s u sin g r ecu r sion .
4 . For th e list sh ow n below , sh ow th e v a lu es of th e in dex es
low, high, a n d mid a t ea ch step of th e bin a r y sea r ch
m eth od discu ssed in th e tex t w h en w e a r e sea r ch in g for
th e key :

1. 15
2. 25
3. 55
4. 40
5. 22
5 . Wr ite a fu n ction leftCirculate th a t ta kes a list a s a n
in pu t a n d left cir cu la tes th e v a lu es in th e list so th a t in
th e fin a l list, ea ch v a lu e is left sh ifted by on e position
a n d leftm ost v a lu e in th e or ig in a l list n ow a ppea r s a s
th e r ig h tm ost v a lu e. For ex a m ple, on ex ecu tion of th e
fu n ction on th e list [1, 2, 3, 4, 5] it w ou ld be
tr a n sfor m ed to th e list [2, 3, 4, 5, 1]. Modify th e
fu n ction to in clu de a n u m er ic a r g u m en t to specify th e
n u m ber of position s by w h ich left r ota tion is to be
ca r r ied ou t.
6 . Wr ite a pr og r a m th a t defin es a cla ss Card w h ich ca n be
u sed to in sta n tia te ca r ds w ith a pa r ticu la r r a n k a n d
su it. Cr ea te a n oth er cla ss DeckOfCards for
m a in ta in in g a sor ted list of ca r ds u sin g a m eth od
sortedInsert th a t ta kes a n object of cla ss Card a s a n
in pu t pa r a m eter a n d in ser ts it a t th e su ita ble position
in th e sor ted list.
!
Th is section m a y be skipped w ith ou t loss of con tin u ity .
CHAPTER 13
DATA STRUCTURES I: STACK AND QUEUES

CHAPTER OUTLINE
1 3 .1 Sta cks

1 3 .2 Qu eu es

Oxford dictionary defines data as follows:

Facts and statistics collected together for reference or


analysis:

Th e qu a n tities, ch a r a cter s, or sy m bols on w h ich oper a tion s


a r e per for m ed by a com pu ter , w h ich m a y be stor ed a n d
tr a n sm itted in th e for m of electr ica l sig n a ls a n d r ecor ded on
m a g n etic, optica l, or m ech a n ica l r ecor din g m edia .
Ph ilosoph y : Th in g s kn ow n or a ssu m ed a s fa cts, m a kin g th e
ba sis of r ea son in g or ca lcu la tion .

diction a r y m ea n in g of da ta

In this chapter, we will be concerned with the first


meaning of the term data. Further, Oxford Dictionary
defines structure as an arrangement of and relations
between the parts of something, a building or other
object constructed from several parts. The terms such as
construction, form, formation, shape, combination,
conformation, pattern, and mold are used as synonyms
for structure. Thus, the phrase data structure refers to
construction, formation, shape, combination,
conformation, pattern, mold, or structure made from
simple forms of data. In this chapter, we shall study the
data structures stacks and queues, and methods to
implement them using lists in Python.
diction a r y m ea n in g of str u ctu r e

da ta str u ctu r es

13.1 STACKS

In a stack, objects are stored one over the other, and


these objects leave in the reverse order of their arrival.
For example, in a restaurant, the waiter puts the used
plate one above the other. The cleaner takes a plate from
the top, cleans it, and puts it onto another stack, from
which the plate placed on top can be picked up for
eating. Note that the used plate that is placed last is
cleaned first and the plate that is cleaned last is taken
first for eating. This is called Last In First Out (LIFO)
arrangement. We observe another example of Last In
First Out arrangement in the library, where the readers
stack used books one above other. Subsequently, a staff
member in the library picks up books one by one from
the top of the stack and places them in appropriate
shelves.

sta ck: objects lea v e in th e r ev er se or der of th eir a r r iv a l

sta ck: La st In Fir st Ou t (LIFO) a r r a n g em en t

Based on the above discussion, a stack is characterized


by the following operations (amongst others, to be
discussed shortly):

pu sh : Pla ce (pu sh ) a n ew elem en t on top of th e sta ck. Th e


pu sh oper a tion is a lso ca lled in ser tion of a n elem en t in a
sta ck.
pop: Rem ov e (pop) top elem en t fr om th e sta ck. Th e pop
oper a tion is a lso ca lled deletion of a n elem en t fr om a sta ck.

pu sh : to pla ce n ew elem en t on top of th e sta ck


pop: to r em ov e top elem en t fr om th e sta ck

The easiest way to represent a stack is using a list. As


stack operations push and pop relate to the top element
of the stack, we need to keep track of the top element of
the stack. Remember, it is only the top element which is
accessible. At any point in time, insertion or removal of
an object takes place at the top of the stack. For example,
beginning with an empty stack, we perform the
following operations in a sequence.

in ser tion a n d deletion of elem en ts ta ke pla ce fr om top of th e


sta ck

1. pu sh 5
2. pu sh 10
3. pop
4. pu sh 20
5. pu sh 25
6. pu sh 30
7. pop
8. pop
9. pop
1 0. pop
11. pop

In Fig. 13.1, we show the stack, in the form of a list, on


execution of each of the above operations. Note that in
step 11, we tried to pop an element from the stack when
it was already empty. When an attempt is made to pop
from an empty stack, it is called underflow condition.

u n der flow con dition : pop oper a tion on a n em pty sta ck

In light of the above discussion, we define the class


Stack (Fig. 13.2). The following operations are often
required to be performed on a stack: check if the stack is
empty, push an object, pop an object, retrieve value at
the top of the stack without removing it from the stack,
find the number of elements in the stack, print contents
of the stack. Note that we do not discuss an operation to
test whether the stack is full as append operation in a
list is limited only by the physical storage available to the
program.

Fig. 13.1 Sta ck oper a tion s

sta ck oper a tion s


sta ck u n der flow

In Fig. 13.2, we present the above-mentioned stack


operations using inbuilt list operations append and pop.
The constructor for the class Stack defines an empty list
– values – to store the data objects that would be
pushed on the stack. Next, we describe each of the
above-mentioned operations for the class Stack.

u se of list oper a tion s a ppen d a n d pop for im plem en tin g sta ck


oper a tion s
Fig. 13.2 Cla ss Stack (stack.py)

1 . Is St a ck Em pt y
Th e m eth od isEmpty deter m in es w h eth er th e sta ck is
em pty by ch eckin g w h eth er th e len g th of th e list
values is zer o, i.e. w h eth er len(self.values) == 0.
Th e m eth od r etu r n s True if th e sta ck is em pty , a n d
False oth er w ise.
2 . Pu sh a n Object
Th e m eth od push ta kes th e elem en t to be pu sh ed a s a n
in pu t pa r a m eter a n d pu ts it a t th e en d of th e list
values by in v okin g th e m eth od append.

op er at i ons f or c l ass Stack


3 . Pop a n Object
Th e m eth od pop fir st ch ecks w h eth er th e sta ck is
em pty by in v okin g th e m eth od isEmpty. If th e sta ck is
n ot em pty , th e object a t th e top of th e sta ck (i.e, th e
elem en t th a t w a s pu sh ed on th e sta ck la st) is popped
a n d r etu r n ed. Oth er w ise, th e m essa g e 'Stack
Underflow' is displa y ed a n d None is r etu r n ed
in dica tin g em pty sta ck.
4 . Ret r iev e V a l u e a t t h e T op of St a ck
Th e m eth od top r etu r n s v a lu e a t th e top of th e sta ck if
th e sta ck is n ot em pty . Oth er w ise, None is r etu r n ed
in dica tin g em pty sta ck. Th e sta ck con ten ts r em a in
u n ch a n g ed.
5 . Fin d t h e Nu m ber of El em en t s in t h e St a ck
Th e m eth od size r etu r n s th e n u m ber of elem en ts in
th e sta ck by r etu r n in g th e len g th of th e list values.
For th e pu r pose of dem on str a tion , w e h a v e pr ov ided
th is m eth od to r etu r n n u m ber of elem en ts in th e sta ck,
ev en th ou g h sta ck oper a tion s do n ot r equ ir e th is
m eth od.
6 . Pr in t Con t en t s of t h e St a ck
Th e m eth od __str__ pr odu ces a str in g r epr esen ta tion
of th e en tir e sta ck by con ca ten a tin g th e str in g
r epr esen ta tion of ea ch v a lu e in th e list values. Th e
str in g r epr esen ta tion is u sed to pr in t th e con ten ts of th e
sta ck. For th e pu r pose of dem on str a tion , w e h a v e
pr ov ided th is m eth od to displa y th e con ten ts of th e
en tir e sta ck, ev en th ou g h sta ck oper a tion s do n ot
r equ ir e th is m eth od.

On executing the script stackOperations (Fig. 13.3),


it prompts the user to choose from various actions that
can be performed on a stack.
Fig. 13.3 main fu n ction illu str a tin g sta ck oper a tion s
(stackOperations.py)

13.1.1 Evaluating Arithmetic Expressions

Next, we discuss the evaluation of arithmetic


expressions. The usual form in which we write an
arithmetic expression is called infix form because the
operator lies in between the two operands. While writing
expressions in the infix form, we use pairs of parentheses
to ensure correct evaluation order. For example,
examine the following expression:

in fix ex pr ession : oper a tor lies in betw een tw o oper a n ds

a + (b + c) * (k + (d + e) * (f + g * h))

Next, we show the evaluation of the above expression


(Fig. 13.4). Note that in order to evaluate the expression
correctly, we need to keep track of precedence of
operators and matching parentheses. In this process, we
have to scan parts of the expression several times. An
alternative form of expressions, called postfix form
removes this difficulty.

Fig. 13.4 Ev a lu a tion of ex pr ession a+(b+c)*(k +(d+e)*


(f+g*h))

ev a lu a tion of in fix ex pr ession

Postfix form: In the postfix form, the operator appears


after the operands. For example, the infix expression a +
b would be written as a b + in the postfix form. Now,
as a b + is the postfix expression for a + b, the postfix
expression for (a + b) + c would be a b + c +.
Before we get into the details of converting expressions
from infix to postfix form, we discuss the evaluation of
postfix form expressions. To evaluate a postfix form
expression, we make use of a stack and scan the postfix
expression from left to right, applying the following
rules:

postfix for m : th e oper a tor a ppea r s a fter th e oper a n ds


On seein g a n oper a n d in th e ex pr ession , pu sh it on to th e
sta ck.
On seein g a n oper a tor in th e ex pr ession , pop th e n ecessa r y
n u m ber of oper a n ds fr om th e sta ck, a pply th e oper a tor on
th e popped oper a n ds, a n d pu sh th e r esu lt on th e sta ck.

ev a lu a tin g a postfix ex pr ession

Next, we examine evaluation of a postfix expression A B


C * + D *, where the variables A, B, C, and D take
values 2, 3, 4, and 5, respectively (see Fig. 13.5). The
arrow marks the position of the symbol being processed
currently. It is evident from the computation shown in
Fig. 13.5 that the postfix expression A B C * + D * is
equivalent to the infix expression (A + B * C)* D.
Fig. 13.5 Ev a lu a tion of postfix ex pr ession A B C * + D *

In light of the above discussion, we develop script


evaluatePostfix (Fig. 13.6). In this program, we
deal with only one digit operands. The function main in
this program invokes the function
evaluatePostfixExp, which takes a postfix
expression as the input parameter and returns the result
obtained on evaluating the input expression.
Fig. 13.6 Scr ipt for ev a lu a tin g postfix ex pr ession
(evaluatePostfix.py)

On executing the script evaluatePostfix (Fig


13.6), it prompts the user to enter a postfix expression
and returns the result obtained on evaluating it. For
example, on entering the expression 75-6*4+,
corresponding to the infix expression(7-5)*6+4,
Python responds with the result 16.

13.1.2 Conversion of Infix Expression to Postfix Expression

In this section, we discuss how to convert an infix


expression into a postfix expression. Once again a stack
will come to our help. Recall that we evaluate the postfix
expression from left to right using a stack. To begin with,
examine the expression A + B * C. As multiplication
has higher precedence than addition, the corresponding
postfix expression would be A B C * + because when
we use a stack to evaluate it, it gets evaluated as A+
(B*C). Note that the expression A B + C * will not
work because it would get evaluated as (A+B)*C. The
preceding example gives us a general clue for converting
an infix expression into equivalent postfix expression. As
we scan the infix expression, we keep on appending
operands to the output string as they are encountered.
To deal with the operators, we use a stack. To decide
how to process the current symbol, we apply the
following rules:

r u les for in fix to postfix con v er sion

If th e ch a r a cter cu r r en tly bein g sca n n ed is a n oper a tor ,


a n d pr eceden ce (oper a tor cu r r en tly sca n n ed) > pr eceden ce
(oper a tor on top of th e sta ck), pu sh it on th e sta ck
If th e ch a r a cter cu r r en tly bein g sca n n ed is a n oper a tor ,
a n d pr eceden ce (oper a tor cu r r en tly sca n n ed) <=
pr eceden ce (oper a tor on top of th e sta ck), pop off a n d
a ppen d to th e ou tpu t str in g , ea ch oper a tor h a v in g
pr eceden ce h ig h er th a n or equ a l to th e pr eceden ce of th e
oper a tor cu r r en tly bein g sca n n ed, u n til a n oper a tor
h a v in g low er pr eceden ce is en cou n ter ed on top of th e sta ck,
or th e sta ck becom es em pty . Now , pu sh th e oper a tor bein g
sca n n ed cu r r en tly on th e sta ck.
If th e ch a r a cter bein g sca n n ed is a n oper a n d, a ppen d it to
th e ou tpu t str in g .
If th e en d of th e in pu t str in g is r ea ch ed, pop off a ll th e
oper a tor s on e by on e a n d a ppen d to th e ou tpu t str in g .

So far, we have not discussed how to deal with the


parentheses. As parentheses have the highest precedence,
as soon as '(' is encountered, it should be placed on the
stack. '(' marks beginning of a sub-expression of the
given infix expression that would be subsequently
terminated by matching ')'. Now, we need to convert
this sub-expression to postfix form. However, the
precedence of '(' being highest, no operator can be
pushed on it and '(' would be popped off the stack
without processing any other operator. To prevent this
situation, we modify the rules for push and pop
operations as follows:

in fix to postfix : ex pr ession s in v olv in g pa r en th eses

pu sh : if oper a tor cu r r en tly sca n n ed is '(', or th e top of th e


sta ck is '(', or pr eceden ce (oper a tor cu r r en tly sca n n ed) >
pr eceden ce (oper a tor on top of th e sta ck)
pop: if oper a tor cu r r en tly sca n n ed == ')', th en pop off a ll
th e oper a tor s u p to a n d in clu din g th e fir st '(' en cou n ter ed
in th e sta ck. If th e ch a r a cter cu r r en tly bein g sca n n ed is a n
oper a tor oth er th a n a pa r en th esis, a n d pr eceden ce
(oper a tor cu r r en tly sca n n ed) <= pr eceden ce (oper a tor on
top of th e sta ck), pop off a n d a ppen d to th e ou tpu t str in g ,
ea ch oper a tor h a v in g pr eceden ce h ig h er th a n or equ a l to
th e pr eceden ce of th e oper a tor cu r r en tly bein g sca n n ed,
on e by on e, u n til '(' or a n oper a tor h a v in g low er
pr eceden ce is en cou n ter ed on top of th e sta ck, or th e sta ck
becom es em pty . Now , pu sh th e oper a tor bein g sca n n ed
cu r r en tly on th e sta ck.
If th e ch a r a cter bein g sca n n ed is a n oper a n d, con ca ten a te
it to th e ou tpu t str in g .
If th e en d of th e in pu t str in g is r ea ch ed, pop off a ll oper a tor s
on e by on e. Con ca ten a te th e oper a tor s to ou tpu t str in g a s
th ey a r e popped off.

Note that a right parenthesis would never be pushed on


the stack. Since ')' terminates a sub-expression, on
encountering ')', we pop off all operators up to the
matching '(', that is, the first '(' encountered on the
stack. As the role of '(' is now over, it can also be
popped out of the stack. However, it is not appended to
the output string as postfix form expressions do not use
parentheses. We put together above ideas in the form of
the function postfix (Fig. 13.7). Note that we have
considered expressions involving +,-,*, /, (,) and
single digit operands only.

On executing the script in Fig. 13.7, it outputs the


postfix expression for a given infix expression:

Enter the expression in infix notation:


((7-5)*6+4) 75-6*4+
Fig. 13.7 Pr og r a m to fin d postfix ex pr ession for th e g iv en in fix
ex pr ession (postfix.py)
13.2 QUEUES

A queue is a data structure that behaves in First In First


Out (FIFO) manner, i.e. objects leave in the same order
in which they arrive. All insertions occur at one end
called rear end, and all deletions occur at another end
called front end. Insertion and deletion operations are
also known as enqueue and dequeue operations
respectively.

qu eu e: fir st in , fir st ou t

enqueue: in ser tion (a t rear en d)

dequeue: deletion (a t front en d)

Beginning with an empty queue, let us perform the


following operations on this queue in sequence: enqueue
5, enqueue 10, dequeue, enqueue 20, enqueue 25,
dequeue, dequeue, dequeue, dequeue. In Fig. 13.8, we
show the queue on execution of each of the
aforementioned operations:
Fig. 13.8 Qu eu e oper a tion s

Underflow denotes a condition when an attempt is


made to delete from an empty queue. As mentioned
earlier, whenever queue is empty, the number of
elements in it is zero.
u n der flow : dequ eu e oper a tion on a n em pty qu eu e

A queue may be implemented in Python using lists. In


the script queue (Fig. 13.9), we define the class Queue.
We describe the enqueue and dequeue operations using
inbuilt list operations append and pop(0).

u se of list oper a tion s append a n d pop(0) for im plem en tin g


qu eu e oper a tion s
Fig. 13.9 Cla ss Queue (queue.py)

The constructor of class Queue introduces the list


values for storing the queue objects. Initially, the list
values is an empty list. We define the following Queue
operations:
1 . isEmpty: Th e m eth od isEmpty r etu r n s True if th e
len g th of th e list values is zer o, a n d False oth er w ise.
2 . enqueue: It ta kes th e elem en t to be in ser ted in th e
qu eu e a s a n in pu t a r g u m en t a n d a dds th e elem en t a t
th e r ea r en d of th e list values by in v okin g th e m eth od
append.
3 . dequeue: Th e m eth od dequeue fir st ch ecks w h eth er
th e qu eu e is em pty by in v okin g th e m eth od isEmpty. If
th e qu eu e is em pty , th e m essa g e 'Queue Underflow' is
displa y ed a n d None is r etu r n ed in dica tin g u n der flow . If
th e qu eu e is n ot em pty , th e v a lu e fr om th e fr on t en d of
th e list values is deleted u sin g th e m eth od pop a n d
r etu r n ed.
4 . front: If th e qu eu e is n ot em pty , th e m eth od front
r etu r n s th e v a lu e a t th e fr on t en d (in dex zer o in th e list
values), w ith ou t deletin g it fr om th e qu eu e.
Oth er w ise, it r etu r n s None in dica tin g em pty qu eu e.

F ig . 13.10 main f u nc t i on i l l u st r at i ng qu eu e op er at i ons


(queueOperations.py)

5 . size: Th e m eth od size r etu r n s th e n u m ber of


elem en ts in th e qu eu e by r etu r n in g th e len g th of th e
list values. For th e pu r pose of dem on str a tion , w e h a v e
pr ov ided th is m eth od to r etu r n th e n u m ber of elem en ts
in th e qu eu e, ev en th ou g h qu eu e oper a tion s do n ot
r equ ir e th is m eth od.
6 . __str__: Th e m eth od __str__ pr odu ces a str in g
r epr esen ta tion of th e en tir e qu eu e by con ca ten a tin g
th e str in g r epr esen ta tion of ea ch v a lu e in th e list
values. For th e pu r pose of dem on str a tion , w e h a v e
pr ov ided th is m eth od to displa y th e con ten ts of th e
en tir e qu eu e, ev en th ou g h qu eu e oper a tion s do n ot
r equ ir e th is m eth od.
SUMMARY

1 . Th e sta ck is a da ta str u ctu r e in w h ich objects a r e stor ed


on e ov er th e oth er , a n d th ese objects lea v e in th e
r ev er se or der of th eir a r r iv a l. Su ch a n a r r a n g em en t of
objects is ca lled Las t In Firs t Out (LIFO) a r r a n g em en t.
2 . A sta ck is ch a r a cter ized by th e follow in g oper a tion s:
1 . pu sh : Pla ce (pu sh ) a n ew elem en t on top of th e
sta ck. Th e pu sh oper a tion is a lso ca lled in ser tion
of a n elem en t.
2 . pop: Rem ov e (pop) top elem en t fr om th e sta ck.
Th e pop oper a tion is a lso ca lled deletion of a n
elem en t.
3 . Poppin g a n elem en t fr om th e sta ck w h en it is em pty
r esu lts in a n u n der flow con dition .
4 . Py th on ’s bu ilt-in list m eth ods append a n d pop a r e
ty pica lly u sed for im plem en tin g a sta ck.
5 . A qu eu e is a da ta str u ctu r e th a t beh a v es in Fir st In
Fir st Ou t (FIFO) m a n n er i.e. objects lea v e in th e sa m e
or der in w h ich th ey a r r iv e. A ll in ser tion s ta ke pla ce a t
on e en d ca lled rear en d, a n d a ll deletion s occu r a t
a n oth er en d ca lled front en d. In ser tion a n d deletion
oper a tion s a r e a lso kn ow n a s enqueue a n d dequeue
oper a tion s r espectiv ely .
6 . Wh en a qu eu e is em pty , dequeue oper a tion on it r esu lts
in a n u n der flow con dition .
7 . Py th on pr ov ides in bu ilt list oper a tion s append a n d pop
for im plem en tin g a qu eu e.

EXERCISES

1 . Im a g in e th a t Py th on list does n ot su ppor t m eth ods


append a n d pop. Ex a m in e th e scr ipt in Fig . 1 3 .1 1 a n d
defin e y ou r im plem en ta tion of pu sh a n d pop oper a tion
of th e sta ck by fillin g u p th e code.
F ig . 13.11 Cl ass St ac k (stackDefined.py)

2 . Im a g in e th a t Py th on list does n ot su ppor t m eth ods


append a n d pop. Ex a m in e th e scr ipt in Fig . 1 3 .1 2 a n d
defin e y ou r ow n im plem en ta tion of en qu eu e a n d
dequ eu e oper a tion on a qu eu e by fillin g u p th e m issin g
code:
F ig . 13.12 Cl ass Queue(queueDefined.py)

3 . Th e qu eu e im plem en ta tion defin ed in qu estion 2 does


n ot u tilize th e stor a g e spa ce effectiv ely sin ce if front
poin ts to in dex j a n d rear poin ts to in dex i >= j,
em pty spa ce a t in dex es 0 to i-1 ca n n ot be u tilized a s
sh ow n in Fig . 1 3 .1 3 .

F ig . 13.13 Qu eu e
F ig . 13.14 Qu eu e

Th e pr oblem ca n be elim in a ted by m a in ta in in g


cir cu la r qu eu e (Fig . 1 3 .1 4 ). Ex a m in e th e skeleton of
th e scr ipt cir cu la r qu eu e (Fig . 1 3 .1 5 ) a n d fill u p th e left
ou t code. Th e v a r ia ble count keeps tr a ck of th e cu r r en t
size of th e qu eu e a n d a lso en a bles u s to discov er
w h eth er th e qu eu e is em pty or fu ll. A s in dex es a r e u sed
in a cir cu la r m a n n er , w h en ev er front or rear is
in cr em en ted, w e a pply th e m odu lo qSize oper a tion , w e
u pda te front a n d rear a s (front + 1) % qSize, a n d
(rear + 1) % qSize r espectiv ely . Th e qu eu e is sa id to
be fu ll if (rear + 1) % qSize == front. Note th a t if
w e in ser t a n oth er elem en t a t th is sta g e, front a n d
rear w ou ld becom e equ a l.
4 . Dev elop a pr og r a m u sin g a sta ck to fin d ou t w h eth er
th e g iv en str in g is a pa lin dr om e.
5 . Rew r ite th e code in ex er cise 2 , so th a t w h en ev er th er e
is a deletion , a ll th e elem en ts in th e qu eu e a r e sh ifted
tow a r ds th e fr on t by on e position .
F ig . 13.15 Cl ass CircularQueue(circQueue.py)

6 . Rew r ite th e code in ex er cise 2 so th a t w h en ev er th er e is


a qu eu e ov er flow scen a r io, a ll th e elem en ts in th e
qu eu e a r e sh ifted (if possible) so th a t th e fr on t elem en t
is a t in dex 0.
7 . Wr ite a pr og r a m to r ev er se a str in g u sin g sta cks.
8 . Ev a lu a te th e follow in g postfix ex pr ession . Sh ow th e
sta tu s of th e sta ck on th e ex ecu tion of ea ch oper a tion .
1 . 99/52*9-+
2 . 25*94/5-+
3 . 526*93/-*
4 . 51+31-*
5 . 687+*82/-
6 . 152-*25*+
7 . 55+93-*3/
8 . 651+21-+*
9 . 836+27-9+*/
9 . Con v er t th e follow in g in fix ex pr ession to its equ iv a len t
postfix ex pr ession , sh ow in g th e sta ck con ten ts a t ea ch
step.
1 . 8+6/(5-3)*2
2 . (8–3-1)*6/2+8/4
3 . 8+(9–9/3–4*7)–5
4 . 7+6–7/2–7*4–3
CHAPTER 14
DATA STRUCTURES II: LINKED LIST

CHAPTER OUTLINE
1 4 .1 In tr odu ction

1 4 .2 In ser tion a n d Deletion a t th e Beg in n in g of a Lin ked List

1 4 .3 Deletin g a Node w ith a Pa r ticu la r V a lu e fr om a Lin ked


List

1 4 .4 Tr a v er sin g a Lin ked List

1 4 .5 Ma in ta in in g Sor ted Lin ked List w h ile In ser tin g

1 4 .6 Sta ck Im plem en ta tion Usin g Lin ked List

1 4 .7 Qu eu e Im plem en ta tion Usin g Lin ked List

In the previous chapter, we studied stacks and queues.


Whereas a stack allows insertion and deletion of objects
at one end, in a queue new objects are inserted at one
end, and the deletion takes place from the other end. In
this chapter, we will discuss a more flexible data
structure called linked list that allows insertion and
deletion of an object at an arbitrary position.

14.1 INTRODUCTION

A linked list is a sequence of objects called nodes. The


relative position of the objects in a linked list is
maintained using next link. Thus, a linked list
comprises a number of objects, each of which contains a
link to the next object (node). For example, let us
examine the list lst shown in Fig. 14.1. The first node of
the linked list comprises an int object 20 and a next
link, which is a reference to the second node in the linked
list. Similarly, the second node comprises an int object
15 and the next link, which is a reference to the third
node. Since the third node is the last node of the linked
list, there is no next object ahead of it. Therefore, it
comprises an int object 25 and the next link refers to
None.
lin ked list: sequ en ce of objects ca lled n odes, ea ch of w h ich
con ta in s a lin k to th e n ex t object

Fig. 14.1 Lin ked list v isu a liza tion

Next, we describe a class Node for dealing with nodes


of a linked list in a program. An instance of this class
comprises two members, namely, data and next. We
define the method __init__ (Fig. 14.3) for the class
Node that creates an instance of a node of the linked list.
In this method, self refers to the Node object being
created, self.data refers to the object value, being
passed as an argument (an instance of class int in Fig.
14.1), and self.next refers to an instance of the class
Node. Note that when we create a node object, by
default, next is assigned the value None. Now, we show
a more accurate representation of the linked list in Fig.
14.1 (Fig. 14.2). However, for reasons of brevity and
simplicity of the figures, we will continue to use the
representation of the linked list shown in Fig. 14.1.

cla ss Node: for cr ea tin g n odes of a lin ked list


Fig. 14.2 V isu a liza tion of a lin ked list

Fig. 14.3 Cla ss Node (node.py)

Now let us examine the script linkedList1 (Fig.


14.4) that creates the linked list shown in Fig. 14.1. In
Fig. 14.5, we show the run-time stack as the execution of
the code proceeds in Python Tutor. Since Python Tutor
does not allow us to import user defined modules, in
order to execute the script in Python Tutor, import
statement should be replaced by the complete definition
of the class.

Execution of line 8 creates a node instance (Fig.


14.5(a)), comprising data (int object 20) and next
link (object None). This node instance is named as lst.
In this context, we use the following phrases
interchangeably: lst refers to the node, lst is a
reference to the node, and lst points to the node.
Execution of line 9 creates another node instance (Fig.
14.5(b)), comprising data (int object 15) and next
link (object None). Now, the name lst.next, which
referred to None on execution of line 8, refers to the new
node just created. Finally, execution of line 10 creates
one more node instance (Fig. 14.5(c)), comprising data
(int object 25) and next link (object None). Now,
lst.next.next, which referred to None on execution
of line 9, refers to the new node just created. Before
proceeding further, it is important to note the following:

w h en a n a m e r efer s to a n ode, w e sa y : it is a r efer en ce to th e


n ode or it poin ts to th e n ode
Fig. 14.4 Lin ked list creation (linkedList1.py)

lst r efer s to th e fir st n ode of th e lin ked list. We m a y a lso sa y


th a t lst r efer s to th e lin ked list. lst.data r efer s to th e data
a ttr ibu te of th e fir st n ode (i.e., int object 20) a n d lst.next
r efer s to th e next a ttr ibu te of th e fir st n ode (i.e., secon d
n ode).
A s lst.next r efer s to th e secon d n ode, lst.next.data r efer s
to th e data a ttr ibu te of th e secon d n ode (i.e., int object
15)a n d lst.next.next r efer s to th e next a ttr ibu te of th e
secon d n ode (i.e. th ir d n ode).
A s lst.next.next r efer s to th e th ir d n ode,
lst.next.next.data r efer s to th e data a ttr ibu te of th e th ir d
n ode (i.e., int object 25) a n d lst.next.next.next r efer s to
th e next a ttr ibu te of th e th ir d n ode (i.e., object. None).
Fig. 14.5 Cr ea tion of a lin ked list lst

In lines 11 to 17 we print data values and node


instances. On executing theses lines, Python produced
the following output:

lst: <node.Node object at 0x0305BD90>

lst.data: 20

lst.next: <node.Node object at 0x0305BDB0>

lst.next.data: 15

lst.next.next: <node.Node object at


0x0305BDD0>

lst.next.next.data: 25

lst.next.next.next: None

ou tpu t on ex ecu tin g th e scr ipt linkedList1

Y ou must have noted that the above method of


accessing nodes of a linked list as a sequence of next
links (e.g., lst.next.next.next) beginning the first
node is not just cumbersome, but also unworkable for
linked lists having several nodes. As an alternative, we
typically introduce, a variable current that keeps track
of the node with which we are currently dealing. We
insert a new node in the linked list by assigning the new
node to current.next. In the script linkedCubes
(Fig. 14.6), we use this method to create a linked list of
cubes of four numbers beginning 1.
cr ea tin g a lin ked list of cu bes: keep tr a ck of th e current n ode

Fig. 14.6 Lin ked list of cu bes (linkedCubes.py)

Execution of line 9 creates the node lst having the data


attribute lst.data equal to 1 (Fig. 14.7(a)). On
execution of line 10, both current and lst refer to this
node (Fig. 14.7(b)). Every time line 12 is executed, a new
node is created with data attribute i**3 and assigned to
current.next. Thus the new node gets inserted in the
linked list. Subsequently, in line 13, current is assigned
current.next to make the node just inserted the
current node for the next iteration. Thus, a new node is
always inserted after the node that was inserted last in
the linked list. The linked list on insertion of each of the
nodes having data values 8, 27, and 64, respectively, is
shown in Fig. 14.7(c), 14.7(d), and 14.7(e), respectively.

14.2 INSERTION AND DELETION AT THE BEGINNING OF A LINKED LIST

In this section, we will discuss linked lists in some more


detail. We develop a class LinkedList (Fig. 14.8) that
provides the following functionality:
Fig. 14.7 Lin ked list lst v isu a liza tion

cr ea te a n em pty lin ked list,


in ser t a n ode a t th e beg in n in g of lin ked list
delete a n ode fr om th e beg in n in g of lin ked list.

This class makes use of the Node class discussed earlier.


We introduce a variable head to refer to the first node of
the linked list. As the linked list is initially empty, head is
initialized to be None in the constructor method (line
10).

v a r ia ble head r efer s to fir st n ode of th e lin ked list


Fig. 14.8 Cla ss Lin kedList (linkedList.py)
Fig. 14.9 Cr ea tin g a lin ked list (linkedListMain.py)

In the script linkedListMain (Fig. 14.9), we


demonstrate the use of class LinkedList. The
execution of line 8 invokes the constructor that creates a
LinkedList instance named lst. This step assigns the
value None to the attribute head of this linked list. The
linked list lst at this stage is shown in Fig. 14.10(a) as
visualized in Python Tutor. Since, the Python Tutor does
not support eval (Fig. 14.9, line 13), we have replaced it
with the function int for for executing the code in
Python Tutor. However, in order to be able to use the
program for data values of arbitrary type, we do not
incorporate this change in Fig. 14.9. Next, the control
enters the while loop. The user is asked to enter his/her
choice of action out of the following:

1 . in ser t a n ode a t th e beg in n in g of th e lin ked list


2 . delete a n ode fr om th e beg in n in g of th e lin ked list
3 . qu it th e lin ked list oper a tion s

lin ked list oper a tion s

When the option 1 is chosen, the user is asked to enter


the value for the node to be inserted in the linked list. We
demonstrate the linked list operations for the following
sequence of choices:
Choice value

1 25

1 15

1 20

On entering choice 1 and value 25, the method


insertBegin is invoked with the argument 25. It
inserts a node having value 25 at the beginning of the
linked list. For this purpose, it first checks whether linked
list is empty, i.e., head contains None as the associated
value. As the linked list is, indeed, currently empty, it
invokes the constructor of the Node class with the
argument 25 (Fig. 14.8, line 21) to create a node having
25 as the value of data and None as the value of the
next link. This node instance is referred to via head of
the linked list (Fig. 14.10(b)).

in ser tin g a n ode a t th e beg in n in g

Next, we wish to insert another node having data


value 15 in the linked list. However, the linked list is
non-empty now. Again, we invoke the method
insertBegin with the argument 15. Execution of line
23 (Fig. 14.8) creates a node instance named temp
having 15 as the value of data and None as the value of
the next link (Fig. 14.10(c)). On execution of line 24,
the node instance temp gets added to the linked list by
assigning the value of head of the linked list lst to the
next link of temp (Fig. 14.10(d)). Note, however, that
we still need to update head to point to the beginning of
the modified list. Execution of line 25 (Fig. 14.8)
achieves this (Fig. 14.10(e)). In Fig. 14.10(f), we see a
compact representation of the same linked list on exit
from the function insertBegin as visualized in Python
Tutor. To add another node having value 20 at the
beginning of the linked list, we invoke the method
insertBegin with the argument 20. On execution of
the method insertBegin, the final linked and its
compact representation are shown in Fig. 14.10(g) and
Fig. 14.10(h), respectively.
Fig. 14.10 In ser tion a t th e beg in n in g of th e lin ked list

Next, we wish to delete a node from the beginning of


the linked list. On entering choice 2, method
delBegin is invoked. It first checks whether linked list
is empty, i.e. whether the value of head is None. If the
linked list is empty, the method displays the message
'Empty List' and returns the control to the main
function (lines 36–37, Fig. 14.8). However, the linked list
lst is non-empty as it contains three nodes. To delete
the first node, we first save a reference to it as temp and
refer to its data as value (lines 39–40: Fig. 14.8, Fig.
14.11(a)). On execution of line 41 (Fig. 14.8), head of
the linked list is updated to point to the second node,
which now becomes the first node of the linked list (Fig.
14.11(b)). On the execution of line 42, the node pointed
by temp is deleted using del (Fig. 14.11(c)). Finally, on
the execution of line 43, method delBegin exits while
returning value (20) (Fig. 14.11(d)).

deletin g a n ode fr om th e beg in n in g


Fig. 14.11 Deletion fr om th e beg in n in g of lin ked list

14.3 DELETING A NODE WITH A PARTICULAR VALUE FROM A LINKED LIST

Often, we are interested in deleting a node having a


particular value from a linked list. The method delVal
(Fig. 14.12) takes the value as an input parameter and
deletes the first node with this value, if found in the
linked list. If the list is empty, the function displays a
message 'Empty List' (line 10) and exits. In line 12,
we check whether the first node itself has the given
value as its data attribute. If so, the execution of lines
13–16 deletes the first node of the linked list. Recall that
this is what we did in the function delBegin.

a ttem pt to delete fr om a n em pty list

deletion of fir st n ode


Fig. 14.12 Meth od delVal of cla ss LinkedList (linkedList.py)

If the node to be deleted is not the first node, we


traverse the linked list to search for the target node
having value as its data attribute. To illustrate the
process of deleting a node (not the first node) having a
given value of data, we consider a linked list having
four nodes comprising data 20, 15, 25, and 10 (Fig.
14.13(a)). Suppose we wish to delete the node having
data 25. In order to delete the target node, we need to
mark the target node as well as the node preceding the
target node. A variable current is used that keeps track
of the node we are currently dealing with. Another
variable prev keeps track of the node previous to the
current node. Initially, current is set to point to the
first node, i.e. head of the linked list (line 18), and prev
is assigned value None (line 19, Fig. 14.13(b)). Execution
of while loop (lines 20–22) causes traversal of the
linked list. Everytime lines 21 and 22 are executed, prev
is assigned current and current is assigned
current.next. i.e., current is updated to point to the
next node until current.data == value or we reach
the end of the linked list. (Fig. 14.13(c and d)).
deletin g a n ode som ew h er e in th e m iddle: tr a v er se th e list to
sea r ch for ta r g et v a lu e

keep tr a ck of th e n ode pr ev iou s to th e ta r g et n ode

Since value 25 is present in the linked list, the


condition in line 23 evaluates to True when current
refers to the node having data 25, and prev refers to
the previous node having data value 15. Now, we have
found the node to be deleted. At this point in time,
current as well as prev.next refer to the target node
to be deleted. Execution of line 24 updates the next link
of the prev node instance to point to the node next to
current node (Fig. 14.13(e)). Finally, the target node
pointed to by current is deleted on the execution of line
25 (Fig. 14.13(f)). In case we reach the last node of the
list without encountering any node with the given
value, the condition in line 23 evaluates to False and
the execution of line 28 displays the message 'Value
not Found!!'.

if a n ode h a v in g th e ta r g et v a lu e is n ot fou n d, displa y 'Value


not Found!!'.
Fig. 14.13 Deletion of a pa r ticu la r v a lu e fr om th e lin ked list

14.4 TRAVERSING A LINKED LIST

Next, we define the string representation for a linked list.


Consider a linked list lst with three nodes having
successive data values 20, 15, and 25. We define the
string representation of this linked list to be the string:
'20->15->25' as shown below:

>>> print(lst)

20->15->25
str in g r epr esen ta tion of a lin ked list

The method __str__ (Fig. 14.14) yields the string


representation of the linked list. When the method
__str__ defined in Fig. 14.14 is included in a script
being executed in Python Tutor that involves the class
LinkedList, it suppresses the visualization of the nodes
being used by Python Tutor. Therefore, when we need
the visualization of linked lists in Python Tutor, we
should remove this method from the class LinkedList.
Fig. 14.14 Meth od __str__ of cla ss LinkedList
(linkedList.py)

14.5 MAINTAINING SORTED LINKED LIST WHILE INSERTING

Many times, we are interested in maintaining data in


sorted order to facilitate easy retrieval. In this section we
will discuss how to use a linked list for maintaining the
data in ascending order. For this purpose, we insert a
new node at the correct position so that data in the
modified linked list is always in sorted order. Let us
examine the method insertSort (Fig. 14.15) for
maintaining a sorted linked list. On execution of the
function main (Fig. 14.16), the user is repeatedly
prompted to provide value for the node to be inserted in
the linked list until the user enters an empty string ('').

m a in ta in in g a sor ted lin ked list fa cilita tes r etr iev a l

As first step, the method insertSort checks whether


linked list is empty i.e. whether head has the value None
(line 21). If the linked list is currently empty, it invokes
the constructor for the Node class with the argument
value (line 22) to create a node having value as data
and None as the value of the next link. The attribute
head of the linked list now refers to this node instance
(line 22). If the linked list is not empty and the value to
be inserted is smaller than the value of the data of the
first node, execution of lines 24–26 creates a new node
and inserts it at the beginning of the linked list and the
modified list remains in ascending order of data values.
Otherwise, we need to find the proper position for
inserting the new node with given value.

in ser tion in em pty list

in ser tin g a n ode w ith low est v a lu e

in ser tin g a n ode som ew h er e in th e m iddle r equ ir es tr a v er sin g


th e list

To illustrate the process of inserting a node (not the


first node) having a given value of data, we consider a
linked list, having three nodes comprising data 1, 3, and
5 (Fig. 14.17(a)). Suppose we wish to insert a node
having data value 4 in the linked list. As usual, the
variable current is used to keep track of the node with
which we are currently dealing. Initially, it is set to point
to the first node, i.e. head of the linked list (line 28). We
use another variable prev to keep track of the node
previous to the current node. Initially, it is set to None
(line 29 (Fig. 14.15), Fig. 14.17(b)). Execution of while
loop (lines 30–34) causes traversal of the linked list until
the control reaches the node before which the new node
is to be inserted (i.e. current.data >value) (Fig.
14.17(c) and Fig. 14.17 (d)), or end of the linked list is
reached. Execution of line 35 invokes the constructor for
the Node class with the argument 4 to create a node
temp having 4 as the value of data and None as the
value of the next link (Fig. 14.17(e)). Execution of line
36 updates the next link of node instance pointed by
prev to point to the new node (being referred to as
temp) (Fig. 14.17(f)). Further, on execution of line 37,
the next link of the temp node instance is updated to
refer to the node instance current (Fig. 14.17(g)). In
Fig. 14.17(h), we see a compact representation of the
same linked list on exit from the function insertSort.
Fig. 14.15 Cla ss Lin kedList (linkedListSorted.py)
Fig. 14.16 Cla ss Lin kedList (linkedListSortedMain.py)
Fig. 14.17 Sor ted lin ked list lst

v a r ia ble current: keeps tr a ck of th e cu r r en t n ode of in ter est

v a r ia ble prev: pr ov ides a lin k/r efer en ce to th e n ode befor e


th e current n ode

14.6 STACK IMPLEMENTATION USING LINKED LIST

In the script linkedStack (Fig. 14.18), we present an


implementation of the stack operations using linked list.
For this purpose, we define the class LinkedStack. We
introduce a variable top to keep track of the node that
was added most recently to the stack and initialize it to
None. We also define the following methods:
Fig. 14.18 Cla ss LinkedStack (linkedStack.py)

push: Pu sh a n ode a t th e top of th e sta ck


pop: Pop off a n ode fr om th e sta ck
isEmpty: Ch eck w h eth er th e sta ck is em pty
getTop: Retr iev e th e v a lu e a t th e top n ode, w ith ou t
a ffectin g th e sta ck con ten ts
__str__: Str in g r epr esen ta tion of th e sta ck th a t com pr ises
th e con ca ten a tion of str in g r epr esen ta tion of da ta in ea ch
n ode beg in n in g th e top n ode. For th e pu r pose of
dem on str a tion , w e h a v e pr ov ided th is m eth od to displa y
th e con ten ts of th e en tir e sta ck, ev en th ou g h sta ck
oper a tion s do n ot r equ ir e th is m eth od.

pu sh : a n a log ou s to in ser tion a t th e beg in n in g

pop: a n a log ou s to deletion fr om th e beg in n in g

As we always push the new node on the stack as the top


node, we must insert it at the beginning of the linked list.
Similarly, we pop off a node from the stack by deleting
the node at the beginning of the linked list. In the script
linkedStackMain (Fig. 14.19), we present the main
function for demonstrating various operations of the
class LinkedStack.
Fig. 14.19 main fu n ction u sin g oper a tion s of cla ss LinkedStack
(linkedStackMain.py)

14.7 QUEUE IMPLEMENTATION USING LINKED LIST

In the script linkedQueue (Fig. 14.20), we present an


implementation of the queue operations using a linked
list. For this purpose, we define the class LinkedQueue.
We introduce variables front and rear to keep track of
the nodes that were inserted first and last, respectively, in
the queue and initialize these variables to None. We also
define the following methods:
enqueue: In ser t a n ode a t th e r ea r en d of th e qu eu e
dequeue: Delete a n ode fr om th e fr on t en d of th e qu eu e
isEmpty: Ch eck w h eth er th e qu eu e is em pty
getFront: Retr iev e th e v a lu e a t th e fr on t en d of th e qu eu e,
w ith ou t a ffectin g its con ten ts
__str__: Str in g r epr esen ta tion of th e qu eu e th a t
com pr ises th e con ca ten a tion of str in g r epr esen ta tion of
da ta in ea ch n ode beg in n in g th e fr on t n ode. For th e
pu r pose of dem on str a tion , w e h a v e pr ov ided th is m eth od to
displa y th e con ten ts of th e en tir e qu eu e, ev en th ou g h
qu eu e oper a tion s do n ot r equ ir e th is m eth od.

enqueue: a dd a n elem en t to a qu eu e

In the script linkedQueue (Fig. 14.20), we define the


class LinkedQueue. In the method enqueue, we first
check whether the linked list is empty, i.e. whether
front == None. If the linked list is empty, we invoke
the constructor for the Node class with the argument
value (line 22). Now we can refer to the node just
created via front and rear of the linked list (line 22).
However, if the linked list is non-empty, we need to
insert the new node after the last node in the linked list
which is being referred by rear (line 24). Also, we
update the rear to point to this newly created node (line
25). The method dequeue deletes the first node of the
linked queue referred by front using the following
approach:
Fig. 14.20 Cla ss LinkedQueue (linkedQueue.py)

if queue is not empty, return the value of the


data attribute of the front node of the queue,
otherwise, return None

deque: delete fr om a qu eu e
The methods isEmpty, getFront, and __str__ are
defined in a manner similar to the corresponding
methods described for the class LinkedStack.

In the script linkedQueueMain (Fig. 14.21), we


present main function to demonstrate various operations
of the class LinkedQueue.
Fig. 14.21 main fu n ction u sin g oper a tion s of th e cla ss
LinkedQueue (linkedQueueMain.py)

SUMMARY

1 . A lin ked list com pr ises objects, ca lled n odes, ea ch of


w h ich con ta in s a lin k to th e n ex t object (n ode). Th u s,
next lin k defin es th e r ela tion sh ip of a n ode to th e next
n ode.
2 . In Py th on , a ll n a m es r efer en ce objects, i.e. in sta n ces of
cla sses.
3 . A lin ked list m a y r equ ir e th e follow in g fu n ction a lity :
1 . Cr ea tin g a n em pty lin ked list
2 . In ser tin g a n ode a t th e beg in n in g of th e lin ked
list
3 . Deletin g a n ode fr om th e beg in n in g of th e lin ked
list
4 . Deletin g a n ode w ith pa r ticu la r v a lu e fr om th e
lin ked list
5 . In ser tin g a n ode in sor ted lin ked list
4 . In th e sta ck im plem en ta tion of lin ked list, push a n d
pop oper a tion s a r e a n a log ou s to th e follow in g
oper a tion s in a lin ked list: in ser tion a t th e beg in n in g
a n d deletion fr om th e beg in n in g .
5 . In qu eu e im plem en ta tion u sin g lin ked list, th e m eth od
enqueue in ser ts a t th e r ea r en d of th e lin ked qu eu e a n d
th e m eth od dequeue deletes fr om th e fr on t en d of th e
lin ked qu eu e.

EXERCISES

1 . Wr ite a m eth od insertEnd for th e cla ss LinkedList


th a t ta kes a v a lu e a s a n in pu t a n d a dds a n ode h a v in g
th a t v a lu e a t th e en d of th e lin ked list.
2 . Wr ite a m eth od delEnd for th e cla ss LinkedList th a t
deletes th e la st n ode of th e lin ked list a n d r etu r n s th e
v a lu e of th e data a ttr ibu te of th e la st n ode.
3 . Wr ite a fu n ction th a t ta kes tw o sor ted lin ked lists a s
in pu t pa r a m eter s a n d r etu r n s th e m er g ed, sor ted list.
4 . Wr ite a m eth od findVal for th e cla ss LinkedList th a t
ta kes n a s a n in pu t pa r a m eter a n d r etu r n s v a lu e of th e
da ta a ttr ibu te of th e nth n ode sta r tin g fr om th e
beg in n in g .
5 . Wr ite a n iter a tiv e m eth od reverse for th e cla ss
LinkedList th a t r ev er ses th e g iv en lin ked list.
6 . Wr ite a r ecu r siv e m eth od reverDisplay for th e cla ss
LinkedList th a t displa y s th e da ta v a lu es of th e lin ked
list fr om th e r ig h t en d.
7 . Wr ite a m eth od divideList for th e cla ss LinkedList.
Th e m eth od sh ou ld cr ea te a n d r etu r n a tu ple
com pr isin g tw o lin ked lists, on e com pr isin g n odes a t
ev en position s a n d a n oth er com pr isin g n odes a t odd
position s.
8 . A v a r ia n t of th e lin ked list is kn ow n a s dou bly lin ked
list or tw o-w a y lin ked list (Fig . 1 4 .2 2 ) com pr isin g th e
follow in g n ode str u ctu r e h a v in g tw o lin ks (next a n d
prev) for tr a v er sin g in both dir ection s.

F ig . 14.22 Dou b l y l i nk ed l i st

class Node:
def __init__(self, value):
'''
Objective: To initialize an object of
class Node
Input Parameter:
self (implicit parameter) - object of
type Node
Return Value: None
'''
self.data = value
self.next = None
self.prev = None

Defin e a cla ss DoublyLinkedList w h ich su ppor ts


m eth ods insertBegin, insertEnd, delBegin, delEnd,
delVal, a n d traverse.
9 . A v a r ia n t of lin ked list is kn ow n a s a cir cu la r list (Fig .
1 4 .2 3 ) for tr a v er sin g th e n odes of th e lin ked list in a
cir cu la r m a n n er . Defin e a cla ss CircularLinkedList
w h ich su ppor ts th e m eth ods insertBegin, insertEnd,
delBegin, delEnd, delVal, a n d traverse.

Fig. 14.23 Cir cu la r lin ked list


CHAPTER 15
DATA STRUCTURES III: BINARY SEARCH
TRESS

CHAPTER OUTLINE
1 5 .1 Defin ition s a n d Nota tion s

1 5 .2 Bin a r y Sea r ch Tr ee

1 5 .3 Tr a v er sa l of Bin a r y Sea r ch Tr ees

1 5 .4 Bu ildin g Bin a r y Sea r ch Tr ee

In the previous chapters, we discussed linear data


structures stacks, queues, and linked lists. However,
there are situations that necessitate the use of the non-
linear arrangement of data; for example, a directory is a
hierarchical structure like a tree. In this chapter, we will
briefly talk about trees and move on to study in detail
binary search trees—a particular form of trees, used for
efficiency in searching.

15.1 DEFINITIONS AND NOTATIONS

A tree is a hierarchical structure. It is a collection of


elements called nodes along with a relation called
parenthood that defines a hierarchical structure on the
nodes. The node not having any parent node is called the
root node. Every node other than the root has a unique
parent node. If node A is the parent of node B, we also
say that node B is a child of the node A. Multiple nodes
may have the same parent node. In a diagram, we
usually represent a node by encircling the node label. A
node label is also called value of the node. In Fig. 15.1,
we see a tree comprising eight nodes including the root
A. The arrows are used to express parent–child
relationships. The node A has three children, namely, B,
C, and D. Alternatively, we may say that A is the parent
of each of the nodes B, C, and D. Similarly, the node D is
the parent node for nodes F and G. Note that a node may
or may not have any children, for example, none of the
nodes E, C, H, and G has any child node.

tr ee: a h ier a r ch ica l a r r a n g em en t of n odes

r oot n ode: n ode w ith ou t a n y pa r en t n ode

n o tw o n odes m a y h a v e th e sa m e ch ild n ode, h ow ev er ,


m u ltiple n odes m a y h a v e th e sa m e pa r en t n ode

Fig. 15.1 A tr ee

r oot: A

in ter n a l n odes: A, B, D, F
lea v es: E, C, H, G

Now, we describe some terminology in the context of the


tree shown in Fig. 15.1:

1 . Lea f: A lea f n ode is a n ode w h ich h a s n o ch ildr en . In


th e fig u r e, th e n odes E, C, H, a n d G a r e lea v es.
2 . In t er n a l n ode: A n ode w h ich is n ot a lea f n ode is
ca lled in ter n a l n ode or a n on -lea f n ode. In th e fig u r e,
th e n odes A, B, D, a n d F a r e in ter n a l n odes.
3 . Pa t h a n d Pa t h Len gt h : If n1, n2, …, nk is a sequ en ce
of n odes in a tr ee su ch th a t ni is th e pa r en t of ni+1 for 1
<= i <= k-1, th e sequ en ce is ca lled a pa th of len g th k-
1 fr om n1 to nk. In th e fig u r e, A, D, G is a pa th of len g th
2.

t r ee t er mi nol ogy

4 . Heigh t : Th e len g th of th e lon g est pa th fr om th e r oot to


a lea f in a tr ee defin es th e h eig h t of th e tr ee. For
ex a m ple, in Fig . 1 5 .1 , A, D, F, H is th e lon g est pa th , a n d
th u s th e h eig h t of th e tr ee is th r ee. A lso, w e defin e
h eig h t of a n em pty tr ee to be zer o.
5 . Lev el : Lev el of a n ode is th e n u m ber of edg es on th e
pa th fr om th e r oot to th e n ode. For ex a m ple, n odes A, D,
F, a n d H a r e a t lev els 0, 1 , 2 , a n d 3 , r espectiv ely .
6 . A n cest or /Descen da n t : If th er e is a pa th fr om n ode n1
to n ode n2, w e sa y th a t n1 is a n a n cestor of n ode n2 a n d
n2 is a descen da n t of n ode n1. Th u s, if n ode n1 is a n
a n cestor of n ode n2, th en n1 is eith er pa r en t of n2 or
pa r en t of a n a n cestor of n ode n2. A lso, by defin ition , a
n ode is a n a n cestor a s w ell a s descen da n t of itself. For
ex a m ple, th e n ode D is a n a n cestor of ea ch of th e n odes
D, F, G, a n d H. Note th a t n ode D bein g pa r en t of ea ch of
th e n odes F a n d G, is a n a n cestor of ea ch of th e n odes
F a n d G. Sim ila r ly , th e n ode F bein g pa r en t of th e
n ode H is a n a n cestor of n ode H. A lso, th e n ode D bein g
a n a n cestor of n ode F, w h ich in tu r n is a n a n cestor of
n ode H, is a n a n cestor of n ode H. Sim ila r ly , th e n odes D,
F, G, a n d H a r e descen da n ts of th e n ode D.
7 . Sibl in gs: Ch ildr en of th e sa m e n ode a r e siblin g s to
ea ch oth er . For ex a m ple, B, C, a n d D bein g ch ildr en of A,
a r e siblin g s. Sim ila r ly , F a n d G a r e siblin g s.
8 . Su bt r ee: A su btr ee of a tr ee is a tr ee th a t com pr ises a
n ode of th e tr ee tog eth er w ith a ll its descen da n ts, for
ex a m ple in Fig . 1 5 .1 , th e tr ee com pr isin g th e n odes D,
F, G, a n d H is su btr ee of th e tr ee h a v in g r oot A.

15.2 BINARY SEARCH TREE

A binary tree is a particular type of tree whose nodes


have two or fewer children. In a binary tree, the child
nodes of a node are called the left-child and right-child.
A binary tree may be an empty tree, comprising no
nodes at all, or may comprise a root node along with
other nodes which may be organized as a left binary
subtree and a right binary subtree of the root node. The
left and right binary subtrees may also be empty (as per
the definition of binary tree). For example, in Fig.
15.2(a), binary tree having the node labelled 6 as the root
(also called binary tree rooted at node 6) has two
subtrees—a binary tree rooted at 10 and another binary
tree rooted at 23. The binary tree rooted at 10 has a left-
child—the binary tree rooted at 15. We say that the
binary tree rooted at 10 does not have a right-child, or
that the right-child is an empty tree. The node labeled 15
is a leaf node as its left-child as well as the right-child is
an empty tree. Similarly, the nodes labelled 30 and 20
are leaves.

bin a r y tr ee: em pty tr ee or a tr ee w ith r oot n ode h a v in g a left


bin a r y su btr ee a n d a r ig h t bin a r y su btr ee

str ictly bin a r y tr ee: bin a r y tr ee in w h ich ev er y n on -lea f n ode


h a s n on -em pty left a n d r ig h t su btr ee

There are some special types of binary tree like strictly


binary tree (Fig. 15.2(b)) and complete binary tree (Fig.
15.2(c)). A strictly binary tree is a binary tree in which
every non-leaf node has non-empty left and right
subtree. Thus, each node in a strictly binary tree has
either two children or none. A complete binary tree is a
binary tree that is full on all levels except the lowest level
which is filled in from left to right.

com plete bin a r y tr ee: a bin a r y tr ee th a t is fu ll on a ll lev els


ex cept th e low est lev el w h ich is filled in fr om left to r ig h t
Fig. 15.2 Bin a r y Tr ee

A binary tree is called a binary search tree if for any node


n of the binary tree, every node in its left subtree has
value smaller or equal to that of the node n, and every
node in its right subtree has value larger than that of
node n. For example, in the following binary search tree
(Fig. 15.3), the root node has value 15. Note that values
10 and 6 in the left subtree of the root are smaller than
15, and values 23, 20, and 30 in the right subtree of the
root are larger than 15. Similarly, value 6 in the left
subtree of binary search tree rooted at 10 is less than 10.
Further, values 20 and 30 in the left and right subtree,
respectively of the binary search tree rooted at 23 are
smaller and larger than 23, respectively. In the rest of
this chapter, we will focus only on the binary search
trees.

bin a r y sea r ch tr ee: bin a r y tr ee in w h ich , for ev er y n ode n ,


ev er y n ode in its left su btr ee h a s v a lu e sm a ller or equ a l to it
a n d ev er y n ode in its r ig h t su btr ee h a v e v a lu e la r g er th a n it
Fig. 15.3 Bin a r y sea r ch tr ee

As a node in a binary tree defines left-child and right-


child relationship, it may be thought of as an object
having three members, namely, left (denoting left-
child), data, and right (denoting right-child). In the
class Node (Fig. 15.4), we define method __init__ for
initializing nodes of a binary tree. Note that when we
create a node object, left and right children are
assigned value None.

da ta m em ber s of Node cla ss: left, data, a n d right

Now let us examine the script BSTree (Fig. 15.5) that


creates the binary search tree bst shown in Fig. 15.3.
Execution of line 8 (Fig. 15.5) creates a node instance
comprising data (int object 15), left link (object
None) and right link (object None) (Fig. 15.6(a)). This
node instance is named as bst. Execution of line 9
creates a node instance comprising data (int object
23), left link (object None) and right link (object
None) (Fig. 15.6(b)). Now, the name bst.right which
referred to None on the execution of line 8, refers to the
new node just created. Thus, execution of line 9 defines
the right-child of the root node. Similarly, execution of
lines 10 and 11 defines the right child and the left child of
the binary search tree having the root with data 23
(Figs. 15.6(c) and 15.6(d)) by creating node instances
with int objects 30 and 20, respectively. Further,
execution of line 12 defines left-child of the root node
(Fig. 15.6(e)). It creates a node instance comprising
data (int object 10), left link (object None), and
right link (object None). Now, bst.left which
referred to None on execution of line 8, refers to the new
node just created. Finally, execution of line 13 defines the
left-child of this node having data (int object 6) (Fig.
15.6(f)).
Fig. 15.4 Cla ss Node of bin a r y sea r ch tr ee (bNode.py)
Fig. 15.5 Cr ea tin g a bin a r y sea r ch tr ee (BSTree.py)

em pty bin a r y tr ee ca n be cr ea ted by a ssig n in g None to bst

Note that an empty binary tree can be constructed by


assigning None to bst.
Fig. 15.6 V isu a liza tion of bu ildin g a bin a r y sea r ch tr ee

15.3 TRAVERSAL OF BINARY SEARCH TREES

Often we need to traverse all nodes of a tree, visiting


each node exactly once. There are several ways in which
the nodes of a binary tree may be visited in an entire
scan of the binary tree. We shall describe some
commonly used binary tree traversal methods, namely
inorder, preorder, and postorder.

15.3.1 Inorder Traversal

Inorder traversal of a non-empty binary tree comprises


the following steps:

1 . In or der tr a v er sa l of th e left su btr ee.


2 . V isit th e r oot.
3 . In or der tr a v er sa l of th e r ig h t su btr ee.

steps in in or der tr a v er sa l: left, r oot, r ig h t


In Fig. 15.7, we describe the function inorder for
inorder traversal of the binary tree. On invoking the
function inorder with the argument bst– binary
search tree instance constructed above, the nodes will be
visited in the following order of data values:

>>> inorder(bst)

6 10 15 20 23 30

Fig. 15.7 Fu n ction inorder (bTree.py)

Note that when we traverse the nodes of a binary search


tree in inorder, the data values appear in ascending
order.

tr a v er sin g bin a r y sea r ch tr ee in in or der y ields n odes in


a scen din g or der of th eir v a lu es

Given the root node object, the function first


traverses the left subtree, then the root, and then the
right subtree. We illustrate the execution of function
inorder using Python Tutor (Fig. 15.8). On invoking
the function with argument bst, root points to the
node having data (=15) as shown in Fig. 15.8(a). Since
root is not None, on execution of line 3, the function
inorder is invoked with the left-child of the root node,
i.e. node having data (=10), which now becomes new
root node for this new function call (Fig. 15.8(b)). It
further invokes the function recursively (line 3) with
left-child node having data (=6). Being a leaf node, the
root is not None (Fig. 15.8(c)). So the function
inorder is invoked with the argument root.left (=
None). Now that root is None (Fig. 15.8(d)), the
function terminates, and the control is returned to line 4
of the previous function call (Fig. 15.8(e)), and value 6 is
printed. On execution of line 5, the function inorder is
invoked with the argument root.right (= None). As
the root is None (Fig. 15.8(f)), the function terminates,
and the control returns to the previous call. The traversal
of the binary tree having root label 6 is now complete
(Fig. 15.8(g)). So, the control returns to the previous call
(root labeled 10, line 4). Now the left subtree of this
subtree (root labeled 10) has already been traversed
(Fig. 15.8(h)). On execution of line 4, root.data
(=10) is printed. On execution of line 5, the function
inorder is invoked with the right-child (None) as the
argument (Fig. 15.8(i)). The right-child of the root
(labeled 10) being an empty tree, the control
immediately returns to the previous call of the function
inorder (root labeled 10, see Fig. 15.8(j)). As this call
to function inorder is now complete, the control is
transferred to the previous call of the function inorder
(root labeled 15, Fig. 15.8(k)). Line 4 is now executed
and the root label (= 15) is printed. Next, on execution
of line 5, the function inorder is invoked with the
right-child (root labeled 23) as the argument.
Continuing in this manner, 20, 23, and 30 get printed.
Fig. 15.8 In or der Tr a v er sa l
15.3.2 Preorder Traversal

Preorder traversal of a non-empty binary tree comprises


the following steps:

1 . V isit th e r oot.
2 . Pr eor der tr a v er sa l of th e left su btr ee.
3 . Pr eor der tr a v er sa l of th e r ig h t su btr ee.

steps in pr eor der tr a v er sa l: r oot, left, r ig h t

In Fig. 15.9, we present the function preorder for


preorder traversal of the binary tree. On invoking the
function preorder with bst as the argument, we get
the data values in preorder traversal:

Fig. 15.9 Fu n ction preorder (bTree.py)

>>> preorder(bst)

15 10 6 23 20 30

15.3.3 Postorder Traversal

Postorder traversal of a non-empty binary tree comprises


the following steps:

1 . Postor der tr a v er sa l of th e left su btr ee.


2 . Postor der tr a v er sa l of th e r ig h t su btr ee.
3 . V isit th e r oot.
steps in postor der tr a v er sa l: left, r ig h t, r oot

The function postorder for postorder traversal of the


binary tree appears in Fig. 15.10. On invoking the
function postorder with bst as the argument, we get
the data values in postorder traversal:

>>> postorder(bst)

6 10 20 30 23 15

Fig. 15.10 Fu n ction postorder (bTree.py)

15.3.4 Height of a Binary Tree

As mentioned before, the number of edges on the longest


path from root to a leaf in the tree defines the height of a
tree. To find the height of a binary tree, we note that the
height of an empty tree as well that of a binary tree
rooted at a leaf node (root.left == None and
root.right == None) is zero, otherwise, the height of
a binary tree is computed as one plus the maximum of
the heights of the left and the right subtrees. This idea is
implemented in the function height (Fig. 15.11). Next,
we compute the height of the binary tree bst:

h eig h t of th e tr ee is on e m or e th a n th e m a x im u m of th e
h eig h ts of left a n d r ig h t su btr ee
h eig h t of em pty tr ee or a tr ee com pr isin g on ly on e n ode is
zer o

>>> height(bst)

Fig. 15.11 Fu n ction height (bTree.py)

Note that each of the longest paths (15->10->6 or 15-


>23->20, or 15->23->30) has length 2.

15.4 BUILDING BINARY SEARCH TREE

To build a binary search tree, we must maintain the


insertion order. We define a class binSearchTree (Fig.
15.12), which includes the method insertVal for
inserting new nodes in a binary search tree.

a n ew n ode sh ou ld be ca r efu lly in ser ted in a bin a r y sea r ch


tr ee, so th a t it still r em a in s a bin a r y sea r ch tr ee

To build a binary search tree from given data, we


proceed as follows: We insert the nodes with new data
values one by one taking care that the resulting tree
remains a binary search tree. To begin with, let us insert
a node with value 15. Initially, the tree is empty (i.e.,
self.root == None). So, execution of line 21 (Fig.
15.12) invokes the constructor for the Node class with
the argument value (=15) to create a node having
data value 15 and None as the value of the left and
right links. Now, the name root refers to the tree
having the node just created (Fig. 15.13(a)). Fig
15.13(a)–15.13(g) have been generated using the script
binarySearchTree (Fig. 15.15) which includes the
methods __init__ and insertVal defined in Fig.
15.12.
Fig. 15.12 Cla ss bin Sea r ch Tr ee (bin a r y Sea r ch Tr ee.py )

To insert a node in a non-empty tree, we have to


determine the position of insertion. If value <=
root.data, then new node will be inserted in the left-
subtree of the root node, otherwise it will be inserted in
the right-subtree of the root node. The search for the
place where the new node is to be inserted, will proceed
until we reach an empty tree (None). Thus, the new
node is always inserted as a leaf node.

in a bin a r y sea r ch tr ee, th e n ew n ode is a lw a y s in ser ted a s a


lea f n ode
To illustrate the process of inserting a node into a non-
empty binary search tree, having a given value of the
data attribute, we consider the binary search tree
shown in Fig. 15.13(b). Suppose, we wish to insert a new
node (having data = 12) in the existing binary search
tree. The variable child is used to keep track of the
node we are currently dealing with. Initially, it is set to
point to the root node (line 23, Fig. 15.12). Another
variable parent is used to keep track of parent of the
child node. Initially, we assign the value None to
parent as the root node does not have any parent node
(Fig.15.13(c)). Execution of while loop (lines 25–30, Fig.
15.12) causes traversal of the binary search tree until an
empty tree is reached (i.e., child == None) is found.
In this process, execution of line 26 (Fig. 15.12) updates
parent (= child), and execution of lines 27–30
updates child (= child.left or = child.right),
depending on the value of data in the new node to be
inserted.

parent a n d child n ode: to keep tr a ck of n odes w h ile


tr a v er sin g th e bin a r y sea r ch tr ee for loca tin g position of
in ser tion for n ew n ode
Fig. 15.13 In ser tion of v a lu e 1 2 in bin a r y sea r ch tr ee

Since value 12 (data value for the new node to be


inserted) is less than the value of child node, i.e. value
(=12) <=child.data (=15), child is updated to
point to the left node of child node (i.e., child =
child.left) on execution of line 28 (Fig. 15.12, Fig.
15.13(d)). Since child is not None (child.data
=10), another iteration of the while loop begins and
execution of line 26 updates parent (parent =
child). Again, value 12 is compared with the data
value (10) at child node, and since 12 > 10, child is
updated to point to the right-child of the child node
(i.e., child = child.right) on execution of line 30
(Fig. 15.12, Fig. 15.13(e)). As child.right is None,
child becomes None on execution of line 30 (Fig.
15.12). This leads to termination of the while loop.

Thus, we have found the place where the new node is


to be inserted. Now, the condition value (=12)
<=parent.data (=10) is False. So, execution of
line 34 (Fig. 15.12) creates a node instance by invoking
the constructor for the Node class with the argument
value (=12). As usual, the constructor assigns the value
None to left and right links of the node being
created. The parent–child relationship is established by
assigning the new node (data =12) to parent.right
(line 34 (Fig. 15.12), Fig. 15.13(f)). Finally, in Fig.
15.13(g), we see the compact representation of binary
search tree after insertion of the node with value 12.

com pa r e th e v a lu e of n ew n ode to be in ser ted a s ch ild n ode


w ith pa r en t n ode a n d a ssig n it a s left or r ig h t ch ild
a ccor din g ly

Alternatively, we may define the method insertVal


using recursion (Fig. 15.14). Since the recursive function
would require passing root as an argument at the point
of call, it leads to violation of abstraction principle. So,
we use the wrapper function insert which calls nested
function insertVal with the argument root (line 24,
Fig. 15.14).

u se of a w r a pper fu n ction
In the script binarySearchTree (Fig. 15.15), we
present complete code for the binary search tree. Note
that inorderTraversal, postorderTraversal,
preorderTraversal, and treeHeight are wrapper
methods used for nested recursive functions inorder,
postorder, preorder, and height.
Fig. 15.14 Recu r siv e m eth od recurInsertVal
Fig. 15.15 Cla ss BinSearchTree (binarySearchTree.py)

SUMMARY

1 . A tr ee is a h ier a r ch ica l str u ctu r e. It is a collection of


elem en ts ca lled n odes a lon g w ith a r ela tion ca lled
pa r en th ood th a t defin es a h ier a r ch ica l str u ctu r e on
n odes.
2 . Th e r oot n ode is a n ode w h ich does n ot h a v e a n y pa r en t
n ode.
3 . A lea f n ode is a n ode w h ich h a s n o ch ildr en .
4 . A n ode w h ich is n ot a lea f n ode is ca lled in ter n a l n ode
or a n on -lea f n ode.
5 . If n , n , …, n is a sequ en ce of n odes in a tr ee su ch
1 2 k
th a t n is th e pa r en t of n for 1 <= i <= k-1, th e
i i+1
sequ en ce is ca lled a pa th of len g th k-1 fr om n to n .
1 k
6 . Th e n u m ber of edg es on th e lon g est pa th fr om th e r oot
to a lea f in a tr ee defin es th e h eig h t of th e tr ee.
7 . Th e lev el of a n ode is th e n u m ber of edg es on th e pa th
fr om th e r oot to th e n ode.
8 . n is a n a n cestor of n ode n if n is eith er pa r en t of n or
1 2 1 2
pa r en t of a n a n cestor of n ode n .
2
9 . n is a descen da n t of n ode n if n is eith er ch ild of n or
1 2 1 2
ch ild of a descen da n t of n ode n .
2
1 0. By defin ition , a n ode is a n a n cestor a s w ell a s
descen da n t of itself.
1 1 . Ch ildr en of th e sa m e n ode a r e ca lled siblin g s.
1 2 . A bin a r y tr ee is a pa r ticu la r ty pe of tr ee w h ose n odes
h a v e tw o or few er ch ildr en . In a bin a r y tr ee, th e ch ild
n odes of a n ode a r e ca lled left-ch ild a n d r ig h t-ch ild. A
bin a r y tr ee m a y be a n em pty tr ee, com pr isin g n o
n odes a t a ll, or m a y com pr ise a r oot n ode a lon g w ith
oth er n odes w h ich m a y be or g a n ized a s a left bin a r y
su btr ee a n d a r ig h t bin a r y su btr ee of th e r oot n ode.
1 3 . Str ictly bin a r y tr ee is a bin a r y tr ee in w h ich ev er y
n on -lea f n ode h a s n on -em pty left a n d r ig h t su btr ee.
Th u s, ea ch n ode in a str ictly bin a r y tr ee h a s eith er tw o
ch ildr en or zer o.
1 4 . A com plete bin a r y tr ee is a bin a r y tr ee th a t is fu ll on
a ll lev els ex cept th e low est lev el w h ich is filled in fr om
left to r ig h t.
1 5 . A bin a r y tr ee is ca lled a sea r ch tr ee if for a n y n ode n of
th e bin a r y tr ee, ev er y n ode in its left su btr ee h a s
sm a ller or equ a l v a lu e a s th a t of th e v a lu e of n ode n,
a n d ev er y n ode in its r ig h t su btr ee w ill h a s v a lu e
la r g er th a n th e v a lu e of n ode n.
1 6 . In or der tr a v er sa l of n on -em pty bin a r y tr ee com pr ises
th e follow in g steps:
1 . In or der tr a v er sa l of th e left su btr ee.
2 . V isit th e r oot.
3 . In or der tr a v er sa l of th e r ig h t su btr ee
1 7 . Pr eor der tr a v er sa l of n on -em pty bin a r y tr ee com pr ises
th e follow in g steps:
1 . V isit th e r oot.
2 . Pr eor der tr a v er sa l of th e left su btr ee.
3 . Pr eor der tr a v er sa l of th e r ig h t su btr ee.
1 8 . Postor der tr a v er sa l of n on -em pty bin a r y tr ee com pr ises
th e follow in g steps:
1 . Postor der tr a v er sa l of th e left su btr ee.
2 . Postor der tr a v er sa l of th e r ig h t su btr ee.
3 . V isit th e r oot.
1 9 . Th e h eig h t of a n em pty tr ee a s w ell th a t of a bin a r y
tr ee r ooted a t a lea f n ode (root.left == None and
root.right == None), oth er w ise, th e h eig h t of a
bin a r y tr ee is com pu ted a s on e plu s th e m a x im u m of
th e h eig h ts of th e left a n d th e r ig h t su btr ees.

EXERCISES

1 . Giv en in or der a n d pr eor der tr a v er sa l, w r ite a m eth od


th a t con str u cts a bin a r y tr ee.
2 . Wr ite a m eth od delVal for cla ss binSearchTree th a t
deletes a n ode h a v in g a g iv en v a lu e fr om th e bin a r y
sea r ch tr ee.
3 . Wr ite a m eth od levelOrderTraversal for th e cla ss
binSearchTree th a t tr a v er ses bin a r y sea r ch tr ee lev el
by lev el.
4 . Wr ite a m eth od count for th e cla ss binSearchTree
th a t cou n ts a n d r etu r n s th e n u m ber of n odes in a
bin a r y sea r ch tr ee.
5 . Wr ite a m eth od countLeaves for th e cla ss
binSearchTree th a t r etu r n s th e n u m ber of lea f n odes
in a bin a r y sea r ch tr ee.
6 . Wr ite a m eth od countNonLeaves for th e cla ss
binSearchTree th a t r etu r n s th e n u m ber of n on -lea f
n odes in a bin a r y sea r ch tr ee.
7 . Wr ite a m eth od delLeaves for th e cla ss
binSearchTree th a t deletes a ll th e n odes th a t a r e
cu r r en tly th e lea f n odes of a bin a r y sea r ch tr ee.
8 . Wr ite a m eth od mirrorBST for th e cla ss
binSearchTree th a t cr ea tes a n d r etu r n s m ir r or im a g e
of a bin a r y sea r ch tr ee.
9 . Wr ite a m eth od copyBST for th e cla ss binSearchTree
th a t cr ea tes a n d r etu r n s a copy of a bin a r y sea r ch tr ee.
1 0. Wr ite a m eth od minVal for th e cla ss binSearchTree
th a t fin ds a n d r etu r n s th e m in im u m v a lu e in a bin a r y
sea r ch tr ee.
1 1 . Wr ite a m eth od ancestor for th e cla ss binSearchTree
th a t fin ds a n d r etu r n s th e fir st com m on a n cestor of a
pa ir of n odes in th e bin a r y sea r ch tr ee.
CHAPTER 16
MORE ON RECURSION

CHAPTER OUTLINE
1 6 .1 Pa tter n With in a Pa tter n

1 6 .2 Gen er a lized Eig h t Qu een s Pr oblem

1 6 .3 Kn ig h t's Tou r Pr oblem

1 6 .4 Sta ble Ma r r ia g e Pr oblem

1 6 .5 Fr a cta l (Hilber t Cu r v e a n d Sier pin ski Tr ia n g le)

1 6 .6 Su du ko

1 6 .7 Gu idelin es on Usin g Recu r sion

In Chapter 8, we discussed recursion and its applications


in detail. In this chapter, we focus on more advanced
problems that can be solved using recursion.

16.1 PATTERN WITHIN A PATTERN

In this section, we will use recursion to print a picture


comprising several squares within each other. For this
purpose, we need to import a graphical package, and
matplotlib is one such choice (discussed in detail in
the next chapter). It contains methods for 2D graphics
that would be required in this section. Let us first plot a
square on the graph. The plot function takes as
arguments two lists, say, x and y, comprising x and y
coordinates, respectively of a sequence of points and
connects them using line segments. Thus, a square of
side size may be constructed by joining the points
(0,0), (size,0), (size,size), (0,size), (0,0)
in sequence using line segments. For this purpose, the
square may be defined using two lists, say, x and y as
follows:

x: list of x -cor din a tes of cor n er s of a squ a r e in a sequ en ce


y: list of y -cor din a tes of cor n er s of a squ a r e in a sequ en ce

x = [0, size, size, 0, 0]


y = [0, 0, size, size, 0]

The script square (Fig. 16.1) creates a square of the


desired size. When we enter 20 as the size of the square,
the square would appear as shown in Fig. 16.2.
Fig. 16.1 Pr og r a m to plot a squ a r e (square.py)

Fig. 16.2 Squ a r e


Next, let us print squares within squares. Evidently,
recursion would be our natural choice to design such a
function. However, before we develop the recursive
function, we need to do some housekeeping. In the script
squareRecur, we develop a separate function
squareWrapper to do the housekeeping work related to
the main function square (Fig. 16.3). Such a function
is called a wrapper function. It accepts the size of the
square as a parameter, initializes the vectors x and y,
invokes the recursive function square, prints the title of
the figure, fixes the axes, invokes the function grid() to
plot the grid, and finally invokes the method show() to
show the result. For every call to the function square,
we decrease the size of the square by two, thus,
causing the square to shrink inwards. Finally, we
terminate the function square when the difference
between adjacent coordinates is less than one. When we
enter 20 as the size of the square, the square would
appear as shown in Fig. 16.4.

squareWrapper: w r a pper fu n ction for h ou sekeepin g w or k

in ev er y r ecu r siv e ca ll to th e fu n ction square, decr ea se


squ a r e size by tw o
Fig. 16.3 Pr og r a m to r ecu r siv ely plot squ a r e w ith in a squ a r e
(squareRecur.py)
Fig. 16.4 Squ a r es w ith in squ a r es

16.2 GENERALIZED EIGHT QUEENS PROBLEM

The eight queens problem is the problem of placing eight


queens on the chessboard so that none can attach each
other. A queen is attackable if another queen lies in the
same row, same column, or same diagonal (either
direction). In this problem, we need to find a solution in
the form of a placement of queens on the 8 × 8
chessboard so that each of the eight queens is non-
attackable (i.e. safe). We may begin as follows: initially,
place a queen at any place in the first row, and then
successively choose the position of the next queen on the
subsequent rows in such a manner that chosen square is
unguarded, i.e. not attackable by any other queen. As we
follow the procedure just described, it is possible that we
may get stuck on the way, as there may be a row for
which no position is a safe position. If this happens, we
backtrack one or more steps as required, to try another
alternative.

pla ce eig h t qu een s on th e ch essboa r d so th a t n o on e ca n a tta ck


a n y on e

u n g u a r ded ch essboa r d squ a r e: n ot a tta cka ble by a n y oth er


qu een

In this section, we develop a general solution to the


problem mentioned above that works not just for an 8 ×
8 chessboard, but for an arbitrary board of size n × n. In
the script nQueens (Fig. 16.5), we define the class
Queens that contains several data members and
methods for keeping track of the current chessboard
configuration, and for adding or removing a queen. The
data member board defines a chessboard of size
boardSize (lines 20 and 21). All entries of the board
are initialized as False, to indicate that initially all
positions are unguarded. The recursive function
solveFrom finds solutions to the n-queens problem.
The function receives an object configuration of class
Queens, and approaches the problem in the following
manner:

cla ss Queens: u sed to m odify a n d keep tr a ck of th e cu r r en t


ch essboa r d con fig u r a tion

n = boardSize
if Queens configuration already contains n queens

print configuration
else

for every chessboard square p that is unguarded


update the configuration by adding a queen on
square p

solveFrom(configuration)
restore the configuration to its initial state

by removing the queen from square p

ex plor in g solu tion s to n -qu een s pr oblem

The function solveFrom extends the current


configuration to an n-queens configuration (of course,
only if the present configuration is extendable to an n-
queens configuration). As mentioned before, class
Queens supports the following methods for solving the
n-queens problem:

m eth ods of cla ss Queens

1 . __init__
Th is m eth od cr ea tes a n in sta n ce of cla ss Queens a n d
in itia lizes th e da ta m em ber s boardSize, count
(n u m ber of qu een s), a n d board.
2 . getBoardSize
Th is m eth od r etu r n s th e size of th e ch ess boa r d.
3 . __str__
Th is m eth od r etu r n s str in g r epr esen ta tion of object of
ty pe Queens.
4 . unguarded
Th is m eth od r etu r n s True, if th e cu r r en t ch essboa r d
squ a r e is u n g u a r ded, a n d False oth er w ise. It ch ecks
w h eth er a qu een is g u a r din g th e cu r r en t squ a r e. A s a ll
th e r ow s of th e boa r d h a v in g r ow n u m ber g r ea ter th a n
th e r ow n u m ber of th e cu r r en t squ a r e a r e v a ca n t (n ot
y et occu pied by a qu een ), w e on ly n eed to ch eck
w h eth er a qu een in th e r ow s a bov e th e cu r r en t squ a r e
is g u a r din g th e cu r r en t squ a r e. Th is is a ccom plish ed by
ch eckin g u pper pa r ts of th e colu m n , left dia g on a l, a n d
th e r ig h t dia g on a l for th e cu r r en t squ a r e. Th is
a ppr oa ch is su m m a r ized below :

c h ec k : i s t h e c u r r ent c h essb oar d squ ar e u ngu ar ded?

if the current square is unguarded in the


upper part of the column, upper-left
diagonal, and upper-right diagonal
return True
else
return False
5 . add
Th is m eth od a dds th e qu een a t th e squ a r e position r ow
= count a n d colu m n = col. It a lso u pda tes th e cu r r en t
n u m ber of qu een s pla ced on th e ch essboa r d by
in cr em en tin g th e count by 1.
6 . remove
Th is m eth od r em ov es th e qu een fr om th e squ a r e
position r ow = count a n d colu m n = col. It a lso u pda tes
th e cu r r en t n u m ber of qu een s pla ced on th e ch essboa r d
by decr em en tin g th e count by 1 .
7 . isSolved
Th is m eth od r etu r n s True, if th e n u m ber of qu een s
a lr ea dy pla ced on th e boa r d equ a ls boardSize, a n d
False oth er w ise.

The complete program is given in Fig. 16.5.


Fig. 16.5 Pr og r a m to solv e n -Qu een s pr oblem (nQueens.py)
Execution of the script nQueens (Fig. 16.5) for 4-queens
problem yields the following chessboard configurations
resulted as the output:

Enter board size: 4

4 -Queens Problem

The board has 4 rows and 4 columns.

Solution No. 1

- Q - -

- - - Q

Q - - -

- - Q -

Solution No. 2

- - Q -

Q - - -

- - - Q

- Q - -

solu tion s to 4 qu een s pr oblem

16.3 KNIGHT'S TOUR PROBLEM

In this section, we will develop a recursive solution for


the well-known problem
2
of Knight's Tour. Given an n ×
n chessboard of n squares; in the tour, the entire board
is traversed by a knight so that each chessboard square is
visited exactly
2
once. We wish to find all such tours. Any
of the n positions on the chessboard can act as an initial
starting candidate for the tour. While traversing the
board, at any step, we need to determine whether
2
the
tour has been completed, i.e. whether all n squares have
been traversed exactly once so that the configuration is
complete. If the current configuration is not yet
complete, we determine the next sequence of possible
moves. For every possible move from the current
position, we need to explore all possible tours. As we
follow the procedure just described, it is possible that we
may get stuck on the way, as there may be a position on
board from where no further move is possible. If this
happens, we backtrack one or more steps as required, to
try another alternative.

Kn ig h t's tou r : tr a v er sin g th e en tir e ch essboa r d, w ith ou t


steppin g ov er a n y squ a r e m or e th a n on ce

Given a particular square position, a knight may move:

tw o steps v er tica lly u pw a r ds or dow n w a r ds, follow ed by


on e step r ig h t or left
tw o steps h or izon ta lly r ig h t or left, follow ed by on e step
v er tica lly u pw a r ds, or dow n w a r ds

possible m ov es for a kn ig h t

Thus, the knight may, possibly, jump to one of the eight


square positions described above. For example, in a 5 × 5
chessboard, if the knight is placed at the centre, there are
eight potential moves (Fig. 16.6). Obviously, the number
of choices for making a move is limited by a horse
position on the chessboard, for example, a horse placed
on any of the four corners of the chessboard has only
two choices.

Note that the class Knight contains several data


members and methods for keeping track of the current
chessboard configuration and carrying out moves of the
knight (Fig. 16.7). The data member board represents
the chessboard configuration of size boardSize. It
keeps track of the history of successive moves. It is
initialized with value 0 to mark all chessboard squares as
untraversed.

Fig. 16.6 Possible m ov es of a kn ig h t

possible m ov es for a kn ig h t pla ced in th e cen ter squ a r e in 5 ×


5 ch essboa r d

if board[x,y] == 0

=>> square x,y has not been visited

else if board[x,y] = i

=>> square x,y has been visited in ith


move

da ta m em ber board: keeps tr a ck of h istor y of m ov es

Function solveFrom finds solutions to Knight's Tour


problem. The function receives an object
configuration of the class Knight. The overall
approach can be summarized as follows:

for every chessboard square p denoting


starting position on the chessboard

place the knight on square p of current


configuration
determine all possible next sequences of moves
from the current square p
remove the knight from square p of the current
configuration

discov er in g Kn ig h t's tou r fr om ev er y possible ch essboa r d


position

In summary, the class Knight supports the following


methods for solving Knight's Tour problem.

m eth ods of th e cla ss Knight

1 . __init__
Th is m eth od cr ea tes a n in sta n ce of cla ss Knight a n d
in itia lizes th e da ta m em ber s boardSize, moveNum
(n u m ber of m ov es ta ken by th e kn ig h t), solNum (keeps
tr a ck of th e n u m ber of solu tion s ex plor ed), moves
(stor es a ll possible m ov es possible fr om th e cu r r en t
position ), a n d board.
2 . getBoardSize
Th is m eth od r etu r n s th e size of th e ch essboa r d.
3 . __str__
Th is m eth od r etu r n s a str in g r epr esen ta tion of th e
object of ty pe Knight.
4 . possible
Th is m eth od r etu r n s True or False depen din g on
w h eth er th e m ov e to a g iv en position in th e ch essboa r d
is possible. It w or ks in th e follow in g m a n n er :

if the position is a valid position on


chessboard i.e. x and y lie in the valid
index range [0, boardSize-1], and the current
chessboard square is not traversed before
Return True to indicate that this move is
possible
else
Return False to reject the move

i s t h e mov e t o a p osi t i on p ossi b l e?

5 . add
Th e m eth od a ssu m es th a t th e cu r r en t ch essboa r d
squ a r e h a s n ot y et been tr a v er sed by th e kn ig h t. It
pla ces th e kn ig h t a t th e g iv en ch essboa r d position by
m a r kin g it travers ed, i.e. a ssig n in g it th e cu r r en t m ov e
n u m ber a n d in cr em en tin g th e moveNum by 1 to den ote
th e n u m ber of m ov es ta ken so fa r .

t r av er se a c h essb oar d squ ar e

6 . remove
Th e m eth od a ssu m es th a t th e kn ig h t h a s tr a v er sed th e
ch essboa r d position (x ,y ). It r em ov es th e kn ig h t fr om
g iv en ch essboa r d position by m a r kin g it untravers ed
(v a lu e zer o), a n d decr em en tin g th e moveNum by 1 to
u pda te th e n u m ber of m ov es ta ken so fa r .

u ndo t h e t r av er sal of a c h essb oar d squ ar e

7 . moveFurther
Th is m eth od deter m in es n ex t sequ en ce of m ov es if th e
cu r r en t con fig u r a tion is n ot y et com plete. It w or ks in
th e follow in g m a n n er :

if a solution to Knight's tour is found


print configuration
else
for every possible candidate move p from the
current position(x,y)
place the knight on square p of the current
configuration.
try the next sequence of moves.
remove the knight from square p of current
configuration.

di sc ov er t h e nex t sequ enc e of mov es f or t h e k ni gh t

8 . isSolved
Th is m eth od deter m in es w h eth er th e cu r r en t
ch essboa r d con fig u r a tion is com plete, i.e. a ll th e
squ a r es h a v e been tr a v er sed. It w or ks in th e follow in g
m a n n er :

Determine the number of total moves in the


current chessboard configuration.
If the total number of moves equals
boardSize*boardSize
return True
else
return False

i s t h e c u r r ent c h essb oar d c onf i gu r at i on c omp l et e?


In the script knightTour (Fig. 16.7), we have
developed a generic solution to the Knight's Tour
problem, which takes chess board size as input from the
user and prints the possible solutions.
Fig. 16.7 Pr og r a m to solv e Kn ig h t's Tou r pr oblem
(knightTour.py)

On executing the script knightTour (Fig. 16.7) for a


chessboard of size 5, it generated 1728 solutions. We give
below a few chessboard configurations generated by the
script knightTour:

Enter board size: 5

The board has 5 rows and 5 columns.

Solution Number: 1
1 6 15 10 21

14 9 20 5 16

19 2 7 22 11

8 13 24 17 4

25 18 3 12 23

Solution Number: 2

1 6 11 18 21

12 17 20 5 10

7 2 15 22 19

16 13 24 9 4

25 8 3 14 23

Solution Number: 3

1 6 11 16 21

12 15 20 5 10

7 2 13 22 17

14 19 24 9 4

25 8 3 18 23

Solution Number: 4
1 6 17 12 21

16 11 20 5 18

7 2 9 22 13

10 15 24 19 4

25 8 3 14 23

Solution Number: 5

1 12 17 6 21

18 5 20 11 16

13 2 9 22 7

4 19 24 15 10

25 14 3 8 23

solu tion s to kn ig h t’s tou r pr oblem

Solution Number: 6

1 16 11 6 21

10 5 20 15 12

17 2 13 22 7

4 9 24 19 14

25 18 3 8 23

Solution Number: 7
1 18 11 6 21

10 5 20 17 12

19 2 15 22 7

4 9 24 13 16

25 14 3 8 23

Solution Number: 8

1 10 15 6 21

16 5 20 9 14

11 2 7 22 19

4 17 24 13 8

25 12 3 18 23

Solution Number: 9

1 16 5 10 21

6 11 20 15 4

19 2 17 22 9

12 7 24 3 14

25 18 13 8 23

Solution Number: 10
1 12 5 18 21

6 17 20 13 4

11 2 9 22 19

16 7 24 3 14

25 10 15 8 23

16.4 STABLE MARRIAGE PROBLEM

In this problem, we deal with two groups of equal


number of persons, one of the men and the other of
women. Each man gives his relative preference for every
woman from best to worst, and each woman gives her
relative preference for every man. Based on their
preferences, we are required to find a pairing between
men and women. Further, the pairing should be stable in
the following sense: there are no two people of the
opposite sex who would both prefer to have each other
than their current partners. For example, let M = {m1,
m2} and W = {w1, w2} be two sets of men and women,
respectively. Let us suppose m1 and m2 have an identical
list of ordered preferences of women [w1, w2], i.e. each
of them prefers w1 over w2. Further, let us suppose w1
and w2 also have an identical list of ordered preferences
of men [m1, m2], i.e. each of them prefers m1 over m2.
Next, suppose we do the following matching {{m1, w2},
{m2, w1}}. This matching is not stable because m1 and
w1 prefer each other over the partners assigned to them.
However, the matching {{m1, w1}, {m2, w2}} is stable
because there are no two persons of opposite sex that
would prefer each other over the partners assigned to
them, for example, although m2 prefers w1 over w2, but
w1 does not prefer m2 over m1.

n otion of a sta ble m a r r ia g e

The goal is to determine n pairs of <m, w> so that


each pair represents a stable marriage, i.e. there is no
pair <m, w> of persons who would prefer each other to
their assigned partners. In other words, a pair <m, w> is
considered to be stable if the following two conditions
hold:

1 . Ev er y w om en ca n dida te w h o is pr efer r ed by m a n m to
h is cu r r en t a ssig n m en t w pr efer s h er cu r r en t pa r tn er
ov er th e m a n m.
2 . Ev er y m a n ca n dida te w h o is pr efer r ed by w om a n w to
h er cu r r en t a ssig n m en t m pr efer s h is cu r r en t pa r tn er
ov er th e w om a n w.

con dition s for a pa ir <m, w>, to be sta ble

A straightforward approach is to enumerate all possible


permutations of women for the given sequential list 1 to
n of men. This simplifies the original problem to the sub-
problem of determining whether each of the n!
permutations represents a stable marriage. However,
examining all the n! permutations is a computationally
expensive task.

menPref: diction a r y for stor in g m en ’s pr efer en ces for w om en

In the following discussion, we will examine another


approach in which we will search for a match w for a
man m on the basis of his preferences. For this purpose,
we define a class StableMarriage that contains
several data members and methods for discovering the
stable pairings for the given set of n men and n women.
The data members menPref and womenPref are
dictionaries that store men's preferences for women and
women's preferences for men, respectively. For example,
for a set of three men, the dictionary menPref may be
{1:[2,1,3], 2:[3,2,1], 3:[1,3,2]}. Another
pair of dictionaries engagedMen and engagedWomen
keep a record of engaged men and engaged women
respectively at any point in time. The list freeWomen
includes women who are not yet engaged. The recursive
function findMatching discovers solutions to the
stable marriage problem. The function receives the
following arguments: an object configuration of the class
StableMarriage and the man for whom a stable
match is to be searched. The approach used in the
function may be summarized as follows:

womenPref: diction a r y for stor in g w om en ’s pr efer en ces for


m en

engagedMen a n d engagedWomen: u sed to keep tr a ck of


en g a g ed m en a n d w om en a t a n y poin t in tim e

freeWomen: list of w om en w h o a r e n ot y et en g a g ed

if a solution to stable marriage problem


is found

(Pairing is determined for all the men)

print the pairing

else

for every woman w in the ordered


preference

list of the man m in consideration

if the woman w is not engaged and


pairing is stable

engage the man m and woman w

find stable matching for the man m+1

Set free the engaged pair of man m and


woman w
discov er in g a ll solu tion s to sta ble m a r r ia g e pr oblem

Note that if for a given man m, if none of the women not


yet engaged yields a stable pairing, the control returns to
the previous call and the matching for the man m-1 is
undone to try another alternative. This backtracking
may proceed up to man m = 1. Finally, the man m would
be paired. Whenever all the men have been matched, a
stable marriage solution is printed.

ba cktr a ck if n o sta ble m a tch in g is fou n d for th e g iv en m a n m

As discussed earlier, the class StableMarriage


supports the following methods for solving Stable
Marriage problem.

m eth ods of th e cla ss StableMarriage

1 . __init__
Th is m eth od cr ea tes a n in sta n ce of cla ss
StableMarriage a n d in itia lizes th e da ta m em ber s
count, menPref, womenPref, freeWomen, engagedMen
a n d engagedWomen.
2 . __str__
Th is m eth od r etu r n s a str in g r epr esen ta tion of th e
object of ty pe StableMarriage.
3 . isStable
Th is m eth od r etu r n s True or False depen din g on
w h eth er th e pa ir in g of g iv en m a n a n d w om a n u n der
con sider a tion in dica tes a sta ble m a r r ia g e. It w or ks in
th e follow in g m a n n er :
1 . For man m, all other women candidate who
are preferred by man m to his current
assignment w, are already married and
prefer their current partners over man
m.

i s t h e gi v en p ai r <m, w> st ab l e?
2 . For woman w, all other men candidate who
are preferred by woman w to her current
assignment m, are either yet not engaged
or prefer their current partners over
woman w. (Candidate men who are not
engaged yet are not considered till
now).
4 . free
Th is m eth od sets fr ee a n en g a g ed pa ir of m a n a n d
w om a n . It a ch iev es th is by a ddin g th e g iv en w om a n to
th e list freeWomen w h o a r e n ot en g a g ed. It a lso u pda tes
diction a r ies engagedMen a n d engagedWomen to r eflect
th a t th ey a r e n o lon g er en g a g ed.

set f r ee an engaged p ai r of man and w oman

5 . engage
Th is m eth od en g a g es th e g iv en m a n a n d w om a n by
pa ir in g th em . It a ch iev es th is by r em ov in g th e g iv en
w om a n fr om th e list freeWomen. It a lso u pda tes
diction a r ies engagedMen a n d engagedWomen to r eflect
th a t th ey a r e en g a g ed.

engage t h e gi v en man and w oman b y p ai r i ng t h em

6 . findMatching
Th is m eth od fin ds sta ble m a tch in g for th e g iv en m a n .

The complete program is given in Fig. 16.8.


Fig. 16.8 Pr og r a m to solv e Sta ble Ma r r ia g e Pr oblem
(stableMarriage.py)

Below we give a sample execution of the script


stableMarriage (Fig. 16.8):

Enter number of men/women: 3

Specify men's preferences: {1:[2,1,3], 2:


[3,2,1], 3:[1,3,2]}

Specify women's preferences: {1:[2,1,3],


2:[3,2,1], 3:[1,3,2]}

Stable pairings:

{1: 2, 2: 3, 3: 1}

{1: 1, 2: 2, 3: 3}

{1: 3, 2: 1, 3: 2}

sta ble pa ir in g s

16.5 FRACTAL (HILBERT CURVE AND SIERPINSKI TRIANGLE)

Fractal is a curve or a geometric figure that repeats itself.


Such a figure comprises a recursive pattern that repeats
itself up to a desired level of nesting. In this section, we
have considered two fractals, Hilbert Curve, and
Sierpinski Triangle. Turtle graphics provided in the
turtle module is used for drawing to draw various
shapes and pictures. turtle methods used in this
section are as follows:
fr a cta l: cu r v e or a g eom etr ic fig u r e w h ich com pr ises a
r ecu r siv e pa tter n th a t r epea ts itself

turtle m odu le: pr ov ides tu r tle g r a ph ics for dr a w in g v a r iou s


sh a pes a n d pictu r es

1 . forward(): Used for m ov in g th e turtle for w a r d by a


g iv en dista n ce in th e dir ection of th e turtle.
2 . Backward(): Used for m ov in g th e turtle ba ckw a r d by
a g iv en dista n ce in th e dir ection of th e turtle.
3 . left(): Used for r ota tin g th e tu r tle in th e left dir ection
by a specified a n g le.
4 . right(): Used for r ota tin g th e tu r tle in th e r ig h t
dir ection by a specified a n g le.
5 . goto(): Used for m ov in g th e tu r tle to th e loca tion
specified (x,y coor din a tes).
6 . penup(): Used to specify n o dr a w in g w h ile m ov in g .
7 . pendown(): Used to specify dr a w in g w h ile m ov in g .
8 . fillcolor(): Used to specify th e colou r to be filled in
th e sh a pe. Colou r specified cou ld eith er be a str in g or a
tu ple (r ,g ,b).
9 . begin_fill(): Used ju st befor e dr a w in g th e sh a pe to
be filled.
1 0. end_fill(): Used to fill th e sh a pe dr a w n a fter la st ca ll
to begin_fill().
1 1 . done(): Com pletes th e tu r tle g r a ph ics w or k.

m eth ods of turtle m odu le

Let us examine the Sierpinski Triangle first. The simplest


Sierpinski triangle is a triangle subdivided into nested
equilateral triangles formed by bisecting sides of the
triangle having the central triangle removed. This results
in an outer triangle with three upward facing equilateral
triangles on top, bottom left and bottom right side with
one downward facing triangle that is removed from the
centre. Each of the triangles facing upward may further
contain three nested equilateral triangles depending
upon the level of depth. Sierpinski triangles of levels 1, 2
and 3 are shown in Fig. 16.9. Next, we describe the
approach used for drawing Sierpinski triangle:
Sier pin ski tr ia n g le: r ecu r siv e tr ia n g le su bdiv ided in to n ested
equ ila ter a l tr ia n g les

Draw an outer triangle.

If the levels of the Sierpinski curve to


be created are more than zero

Call Sierpinski curve method for each of


the nested three Sierpinski triangles.

a ppr oa ch for dr a w in g sier pin ski tr ia n g le

The nested triangles are formed by


joining the midpoints of the sides of
given equilateral triangle. The function
mid is repeatedly used for this purpose.
Fig. 16.9 Sier pin ski Tr ia n g le of Lev el 1 , 2 a n d 3

The triangle drawn as the part of the first statement in


Sierpinski triangle can be created using the following
steps:

1 . Specify th e color to be filled in th e closed object to be


cr ea ted, u sin g fillcolor m eth od.
2 . Position th e tu r tle to on e of th e en d poin ts of th e
tr ia n g le in pen -u p m ode so th a t th er e is n o dr a w in g
w h ile m ov in g .
3 . In v oke m eth od begin_fill befor e dr a w in g th e sh a pe
to be filled.
4 . A fter su ccessfu l position in g , cr ea te a tr ia n g le by
tr a v er sin g a ll its en dpoin ts in th e pen -dow n m ode.
5 . In v oke m eth od end_fill a fter dr a w in g th e sh a pe to be
filled.

Program for drawing Sierpinski triangle is given in the


script sierpinski (Fig. 16.10).
Fig. 16.10 Pr og r a m dr a w Sier pin ski Tr ia n g le (sierpinski.py)

We may also set the speed of the turtle using function


speed. Next, we develop a program for drawing Hilbert
curve. A Hilbert curve is a curve that is formed by
connecting a sequence of U-shaped curves oriented in
different directions. These U-shaped curves are placed at
a certain step size distance apart. Level 1 Hilbert curve is
a simple U-curve that is formed by moving down step
size, then moving right step size, followed by moving up
step size as shown in Fig. 16.11. Level 2 Hilbert curve is
formed by orienting level 1 Hilbert curve in different
directions and connecting them. Thus, in general, Hilbert
curve of level n can be formed by orienting the Hilbert
curve at level n − 1 in different directions and connecting
them.

Hilber t cu r v e: cu r v e for m ed by con n ectin g a sequ en ce of U-


sh a ped cu r v es or ien ted in differ en t dir ection s

Fig. 16.11 Hilber t cu r v e of Lev el 1 , 2 a n d 3

Let us examine Hilbert curve at level 1. Since turtle


initially points towards the right, the following steps will
draw a simple U curve.

1 . Mov e r ig h t step size.


2 . Mov e left step size.
3 . Mov e left step size.
steps for dr a w in g lev el 1 Hilber t cu r v e

Let y = 90 degrees. The above steps may be re-written as


follows:

1. Rota te y deg r ee tow a r ds th e r ig h t.


2. Mov e step size.
3. Rota te y deg r ee tow a r ds left.
4. Mov e step size.
5. Rota te y deg r ee tow a r ds left.
6. Mov e step size.
7. Rota te y deg r ee tow a r ds th e r ig h t.

Next, let us examine level 2 Hilbert curve. Again,


assuming that initially turtle points towards the right,
the following steps may be used to draw a level 2 Hilbert
curve:

1 . Rota te y deg r ee tow a r ds th e r ig h t.


2 . Cr ea te a Hilber t cu r v e a t lev el 1 r ota ted by –y deg r ee
(i.e. y deg r ee in a n ticlockw ise dir ection ).
3 . Mov e step size.
4 . Rota te y deg r ee tow a r ds th e left.
5 . Cr ea te a Hilber t cu r v e a t lev el 1 r ota ted by y deg r ee
(i.e. y deg r ee in clockw ise dir ection ).
6 . Mov e step size.
7 . Cr ea te a Hilber t cu r v e a t lev el 1 r ota ted by y deg r ee
(i.e. y deg r ee in clockw ise dir ection ).
8 . Rota te y deg r ee tow a r ds th e left.
9 . Mov e step size.
1 0. Cr ea te a Hilber t cu r v e a t lev el 1 r ota ted by −y deg r ee
(i.e. y deg r ee in a n ticlockw ise dir ection ).
1 1 . Rota te y deg r ee tow a r ds th e r ig h t.

steps for dr a w in g lev el 2 Hilber t cu r v e

Thus, Hilbert curve of any level n greater than zero with


given degree y can be drawn using the following steps:

1 . Rota te y deg r ee tow a r ds th e r ig h t.


2 . Cr ea te a Hilber t cu r v e a t lev el n − 1 r ota ted by –y
deg r ee (i.e. y deg r ee in a n ticlockw ise dir ection ).
3 . Mov e step size.
4 . Rota te y deg r ee tow a r ds th e left.
5 . Cr ea te a Hilber t cu r v e a t lev el n − 1 r ota ted by y deg r ee
(i.e. y deg r ee in clockw ise dir ection ).
6 . Mov e step size.
7 . Cr ea te a Hilber t cu r v e a t lev el n − 1 r ota ted by y deg r ee
(i.e. y deg r ee in clockw ise dir ection )
8 . Rota te y deg r ee tow a r ds th e left.
9 . Mov e step size.
1 0. Cr ea te a Hilber t cu r v e a t lev el n − 1 r ota ted by −y
deg r ee (i.e. y deg r ee in a n ticlockw ise dir ection ).
1 1 . Rota te y deg r ee tow a r ds th e r ig h t.

steps for dr a w in g lev el n Hilber t cu r v e

Program for drawing Hilbert curve is given in Fig. 16.12.


Fig. 16.12 Pr og r a m dr a w Hilber t cu r v e (hilbert.py)

16.6 SUDOKU

A Sudoku puzzle comprises a 9 × 9 grid divided into nine


blocks of size 3 × 3. Each of the blocks contains digits
from 1 to 9 without repetition as shown in Fig. 16.13.
The same constraint is applicable on every row and
column. In a Sudoku problem, a partially filled 9 × 9
grid is given, and the challenge is to find the missing
numbers while ensuring that all the constraints are
satisfied. Apart from the Sudoku, which we just
mentioned, there are other variants of differing grid size,
alphabetical Sudoku, hyper sudoku, etc. However, in this
section, we will develop a recursive approach for solving
the common Sudoku having grid size 9 × 9:

ch a llen g e: a ssig n dig its 1 to 9 w ith ou t r epetition in ea ch of


th e blocks of size 3 × 3 w ith in th e 9 × 9 g r id
n o v a lu e is a llow ed to r epea t in a n y r ow or colu m n

Fig. 16.13 Su doku g r id

The simplest way to represent a 9 × 9 grid is in the form


of a nested list. We will use the value 0 to represent a
missing value, yet to be determined. The problem can be
solved by searching for the target locations with missing
values, one by one, so long as the search is not
exhausted. For every target location, we will find all such
solutions x that do not violate any of the constraints, i.e.
a number not repeated in the row, column, or block
containing the target location. For every currently
determined solution, the search will proceed by calling
the function for solving Sudoku recursively. Approach
for determining a solution to Sudoku is mentioned
below:

0 : den otes a m issin g v a lu e, y et to be deter m in ed


if the sudoku is solved, i.e. there are no
zeroes in the grid lst,

print the solution.

else,

find a target index (i,j) on the grid


with value 0.

# To find values that cannot be used in

# target index (i,j) in current solution

Create set excludeNums to store elements


to be excluded.

for every position containing non-zero


value in the grid

if the position lies in the same row,


column, or the block containing target
index

add the value at that position to


excludeNums set

# For discovering a solution

for every number in possible number list


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

if number is not in excludeNums set:

Place number at index (i,j)

Call sudokuSolver with current partial


solution lst.

Replace number at index (i,j) by 0.


Program for solving sudoku is given in Fig. 16.14.
Fig. 16.14 Pr og r a m for solv in g su doku (sudoku.py)

On executing the script sudoku (Fig. 16.14) with the


following input,
Enter the list (0 for missing values):
[[5, 3, 0, 0, 7, 0, 0, 0, 0], [6, 0, 0, 1,
9, 5, 0, 0, 0], [0, 9, 8, 0, 0, 0, 0, 6,
0], [8, 0, 0, 0, 6, 0, 0, 0, 3], [4, 0, 0,
8, 0, 3, 0, 0, 1], [7, 0, 0, 0, 2, 0, 0,
0, 6], [0, 6, 0, 0, 0, 0, 2, 8, 0], [0, 0,
0, 4, 1, 9, 0, 0, 5], [0, 0, 0, 0, 8, 0,
0, 7, 9]]

Python responded with the following solution:

Solution:

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

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

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

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

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

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

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

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

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

su doku solu tion s for th e g iv en g r id v a lu es

16.7 GUIDELINES ON USING RECURSION

Recursion is an important programming tool. But the


unnecessary use of recursion makes the programs
inefficient. However, we would like to point out that in
special cases of recursion like tail recursion that occurs at
the tail of the function (no code occurring after the
recursive call), an optimizing compiler would replace the
recursive call by an iterative code.

r ecu r sion m a y lea d to in efficien cy

SUMMARY

1 . Wr a pper fu n ction is th e fu n ction n eeded to do som e


h ou sekeepin g .
2 . Eig h t-qu een s pr oblem : pla ce eig h t qu een s on th e
ch essboa r d so th a t n on e ca n a tta ch ea ch oth er . A qu een
is a tta cka ble if a n oth er qu een lies in th e sa m e r ow ,
sa m e colu m n , or sa m e dia g on a l (eith er dir ection ).
3 . Kn ig h t's Tou r : tr a v er se th e en tir e ch essboa r d, w ith ou t
steppin g ov er a n y squ a r e m or e th a n on ce.
4 . Sta ble Ma r r ia g e pr oblem : We a r e g iv en tw o g r ou ps of
equ a l n u m ber of per son s, on e of th e m en a n d th e oth er
of w om en . Ea ch m a n g iv es h is r ela tiv e pr efer en ce for
ev er y w om a n fr om best to w or st, a n d ea ch w om a n
g iv es h er r ela tiv e pr efer en ce for ev er y m a n . Ba sed on
th eir pr efer en ces, w e a r e r equ ir ed to fin d a pa ir in g
betw een m en a n d w om en . Th e pa ir in g sh ou ld be sta ble
in th e follow in g sen se: th er e a r e n o tw o people of
opposite sex w h o w ou ld both pr efer to h a v e ea ch oth er
th a n th eir cu r r en t pa r tn er s.
5 . A fr a cta l is a cu r v e or a g eom etr ic fig u r e th a t r epea ts
itself. Su ch a fig u r e com pr ises a r ecu r siv e pa tter n th a t
r epea ts itself u p to a desir ed lev el of n estin g .
6 . Th e sim plest Sier pin ski tr ia n g le is a tr ia n g le
su bdiv ided in to n ested equ ila ter a l tr ia n g les for m ed by
bisectin g sides of th e tr ia n g le h a v in g th e tr ia n g le a t
th e cen ter r em ov ed. Th is r esu lts in a n ou ter tr ia n g le
w ith th r ee u pw a r d fa cin g equ ila ter a l tr ia n g les on top,
bottom left a n d bottom r ig h t side w ith on e dow n w a r d
fa cin g tr ia n g le th a t is r em ov ed fr om th e cen tr e. Ea ch
of th e tr ia n g les fa cin g u pw a r d m a y fu r th er con ta in
th r ee n ested equ ila ter a l tr ia n g les depen din g u pon th e
lev el of depth .
7 . A Hilber t cu r v e is a cu r v e th a t is for m ed by con n ectin g
a sequ en ce of U-sh a ped cu r v es or ien ted in differ en t
dir ection s. Th ese U-sh a ped cu r v es a r e pla ced a t a
cer ta in step size dista n ce a pa r t. Lev el 1 Hilber t cu r v e is
a sim ple U-cu r v e th a t is for m ed by m ov in g dow n a
dista n ce step size, th en m ov in g r ig h t a dista n ce step
size, a n d fin a lly m ov in g u p a dista n ce step size. Lev el 2
Hilber t cu r v e is for m ed by or ien tin g lev el 1 Hilber t
cu r v e in differ en t dir ection s a n d con n ectin g th em .
Th u s, in g en er a l, Hilber t cu r v e of lev el n ca n be for m ed
by or ien tin g th e Hilber t cu r v e a t lev el n − 1 in differ en t
dir ection s a n d con n ectin g th em .
8 . A Su doku pu zzle com pr ises a 9 × 9 g r id div ided in to
n in e blocks of size 3 × 3 . Ea ch of th e blocks sh ou ld
con ta in dig its fr om 1 to 9 w ith ou t r epetition . Th e sa m e
con str a in t is a pplica ble on ev er y r ow a n d colu m n .
Giv en a pa r tia lly filled 9 × 9 g r id, th e ch a llen g e is to
fin d th e m issin g n u m ber s w h ile en su r in g th a t a ll th e
con str a in ts a r e sa tisfied.

EXERCISES

1 . Wr ite a g en er a lized v er sion of Su doku pr oblem .


2 . Wr ite a pr og r a m th a t ta kes a n u m ber n a s a n in pu t
a n d pr in ts pa sca l tr ia n g le com pr isin g fir st n r ow s. For
ex a m ple, for n = 5 , follow in g ou tpu t sh ou ld be
displa y ed:

1 1

1 2 1

1 3 3 1

1 4 6 4 1

3 . Wr ite a r ecu r siv e fu n ction for Tu g of w a r pr oblem . Th e


fu n ction sh ou ld ta ke a list of n in teg er s a n d sh ou ld
div ide th e elem en ts in to tw o lists of n/2 sizes so th a t th e
a bsolu te differ en ce betw een th e su m of elem en ts of th e
tw o lists is th e m in im u m possible.
4 . Wr ite a r ecu r siv e fu n ction th a t dr a w s or der n Koch
fr a cta l cu r v e (Fig . 1 6 .1 5 ).

F ig . 16.15 Koc h f r ac t al c u r v e

5 . Wr ite a pr og r a m to solv e Sta ble Ma tch in g Pr oblem .


Giv en , n (ev en ) in div idu a ls a n d th eir or der ed
pr efer en ce list for th eir r oom pa r tn er , th e pr oblem is to
div ide th em in to n/2 sta ble pa ir s ba sed on th eir
pr efer en ces. Fu r th er , th e pa ir in g sh ou ld be sta ble in
th e follow in g sen se: th er e a r e n o tw o per son s (n ot
for m in g a pa ir ) both of w h om w ou ld pr efer ea ch oth er
th a n th eir cu r r en t pa r tn er s.
6 . Wr ite a pr og r a m th a t ta kes a m a tr ix (list of lists) of 0’s
a n d 1 ’s a s a n in pu t fr om th e u ser a n d in v okes a
r ecu r siv e fu n ction w h ich r etu r n s th e m a x im u m
len g th of con n ected cells h a v in g v a lu e 1 . Th e tw o cells
a r e sa id to be con n ected if th ey a r e a dja cen t to ea ch
oth er , h or izon ta lly , v er tica lly , or dia g on a lly .
CHAPTER 17
GRAPHICS

CHAPTER OUTLINE
1 7 .1 2 D Gr a ph ics

1 7 .2 3 D Gr a ph ics

1 7 .3 A n im a tion – Bou n cin g Ba ll

So far, we have developed programs, which produce


output in the form of text content. However, there is a
famous saying, ‘A picture is worth a thousand words.’ In
this chapter, we shall study, how to visualize the input
data and the results produced by a program, in the form
of graphs, pie-charts, histograms, and 3D plots. We will
also see the effectiveness of animation in
communication. Python supports 2D and 3D graphics,
and animations in the form of various packages and
libraries like Matplotlib, PyQtGraph (Scientific Graphics
and GUI Library for Python), VisPy (2D/3D
visualization library), OpenGL (library for 2D and 3D
graphics), turtle, plotly (2D and 3D graphics library),
VisPy, Biggles (2D scientific plotting package), and
VPython (3D and animation). In this chapter, we use
the standard library matplotlib for 2D graphics and the
visual library of VPython for 3D graphics and animation.

g r a ph ics a n d a n im a tion : u sed for v isu a liza tion

17.1 2D GRAPHICS

Two-dimensional graphical objects include point, line,


circle, rectangle, oval, polygon, and text. Python library
matplotlib provides several methods that facilitate
drawing these objects. To be more specific, the library
supports graphs, histograms, bar charts, pie charts,
scatter plots, error charts, etc. A graphics library, suited
to a particular hardware and operating system, may be
downloaded from
http://matplotlib.org/downloads.html. The graphics
libraries typically have a few required dependencies,
which include setuptools, numpy, dateutil, pyparsing,
six, and pytz
(http://matplotlib.org/users/installing.html). For
windows, we may directly install these dependencies
using the following command at command prompt:

pip install numpy python-dateutil pytz


pyparsing six setuptools

If python fails to recognize the pip command, it can be


downloaded from https://bootstrap.pypa.io/get-pip.py
and installed on the machine by pressing the keys
WINDOWS R, and executing the following commands:

cmd

python get-pip.py

Alternatively, the downloaded file get-pip.py may


directly be executed in Python IDLE. Also, the
environment path (system variable) should be updated
to include C:\Users\
<user_name>\AppData\Local\Programs\Python\
Python36-32\Scripts.

The module matplotlib can be downloaded and


installed by pressing the keys WINDOWS R, and
executing the following commands:

cmd

pip install matplotlib

in sta llin g m odu le matplotlib


In this chapter, we make use of pyplot module of
matplotlib, which contains several functions for
plotting figures and modifying or setting various
properties such as labels for the figure and layout of the
plot area. To be able to use graphics, we need to import
matplotlib.pyplot module in the current shell
environment. Another important module of
matplotlib that serves the same purpose as pyplot is
pylab.

pyplot m odu le: con ta in s fu n ction s for plottin g fig u r es a n d


settin g v a r iou s pr oper ties

17.1.1 Point and Line

Suppose we wish to draw a single point, say, (3, 2) on


the graph. For this purpose, we use the function
plot(x,y) that takes two arguments x and y as
coordinates (on x-axis and y-axis respectively) of the
point to be plotted on the graph. The following sequence
of commands will display the point (Fig. 17.1):

import matplotlib.pyplot as plt

plt.plot(3, 2)

plt.show()

plottin g a poin t

The function show is used for displaying the figure. Once


the function show is executed, the system waits for us to
have a look at the graph, and execution of other
instructions is blocked until the graphical window is
closed. Hence, the function show is called a blocking
function. When we wish to continue the execution of
other statements, without closing the window manually,
we specify block = False as an argument while
invoking the function show. Note that the first line
introduces plt as an alternative name of the module
matplotlib.pyplot.

show(): to displa y a fig u r e

Note that the point shown in Fig. 17.1 is hardly visible.


The use of color and style comes in handy in such
situations. Table 17.1 and Table 17.2 show a few choices
for color and style.

Fig. 17.1 Fu n ction plot(3, 2) to displa y poin t (3, 2) (see pa g e


5 8 3 for th e colou r im a g e)
T a bl e 17.1 Color

ch oices for color


T a bl e 17.2 Poin t sty le

ch oices for m a r ker sty le

Let us plot the point (3, 2) as a circular red-colored


point (Fig. 17.2) as follows:

plt.plot(3, 2, 'ro')

plottin g a cir cu la r r edcolor ed poin t


The third argument (format string) is a string that
describes a combination of point style and color, which
may appear in any order. Thus, above call to function
plot may also be written as:

plt.plot(3, 2, 'or')

in ter a ctiv e bu tton s on th e bottom pa n el for m a n ipu la tin g


cu r r en t v iew of th e fig u r e

Fig. 17.2 Poin t (3 , 2 ) (see pa g e 5 8 3 for th e colou r im a g e)

Note that Fig. 17.2 has several interactive buttons on the


bottom panel that help in manipulating the current view
of the figure. The first button is called the home button
and is used to reset original view of the figure. The
fourth button is used for controlling the axis by panning
the axis with the left button of mouse and zooming with
the right button of the mouse. We may also zoom in the
rectangular portion of the current view of the figure
using the fifth button. In the case of multiple sub-plots,
we may configure them with the sixth button. At any
point in time, we may revert to previous view or next
view using second and third button respectively. The
seventh button is used for saving the figure in the desired
directory.

At times, we may be interested in plotting several


points on the graph. For example, suppose we wish to
plot five points: (2,3), (4,5), (6,7), (8,9),
(10,11). We construct two lists: x and y — the list
x comprising x-coordinates of all the points, and the list
y comprising y-coordinates of the corresponding points.
As each point comprises an x-coordinate and a y-
coordinate, both lists have the same length. Now we are
ready to call the plot function with arguments x, y,
and 'ro'. The resulting graph is shown in Fig. 17.3.

import matplotlib.pyplot as plt

x = [2, 4, 6, 8, 10]

y = [3, 5, 7, 9, 11]

plt.plot(x,y, 'ro')

plt.show()

plottin g sev er a l poin ts on th e g r a ph


Fig. 17.3 Mu ltiple poin ts (see pa g e 5 8 3 for th e colou r im a g e)

Often, we are interested in plotting a line connecting a


list of points. Indeed, the plot function can be used
again for this purpose. When we skip the third argument
entirely, or just skip the shape of the points to be plotted
as part of the third argument, by default, Python joins
the points based on input lists x and y, by line segments,
as shown below:

plt.plot(x, y)

plottin g a lin e con n ectin g coor din a tes of poin ts specified a s


lists
On execution of the above instruction, a line joining the
points determined by lists x and y is displayed.

Fig. 17.4 Lin e join in g poin ts specified by v ector x a n d y (see pa g e


5 8 3 for th e colou r im a g e)

Note that the system displays a solid line in blue color.


These are default options for line style and color. Thus,
default format string is 'b-'. We may choose any of the
four line styles that appear in Table 17.3. Color options
have already been described in Table 17.1.

by defa u lt, th e lin e is plotted a s a solid lin e in blu e color

defa u lt for m a t str in g : 'b-'


T a bl e 17.3 Lin e sty le

ch oices for lin e sty le

Next, we display a line comprising dashes and asterisks


(in red color) (Fig. 17.5).

x = [2, 4, 6, 8, 10]

y = [3, 5, 7, 9, 11]

plt.plot(x, y, 'r*--')

plt.show()

plottin g a lin e com pr isin g da sh es a n d a ster isks (in r ed color )


Fig. 17.5 Da sh ed lin e join in g poin ts (sta r m a r ker ) specified by
v ector x and y (see pa g e 5 8 3 for th e colou r im a g e)

In general, the plot function may be specified as follows:

plot (x, y, LineSpecification)

sy n ta x of plot fu n ction

Note that if only one list is specified as an argument to


plot function, it assumes x-list to be values in the
range(0, len(y)). For example, in Fig. 17.6, we show
the output on invoking the function plot(y):

plt.plot(y)

The function plot supports several properties that may


be set as per the user preferences such as
markerfacecolor, markersize (decimal value),
markeredgecolor, markeredgewidth (decimal
value), linestyle and linewidth (decimal value).
For example, to set the width of the line as 2.2 and size
of the marker as 10.5, we use the following call to plot
function (Fig. 17.7):

Fig. 17.6 Solid lin e join in g poin ts defin ed by v ector s [0, 1 , 2 , 3 , 4 ]


a n d y (see pa g e 5 8 3 for th e colou r im a g e)

plt.plot(x, y, 'r*--', markersize = 10.5,


linewidth = 2.2)

settin g markersize a n d linewidth of th e lin e


Fig. 17.7 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e
5 8 4 for th e colou r im a g e)

Axis, Title, and Label

In the above examples, given lists, x and y, the system


determined the plot area, sufficient for the output graph.
However, the use of axis function enables us to specify
the plot area explicitly through use of the axis
parameters xmin, xmax, ymin, and ymax:

specify in g plot a r ea a x is pa r a m eter s

axis ([xmin, xmax, ymin, ymax])

For example, we redraw Fig. 17.7 by setting the axis


parameters (Fig. 17.8):
x = [2, 4, 6, 8, 10]

y = [3, 5, 7, 9, 11]

plt.plot(x, y, 'r*--', markersize = 10.5,


linewidth = 2.2)

plt.axis([1, 11, 2, 12])

plt.show()

Fig. 17.8 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e


5 8 4 for th e colou r im a g e)

To make the graph easy to understand, we label the axes


and assign a title to the graph. Functions xlabel,
ylabel, and title may be used for this purpose, as
illustrated below:
plt.xlabel('X')

plt.ylabel('X * X')

plt.title('X vs X * X')

specify in g x a n d y la bels

s pecifying figure title la bels

The appearance of a grid in the background makes it


easy to read the coordinates of the points in a graph. To
display a grid, we need to invoke the function grid (Fig.
17.9):

plt.grid()

displa y in g a g r id

Plotting Multiple Functions in the Same Figure

Sometimes, we wish to plot graphs of two or more


functions in the same figure. For example, we may like
to compare two graphs. For this purpose, we may make
repeated calls to plot function as illustrated below:

plot (X1, Y1, LineSpec1)

plot (X2, Y2, LineSpec2)

plot (Xn, Yn, LineSpecn)


Fig. 17.9 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e
5 8 4 for th e colou r im a g e)

Alternatively, several functions may be plotted using a


single call to plot function as shown below:

plot (X1, Y1, LineSpec1, X2, Y2, LineSpec2,


…, Xn, Yn, LineSpecn)

sy n ta x for plottin g m u ltiple fu n ction s in th e sa m e g r a ph

2 3
For example, let us plot functions f(x) = x and f(x) = x
in the same figure in the interval [a,b] in steps of
step. When we display more than one graph in the
same figure, we need a mechanism to distinguish
between them. For this purpose, we make use of
different colors, width, and style, or a combination of
these as illustrated in the function plotFunctions
(Fig. 17.10). In the script plotLines1, we have chosen
colors red and blue for plotting the functions x**2 and
x**3 respectively. Legends associated with different plot
functions are specified using the keyword label while
invoking the plot function (lines 13 and 14). Finally, we
invoke function legend for displaying the legends for
the two functions being plotted (line 15).

key w or d label is u sed for specify in g leg en d


2 3
Fig. 17.10 Pr og r a m to plot fu n ction s f(x) = x a n d f(x) = x on th e
g r a ph (plotLines1.py)

legend(): for displa y in g th e leg en ds

On executing the script plotLines1 (Fig. 17.10), the


user is asked to enter the range parameters and the step
size:
Enter first element of the range: 2.5

Enter last element of the range: 4.5

Enter step size: 0.1

On entering the range parameters 2.5 and 4.5, Python


responds with Fig. 17.11.

Multiple Plots

Suppose we wish to plot several functions, each in a


separate graph, but in the same figure. The function
subplot described below may be used for this purpose.

subplot(): plottin g in su b-g r a ph s

sy n ta x for fu n ction subplot

subplot(rowNum, colNum, FigNum)


2 3
Fig. 17.11 Fu n ction s f(x) = x a n d f(x) = x plotted in th e in ter v a l
[2 .5 , 4 .5 ] in steps of 0.1 (see pa g e 5 8 4 for th e colou r im a g e)

The function takes three arguments, the number of


rows, the number of columns, and the figure number.
Instead of a comma-separated sequence of parameters,
we may specify an ordered sequence of these values, for
example, we may use either of the function calls
subplot(1, 2, 1) and subplot(121). In the script
plotLines2 (Fig. 2
17.12), we3 plot six functions
4
f(x) =
x,
5
f(x) = x , f(x)
6
= x , f(x) = x , f(x) =
x , and f(x) = x as six different graphs (two rows and
three columns) but in the same figure (Fig. 17.13). Note
that the call to the function plot in line 20 plots the
graph in the subplot mentioned in line 19. On executing
the script plotLines2 (Fig. 17.12), Python prompts the
user to enter the list x to be plotted:
Fig. 17.12 Pr og r a m to plot six fu n ction s on differ en t su bg r a ph s in
th e sa m e fig u r e (plotLines2.py)

Enter list x to be plotted: range(1,15)

On providing the input range(1,15), Python outputs


Fig. 17.13. All the list sequences that are provided to
functions of matlplotlib.pyplot are internally
converted to numpy arrays (homogeneous
multidimensional arrays). Also, to add sufficient spacing
between subplots so that they do not overlap, function
tight_layout has been invoked in line 61.

tight_layout(): to a dd su fficien t spa cin g betw een su bplots

Saving Figure
2
Suppose, we wish to plot a graph between x and x , and
save it in a file for future reference, thus, avoiding the
need to re-run the code every time such a figure is
needed. To save a graph in the current directory, we use
the function savefig, for example,

savefig(): to sa v e a g r a ph in th e cu r r en t dir ector y

x = range(0,5)

y = [i**2 for i in x]

plt.plot(x, y, label = 'X vs X**2')

plt.savefig('xSquare')
Fig. 17.13 Six fu n ction s plotted on differ en t su bg r a ph s in sa m e
fig u r e (see pa g e 5 8 5 for th e colou r im a g e)
17.1.2 Histogram and Pi Chart

A histogram is used to represent the frequency of various


values in a data set using bars, also known as bins. The
function hist is used for plotting the histogram for a
given data set as illustrated in the script histogram
(Fig. 17.14). In line 13, we define the limits of x-axis
using the function xlim. Next, we execute the script
histogram (Fig. 17.14) and Python outputs a
histogram (Fig. 17.15) for the list
[1,1,4,4,1,2,2,3,3,3,4,4,4,6]:

hist(): to plot h istog r a m for a g iv en da ta set

xlim(): to defin e th e lim its of x -a x is

Enter data to be plotted as histogram:


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

By default, the method hist assumes the maximum


number of bins to be 10. If we wish to have more than
10 bins, we need to set the number of bins to the desired
value explicitly, say n, using keyword argument bins =
n along with input data. Also, as the bins of the
histogram are not centred around values (Fig. 17.15), we
may prefer to specify the range (boundaries) for each bin
of the histogram. For example, the following statement
defines the bins with boundaries 0.5, 1.5, 2.5, 3.5, 4.5,
5.5, and 6.5 which creates six bins as [0.5,1.5), [1.5,2.5),
[2.5,3.5), [3.5,4.5), [4.5,5.5), and [5.5,6.5].
Fig. 17.14 Pr og r a m to plot h istog r a m (histogram.py)

Fig. 17.15 Histog r a m (see pa g e 5 8 5 for th e colou r im a g e)

plt.hist(data,bins = [i-0.5 for i in \

range(0,max(data)+2)])

u se of key w or d a r g u m en t bins for specify in g bin bou n da r ies

On replacing line 8 by the above statement in the script


histogram (Fig. 17.15), we get the desired histogram
(Fig. 17.16).
Fig. 17.16 Histog r a m (see pa g e 5 8 5 for th e colou r im a g e)

A pie chart is a circular representation of data under


different categories. A circle is divided into sectors, also
called wedges. A sector denotes the proportion of data
that falls in the corresponding category. The function
pie is used for creating a pie chart for the given
sequence of data. The function pie requires two
arguments: a sequence X of numeric values and a
sequence of labels to be assigned to the wedges (Fig.
17.17). For plotting the pie chart; the function computes
the proportion of each data value x of the sequence X as
x/sum(X). Sometimes, we need to display the percent
area covered by each wedge. For this purpose, we use the
argument autopct. In the script piechart (Fig.
17.17), we have set formatted percentage string to
contain two digits after the decimal point.
pie(): to cr ea te a pie ch a r t for th e g iv en sequ en ce of da ta
n ode

autopct: key w or d a r g u m en t to specify th e per cen t a r ea


cov er ed by ea ch w edg e

On executing the script piechart (Fig. 17.17),


Python prompted with following inputs and displayed pie
chart as shown in Fig. 17.18.
Fig. 17.17 Pr og r a m to plot pie-ch a r t (piechart.py)

Fig. 17.18 Pie ch a r t (see pa g e 5 8 6 for th e colou r im a g e)

Enter data to be plotted as pie chart:


[30, 40, 90, 50]

Enter the labels: ['VolleyBall', 'Hockey',


'Cricket', 'Badminton']

17.1.3 Sine and Cosine Curves


In this section, we develop two functions sineCurve
and cosineCurve to plot sine and cosine curve in the
range 0° to 360° (Fig. 17.19). We determine sine values
in the range 0° to 360° using sine function of math
module. The sine values so obtained are then plotted
using plot function (sineCurve). The cosine values
are plotted similarly in the function cosineCurve. The
curves obtained on executing the script curve are
shown in Fig.17.20.

plottin g sin e a n d cosin e cu r v es


Fig. 17.19 Pr og r a m to plot sin e a n d cosin e cu r v e (curve.py)
Fig. 17.20 Sin e a n d cosin e cu r v e (see pa g e 5 8 6 for th e colou r
im a g e)

17.1.4 Graphical Objects: Circle, Ellipse, Rectangle, Polygon,


and Arrow

To support the classes such as Rectangle, Circle,


Ellipse, RegularPolygon, Polygon,
CirclePolygon, Rectangle, Arrow, and
FancyArrow, matplotlib library provides patches
module. Consequently, the graphical shapes such as
rectangle, circle, ellipse, regular polygon, polygon, circle
polygon, rectangle, arrow, and fancy arrow are called
patches. All these classes are sub-classes of the class
Patch which further inherits from the class Artist of
the module artist.

patches: th e m odu le pr ov ides su ppor t for g r a ph ica l objects

Drawing a graphical object requires creating the object


of a particular shape and adding that patch to the
current figure’s axis using the function add_patch. We
can obtain current figure’s axis using the function gca
(get current axis). When the axis is set to 'scaled', the
system chooses a suitable scale for displaying the figure.

In Table 17.4, we describe some of the properties of


the graphical objects that they inherit from class Patch.
These properties can be set to suitable values for
improving the visual effectiveness of a figure.
T a bl e 17.4 Patch cla ss pr oper ties

pr oper ties of Patch cla ss

Circle

Creating an instance of the class Circle requires a tuple


(x, y) denoting the centre of the circle and an optional
value for the parameter radius (default 5). Further, we
may set different properties of the class Patch while
instantiating the class Circle. In the script circle
(Fig. 17.21), we draw a circle on the plot area. The circle
is centred at (0, 0) and has the user-specified radius.
Further, facecolor, edgecolor, linestyle, and
linewidth have been set to green, red, dotted, and
2.2, respectively.

Circle: th e cla ss u sed to plot a cir cle

defa u lt v a lu e of r a diu s: 5
Fig. 17.21 Pr og r a m to dr a w a cir cle (circle.py)

On executing the script circle (Fig. 17.21), Python


prompts the user to enter the radius and displays circle
(Fig. 17.22).

Enter the radius: 4


Fig. 17.22 Cir cle (see pa g e 5 8 6 for th e colou r im a g e)

Ellipse

Creating an instance of the Ellipse class takes width


and height as the required attributes and an optional
value for the parameter angle (default 0.0) denoting
rotation in degrees (anti-clockwise). As usual, we may
set different properties of the class Patch while
instantiating the class Ellipse. In the script ellipse
(Fig. 17.23), we draw an ellipse on the plot area. The
ellipse is centred at (0, 0) and has user-specified width
and height. Further, fc, ec, linestyle, and lw
have been set to cyan, red, dashed, and 2.2,
respectively.

Ellipse: th e cla ss u sed to plot a n ellipse


Fig. 17.23 Pr og r a m to dr a w a n ellipse (ellipse.py)

On executing the script ellipse (Fig. 17.23), Python


prompts the user to enter the width and the height. On
entering values 5 and 3 for width and height,
respectively, an ellipse is displayed (Fig. 17.24).

Enter the width: 5

Enter the height: 3

Fig. 17.24 Ellipse (see pa g e 5 8 6 for th e colou r im a g e)

Rectangle

For creating an instance of Rectangle class, we specify


width and height as the required attributes. We may also
specify the optional parameter angle (default 0.0)
denoting rotation in degrees (anti-clockwise). In the
script rectangle (Fig. 17.25), we draw a rectangle on
the plot area. The rectangle is centred at (0, 0) with
user-specified length and breadth. As usual, we set
some of the properties of the class Patch while
instantiating the class Rectangle. Default values are
used for other properties.

Rectangle: th e cla ss u sed to plot a r ecta n g le


Fig. 17.25 Pr og r a m to dr a w a r ecta n g le (rectangle.py)

On executing the script rectangle (Fig. 17.25), and


entering 6 and 3 as the values of length and breadth,
respectively, a rectangle is displayed (Fig. 17.26).

Enter the length: 6

Enter the breadth: 3

Fig. 17.26 Recta n g le (see pa g e 5 8 7 for th e colou r im a g e)

Polygon

Creating an instance of Polygon class requires a list


(vector) of points. Each point in the list denotes one of
the endpoints of the line segments of the polygon. As
usual, we may set different properties of the class Patch
while instantiating the class Polygon. In the script
polygon (Fig. 17.27), we draw a polygon on the plot
area that joins the user-specified points having ec,
linestyle, and lw set to red, dashdot, and 4,
respectively.

Polygon: th e cla ss u sed to plot a poly g on

On executing the script polygon (Fig. 17.27), Python


prompts the user to enter the list of endpoints of a
polygon. On entering the input [[2.5,4], [2,6],
[4,8], [6,6], [5.5,4]], a polygon is displayed
(Fig. 17.28).

Enter the points: [[2.5,4], [2,6], [4,8],


[6,6], [5.5,4]]
Fig. 17.27 Pr og r a m to dr a w a poly g on (polygon.py)

Fig. 17.28 Poly g on (see pa g e 5 8 7 for th e colou r im a g e)

Arrow

Creating an instance of Arrow class requires attributes


x, y, dx, and dy. Whereas (x, y) denotes the
starting point (base) of the arrow, and (dx, dy) defines
the the position of the head of the arrow relative to its
base. As usual, we may set different properties of the
class Patch while instantiating the class Arrow. In the
script arrow (Fig. 17.29), we draw an arrow that begins
from a user specified position (x, y) having
coordinates of head of the arrow as (x + dx, y +
dy). We set the fill property to False so that the
arrow is not filled with any color. Also, we set the hatch
property to value 'O' so that the arrow is filled with Os.
Arrow: th e cla ss u sed to plot a n a r r ow
Fig. 17.29 Pr og r a m to dr a w a n a r r ow (arrow.py)

On executing the script arrow (Fig. 17.29), Python


prompts the user to enter the specifications for a polygon
and displays it (Fig. 17.30).

Enter the starting position (x,y): (1,2)

Enter the dx: -1

Enter the dy: 3


Fig. 17.30 A r r ow

17.2 3D OBJECTS

The visual module of Visual Python supports 3D


graphics and animation. It may be downloaded from
vpython.org. Since Python 3 does not support
VPython6 (latest version till date), we will be using older
version 5.74 of VPython. Also, note that Vpython version
5.74 is supported with Python 3.2.2, thus, if you wish to
use 3D objects, you may need to install Python 3.2.2
before installing VPython version 5.74.

When we click on the icon VIDLE for VPython, 3D


graphics and animation functionality becomes available
to us. Module visual of VPython contains several classes
such box, sphere, cone, cylinder, arrow, ring,
pyramid, ellipsoid, and helix which facilitate us
to draw various 3D graphical objects. All these classes
inherit from the class py_renderable. In Table 17.5,
we list some important attributes used in 3D graphics.
We may set these attributes of the py_renderable
class while instantiating the classes box, sphere, cone,
cylinder, arrow, ring, pyramid, ellipsoid, and
helix.

visual: th e m odu le u sed to cr ea te 3 D g r a ph ics a n d


a n im a tion

cla sses cor r espon din g to 3 D objects in h er it fr om


py_renderable

T a bl e 17.5 py_renderable cla ss a ttr ibu tes

Box

A box may be drawn by creating an instance of class


box. While creating an instance of box class, we may
specify attributes listed in Table 17.6.

box: th e cla ss u sed to cr ea te a box


T a bl e 17.6 box cla ss a ttr ibu tes

a ttr ibu tes of cla ss box


A box, green in color, having length 7, height 4, breadth
5, and opacity 0.25 may be drawn on the plot area by
invoking class box as follows:

from visual import *

box(size = (7,4,5), color = color.green,


opacity = 0.25)

The box is shown in Fig. 17.31.

Sphere

A sphere may be drawn by creating an instance of the


class sphere as shown below:

sphere()

sphere: th e cla ss u sed to cr ea te a sph er e


Fig. 17.31 Box (see pa g e 5 8 7 for th e colou r im a g e)
Fig. 17.32 Sph er e (see pa g e 5 8 7 for th e colou r im a g e)

While creating an instance of the sphere class, we may


specify attributes listed in Table 17.7.

T a bl e 17.7 sphere cla ss a ttr ibu tes


a ttr ibu tes of cla ss sphere

We may set various attributes of the py_renderable


class while instantiating the class sphere. The following
sequence of statements draws a sphere on the plot area
(Fig. 17.32):

from visual import *

sphere(pos=(0,0,0), radius = 0.6, color =


\

color.cyan, opacity = 0.75, material = \

materials.rough)

Ring

A ring can be drawn by creating an instance of the class


ring. While creating an instance of ring class, we may
specify attributes listed in Table 17.8.

ring: th e cla ss u sed to dr a w a r in g


T a bl e 17.8 ring cla ss a ttr ibu tes

a ttr ibu tes of th e cla ss ring

We may also set various attributes of the


py_renderable class while instantiating the class
ring. The following sequence of statements draws a
ring on the plot area (Fig. 17.33).
from visual import *

ring(axis=(0.5,0,0.9), radius=0.5,\

thickness=0.15)

Fig. 17.33 Rin g (see pa g e 5 8 7 for th e colou r im a g e)

Cylinder

Graphical object cylinder can be drawn by creating an


instance of the class cylinder. While creating an
instance of cylinder class, we may specify attributes
listed in Table 17.9.

cylinder: th e cla ss u sed to dr a w a cy lin der


T a bl e 17.9 cylinder cla ss a ttr ibu tes

a ttr ibu tes of th e cla ss cylinder

We may also set various attributes of the


py_renderable class while instantiating the class
cylinder. The following instantiation of class
cylinder yields a cylinder on the plot area (Fig. 17.34).
from visual import *

cylinder(pos=(-2,2,1), axis=(5,0,5),
radius=2)

Fig. 17.34 Cy lin der (see pa g e 5 8 7 for th e colou r im a g e)

Arrow

An arrow can be drawn by creating an instance of the


class arrow. While creating an instance of arrow class,
we may specify attributes listed in Table 17.10.

arrow: th e cla ss u sed to dr a w a n a r r ow


T a bl e 17.10 arrow cla ss a ttr ibu tes

a ttr ibu tes of th e cla ss arrow

We may also set various attributes of the


py_renderable class while instantiating the class
arrow. The following sequence of statement draws an
arrow on the plot area (Fig. 17.35):

from visual import *

arrow(pos = (-3,0,0), axis = (5,2,0),\

shaftwidth=0.5, color = color.yellow,\

up = (0,10,20))

Fig. 17.35 A r r ow (see pa g e 5 8 8 for th e colou r im a g e)

Cone

A cone can be drawn by creating an instance of the


class cone. While creating an instance of cone class, we
may specify attributes listed in Table 17.11.

cone: th e cla ss u sed to dr a w a con e


T a bl e 17.11 cone cla ss a ttr ibu tes

a ttr ibu tes of th e cla ss cone

We may also set various attributes of the


py_renderable class while instantiating the class
cone. The following sequence of statement draws a cone
on the plot area (Fig. 17.36):

from visual import *

cone(pos=(0,-2,0), axis=(0,4,0),radius=2)
Fig. 17.36 Con e (see pa g e 5 8 8 for th e colou r im a g e)

Curve

An object curve can be drawn by creating an instance of


the class curve. While creating an instance of curve
class, we may specify attributes listed in Table 17.12.

curve: th e cla ss u sed to dr a w a cu r v e


T a bl e 17.12 curve cla ss a ttr ibu tes

a ttr ibu tes of th e cla ss curve

We may also set various attributes of the


py_renderable class while instantiating the class
curve. The following sequence of statements yields a
curve on the plot area (Fig. 17.37):

from visual import *

curve(pos=[(-2,-2,0),(-2,0,1),(0,0,0),
(3,0,0),\

(2,1,0), (3,4,2)], radius=0.05)


Fig. 17.37 Cu r v e (see pa g e 5 8 8 for th e colou r im a g e)

17.3 ANIMATION – BOUNCING BALL

The animation is a continuous sequence of graphics,


often termed frames, that are played back to back with
respect to time. In the script bouncingBall (Fig.
17.38), we create an animation of a bouncing ball as
shown in snapshots (Fig. 17.39).

a n im a tion : con tin u ou s sequ en ce of g r a ph ics

In lines 2 and 4 (Fig. 17.38), we create a base ground


using a box object and a ball using sphere object and
define their attributes. The center point of the visual
display window is positioned at (0, 5, 5) (lines 6). The
ball is projected with an initial velocity 10 unit/sec in the
direction of y-axis, and the coefficient of restitution is 0.9
(line 7 and 8). Change in time dt is set to 0.01 sec (line
9). The while loop produces a bouncing ball animation.
Function rate defines a maximum number of loops per
second. The position of the bouncing ball in each
iteration is updated using current velocity and time. If
the current position of the ball is less than the radius of
the ball, it touches the floor. In this case, the velocity of
the ball is negated changing the direction of motion and
its position is set to coordinates (0,1,0). Also, velocity is
updated using the formula v = u + a*t. Note that
bouncing ball animation lasts until the position of the
ball becomes static i.e. there is no change in the position
of the ball in successive iterations (line 17). Also, we may
set the visual display window to full-screen by using the
following command immediately after importing the
module visual:

rate(): m a x im u m n u m ber of loops per secon d

u pda te v elocity w h en ev er ba ll ch a n g es its dir ection

scene.fullscreen = True
Fig. 17.38 Pr og r a m to cr ea te a bou n cin g ba ll
(bouncingBall.py)
Fig. 17.39 Sn a psh ots of bou n cin g ba ll (see pa g e 5 8 8 for th e colou r
im a g e)

SUMMARY

1 . Py th on libr a r y matplotlib pr ov ides sev er a l m eth ods


th a t fa cilita te u s to dr a w g r a ph ica l objects in clu din g
poin t, lin e, cir cle, r ecta n g le, ov a l, a n d poly g on . Th e
libr a r y a lso su ppor ts objects like g r a ph s, h istog r a m s,
ba r ch a r ts, pie ch a r ts, sca tter plots, a n d er r or ch a r ts.
2 . pyplot m odu le of matplotlib con ta in s sev er a l
fu n ction s for plottin g , a n d m odify in g or settin g v a r iou s
pr oper ties su ch a s th e la y ou t of th e plot a r ea , la bels,
a n d a ttr ibu tes of th e fig u r e.
3 . Th e fu n ction plot of pyplot m odu le m a y u sed for
plottin g a s follow s:
plot (x, y, LineSpecification)
4 . Th e fu n ction show of pyplot m odu le is u sed for
displa y in g th e fig u r e.
5 . Th e fu n ction axis of pyplot m odu le is u sed for settin g
a x is pa r a m eter s xmin, xmax, ymin a n d ymax.
6 . Th e fu n ction s title, xlabel, a n d ylabel of pyplot
m odu le a r e u sed for settin g title a n d la bellin g a x es.
7 . Th e fu n ction subplot of pyplot m odu le is u sed for
plottin g sev er a l fu n ction s, ea ch in a sepa r a te g r a ph ,
bu t in th e sa m e fig u r e. Th e fu n ction ta kes th r ee
a r g u m en ts, th e n u m ber of r ow s, th e n u m ber of
colu m n s, a n d th e fig u r e n u m ber .
8 . Th e fu n ction savefig of pyplot m odu le is u sed to sa v e
a g r a ph .
9 . Th e fu n ction hist of pyplot m odu le is u sed for plottin g
a h istog r a m for th e g iv en da ta set.
1 0. Th e fu n ction pie of pyplot m odu le is u sed for cr ea tin g
a pie ch a r t for a g iv en sequ en ce of da ta .
1 1 . In matplotlib ter m in olog y , th e g r a ph ica l sh a pes su ch
a s a cir cle, r ecta n g le, poly g on , a n d ellipse a r e kn ow n a s
pa tch es. Th e m odu le patch su ppor ts cla sses su ch a s
Rectangle, Circle, Ellipse, RegularPolygon,
Polygon, CirclePolygon, Rectangle, Arrow, a n d
FancyArrow.
1 2 . V isu a l Py th on h a s visual m odu le th a t su ppor ts 3 D
g r a ph ics a n d a n im a tion . It con ta in s sev er a l cla sses
su ch box, sphere, cone, cylinder, arrow, ring,
pyramid, ellipsoid, a n d helix th a t fa cilita te u s to
dr a w v a r iou s 3 D g r a ph ica l objects.

EXERCISES

1 . Wr ite a pr og r a m th a t plots g r a ph s cor r espon din g to th e


follow in g equ a tion s by ta kin g su ita ble lists a s a n in pu t
fr om th e u2ser :
1 . y = 3 x + 4 x + 2 (y v s. x)
2 . v = u + at (v v s. t)
3 . F = ma (F v s. m)
2 . Wr ite a pr og r a m th a t plots th e follow in g fu n ction s in
th e r a n g e 0° to 3 6 0° in th e sa m e fig u r e:
1 . ta n
2 . cot
3 . sec
4 . cosec
3 . Wr ite a pr og r a m th a t illu str a tes su per position of tw o
w a v es of th e sa m e a m plitu de.
4 . Wr ite a pr og r a m th a t sh ow s th e m ov in g ca r .
5 . Wr ite a pr og r a m th a t sh ow s th e m otion of a r ocket.
CHAPTER 18
APPLICATIONS OF PHYTHON

CHAPTER OUTLINE
1 8 .1 Collectin g In for m a tion fr om Tw itter

1 8 .2 Sh a r in g Da ta Usin g Sockets

1 8 .3 Ma n a g in g Da ta ba se Usin g Str u ctu r ed Qu er y La n g u a g e

1 8 .4 Dev elopin g Mobile A pplica tion for A n dr oid

1 8 .5 In teg r a tin g Ja v a w ith Py th on

1 8 .6 Py th on Ch a t A pplica tion Usin g Kiv y a n d Socket


Pr og r a m m in g

Python is rapidly evolving as one of the most powerful


and preferred programming choice amongst the
developers. The extensive third party support has made
Python a viable option in almost every application area
such as handling twitter data, web access, database
management, and mobile app development. In this
chapter, we briefly cover the above-mentioned
application areas. As a lot of application code is
developed in Java, we also discuss, how Python code can
be integrated with Java code seamlessly.

Py th on h a s em er g ed a s a pr efer r ed ch oice for pr og r a m m in g


in a lm ost ev er y a pplica tion a r ea

18.1 COLLECTING INFORMATION FROM TWITTER

Often we are interested to know the current trend, i.e., to


find the ongoing activity about an event, place, or
person. Twitter is one such source of information about
almost everything happening in the world. Indeed,
Twitter has emerged as a popular social networking site,
and people use it to air their views and increase their
awareness. Because of the millions of active users
sharing the latest updates, a lot of interesting data can be
collected from Twitter. Twitter can also be used to
retrieve information about the tweets, connections, or
followers of a user, or topics trending on Twitter.

Tw itter : a r ich sou r ce of u p-to da te in for m a tion

Information is shared on Twitter in the form of


tweets. A tweet may contain photos, videos, links, and up
to 140 characters of text. A tweet may be published on
Twitter by registered users. However, all the users,
whether registered or unregistered can read the tweets.
Tweets are of two types, namely, public tweets and
private tweets. Public tweets are the tweets visible to
anyone accessing Twitter, whereas private tweets can be
seen by permitted Twitter followers. Twitter provides
several APIs (Application Programming Interfaces) to
access Twitter data such as user’s profile information or
tweets posted. These APIs are mainly categorized as
Streaming and REST APIs. While streaming APIs
provide a continuous stream of data in real time from
Twitter server, REST APIs are used for retrieving data
using a query to the Twitter server.

pu blic tw eets: ca n be a ccessed by a n y on e

pr iv a te tw eets: ca n be a ccessed on ly by a u th or ized follow er s

Tw itter A PIs a r e u sed for a ccessin g tw itter da ta in a scr ipt


In this section, we will build a simple crawler that
searches and collects Twitter data in real time. So we will
be using streaming APIs. An API request on Twitter is
first authenticated using Open Authentication (OAuth).
OAuth allows the users to connect to Twitter and send
authorized Twitter API request. Every registered
application (consumer) of Twitter is assigned a
Consumer Key (API Key) and Consumer Secret ( API
Secret) using which the applications can authenticate
themselves. Twitter verifies the user’s identity and
assigns PIN (OAuth verifier) that will be required by the
application to request Access Token and Access Secret to
be used in an application for invoking API calls. The
Access Token and Access Secret pair uniquely identify a
user.

OA u th : u sed to a u th en tica te A PI r equ est

For Open Authentication, we need to follow the steps


given in Fig. 18.1.

For performing analysis on Twitter data, we need the


package tweepy. It may be downloaded using the
following cmd command on windows:

Tw itter da ta a n a ly sis r equ ir es im por tin g tweepy pa cka g e

pip install tweepy


Fig. 18.1 Open a u th en tica tion sequ en ce

If system fails to recognize pip command, it can be


downloaded from https://bootstrap.pypa.io/get-pip.py,
and installed using the following commands from
command line interface:

cd <pathname of the directory containing

get-pip.py>

python get-pip.py

in sta llin g pip

Alternatively, we may open and execute the script get-


pip.py from Python IDLE. Also, the environment path
for system variable should be updated to include
C:\Python27\Scripts.

Open Authentication

Accessing Twitter data requires open authentication of


the application. In the script TwitterOAuth (Fig. 18.2),
we aim at authorizing a Python application to access
Twitter. The function OAuthVerifier is used for doing
so. It first initializes the variables consumerKey,
consumerSecret, accessToken, and accessSecret
(lines 9, 10, 12, and 13). Execution of line 11 creates an
OAuthHandler object for using API key and API secret.
The accessToken and accessSecret are set for this
object using the method set_access_token. The
authentication handler, that we just obtained, can be
passed as a parameter to class API of the tweepy
module (a wrapper for API as provided by Twitter). An
object of this class (api) can be used for retrieving user
information such as his/her followers, friends, and
tweets.

a n object of cla ss OAuthHandler is u sed to in sta n tia te th e cla ss


API
Fig. 18.2 Open A u th (TwitterOAuth.py)

Note that the keys used in the program are only for
illustration purpose; however, the user is expected to
generate the keys himself and replace them
appropriately in the given code.

An Example – Collecting User Information

Often, we are interested in retrieving user statistics such


as name, id, location, description, friends and followers
count, and posted tweets. To retrieve such user statistics,
we require an associated user object. In the script
TwitterUserInfo1 (Fig. 18.3), we retrieve
information about an authenticated user and a user
whose id or screen name (@handle) is known. For
example, the user Sachin Tendulkar has @sachin_rt as
screen name with associated id 135421739.

r etr iev in g u ser sta tistics


Fig. 18.3 User in for m a tion (TwitterUserInfo1.py)

The user method me (line 32) of the api returns


authenticated user information. Another user method
get_user returns information about the particular
user, whose id/screen name is taken as input in line 35.
We define a function getUserStatistics for
accessing and printing the user information. Table 18.1
lists variables associated with user object that may be
accessed for information.

T a bl e 18.1 V a r ia bles a ssocia ted w ith u ser object

On executing the script TwitterUserInfo1 (Fig. 18.3),


Python responds with the following output:

>>>

Name: Suzzane Mathew

Screen Name: SuzzaneMathew

ID: 727494459118653446
Account creation date and time: 2016-05-03
13:46:10

Location: India

Description: A Python Programmer

No. of followers: 3

No. of friends: 34

No. of favorite tweets: 0

No. of posted tweets: 3

Associated URL: None

sta tistics of a n a u th en tica ted u ser

Enter the user identification: @sachin_rt

Name: sachin tendulkar

Screen Name: sachin_rt

ID: 135421739

Account creation date and time: 2010-04-21


07:42:23

Location: ÜT: 18.986431,72.823769

Description: Proud Indian

No. of followers: 15690592

No. of friends: 79

No. of favourite tweets: 39

No. of posted tweets: 1519

Associated url: http://t.co/TCNcUDBwuE


sta tistics of th e u ser w ith scr een n a m e @ sachin_rt

Collecting Followers, Friends, and Tweets of a User

Now we develop a program that discovers followers,


friends, and tweets of a user. For a given user, the
methods followers, friends, and user_timeline
return information about followers, friends, and public
tweets, respectively (Fig. 18.4).
Fig. 18.4 Fr ien ds, follow er s, a n d tw eets of a u ser
(TwitterUserInfo2.py)

On executing the script TwitterUserInfo2 (Fig.


18.4), Python responds with the following output:

>>>

Followers:

PeaceAlwaysPARI

ikindlebook

gauravparashari

follow er s
Friends:

gvanrossum

iamsrk_sharukh

DataSciFact

CompSciFact

Delhi_U

htTweets

ndtv

timesofindia

EconomicTimes

msdhoni

BeingSalmanKhan

SrBachchan

imVkohli

sachin_rt

PythonHub

PythonStack

pycoders

pythoncoders

djangoproject

ThePSF
fr ien ds

Tweets:

RT @gvanrossum: The very first


https://t.co/2j12YXhlJD home page, from
May 1997: https://t.co/KwtE7rjX9P

RT @gvanrossum: MicroPython 1.7 released!


Now with cross-compiler.
https://t.co/gWq50gVEwk Congrats Damien
and contributors!

Hello Twitter! #myfirstTweet

tw eets

If the number of friends, followers, or tweets exceeds 20,


only first 20 results are displayed. These 20 results
correspond to the first page returned by these methods.
However, if all possible results are required to be shown,
the method items of the object of type Cursor of the
module tweepy can be used (Fig. 18.5).

items(): r etu r n s a n iter a ble object com pr isin g desir ed


n u m ber of sea r ch r esu lts
Fig. 18.5 Fr ien ds, follow er s, a n d tw eets of a u ser
(TwitterUserInfo3.py)

While invoking the method items(), integer argument


limit can be used to restrict the number of results to be
displayed.

Collecting Tweets Having Specific Words


Often, we wish to collect some specific tweets streaming
in real time. The data collected may be further used for
analysis. We use Twitter Streaming API for downloading
Twitter messages in high volume in real time. Python
class StreamListener is used for collecting streaming
tweets. In this section, we define a class
MyStreamListener that inherits the class
StreamListener of the tweepy module. In the class
MyStreamListener, we define two methods:
on_status and on_error. The method on_status
tells what to do when a status (input parameter)
known as tweet update is received. The overridden
method on_status receives the data from the method
on_data of the class StreamListener. The method
on_error handles the error and gets automatically
invoked on occurrence of an error. As shown in the
script KeyTweets (Fig. 18.6), the method handles error
420 and disconnects the stream by returning False
when error 420 occurs. This error occurs if the number
of user attempts to connect to streaming API exceeds a
particular limit.

StreamListener: a cla ss for collectin g str ea m in g tw eets

Suppose, we are interested in tweets containing the


word Python. The execution of the script KeyTweets
(Fig. 18.6) outputs streaming data containing the
keyword Python. It first authorizes the application to
access Twitter using the function OAuthVerifier (line
37). It then creates a stream listener instance
listenerOb of class MyStreamListener (line 39).
The class Stream of module tweepy is then used for
creating a Stream object myStream, which takes two
parameters: auth – an attribute of api and
listenerOb – a stream listener object (line 41). It
establishes a streaming session and routes all the tweets
to the object listenerOb. For streaming all tweets
containing the word Python, we make use of the stream
object method filter, which takes a list parameter
track containing the search keywords for the stream
(line 44).

Stream: a cla ss u sed to cr ea te a str ea m object


Fig. 18.6 Tw eets h a v in g specific w or ds (KeyTweets.py)

On executing the script KeyTweets (Fig. 18.6), Python


prompts the user for input and on providing the input
['Python'], responds with the following output:

>>>

Enter search keywords list: ['Python']

I liked a @YouTube video


https://t.co/cLNOpZTD3b Monty Python -
Execution in Russia (funny sketch!)
RT @rogerhoward: Sublime still feels near
perfect for Python; VSCode definitely
better for JS. Hate the thought of using
both.

RT @dbader_org: Writing a little GUI


helper tool for macOS with Python—Nice
"scratch your own itch with Python"
article: https://t.co/yKTI1…

If you're looking for work in MO, check


out this #job: https://t.co/iuSMypbtOc
#Python #Relocate #NYC…
https://t.co/EMLMnedNgU

RT @fmasanori: "Dev-ia C em Python". Nome


de equipe na maratona de programação. Como
os alunos são criativos.

1-2-6 are my top three


https://t.co/zLmfaaPI3s

RT @KirkDBorne: #DeepLearning Cheat Sheet


(using Keras + #Python Libraries)
https://t.co/QIivKejlNt #abdsc #BigData
#DataScience….

tw eets for th e sea r ch key w or d: Python

18.2 SHARING DATA USING SOCKETS

Often two processes need to communicate with each


other for sharing data. These processes may reside either
on the same machine or on different machines
connected to a network. The two processes involved in
this interprocess communication are typically the client
and the server applications. The client application
requests data and the server application responds by
fulfilling the request. The client-server architecture
allows two remote entities to communicate. For this
purpose, HTTP is often used in Internet applications as
shown in Fig. 18.7.

sh a r in g da ta a cr oss a pplica tion s: pr ocesses n eed to


com m u n ica te w ith ea ch oth er

Fig. 18.7 Web a pplica tion a r ch itectu r e

client - server a r ch itectu r e

clien t: r equ ests da ta ser v er : r espon ds by fu lfillin g th e r equ est

Interprocess communication can be achieved using


one or more of the several available options such as file,
signal, socket, shared memory, pipe, and message. In
this section, we will learn interprocess communication
via use of socket programming using Python. For the
purpose of smooth communication, the communicating
processes need a protocol that defines the rules for
communication between the client and the server. The
network architecture mainly uses TCP/IP (Transmission
Control Protocol/Internet Protocol) for communication.

socket: u sed for in ter pr ocess com m u n ica tion

Suppose, process A (say, client) needs to communicate


with process B (say, server). In order to communicate,
the client and the server need to make a connection
between themselves. A socket defines the client and the
server as the end points of such a connection. A socket
works much like communication over the telephone.
The two parties that wish to communicate with each
other have telephone handsets at the end points. For
communication to take place, one party needs to dial up
a connection, and the other party must be available to
attend the phone call. In the client-server environment,
each of the client and the server would require a socket.
A socket is uniquely identified by a pair of IP address and
port number. IP address is the machine’s network
address, which uniquely identifies every machine on the
network. Port number determines the
service/application (e.g., FTP, email service) on the
server that should respond to the request. For example, a
server with an IP address may have several applications,
each with a unique port number for handling request
related to email, news, file transfer, remote login, and so
on. Since the client initiates the connection and the
server responds to it, a socket pair for communication is
identified by client IP address, client port number, server
IP address, and server port number.

a socket is u n iqu ely iden tified by a pa ir of IP a ddr ess a n d por t


n u m ber
Client-Server Communication on the Same Machine – A
Simple Example

Python has a library that provides support for TCP/IP


sockets. It offers two socket modules – socket and
socketserver. While the former provides low-level
networking interface, the latter provides support in the
form of classes for developing network server
applications. In this chapter, we will focus on basic
networking services. So, we will use the socket module.
The socket module provides the class socket for
creating a socket object.

mySock = socket.socket(socket_family,
socket_type,protocol=0)

cr ea tin g a socket object u sin g socket cla ss of socket m odu le

The first two parameters specify the domain, i.e.,


family of the protocol, such as AF_INET, AF_INET6,
and AF_UNIX, and the type of socket to be created such
as stream socket (SOCK_STREAM) for connection-
oriented protocol and datagram socket (SOCK_DGRAM)
for the connectionless protocol. The third parameter is a
default parameter, which specifies a particular variant of
protocol within given domain and socket type. The
socket object mySock created above is a unique socket
identifier which is used for communicating with other
process.

A stream socket is a connection in which data is sent


as a stream of bytes in an ordered manner. In this
section, we create a socket using SOCK_STREAM. For
simplicity, we create a socket object of the class socket
without specifying any parameters, thus using the
default parameters AF_INET as domain and
SOCK_STREAM as the type of socket.

SOCK_STREAM: u sed to cr ea te a str ea m socket


Before we proceed further, it is important to
understand the methods associated with a socket object.
These methods are categorized as server, client, and
general socket methods. We describe these methods in
Tables 18.2, 18.3, and 18.4 respectively.

T a bl e 18.2 Ser v er socket m eth ods a ssocia ted w ith socket object
mySock

T a bl e 18.3 Clien t socket m eth ods a ssocia ted w ith socket object
mySock
T a bl e 18.4 Gen er a l socket m eth ods

Let us suppose that each of the client and the server


has a socket created at its end. To communicate with
each other, the client and the server must go through a
sequence of steps:

1 . SERV ER: On cr ea tin g th e socket, th e ser v er m u st bin d


it to th e pa r ticu la r por t n u m ber on th e loca l a ddr ess,
specify in g th e a pplica tion th a t w ill listen to th e
in com in g clien t r equ ests. Th e m eth od bind of th e
socket cla ss ta kes a tu ple com pr isin g loca l a ddr ess a s
th e fir st pa r a m eter , a n d por t n u m ber a s th e secon d
pa r a m eter . Her e, h ostn a m e a n d IP a ddr ess a r e u sed a s
a lia ses. Sin ce a ll por ts below 1 02 4 a r e r eser v ed, w e
m a y u se a por t n u m ber betw een 1 02 5 a n d 6 5 5 3 5 ,
both in clu ded. We m a y iden tify th e por ts a lr ea dy in
u se by ex ecu tin g th e com m a n d (a t com m a n d pr om pt):
netstat –a.

bind(): b i nds a soc k et t o a p or t nu mb er on l oc al addr ess

2 . SERV ER: On ce th e ser v er is bou n d to a socket, it m u st


be r ea dy to ser v ice r equ ests fr om th e clien t. Th e ser v er
listen s for in com in g con n ection s fr om th e clien ts u sin g
th e m eth od listen. Th is m eth od ta kes the maximum
number of connections allow ed to be queued a s th e in pu t
pa r a m eter .

listen(): l i st ens f or i nc omi ng c onnec t i ons f r om t h e c l i ent on t h e


soc k et
3 . SERV ER: Th e ser v er w a its in a loop in defin itely u n til
th e clien t con n ects to th e por t to w h ich ser v er h a s
bou n d itself. Wh ile listen in g on th e socket, if a
con n ection r equ est fr om a clien t a r r iv es, th e ser v er
n eeds to a ccept it. Th e m eth od accept g ets th e pen din g
con n ection fr om th e con n ection qu eu e, a n d r etu r n s (i)
th e socket object for th e clien t to be u sed for da ta
tr a n sfer (ii) th e a ddr ess of th e clien t (destin a tion IP
a ddr ess a n d por t n u m ber ).

accept(): get s p endi ng c onnec t i ons f r om t h e c onnec t i on qu eu e

4 . CLIENT : On ce th e socket is cr ea ted a t th e clien t en d,


w e m a y u se it to esta blish th e con n ection betw een th e
clien t (ou r Py th on pr og r a m ) a n d th e a pplica tion
r u n n in g on th e ser v er by specify in g th e h ost n a m e a n d
th e por t n u m ber . Th e m eth od connect of th e socket
m odu le is u sed for th is pu r pose. It r equ ir es a tu ple
com pr isin g th e n a m e of th e h ost a n d th e destin a tion
por t n u m ber listen in g to a clien t r equ est.

connect(): u sed t o c onnec t t o t h e h ost

5 . Now th e clien t a n d th e ser v er m a y ex ch a n g e th e da ta


u sin g send a n d recv m eth ods. Sin ce th e clien t a n d
ser v er ca n u n der sta n d a bytes -like object, w e u se
encode fu n ction to cov er t a str in g in to bytes object. By
defa u lt, encode fu n ction u ses u tf-8 en codin g sch em e.
Su bsequ en tly , th e en coded bytes object is con v er ted to
a str in g u sin g decode fu n ction .

send() and recv(): t o send and r ec ei v e b y t es-l i k e ob jec t t o and


f r om t h e soc k et

6 . Fin a lly , th e clien t a n d th e ser v er close th e socket u sin g


th e close m eth od.

close(): c l oses t h e soc k et

The order in which these socket methods should be


invoked by client and server is illustrated in Fig. 18.8. In
Figs. 18.9 and 18.10, we give the scripts for the server
and the client respectively. Before the client can request
the server, the server must be listening for the incoming
request by the client. The server and client both create a
socket object. The server binds local address, and unused
port 65535 to it using the method bind, and waits for
single incoming connection by executing the method
listen. It then accepts the pending connection using
the method accept and responds with the encoded
version of the string 'Thank you for connecting
client' on that connection. The client, on the other
hand, connects to the destination host and the port using
connect method. Since, in our case, we are running the
two processes on the same machine, the destination host
will be same as the source host. It receives the data on
the connected socket using recv method. Both the client
and the server close the socket using the close method.

or der of ex ecu tion of socket m eth ods


Fig. 18.8 Or der of ex ecu tion of socket m eth ods
Fig. 18.9 Clien t (client.py)

Fig. 18.10 Ser v er (server.py)

On executing the server program,

F:\PythonCode\Ch18>python server.py

Python responds with the following output on the client


side:

ser v er m u st be listen in g to r equ ests befor e a clien t ca n


con n ect to it
F:\PythonCode\Ch18>python client.py

Thank you for connecting client


('192.168.56.1', 64203)

F:\PythonCode\Ch18>

Note that an unused port is randomly chosen for the


client process.

An Echo Server

Next, we develop an echo application, in which the


server program (Fig. 18.12) echoes the data sent by a
client application (Fig. 18.11) running on a different
system. So, in this case, the client invokes send method
to send the data to the server. Subsequently, the server
receives the data using recv method. The data received
is echoed back to the client using send method. The
client then receives it using recv method. The procedure
continues as long as client provides the input data to be
sent to echo server. Since the client and the server reside
on two different systems in the network, client and
server host names will be different.

ech o ser v er : ech oes th e da ta sen t by a clien t


Fig. 18.11 Ech o clien t (clientEcho.py)

Fig. 18.12 Ech o ser v er (serverEcho.py)

In this example, we have considered two applications


that reside on machines connected to the same WiFi
hotspot, each having its unique IP address. The IP
address of a machine can be determined using
ipconfig command. IP address assigned to Wireless
LAN adapter of the server machine is required in each of
the server and client programs. On executing the server
program,

F:\PythonCode\Ch18>python serverEcho.py

Python responds with the following output on the client


side:

F:\PythonCode\Ch18>python clientEcho.py

Enter data to be sent: Hello

Hello

Enter data to be sent: I love Python

I love Python

Enter data to be sent: I am connected to


echo server

I am connected to echo server

Enter data to be sent:

F:\PythonCode\Ch18>

ou tpu t on ex ecu tin g scr ipt clientEcho

Accessing Web Data (Downloading a Pdf File)

Many times, we need to access documents on the web.


For example, we may need to download a text or a pdf
file. Using socket programming, we can write an
application that connects to the server on the web and
retrieves the content of the file. Communication over the
Internet often uses the most common protocol –
Hypertext Transfer Protocol (HTTP). The port number
used for HTTP connection is 80. For accessing data over
the Internet (say, contents of a page), the user needs to
send a GET request. A GET request needs to specify the
following pieces of information: url of the page,
protocol for communication and its version
(protocol/version), and a blank line (thus, double
newline).

GET url protocol/version \n\n

GET r equ est for a ccessin g da ta ov er th e In ter n et

Suppose we need to download the Python manual


containing python tutorial by Guido Van Rossum from
website of University of Idaho. For this purpose, we need
to connect to Idaho server (listening to requests) having
hostname marvin.cs.uidaho.edu at port 80 (HTTP
port). Together, the hostname and the port number
define a socket. Also, we need to send GET request to the
server for the pdf file with the url

h ttp://m a r v in .cs.u ida h o.edu /Tea ch in g /CS5 1 5 /py th on Tu tor ia l.p


df

The data received from this socket can be written to


another pdf file on the system. The data will be received
and written to the file as long as the entire content of the
file is not transferred (Fig. 18.13). Note that we open the
new file PythonGuidoVanRossum.pdf in 'wb' (write,
binary) mode (line 10) since pdf files are binary files.

pdf files sh ou ld be open ed in bin a r y m ode


Fig. 18.13 Dow n loa d pdf file (pdfDownload.py)

Python library urllib.request simplifies the task of


manually creating a socket, connecting to a server, and
sending and receiving data using the socket library.
The library treats a web page as a file. It provides the
method urlopen for specifying the web page to be
accessed. The function returns a file-like object unless
there is an error in connecting to the server, in which
case it returns IOError. The script
pdfDownloadUrllib (Fig. 18.14) can be used to
download a pdf file using the urllib library. The
method urlopen returns a file-like object which is an
iterator. We have used writelines to write
fileContent to file PythonGuidoVanRossum.pdf.
Alternatively, for loop could have been used to iterate
over fileContent and write the content to pdf file line
by line.

urllib: m odu le for a ccessin g da ta ov er w eb

Fig. 18.14 Dow n loa d pdf file (pdfDownloadUrllib.py)

18.3 MANAGING DATABASES USING STRUCTURED QUERY LANGUAGE (SQL)

In almost every field, be it, business, railways,


healthcare, education, or defense, we have been dealing
with data, indeed much before computers were invented.
Such data is required to be stored and managed and to
be accessed. Since any decision making by an
organization is highly dependent on the timely
availability of information, the need was felt for a system
which could store and facilitate management of all
related data. Database Management System (DBMS)
helps in storing the collection of related data in the
database and managing it through application
programs. Structured Query Language (SQL) is widely
used for database creation and management. Several
popular database systems such as Oracle, MySQL,
Microsoft SQL Server, and SQLite exist, however, in this
section, we will be using SQLite database already
integrated with Python.

DBMS: h elps in stor in g a n d m a n a g in g r ela ted da ta

SQL: la n g u a g e for da ta ba se cr ea tion a n d m a n a g em en t

18.3.1 Database Concepts

Suppose we wish to store information about a College.


Let us name the database for the college as COLLEGE. It
may need to store information about students such as
roll number, name, and percentage. A real-world object
such as STUDENT, about whom the data is to be stored in
the database is known as an entity, and the
characteristics of this entity such as roll number, name,
and percentage are called attributes. The database
COLLEGE may store information about several entities
such as Students, Teachers, Courses, and Departments in
the form of tables. A two-dimensional table of rows and
columns in the database is called a relation.

en tity : r ea l-w or ld object a bou t w h ich da ta is to be stor ed

a ttr ibu tes: ch a r a cter istics of en tity

r ela tion : tw o-dim en sion a l ta ble of r ow s a n d colu m n s


T a bl e 18.5 Rela tion STUDENT

Examine the relation STUDENT (Table 18.5). Each


column of the table denotes a unique attribute, for
example, RollNum, Name, and Percentage. Each row
in the table stores information about all the attributes of
an entity and is known as a tuple. The number of
attributes in a relation is known as the degree of the
relation. The collection of rows in a relation is called
entity set of a relation. The number of rows in the entity
set of a relation defines cardinality of the relation.
Each column attribute is of a particular type such as
numeric type or character type. All the values in a
column must conform to a predefined data type. For
example, the attributes RollNum and Percentage are
numeric, and the attribute Name is of string type. Each
row in a table is uniquely identified by an attribute or a
combination of attributes called key. Therefore, no two
tuples should have the same key. For example, the value
of attribute RollNum of relation STUDENT is unique for
each row, and thus, it is a key. If the value of an
attribute is unknown for a tuple, a special value called
NULL (no value indicator) should be used.

tu ple: a r ow in a r ela tion


deg r ee: n u m ber of a ttr ibu tes in a r ela tion

ca r din a lity : n u m ber of tu ples in a r ela tion

key : a ttr ibu te(s) th a t u n iqu ely iden tify tu ples in a r ela tion

Structured Query Language (SQL) is a relational


database language. It is used for creation and
manipulation of the database. It is a high-level language
that allows users to specify what is required to be done in
the form of queries, without the need to specify the
procedure: how it is to be done. SQL is a widely used
database language and has numerous advantages.

SQL is a r ela tion a l da ta ba se la n g u a g e

Based on the functionality, SQL operations are


organized into two categories, namely, Data Definition
Language (DDL) and Data Manipulation Language
(DML) as described below:

1 . Da t a Defin it ion La n gu a ge (DDL)


DDL is u sed for defin in g da ta ba se str u ctu r e a n d
specify in g con str a in ts. DDL in clu des th ose com m a n ds
of th e da ta ba se th a t dea l w ith th e defin in g a n d
m odify in g da ta ba se str u ctu r es. For ex a m ple, DDL
com m a n d CREATE ca n be u sed to cr ea te a ta ble:

DDL: u sed t o def i ne and modi f y dat ab ase st r u c t u r e

CREATE TABLE ta ble-n a m e

Oth er DDL com m a n ds in clu de ALTER a n d DROP.


2 . Da t a Ma n ipu l a t ion La n gu a ge (DML)
DML is u sed for r etr iev a l a n d m odifica tion of da ta . It
in clu des com m a n ds th a t h elp to m a n ipu la te th e
da ta ba se. It pr ov ides fu n ction s th a t dea l w ith (i)
r etr iev in g da ta fr om r ela tion s, a n d (ii) m odify in g th e
da ta ba se by in ser tin g , u pda tin g , or deletin g it.
Ex a m ples of DML com m a n ds in clu de INSERT, SELECT,
DELETE, a n d UPDATE.

DML: u sed t o r et r i ev e and modi f y dat a

18.3.2 Creating Database and Tables

Before we can use a database for storing or


manipulating information, we need to create the
database structure. This step is called metadata (data
about data) creation. The following lines of code can be
used for creating and connecting to the COLLEGE
database.

m eta da ta : da ta a bou t da ta

import sqlite3

conn = sqlite3.connect('COLLEGE.db')

cur = conn.cursor()

sqlite3: m odu le for da ta ba se m a n a g em en t

First, we import module sqlite3 which provides the


functionality required for database management. Next,
we need to establish a connection to the database having
the name COLLEGE.db (specified as an argument). The
database name should have extension db. Thus, the
second line in above segment of code connects to
database COLLEGE.db. Thus, we have named this
connection conn. If the database mentioned already
exists in the current directory, a connection is established
with the already existing database, otherwise a new
database is created. For performing operations on the
data stored in the database, we need a handler. The class
cursor associated with the connection identifier conn
returns a handler/cursor object (cur in this case). To
close the connection, we use the method close
associated with the conn object:

connect(): esta blish es da ta ba se con n ection

conn.close()

close(): closes th e da ta ba se con n ection

The method execute of the cursor object is used for


executing SQL commands. However, the method can be
used for executing only one SQL command at a time. If
one wishes to execute multiple SQL commands, the
method executescript may be used. The method
execute allows the use of several parameters discussed
in subsequent sections.

execute(): a m eth od of th e cu r sor object for ex ecu tin g SQL


com m a n ds

Having created the database COLLEGE, let us now


create relations corresponding to different entities
involved. CREATE TABLE command is used for creating
relations (tables):

CREATE TABLE table_name(

attribute1 data_type [constraint][,

attribute2 data_type [constraint]][,


.

table_constraints]

);

sy n ta x of CREATE TABLE com m a n d

In the description of SQL command, a pair of square


brackets ([]) denotes optional part. Thus, in the CREATE
TABLE command, there may be any number of
attributes or constraints. The attributes and the
constraints are specified within parenthesis and are
separated by commas. Each attribute name is followed
by the type of data it contains. The data type for a given
attribute determines the domain of values it can take. A
data type may include INT (integer) for a numeric
value, VARCHAR (a sequence of characters) for a
string value, and DATE for the date value. Data type may
further be followed by constraints on attributes such as
UNIQUE and NOT NULL. Each SQL command
terminates with a semicolon. However, we may skip
semicolon when a command is executed by a Python
script.

dom a in : th e v a lu es, a n a ttr ibu te ca n ta ke

Suppose we wish to create the table STUDENT. The


following SQL command may be used this purpose:
SQL com m a n d for cr ea tin g STUDENT ta ble

Since each student has a unique roll number, no two


students can have the same value of the attribute
RollNum. So, RollNum must be unique across all tuples
of STUDENT table. As we would like to use RollNum to
identify a student uniquely, this attribute cannot be
NULL. So, we apply column constraints UNIQUE and NOT
NULL to the attribute RollNum. The attribute RollNum
has been declared primary key of the table in the last line
of CREATE TABLE command. Also, RollNum being the
primary key, column constraints UNIQUE and NOT
NULL automatically hold for it, and thus, do not need to
be mentioned explicitly.

n o tw o tu ples in a da ta ba se ca n h a v e th e sa m e pr im a r y key

v a lu e of a ttr ibu te(s) th a t for m th e pr im a r y key m u st n ot be


NULL

If the primary key comprises a single attribute, we


may include the phrase PRIMARY KEY while defining
the attribute in the CREATE command, as shown below:

CREATE TABLE STUDENT(

RollNum INT PRIMARY KEY,

Name VARCHAR(20) NOT NULL,

Percentage INT NOT NULL

);

SQLite does not enforce strict type requirement. To


ensure strict type conformity, CHECK constraint must be
associated with an attribute.

u se CHECK to en for ce ty pe con str a in t

CREATE TABLE STUDENT(

RollNum INT CHECK(TYPEOF(RollNum) =


"integer") PRIMARY KEY ,

Name VARCHAR(20) CHECK(TYPEOF(Name) =


"text") NOT NULL,

Percentage INT CHECK(TYPEOF(Percentage)


= "integer") NOT NULL

);

In the script SQLCommands (Fig. 18.15), we create the


database COLLEGE having a table STUDENT.
Fig. 18.15 Cr ea tin g da ta ba se COLLEGE a n d ta ble STUDENT
(SQLCommands.py)

18.3.3 Inserting Data into Table

Having created the tables, we would like to store the data


in the database. The process of storing the data in the
database is called loading the database or populating the
database. SQL command INSERT is used for this
purpose. The syntax for INSERT command is given
below:

INSERT INTO table_name

VALUES (value1,value2, …,valueN);

sy n ta x of INSERT com m a n d

Given the name of a table and associated attribute


values in the form a tuple, INSERT command inserts a
tuple in the table. The order of values within the tuple
should correspond to the order of the attributes of the
table. The character and date type values should be
enclosed in single quotes. When the value of an attribute
is not known/missing/not applicable for a tuple, we use
the NULL value. For example, suppose we wish to insert
information about a Student having RollNum 1,
Name Hiten, and Percentage 89. To do this, we
may use the following INSERT command:
INSERT INTO STUDENT

VALUES (1, 'Hiten', 89);

In the script SQLCommands (Fig. 18.16), we insert five


rows in the table STUDENT.

Fig. 18.16 In ser tin g da ta in STUDENT ta ble (SQLCommands.py)

In sqlite3, commit method associated with the object


connect is used for forcefully saving the current state of
the database, thus making the changes permanent. For
example, in the script SQLCommands (Fig. 18.16),
commit method is executed after inserting the five tuples
in the table. This ensures that the tuples just inserted in
the table STUDENT of the database become immediately
visible to other connections to this database.

commit(): to for cefu lly sa v e cu r r en t sta te of th e da ta ba se

Next, we present another format for inserting a tuple


into a table using a question mark. For example, we may
add a tuple in the table STUDENT using the question
mark as a placeholder for the data being provided as the
second argument to method execute:

?: qu estion m a r k m a y be u sed a s a pla ceh older in a n SQL


com m a n d

rollNum = int(input('Enter roll number:


'))

name = input('Enter name: ')

percent = int(input('Enter percentage: '))

cur.execute("INSERT INTO STUDENT VALUES\

(?,?,?);", (rollNum, name, percent))

18.3.4 Retrieving Data from Table

SELECT command is used to retrieve data from the


database tables. The syntax of SELECT command is
given below:

SELECT attribute_list

FROM relation_list;

sy n ta x of SELECT com m a n d

attribute_list is a comma-separated list of attribute


names whose values are to be retrieved. For example, to
retrieve roll number, name, and percentage of students,
we use the following SQL command:

SELECT RollNum, Name, Percentage


FROM STUDENT;

In the above command, first line comprising of keyword


SELECT along with a list of attributes RollNum,
Name, Percentage is called SELECT clause, and the
second line is called FROM clause. On executing the
above command, SQL will respond with the relation
given in Table 18.6.

T a bl e 18.6 Rela tion STUDENT

When we wish to extract all the attributes of a relation,


we may use the wild card character * (asterisk) as a
substitute for all the attributes occurring in the
relation(s). Thus, the above SELECT command may be
rewritten as follows:

SELECT *

FROM STUDENT;
*: w ild ca r d ch a r a cter , u sed in a n SQL com m a n d a s a
su bstitu te for a ll th e a ttr ibu tes occu r r in g in th e r ela tion (s)

Next, suppose that we wish to list only roll numbers and


names of the students in the college. For this purpose, we
need to specify in the SELECT clause, the relevant
attributes RollNum and Name of the relation STUDENT,
as shown below:

SELECT RollNum, Name

FROM STUDENT;

Next, suppose we wish to retrieve information about


students who have secured percentage more than 80.
WHERE clause in an SQL query facilitates retrieval of
only those tuples which satisfy a condition such as
Percentage > 80. Thus, the following SQL query
would retrieve the desired information:

WHERE cla u se: u sed to specify con dition for selection of tu ples

SELECT *

FROM STUDENT

WHERE Percentage > 80;

The syntax of SELECT command with WHERE clause is


given below:

SELECT attribute_list

FROM relation_list

WHERE condition_list;
sy n ta x of SELECT com m a n d in v olv in g WHERE cla u se

Here, condition_list may comprise a single


condition, or several conditions joined using Boolean
operators: AND, OR, and NOT. The output of an SQL
query returns values of attributes mentioned in attribute
list for the tuples of table that satisfy the condition(s)
specified in the WHERE clause.

Instead of retrieving the information interactively, we


may use a Python script such as SQLCommands (Fig.
18.17) to retrieve the information from the table
STUDENT.
Fig. 18.17 Retr iev in g da ta fr om STUDENT ta ble
(SQLCommands.py)

The result returned by an SQL query may be accessed


using the method fetchall that returns a list of tuples
(line 6, Fig. 18.17). Alternatively, we may retrieve the
data from the database row by row by iterating through
the cursor object as shown below:
fetchall(): r etu r n s a list of tu ples a s th e r esu lt of ex ecu tin g
a n SQL qu er y

for row in cur:

print(row)

The method execute also allows the use of named


placeholders for SQL literals. For example, the query

cur.execute('SELECT * FROM STUDENT WHERE


Percentage > 80;')

may be rewritten as follows:

cur.execute('SELECT * FROM STUDENT WHERE


Percentage > :value;', {'value':80})

u se of n a m ed pla ceh older

In the above query, the method execute makes use of


the name value as a placeholder for the actual data 80
that appears as the second argument.

18.3.5 Updating Data in a Table

UPDATE command is used to modify the attribute


value(s) in one or more tuples. Given the name of the
relation to be modified and an optional WHERE clause to
select a particular set of tuples, the UPDATE command
updates value(s) of one or more attributes. The UPDATE
command uses the following syntax:

sy n ta x of UPDATE com m a n d
UPDATE relation

SET attribute-value_pairs

[WHERE condition_list1];

For example, to increment percentage of all students


having a percentage less than 50% by 2%, we use the
following SQL command:

UPDATE STUDENT

SET Percentage = Percentage * 1.02

WHERE Percentage < 50;

In the UPDATE command, SET clause may take any


number of comma-separated attributes and their
updated values. In a Python program, the following
statements can be used for updating data:

cur.execute('UPDATE STUDENT \

SET Percentage = Percentage * 1.02 \

WHERE Percentage < 50;')

18.3.6 Deleting Data from Table / Deleting Table

DELETE command is used to delete the tuples from a


relation which satisfy the condition appearing in the
optional WHERE clause. In case of absence of WHERE
clause, all the tuples of the table mentioned in DELETE
command will be deleted. The DELETE command has
the following syntax:

sy n ta x of DELETE com m a n d

DELETE FROM relation_name

[WHERE condition_list1];
Suppose a student with roll number 3 has left the
college. We may delete the information about that
student using the following SQL command:

DELETE FROM STUDENT

WHERE RollNum = 3;

The command

DELETE FROM STUDENT;

deletin g en tir e da ta fr om th e ta ble

will delete the entire data from the table STUDENT. If


we wish to delete the table itself along with all its tuples,
we may use the DROP TABLE command. For example,
the following SQL command will delete the entire table
STUDENT:

DROP TABLE STUDENT;

deletin g th e ta ble

18.4 DEVELOPING MOBILE APPLICATION FOR ANDROID

In this section, we will study how Python can be used for


creating applications for android. For illustrating this, we
will develop the popular two-player game Tic-Tac-Toe,
also known as the game of Xs and Os. In this game, the
player who successfully places three consecutive symbols
horizontally, vertically or diagonally wins the game. For
developing the game, we will first create a cross-
platform application of the game that can be executed
on the Android device. Before developing this game, we
will create a registration interface for the user.
u se m odu le kivy for bu ildin g cr oss pla tfor m a pplica tion s

Python provides an open source library kivy for


building cross-platform applications. It is a graphical
user interface toolkit which supports
®
desktop ®
environments such as Windows , Linux, and Mac OS .
It also supports multi-touch devices such as Android and
IOS. Next, we describe how to install kivy in Windows
environment. For this purpose, we use a sequence of
commands from Windows command line interface
(<Windows key +R>, cmd). First, we need to upgrade
wheel and pip libraries to the latest versions. The first
command upgrades wheel and pip to latest versions
along with setuptools and tokenize. Smooth
execution of a software package may require some
related software/files. These are called dependencies. The
second and third command downloads and installs all
the dependencies of kivy.

python -m pip install --upgrade pip wheel


setuptools tokenize

kivy in sta lla tion

python -m pip install docutils pygments


pypiwin32 kivy.deps.sdl2 kivy.deps.glew
kivy.deps.gstreamer cython --extra-index-
url
https://kivy.org/downloads/packages/simple
/

python -m pip install kivy.deps.angle

Finally, for installing kivy package, download the


nightly wheel from the link
https://kivy.org/downloads/appveyor/kivy/Kivy-
1.9.2.dev0-cp36-cp36m-win32.whl and install it using
the following command (the file just downloaded from
kivy.org should be available in the working directory and
needs to be moved to working directory, if downloaded
in a different folder):

python -m pip install Kivy-1.9.2.dev0-


cp36-cp36m-win32.whl

To develop an application, we create a folder with a


suitable name containing the application titled main.py.
During deployment, build tools search for a file named
main.py. The App class is the base class for developing
kivy applications containing important methods for
initializing, launching, building, stopping, pausing, and
resuming applications. So, whenever we wish to define
an implementation of an Android application as a class,
it should inherit the App class of the kivy.app module.
The run method available in the App class defines the
entry point of a kivy application and is used for
launching the application. Fig. 18.18 illustrates the
execution sequence of a kivy application.

App cla ss: u sed a s a ba se cla ss for dev elopin g kiv y a pplica tion s
Fig. 18.18 Kiv y A pplica tion th a t displa y s a bu tton (main.py)

An application will include several layouts and widgets


(graphical objects) such as buttons, labels, checkboxes,
and dropdowns required for defining the user interface.
Widget arguments are called properties. These user
interface elements are defined in uix module of kivy.
Let us first create a simple application main (Fig. 18.19)
that displays a clickable button with text Hello. For this
purpose, we import the class App, available in the
module kivy.app, and develop a user defined class
CreateButtonApp as a derived class of the class App.
The method build of the user defined class
CreateButtonApp overrides the method build of the
parent class App. Thus, we make use of the method
Button to create a button. This widget should be
returned by overridden build method of the user-
defined class. When the script executes, an instance of
the user-defined class CreateButtonApp is created
(line 17), which is used for invoking the method run
(inherited from class App), which in turn starts the
application by invoking the method build of
CreateButtonApp.

w idg ets: g r a ph ica l objects w idg et a r g u m en ts: u sed to set


pr oper ties

uix m odu le con ta in s u ser in ter fa ce elem en ts

build: m eth od u sed to in itia lize a pplica tion w ith th e w idg et


tr ee
Fig. 18.19 Kiv y a pplica tion th a t displa y s a bu tton (main.py)

When the method CreateButtonApp().run() is


launched, it invokes the method build of the class
CreateButtonApp that defines the user interface. The
method build returns a root widget (button in this
case) of our application. Note that the class Button is
imported in line 2. In line 14, we have set the text
property (argument) of the widget Button as 'Hello'.

build m eth od r etu r n s th e r oot w idg et


On executing the script main (Fig. 18.19), Python
responds with the following output shown in Fig. 18.20.
Left window of the figure displays the button when the
application starts. Right window displays the button
when it is pressed.

Fig. 18.20 Ou tpu t of pr og r a m 1 8 .1 9

Another approach for using widgets and their definitions


is to use separate files for specifying them (Fig. 18.21).
Note that the widget definition is stored in a separate file
having .kv as a suffix. The .kv file is named after the
main app class containing build method. While name
of a class may include uppercase letters, to name the
.kv file, we use the same name as that of the class, but
in lowercase letters and drop the suffix App, if included
in the name of the class. The file contains the colon-
separated properties and their values for each widget.
Also, the root widget is enclosed in angular brackets
followed by a colon.
w idg et defin ition s m a y be stor ed in a sepa r a te file h a v in g .kv
suffix

Fig. 18.21 Widg et defin ition (cr ea tebu tton .kv )

The kivy application that displays a button appears in


Fig. 18.22.
Fig. 18.22 Kiv y a pplica tion th a t displa y s a bu tton (main.py)

18.4.1 A Simple Application Containing Registration


Interface

If you have been using a smart phone for sometime, you


must have observed that several mobile apps require you
to register with them. Next, we will develop a simple
user interface for registration. On clicking the Register
button, it prompts the user for username and password
and displays a window with the message
Registration Successful. However, while
implementing this interface, we do not maintain a
database of valid usernames and passwords. Indeed, we
not only disregard whether a valid user having the
credentials entered by the user exists, but we also do not
care whether the user entered the name and password
information at all or just left these fields empty.
However, then you may wonder: what is the purpose of
this application? Through this application, we intend to
illustrate how several widgets can be added using a
layout, and how an event can be invoked on clicking a
button. In Fig. 18.23, we present an application program
for displaying a user interface for registration. As this
interface contains button, label, textinput, and
popup, we need to import all these widgets in our
script. For organizing the widgets in this program, we
have used a grid layout comprising of one column. The
class GridLayout of module gridlayout is used for
defining this layout. Kivy also supports several other
layouts such as BoxLayout, StackLayout, and
FloatLayout which can be used for organizing the
widgets.

a ddin g sev er a l w idg ets u sin g a la y ou t

clickin g a bu tton in v okes a n ev en t


Fig. 18.23 Kiv y a pplica tion th a t displa y s a r eg ister in ter fa ce
(main.py)
We have defined RegistrationApp as the main class
containing the build method. The build method
returns an instance of Register class as the root
widget. Register class inherits the GridLayout class.
In this class, we set the properties of the layout by
invoking the __init__ method (line 18). We have set
the number of columns as 1, spacing between widgets as
10, and horizontal padding from the left and right side of
the window as 150. In the method __init__ of
Register class, we add to the layout, widgets label
and textbox for username as well as the password
using add_widget method. Note that for the
TextInput widget, the password property has been set
to be True for hiding the password. In line 23, we add
the Button widget. We have associated an event
on_press with the button that invokes the method
displayPopup when the button is clicked. The method
displayPopup creates an instance of Popup. It has
the title 'Registration Status', content
Label(text = 'Registration Successful'),
and a size_hint property that enables us to specify the
height and width on a scale of 1. Here, we have set the
content property to be an instance of the widget
Label. Note that the method displayPopup contains
two parameters – the implicit parameter self and the
widget instance associated with it.

settin g GridLayout pr oper ties

displayPopup(): m eth od a ssocia ted w ith ev en t on _pr ess of


Bu tton w idg et

On executing the script in Fig. 18.23, Python responds


with the output given in Fig. 18.24. Left window (Fig.
18.24(a)) displays a user interface for registration, and
the right window (Fig. 18.24 (b)) shows popup window
which appears when Register button is clicked.
Fig. 18.24 Ou tpu t of pr og r a m 1 8 .2 3

Alternatively, we may specify kivy widget definitions in


a separate file (Fig. 18.25), Register being the root
widget.

w idg et defin ition s in a sepa r a te .kv file


Fig. 18.25 Widg et defin ition s (registration.kv)

The modified script main is shown in Fig. 18.26.


Fig. 18.26 Kiv y a pplica tion th a t displa y s a bu tton (main.py)

18.4.2 Tic-Tac-Toe Game

In this section, we will develop Tic-Tac-Toe game as an


android application (Fig. 18.27). In this game, we have a
grid of size 3X3. We have initialized a grid of this size to
contain Button widgets (line 25). We have defined O
and X as two symbols used by the two players. We
update the value of count every time a user makes a
move. A user click invokes the method action that sets
the corresponding symbol in the grid. It increments the
number of moves, and checks if there is any winner at
this stage. The check for the winner is performed by
invoking the method checkResult (line 39). The
method checkResult further invokes the method
getWinner . In case there is a winner at this stage, it
returns the symbol (O or X) corresponding to the
winner, otherwise it returns None. Now a
closeButton is created. If there is a winner, the
closeButton displays the name of the winner.
However, if there is no winner, but the game is over, the
closeButton displays the message indicting that the
game is finished. In either case, checkResult method
displays a popup containing this closeButton. Note
that in line 62 we have set on_press property of the
button myPopUp to the dismiss method which closes
the popup and on_release property to restartGame
(lines 118–129) which re-initializes the game grid with
blanks, and sets the number of moves for a new game to
0.

la y ou t: GridLayout w idg ets: Button

a u ser click in v okes th e m eth od action w h ich sets th e sy m bol


on th e g r id a n d ch ecks for th e w in n er

settin g on_press a n d on_release pr oper ty of Bu tton w idg et

Let us now examine how the getWinner method


(lines 66–101) determines the winner of the game. The
method checks if all cells in some row, column, forward
diagonal or backward diagonal contain the same symbol
(O or X) using the method sameSymbol (lines 104–116).
If so, the method getWinner returns that symbol,
otherwise, it returns False.
Fig. 18.27 Kiv y a pplica tion th a t displa y s a r eg ister in ter fa ce
(main.py)
On executing the script main (Fig. 18.27), Python
responds with the output given in Fig. 18.28. We have
shown the output in each of the two scenarios: when
there is a winner (Fig. 18.28(a)) and when the game
results in a draw (Fig. 18.28(b)).

Fig. 18.28 Ou tpu t of pr og r a m 1 8 .2 7

18.4.3 Running Kivy Applications on Android

Android play store has an application Kivy Launcher


that enables us to run Python kivy applications on
android devices. The kivy applications are stored in the
directory kivy in the
/sdcard/kivy/<yourapplication>. A kivy
application developed on the desktop can be run on Kivy
Launcher by creating a container folder (say,
/sdcard/kivy/TicTacToe) and pasting the
application including main.py in the directory
/sdcard/kivy/TicTacToe. Apart from the file
main.py, the application folder should also contain a
file named, android.txt that includes the title, author,
and layout (orientation) of the application in the
following format:

Kiv y La u n ch er on a n dr oid pla y stor e en a bles u s to r u n kiv y


a pplica tion s dev eloped on Desktop

title=<Application Title>

author=<Your Name>

orientation=<portrait|landscape>

Next, go to Kivy Launcher and choose the project you


wish to execute.

An alternative option to run a Desktop application on


android is to convert it to android compatible
application. Since android platform supports APK
applications, the Python application must be first
converted to this format. A kivy application i.e. a
Python source code can be converted to APK application
using buildozer tool which simplifies the task at hand.
However, as of now, kivy applications for android can
only be built in the Unix environment. The sequence of
steps for building an APK file from buildozer is
available on the website
https://kivy.org/docs/guide/packaging-
android.html. The APK can also be built using
python-for-android.

con v er tin g Py th on a pplica tion to A PK

18.5 INTEGRATING JAVA WITH PYTHON


While programming in a language, a developer may feel
the need to use some functionality which may have
better support in another language. For example,
suppose, an application has already been developed in
Java, and we wish to use it in Python code. To invoke an
existing Java application in Python, we need a bridge
between Python and Java. Packages like P y4j,
Pyjnius, Jpype, javabridge, and JCC help in
invoking Java programs from Python. Also, since Java
provides a wide variety of collections, we can directly use
them in a Python program by including their java
packages in the program.

for in v okin g Ja v a fu n ction a lity fr om Py th on , u se a pa cka g e


like Py 4 j, Py jn iu s, Jpy pe, ja v a br idg e, JCC

We will make use of py4j for invoking Java


functionality from Python. It can be installed by
executing the following command from command line:

u se of pa cka g e py4j for in v okin g Ja v a fu n ction a lity fr om


Py th on

pip install py4j

Since we are using Eclipse as the development


environment for writing Java programs, we need to
include the jar file of py4j in the Java project. The jar
file is typically available in the directory C:\Users\
<User_Name>\AppData\Local\Programs\Python\
Python36-32\share\py4j. We can add this file by
right-clicking on the project in the Package Explorer
panel, and selecting option Add External Archives
in the Build Path option. It is important to point out
that py4j supports Java version 6 and above only.
in clu de ja r file of py4j in Ja v a pr oject

Let us examine a simple Java program


HelloClass.java (Fig. 18.29) that has a method
Message which returns Hello.

for a ccessin g Ja v a cla ss in a Py th on pr og r a m :


in Ja v a pr og r a m , in sta n tia te GatewayServer cla ss of libr a r y
py4j

To make the HelloClass accessible in a Python


program, two things are required. First, the Python
program should be able to access the Java Virtual
Machine (JVM) running the Java program. This
requires an instance of the GatewayServer class
available in the library py4j that makes this
communication possible. Second, an entry point should
be mentioned in the call to the constructor of the class
GatewayServer. This entry point can be any object we
wish to deal with in a Python program. In our case, an
object of HelloClass serves as an entry point (line 10,
Fig. 18.29). Here it is important to mention that a
Python program will be able to use a Java program only
if it (Java program) is ready to accept incoming
requests. Therefore, in line 11, we start the gateway
using the method start. Also, for communication to
take place, the Java program must be compiled and
executed before the Python program.
Fig. 18.29 Ja v a pr og r a m (HelloClass.java)

for com m u n ica tion to ta ke pla ce, Ja v a pr og r a m m u st be


com piled a n d ex ecu ted befor e th e Py th on pr og r a m

The script hello.py (Fig. 18.30) uses the Java


program that we discussed above. For this purpose, we
need to create an instance of the class JavaGateway
available in the module py4j.java_gateway. The first
two lines of the Python script hello achieve this. When
we invoke JavaGateway (line 2), Python tries to
connect with JVM of Java program already running and
returns an instance. We can access the entry point object
using the member entry_point (line 3). This object
now enables us to use Java functionality in the Python
program (line 4). However, if no JVM is waiting for a
connection, an error message Py4JNetworkError is
displayed.

Fig. 18.30 Py th on a pplica tion s th a t u ses a m eth od of ja v a


pr og r a m (hello.py)

On running the script hello (Fig. 18.30), Python


outputs Hello. If the error message address already in
use appear while running the Java program, we need to
explicitly specify a new port number (between 1025 and
65535) in each of the Java and Python programs. For
example, in the Java program HelloClass (Fig.
18.29), we may replace line 10 by:

ex plicitly specify in g n ew por t n u m ber

GatewayServer gatewayServer = new


GatewayServer(new HelloClass(), 25539);

and in the Python script hello (Fig. 18.30), we replace


line 2 by:

gateway =
JavaGateway(gateway_parameters=GatewayPara
meters(port=25539))

For setting the gateway_parameters explicitly, we


need to import GatewayParameters along with
JavaGateway (Fig. 18.34). Since we need to compile
and execute Java program first and then the Python
program, we create a batch file (say, HelloApp.bat)
comprising these two tasks one after the other. Since
compiling and running an eclipse program from the
command line is a more complex job, we can convert
the entire project to an executable jar file which can be
used anywhere. For this purpose, we right-click on the
Java project (say, DemoProject) in the Package
Explorer, and choose the following options in a
sequence: the Export option, Runnable JAR file
option. In the next window, choose the appropriate
Launch configuration and export
destination folder where you wish to save the jar
file, say DemoProject.jar. This creates an executable
jar file. We create a .bat file that has the following
sequence of commands.

m a kin g a ja r file m a kes th e u se of Ja v a a pp ea sier .

@echo off

start cmd /k java -jar


<CompletePath>\DemoProject.jar

start cmd /k python


<CompletePath>\hello.py

ba tch file

Note that the second and third commands in the above


sequence, i.e.,

java -jar <CompletePath>\DemoProject.jar

and

Python <CompletePath>\hello.py
are executed in command prompt using start
command followed by parameter cmd. Further, use of
the option /k prevents the application initiated, from
involuntary closure until explicitly closed by the user.
The batch file so created can be run by double-clicking it.

18.5.1 Accessing Java Collections and Arrays in Python

Java supports arrays and several collections such as list,


set, and hash map. Let us create a Java array of type
int in Python. The method new_array associated with
the object gateway created in Hello.py can be used
for creating this array. The method takes Java type and
size of the array as an input. We have created an int
array of size 2 and initialized it with values 0 and 1.
Once we have created a Java array in Python, we can
iterate over this array, much like a standard sequence
(list, tuple, range, etc.) in Python as shown below:

from py4j.java_gateway import JavaGateway

gateway = JavaGateway()

intArray =
gateway.new_array(gateway.jvm.int,2)

intArray[0] = 0

intArray[1] = 1

for value in intArray:

print(value)

u sin g Ja v a a r r a y in Py th on

On executing the above Python code (after starting Java


Gateway Server), Python responds with the following
output:

0
1

Similarly, we can also create a Java list using the


gateway object. Subsequently, we may add elements to
that list, either by using append method of Python list
or by using add method of Java as shown below:

cr ea tin g a Ja v a list in Py th on

Python responds with the following output on the


execution of above piece of code:

['red', 3]

18.5.2 Converting Python Collections to Java Collections

Suppose, we have a Python list that we need to pass to a


Java method. For this purpose, we must convert Python
list to Java compatible list. Module
py4j.java_collections provides classes such as
SetConverter, MapConverter, and
ListConverter, which make this conversion possible.
Let us examine the program in Fig. 18.31, where we
create a Python list and convert it to a Java list by using
convert method of the ListConverter class. We
then use sort method of Java to sort the list.

u se of convert m eth od of List-Converter cla ss for


con v er tin g Py th on list to Ja v a list
Fig. 18.31 Sor tin g py th on list u sin g Ja v a m eth od sor t
(SortPythonList1.py)

Note that javaList obtained from pythonList is


sorted using Java method sort (line 7). Python
responds with the following output on the execution of
the program SortPythonList1.py (Fig. 18.31):

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

Alternatively, we may request py4j to convert Python


objects to compatible Java collections when invoking a
Java method. This can be done by setting
auto_convert to True while creating a JavaGateway
as shown in the script SortPythonList2 (Fig. 18.32).
Since the Python list and the corresponding java list are
two different objects (py4j makes a copy of Python list),
pythonList does not get sorted when we invoke
Collections.sort.

a u tom a tica lly con v er tin g Py th on objects to Ja v a com pa tible


collection s
Fig. 18.32 Sor tin g Py th on list u sin g Ja v a m eth od
(SortPythonList2.py)

18.5.3 Invoking a Parameterized Java Method from Python

Suppose we wish to modify a list by multiplying all its


elements by 2. The Java program
ListManipulation.java shown in Fig. 18.33
achieves this by defining method Update. The method
takes a list as an input parameter and returns the
modified list.
Fig. 18.33 Ja v a Pr og r a m w h ich m odifies elem en ts of th e list
r eceiv ed a s pa r a m eter (ListManipulation.java)

To make methods of the class ListManipulation


accessible in a Python program, it must be compiled and
executed before execution of Python program. Examine
the Python script in Fig. 18.34 that uses this Java
program. In lines 2 and 3, we have created an instance
of class JavaGateway available in module
py4j.java_gateway. Entry point object is used for
accessing Update method by passing pythonList as
an input argument. Note that the input argument is not
converted to Java compatible type explicitly. Instead, we
have set gateway parameter auto_convert which
automatically achieves this.

Fig. 18.34 Py th on a pplica tion s th a t u ses th e m eth od Upda te fr om


Ja v a pr og r a m (ListMa n ipu la tion .py )

On executing the script ListManipulation (Fig.


18.34), Python responds with the following output:

>>>

Enter the list: [1,2,3]

Resultant list is [2, 4, 6]

18.5.4 Invoking Parameterized Python Method from Java

Once again, we wish to modify the given list by


multiplying each of its elements by 2. However, this
time, we wish to develop a Python program that
achieves this. As shown in Fig. 18.35, class
ListManipulation has a method Update, which
takes a list as input parameter and returns the modified
list.

Fig. 18.35 Py th on pr og r a m w h ich u pda tes elem en ts of th e list


r eceiv ed a s pa r a m eter (ListManipulation1.py)

In order that a Java program may be able to invoke


Python methods, we need to set
start_callback_server attribute to True (line 14).
Also, we need to pass the object lst of the class
ListManipulation (line 16) to Java program so as to
allow the Java method to call the Python methods. In
line 17, we create an object javaClasslst of a Java
class and pass Python class object lst to its method
ListOperation (line 20).

in Py th on pr og r a m , set start_call-b a c k _ s e r v e
r a ttr ibu te of Java-Gateway to Tr u e for en a blin g Ja v a
pr og r a m s to in v oke Py th on m eth ods
Fig. 18.36 Ja v a a pplica tion s th a t u ses a m eth od Upda te of Py th on
pr og r a m (List.java)
As shown in the program List (Fig. 18.36), object
lst passed via Python program is received as object op
in Java method ListOperation of class List (line 5).
Note that, for every Python method, an interface
method should be defined in Java. In Fig. 18.37, we have
defined an interface ListManipulationInterface
which declares the method Update.

On running the Java program followed by Python script,


Java responds with the following output:

Updated List:

2 4 6

Fig. 18.37 In ter fa ce ListManipulationInterface


(ListManipulationInterface.java)

18.6 PYTHON CHAT APPLICATION USING KIVY


AND SOCKET PROGRAMMING

In this section, we will build a chat application that


allows two parties to communicate with each other via
type and send chat interface. We have used kivy library
to create a chat interface, one for each communicating
party. The interface comprises a textbox named
ChatBox where chat logs are displayed, an entry text
box named EntryBox to type a message to be sent, and
a button named SendButton to send the message. Note
that each widget can be assigned a name identifier using
id property and referenced in the program using
dictionary ids maintained by the root widget that
comprises all widgets having an id attribute. We present
the widget definitions in the file
chatappinterface.kv file (Fig. 18.38).

w idg ets u sed in ch a t in ter fa ce: ChatBox, EntryBox, a n d


SendButton

Fig. 18.38 Widg et defin ition s (chatappinterface.kv)

In the scripts host (Fig. 18.39) and client (Fig.


18.40), we have defined the respective chat application.
The host program will initiate the communication by
listening to request, and the client will connect to the
host waiting for a connection and communicate with
it. A message typed by either party will be displayed in its
own ChatBox as well as the ChatBox of another
communicating party. Thus, we need to perform the two
tasks for each application: the first task takes the user
input through EntryBox and displays it in his/her own
ChatBox, and the second task sends the input to the
connected party. Further, the chat application running
at each end should be ready to receive a message sent by
another party for displaying it in the ChatBox. Former
functionality is performed by the clickAction method
associated with the widget SendButton. The latter
functionality is performed by getHostConnected and
getClientConnected methods of the host and the
client respectively. For this purpose, we create a separate
thread by using the method start_new_thread of the
module _thread which takes the method to be
executed as the first parameter and a list of arguments to
be sent to the method as the second parameter.

th e ch a t a pplica tion s a t th e tw o en ds sen d a n d r eceiv e


m essa g es a t th eir ow n pa ce
Fig. 18.39 Host a pplica tion (host.py)
Fig. 18.40 Clien t a pplica tion (client.py)

In Fig. 18.41, we show the output of a sample chat


session when the host application is run, followed by the
client application.
Fig. 18.41 Ch a t a pplica tion

SUMMARY

1 . tweepy pa cka g e of Py th on is u sed for h a n dlin g Tw itter


da ta .
2 . A ccessin g Tw itter da ta r equ ir es open a u th en tica tion of
a n a pplica tion . Th e a u th en tica tion h a n dler object of
cla ss OAuthHandler is pa ssed a s a pa r a m eter to cla ss
API of th e tweepy m odu le (a w r a pper for A PI a s
pr ov ided by Tw itter ). A n object of th is cla ss (api) ca n
be u sed for r etr iev in g u ser in for m a tion su ch a s h is/h er
follow er s, fr ien ds, a n d tw eets.
3 . Py th on pr ov ides tw o socket m odu les - socket a n d
socketserver. Wh ile th e for m er pr ov ides low -lev el
n etw or kin g in ter fa ce, th e la tter pr ov ides su ppor t in th e
for m of cla sses for dev elopin g th e n etw or k ser v er
a pplica tion .
4 . Th e sqlite3 m odu le pr ov ides th e fu n ction a lity
r equ ir ed for da ta ba se m a n a g em en t. Th e cla ss connect
is u sed for esta blish in g a con n ection w ith th e da ta ba se.
Th e m eth od close is u sed for closin g th e con n ection .
Th e m eth od execute of th e cu r sor object of cla ss
Cursor is u sed for ex ecu tin g SQL com m a n ds.
5 . Py th on pr ov ides a n open sou r ce libr a r y Kivy for
bu ildin g cr oss-pla tfor m a pplica tion s. It is a g r a ph ica l
u ser in ter fa ce toolkit w h ich su ppor
® ts desktop ®
en v ir on m en ts su ch a s Win dow s , Lin u x , a n d Ma c OS .
It a lso su ppor ts m u lti-tou ch dev ices th a t su ppor t
a n dr oid/ IOS.
6 . Pa cka g es like Py4j, Pyjnius, Jpype, javabridge,
a n d JCC a r e u sed to Ja v a pr og r a m s fr om Py th on .

EXERCISES

1 . Wr ite a pr og r a m th a t ta kes a u ser h a n dler a s a n in pu t


a n d ex tr a cts a ll tw eets posted by h im .
2 . Wr ite a pr og r a m th a t ex tr a cts a ll tw eets tw eeted in th e
pa st fiv e da y s r eg a r din g In dia ’s econ om y . Use th e
a ppr opr ia te list of sea r ch w or ds.
3 . Wr ite a socket pr og r a m m in g a pplica tion for
tr a n sfer r in g files a cr oss th e n etw or ks.
4 . Wr ite a pr og r a m th a t pr ov ides fu n ction a lity for
m a n a g in g in for m a tion a bou t th e colleg e in th e
da ta ba se COLLEGE. Th e da ta ba se sh ou ld con ta in
r ela tion s for stor in g in for m a tion a bou t en tities su ch a s
stu den ts, tea ch er s, cou r ses, a n d depa r tm en ts.
5 . Dev elop a kiv y a pplica tion for Tic-Ta c-Toe g a m e w ith a
g r id of size 4 × 4 .
6 . Dev elop a kiv y pa in t a pplica tion th a t pr ov ides a pa in t
pa lette con ta in in g ba sic 1 2 colou r s a lon g w ith th e
pa in t a r ea a n d a br u sh for pa in tin g .
7 . Dev elop a kiv y a pplica tion for th e pon g g a m e. Th e pon g
g a m e is a ta ble ten n is g a m e w h er e th e pla y er w h o
scor es 1 1 poin ts fir st by h ittin g th e ba ll w in s th e g a m e.
Index

A
a bc m odu le, 3 03
ABCMeta, 3 03
A bstr a ct Ba se Cla sses (A BCs), 3 03
A bstr a ct cla ss, 3 03
A bstr a ct da ta ty pe, 2 5 9
A bstr a ct m eth ods, 3 03
A bstr a ction , 2 7 9
A ccessin g Web Da ta , 5 3 9
A ccessor m eth ods, 2 8 0
A ccessor s, 2 8 0
A ctiv a tion r ecor d, 1 9 1
A ctu a l pa r a m eter s, 3 3
A ddin g m eth ods dy n a m ica lly , 2 8 2
A lia sin g , 1 5 1
A lph a bet, 1 3 7
A n im a tion : bou n cin g ba ll, 5 1 7
A ppen d, 3 5 9
A pplica tion pr og r a m m in g in ter fa ces (A PI), 5 2 2
A r g u m en t, 2 0, 3 3
A r ith m etic oper a tor s, 5
A SCII v a lu es, 6
A sser t sta tem en t, 3 9
A ssig n m en t sta tem en ts, 9 , 1 0
A ssocia tion , 1 0
A ttr ibu te r esolu tion or der , 3 07
A ttr ibu tes, 5 4 1

B
Ba se cla ss, 2 8 5
Bin a r y sea r ch tr ee, 4 1 9
bu ildin g , 4 3 1
tr a v er sa l of, 4 2 2
Bin a r y sea r ch , 3 3 1
Bin a r y tr ee, 4 1 8
h eig h t of a , 4 3 0
Bin din g , 1 0
Bits, 8
Bitw ise oper a tor s, 8
Blockin g fu n ction , 4 8 4
Boolea n (bool), 2 5 0
Boolea n v a lu es, 6
Br ea k poin t, 8 7
break sta tem en t, 7 2
Bu bble sor t, 3 2 0
Bu ild, 5 5 1
Bu ilt-in cla sses, 2 5 0
boolea n (bool), 2 5 0
diction a r y (dict), 2 5 0
floa tin g poin t (float), 2 5 0
in teg er (int), 2 5 0
list, 2 5 0
str in g (str), 2 5 0
tuple, 2 5 0
Bu ilt-in fu n ction , 2 0, 2 7
Bu ilt-in fu n ction s for cla sses, 3 09
Bu ilt-in fu n ction s on str in g s, 1 2 7

C
Ca lled fu n ction , 3 0
Ca llee fu n ction , 3 0
Ca ller fu n ction , 3 0
Ca llin g th e fu n ction , 2 0
Ca r din a lity , 5 4 1
Ch a t a pplica tion s, 5 7 1
Ch ild cla ss, 2 8 5
Cla ss a ttr ibu tes, 2 5 0
Cla ss con str u ctor , 2 5 3
Cla ss in itia lizer , 2 5 3
Cla ss n ode, 3 8 5
Cla sses, 2 5 0
Com m a n d lin e a r g u m en ts, 4 1 –4 2
Com plete bin a r y tr ee, 4 1 8
Com position , 2 0, 2 8 4
Con dition a l ex pr ession , 5 1
Con tin u e sta tem en t, 7 2
Con tr ol str u ctu r es, 4 6 –8 0
Con tr ol str u ctu r es, 7 8
Con v er tin g py th on collection s to Ja v a collection s, 5 6 6
Cr ea te ta ble, 5 4 3
Cr ea tin g a lin ked list of cu bes, 3 8 8

D
Da ta , 2 7 9 , 3 5 7
Da ta defin ition la n g u a g e (DDL), 5 4 1 , 5 4 2
Da ta h idin g , 2 7 9
Da ta m a n ipu la tion la n g u a g e (DML), 5 4 2
Da ta str u ctu r es, 3 5 7
Da ta ba se
con cepts, 5 4 1
cr ea tin g , 5 4 2
loa din g th e, 5 4 5
popu la tin g th e, 5 4 5
Da ta ba se m a n a g em en t sy stem (DBMS), 5 4 0
Da te cla ss, 2 6 5
Debu g g in g , 8 5 –9 5
com m a n ds, 8 8 –8 9
Deep copy , 2 1 0
Defa u lt v a lu es, 3 7
Deg r ee, 5 4 1
Deletion , 1 7 7
Depen den cies, 5 5 0
Dequ eu e, 3 6 9 , 4 1 2
Der iv ed cla ss, 2 8 5
Destr u ctor , 2 5 7
Dev elopin g m obile a pplica tion for a n dr oid, 5 5 0
Dict, 2 5 0
Diction a r y , 1 7 5
in v er ted, 1 7 9
oper a tion s, 1 7 7
Docstring, 4
Dom a in , 5 4 3

E
Ech o ser v er , 5 3 7
else sta tem en t, 7 7
Em pty ex cept cla u se, 2 3 2
Em pty la n g u a g e, 1 3 8
En ca psu la tion , 2 7 9
En qu eu e, 3 6 9 , 4 09
En tity , 5 4 1
Er r or s, 2 2 7
ex ception s, 2 2 8
in den ta tion er r or , 2 2 8
in den ta tion , 2 2 8
IndexError, 2 3 0
NameError, 2 2 8
OSError, 2 3 0
sy n ta x , 2 2 7
TypeError, 2 2 9
ValueError, 2 2 9
ZeroDivisionError, 2 2 9
Esca pe sequ en ces, 2 2
eval fu n ction , 2 0
Ex ception s, 2 2 8
Ex tr a ctin g com m en ts, 1 4 4

F
File, 2 2 1
h a n dlin g , 2 2 1
Fin din g com m on fa ctor s, 1 7 1
Floa tin g poin t (float), 2 5 0
Floa tin g poin t n u m ber s, 2
for loop, 5 8
For m a l pa r a m eter s, 3 3
Fr a cta l, 4 7 1
Fr on t, 3 7 2
Fr on t en d, 3 6 9
Fr u itfu l fu n ction , 3 6
Fu n ction pa r a m eter s, 3 3
Fu n ction (s), 1 9 –4 2
append, 1 5 4
axis, 4 8 9
bu ilt-in , 2 0, 2 7
ca lled, 3 0
ca llee, 3 0
ca ller , 3 0
ca llin g th e, 2 0
com position , 2 0
com pr eh en sion , 1 5 7
copy, 1 7 0, 1 7 9
count, 1 2 7 , 1 5 4 , 1 7 5
decode, 1 3 2
defin ition a n d ca ll, 2 7 –3 8
dump, 2 2 6
encode, 1 3 2
en dsw ith , 1 3 2
eval, 2 0
extend, 1 5 4
filter, 1 6 4
find, 1 2 8
fr om m a th m odu le, 2 5
fr u itfu l, 3 6
fu n ction s, 1 5 7
get, 1 7 8
help, 3 7
index, 1 5 4 , 1 7 5
input, 2 0
insert, 1 5 4 , 1 5 6
in v okin g th e, 2 0
isalnum, 1 3 1
isalpha, 1 3 1
isdigit, 1 3 1
islower, 1 2 9
isspace, 1 3 1
istitle, 1 2 9
isupper, 1 2 9
join, 1 3 1
list, 1 5 4
load, 2 2 7
lstrip, 1 3 0
map, 1 6 4
max, 2 4
min, 2 4
n ested, 5 6
ov er loa din g , 2 7 7
pa r tition , 1 3 0
pop, 1 5 4
pow, 2 4
print, 2 1
readline, 2 2 4
r ecu r siv e, 1 8 8
reduce, 1 6 4
remove, 1 5 4 ,
replace, 1 3 0
reverse, 1 5 6
rfind, 1 2 8
round, 2 2
rstrip, 1 3 0
seek, 2 2 5
show, 4 8 4
sort, 1 5 6
split, 1 3 0
sta r tsw ith , 1 3 2
strip, 1 3 0
su per set test
tuple, 1 7 4
type, 2 2
update, 1 7 8
wrapper, 4 3 8
writelines, 2 2 5
zip, 1 7 4

G
Ga m e of Xs a n d Os, 5 5 0
Globa l fr a m e, 2 9
Globa l n a m es, 1 1 4
Gr a ph ica l pa cka g e, 4 4 5
Gr a ph ics, 4 8 3 –5 1 9
2 D, 4 8 3
3 D, 5 09
a n im a tion , 5 1 7 –5 1 9
a r r ow (2 D), 5 08
a r r ow (3 D), 5 1 4
box , 5 1 0
cir cle, 5 02
con e, 5 1 5
cosin e cu r v e, 5 00
cu r v e, 5 1 6
cy lin der , 5 1 3
ellipse, 5 04
h istog r a m , 4 9 6
pie ch a r t, 4 9 8
poly g on , 5 06
r ecta n g le, 5 05
r in g , 5 1 2
sin e cu r v e, 5 00
sph er e, 5 1 0

H
Ha n dler , 2 3 5
Ha r d-codin g , 2 05
hasattr, 3 09
Hier a r ch ica l in h er ita n ce, 2 9 5
Hilber t cu r v e, 4 7 1
Hom e bu tton , 4 8 6

I
Idle, 1
If con dition a l sta tem en t, 4 6
If-elif-else con dition a l sta tem en t, 5 5
If-else con dition a l sta tem en t, 5 2
Im por tin g u ser -defin ed m odu le, 3 8 –3 9
In den ta tion er r or , 2 2 8
In den ta tion , 2 9
IndexError, 2 3 0
In fin ite loops, 6 4
In fix ex pr ession , 3 6 3
In fix for m , 3 6 3
In h er ita n ce, 2 8 5
h ier a r ch ica l, 2 9 5
m u ltilev el, 2 9 5
m u ltiple, 2 9 9
sin g le, 2 8 6
inner fu n ction , 5 7
In or der tr a v er sa l, 4 2 3
input fu n ction , 2 0
In ser tion sor t, 3 2 6
In sta n ce m eth od, 2 8 0
In teg er (int), 2 5 0
In ter section oper a tion on list, 1 7 1
In v er ted diction a r y , 1 7 9
In v oikin g th e fu n ction , 2 0
isEmpty, 3 6 1
isSubclass, 3 09
Iter a tion , 5 7
Iter a tion of th e loop, 5 8

J
Javabridge, 5 6 3
Jpype, 5 6 3
K
Key , 3 1 6 , 5 4 1
Key w or d a r g u m en ts, 3 8
Key w or ds, 1 3
Kiv y , 5 5 0
a pplica tion , 5 6 2
in sta lla tion , 5 5 0
py th on ch a t a pplica tion u sin g , 5 7 0

L
La n g u a g e, 1 3 7
em pty , 1 3 8
n u ll, 1 3 8
r eg u la r , 1 3 7
La st in fir st ou t (LIFO) a r r a n g em en t, 3 5 8
Left bin a r y su btr ee, 4 1 8
Left-ch ild r ela tion sh ip, 4 1 9
LEGB Ru le, 1 1 4
Lin ea r sea r ch , 3 3 0
Lin ked list, 3 8 4
in ser tion a n d deletion a t th e beg in n in g of, 3 8 8
m a in ta in in g sor ted, 4 00
oper a tion s, 3 9 2
sta ck im plem en ta tion u sin g , 4 05 –4 09
str in g r epr esen ta tion of a , 3 9 9
tr a v er sin g a , 3 9 9
list, 2 5 0
List m a n ipu la tion , 3 1 5 –3 5 4
List objects; copy in g , 1 5 9
Lists, 1 5 0–1 5 2
a s a r g u m en t, 1 5 8
in ter section oper a tion on , 1 7 1
tw o-dim en sion a l, 1 5 2
u n ion oper a tion on , 1 7 1
Loa din g th e da ta ba se, 5 4 5
Log ica l oper a tor s, 6
Loop, 5 8
for, 5 8
in fin ite, 6 4
iter a tion of th e, 5 8
n ested, 6 9
while, 6 3

M
Ma ster da ta , 2 4 0
Ma tplotlib, 4 4 5 , 4 8 4
max fu n ction , 2 4
Mem ber sh ip, 1 2 7
Mem or y m a p, 3 4
Meta da ta , 5 4 2
Meth od ov er r idin g , 2 8 9
min fu n ction , 2 4
Modifier , 2 8 0
Modu la r a ppr oa ch , 1 9
Modu le, 1 4
Modu lu s, 2
Mu ltilev el in h er ita n ce, 2 9 5
Mu ltiple in h er ita n ce, 2 9 9
Mu ltiple plots, 4 9 2
N
Na m e m a n g lin g , 2 7 9
NameError, 2 2 8
Na m es, 1 0
Na m espa ces, 1 1 4
Nested fu n ction , 5 6
Nested if-elif-else con dition a l sta tem en t, 5 5
Nested loops, 6 9
Nestin g , 5 5
New -sty le cla sses, 3 06
Node(s), 3 8 4
deletin g , 3 9 6
in ter n a l, 4 1 7
keep tr a ck of, 3 9 7
r oot, 4 1 6
v a lu e of th e, 4 1 6
Nu ll la n g u a g e, 1 3 8
Nu ll str in g , 1 3 7

O
Object a ttr ibu tes, 2 5 5
Object com position , 2 8 4
Object-or ien ted pr og r a m m in g (OOP), 2 7 2
Objects, 2 , 2 5 0
Open a u th en tica tion (OA u th ), 5 2 2
Oper a n ds, 2
Oper a tor ov er loa din g , 2 7 2 , 2 7 3
Oper a tor , 2
a r ith m etic, 5
bitw ise, 8
log ica l, 6
r ela tion a l, 5
OSError, 2 3 0
Ou ter fu n ction , 5 7

P
Pa r a m eter s, 3 3
a ctu a l, 3 3
for m a l, 3 3
fu n ction , 3 3
Pa r en t cla ss, 2 8 5
Pa ss sta tem en t, 7 2
Pa tch es, 5 02
Pa tter n m a tch in g , 1 3 7
Pa tter n w ith in a pa tter n , 4 4 5
Picklin g , 2 2 6
Piv ot elem en t, 3 5 1
Plottin g a poin t, 4 8 4
Poly m or ph ism , 2 7 2
Pop, 3 5 8 , 3 6 1
Popu la tin g th e da ta ba se, 5 4 5
Postfix for m , 3 6 3
Postor der tr a v er sa l, 4 3 0
pow fu n ction , 2 4
Pr eor der tr a v er sa l, 4 2 9
print fu n ction , 2 1
Pr oblem of Tow er of Ha n oi, 2 1 4 –2 1 8
Pr oblem s
eig h t qu een s, 4 4 8
Kn ig h t’s Tou r , 4 5 5
sta ble m a r r ia g e, 4 6 4
Pr og r a m , 1 4
Pr oper ties, 5 5 1
Pseu docode, 3 2
push, 3 5 8 , 3 6 1
Py4j, 5 6 3
Pyjnius, 5 6 3
Pyplot m odu le, 4 8 4
Py th on , 1
a pplica tion s of, 5 2 1 –5 7 6
a r r a y s in , 5 6 5
code, 1
editor , 1
er r or s, 2 2 7
in teg r a tin g ja v a w ith , 5 6 3
sh ell, 2
str in g s, 4 , 1 2 5
sty le, 1 0
tu tor , 1 01
v isu a l, 5 09
Py th on Copy , 2 2 5
Py th on tu tor in ter fa ce, 1 01
Py th on ic sty le, 1 0
Py th on ic w a y , 1 0

Q
Qu eu e, 3 6 9
Qu eu e oper a tion s, 3 7 2

R
raise key w or d, 2 3 6
Ra n dom n u m ber g en er a tion , 2 4 –2 5
Rea r en d, 3 6 9
Recu r sion , 1 8 8 –2 1 8
Recu r siv e fu n ction , 1 8 8
Recu r siv e solu tion s for pr oblem s on lists, 2 04
copy in g a list, 2 09
deep copy , 2 1 0
fla tten a list, 2 04
per m u ta tion , 2 1 1
Recu r siv e solu tion s for pr oblem s on n u m er ic da ta , 1 8 8 –1 9 7
fa ctor ia l, 1 8 8
fibon a cci sequ en ce, 1 9 4
Recu r siv e solu tion s for pr oblem s on str in g s, 1 9 7 –2 04
len g th of a str in g , 1 9 7
pa lin dr om e, 2 01
r ev er sin g a str in g , 1 9 9
Recu sion , 4 8 1
Reg u la r la n g u a g es, 1 3 7
Rela tion , 5 4 1
Rela tion a l oper a tor s, 5
Retr iev in g a ll m a tch in g pa tter n s, 1 4 4
Rev er sin g a str in g , 1 3 6
Rig h t bin a r y su btr ee, 4 1 8
Rig h t-ch ild r ela tion sh ip, 4 1 9
Root n ode, 4 1 6
Rou n d fu n ction , 2 2

S
Sa v in g fig u r e, 4 9 5
Sca la r da ta ty pes, 1 2 3 , 1 5 0
Scope r u le, 2 9 0
Scope, 1 00–1 2 0
Scr ipt m ode, 1 4
Sea r ch in g , 3 1 5 , 3 2 9
Selection sor t, 3 1 6
set fu n ction s, 1 6 7 , 1 7 1
add, 1 6 7
clear, 1 6 7
difference, 1 6 8
intersection, 1 6 8
pop, 1 6 7
remove, 1 6 7
sy m m etr ic_differ en ce, 1 6 8
union, 1 6 8
update, 1 6 7
Sets, 1 6 6
Sh a llow copy , 2 1 0
Sh a r ed session , 1 02
Sh a r in g da ta a cr oss a pplica tion s, 5 3 2
Sh a r in g da ta u sin g sockets, 5 3 2
Sh or t-cir cu it ev a lu a tion , 7
Sh or th a n d n ota tion , 1 1
Sier pin ski Tr ia n g le, 4 7 1
Sin g le in h er ita n ce, 2 8 6
Sin g leton tu ple, 1 7 3
Size, 3 6 1 , 3 7 3
Slice, 1 2 5
Slicin g , 1 2 5 –1 2 6
socket, 5 3 3
Socket pr og r a m m in g , 5 7 0
Sor t
bu bble, 3 2 0
in ser tion , 3 2 6
m er g e, 3 4 9
qu ick, 3 5 1
Sor tin g , 3 1 5
Sou r ce code, 1 4
Sou r ce file scr ipt, 1 4
SQLite da ta ba se, 5 4 0
Sta ck fr a m e, 1 9 1
Sta ck, 3 5 7
deletion of a n elem en t fr om a , 3 5 8
in ser tion of a n elem en t in a , 3 5 8
Sta tic m eth od, 2 8 0
Stepw ise r efin em en t m eth od, 1 9
Stepw ise r efin em en t pr ocess, 3 2
Str a ig h t lin e fu n ction s, 4 6
Str ea m , 5 3 0
streamListener, 5 3 0
Str ictly bin a r y tr ee, 4 1 8
Str in g (str), 2 5 0
Str in g , 1 3 7
n u ll, 1 3 7
Str in g s, 1 2 3 –1 4 7
r ev er sin g , 1 3 6
Str u ctu r ed qu er y la n g u a g e (SQL), 5 4 1
Su b, 2 8 5
Su b-pr og r a m s, 1 9
Su bset, 1 7 0
Su doku pu zzle, 4 7 7
Su per cla ss, 2 8 5
Su per set test, 1 7 0
Sy m bols u sed in r eg u la r ex pr ession s, 1 3 9 –1 4 0
Sy n ta x er r or , 2 2 7

T
Ta ble(s)
cr ea tin g , 5 4 2
deletin g , 5 4 9
in ser tin g da ta in to, 5 4 5
r etr iev in g da ta fr om , 5 4 6
u pda tin g da ta in a , 5 4 8
Tem por a r y v a r ia ble, 1 3
Testin g , 8 5
Tic-Ta c-Toe g a m e, 5 5 8
Top, 3 6 1
Tr a n sa ction da ta , 2 4 0
Tr a n sm ission Con tr ol Pr otocol/In ter n et Pr otocol (TCP/IP), 5 3 3
Tr ee, 4 1 6
a n cestor /descen da n t, 4 1 7
h eig h t, 4 1 7
in ter n a l n ode, 4 1 7
lea f, 4 1 7
lev el, 4 1 7
pa th a n d pa th len g th , 4 1 7
siblin g s, 4 1 8
su btr ee, 4 1 8
try…except cla u se, 2 3 0
Tu ple, 1 7 2 , 2 5 0, 5 4 1
Tw eet u pda te, 5 3 0
Tw itter , 5 2 1
collectin g follow er s, fr ien ds, a n d tw eets of a u ser , 5 2 6
collectin g tw eets h a v in g specific w or ds, 5 3 0
collectin g in for m a tion fr om , 5 2 1
da ta a n a ly sis, 5 2 2
open a u th en tica tion , 5 2 3
Tw o-dim en sion a l list, 1 5 2
Ty pe con v er sion , 2 3
type fu n ction , 2 2
TypeError, 2 2 9

U
uix m odu le, 5 5 1
Un der flow con dition , 3 5 8
Un der flow , 3 7 0
Un h a n dled ex ception s, 2 3 0
Un ion oper a tion on list, 1 7 1
Un ion oper a tor , 1 3 8
Un picklin g , 2 2 6
Upda te com m a n d, 5 4 8
User -defin ed cla sses, 2 5 0

V
V a lu e of th e n ode, 4 1 6
ValueError, 2 2 9
V a lu es, 2
V a r ia ble cu r r en t, 4 02
V a r ia bles, 9
V isu a lize ex ecu tion , 1 02
V oid fu n ction , 3 6
W
Web Da ta ; A ccessin g , 5 3 9
Wedg es, 4 9 8
Where cla u se, 5 4 7
while loop, 6 3
Widg ets, 5 5 1
Wr a pper fu n ction , 4 3 8 , 4 4 7
Wr itin g str u ctu r es to a file, 2 2 6

Z
ZeroDivisionError, 2 2 9
Colour Illustrations
Pl a t e 1 Fu n ction plot(3 , 2 )to displa y poin t (3 , 2 )(see pa g e 4 8 5 )
Pl a t e 2 Poin t (3 , 2 ) (see pa g e 4 8 6 )

Pl a t e 3 Mu ltiple poin ts (see pa g e 4 8 7 )


Pl a t e 4 Lin e join in g poin ts specified by v ector x a n d y (see pa g e
487 )
Pl a t e 5 Da sh ed lin e join in g poin ts (sta r m a r ker ) specified by
v ector x a n d y (see pa g e 4 8 8 )
Pl a t e 6 Solid lin e join in g poin ts defin ed by v ector s [0, 1 , 2 , 3 , 4 ]
a n d y (see pa g e 4 8 9 )
Pl a t e 7 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e
489)
Pl a t e 8 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e
4 9 0)
Pl a t e 9 Lin e join in g poin ts specified by v ector s x a n d y (see pa g e
491 )
2 3
Pl a t e 10 Fu n ction s f(x ) = x a n d f(x ) = x plotted in th e in ter v a l
[2 .5 , 4 .5 ] in steps of 0.1 (see pa g e 4 9 3 )
Pl a t e 11 Six fu n ction s plotted on differ en t su bg r a ph s in sa m e
fig u r e (see pa g e 4 9 6 )
Pl a t e 12 Histog r a m (see pa g e 4 9 7 )
Pl a t e 13 Histog r a m (see pa g e 4 9 8 )
Pl a t e 14 Pie ch a r t (see pa g e 4 9 9 )
Pl a t e 15 Sin e a n d cosin e cu r v e (see pa g e 5 01 )
Pl a t e 16 Cir cle (see pa g e 5 03 )
Pl a t e 17 Ellipse (see pa g e 5 05 )

Pl a t e 18 Recta n g le (see pa g e 5 06 )
Pl a t e 19 Poly g on (see pa g e 5 07 )
Pl a t e 20 Box (see pa g e 5 1 1 )
Pl a t e 21 Sph er e (see pa g e 5 1 1 )
Pl a t e 22 Rin g (see pa g e 5 1 3 )
Pl a t e 23 Cy lin der (see pa g e 5 1 4 )
Pl a t e 24 A r r ow (see pa g e 5 1 5 )
Pl a t e 25 Con e (see pa g e 5 1 6 )
Pl a t e 26 Cu r v e (see pa g e 5 1 7 )
Pl a t e 27 Sn a psh ots of bou n cin g ba ll (see pa g e 5 1 8 )
Editor—Acquis itions : Neh a Goom er
Editor—Production: M. Ba la kr ish n a n
Copy r igh t © 2018 Pea r son In dia Edu ca t ion Ser v ices Pv t .
Lt d
Th is book is sold su bject to th e con dition th a t it sh a ll n ot, by w a y
of tr a de or oth er w ise, be len t, r esold, h ir ed ou t, or oth er w ise
cir cu la ted w ith ou t th e pu blish er ’s pr ior w r itten con sen t in a n y
for m of bin din g or cov er oth er th a n th a t in w h ich it is pu blish ed
a n d w ith ou t a sim ila r con dition in clu din g th is con dition bein g
im posed on th e su bsequ en t pu r ch a ser a n d w ith ou t lim itin g th e
r ig h ts u n der copy r ig h t r eser v ed a bov e, n o pa r t of th is
pu blica tion m a y be r epr odu ced, stor ed in or in tr odu ced in to a
r etr iev a l sy stem , or tr a n sm itted in a n y for m or by a n y m ea n s
(electr on ic, m ech a n ica l, ph otocopy in g , r ecor din g or oth er w ise),
w ith ou t th e pr ior w r itten per m ission of both th e copy r ig h t ow n er
a n d th e pu blish er of th is book.
ISBN 9 7 8 -9 3 -3 2 5 -8 5 3 4 -8
eISBN 9 7 8 -9 3 -5 2 8 -6 6 03 -8
Fir st Im pr ession
Pu blish ed by Pea r son In dia Edu ca tion Ser v ices Pv t. Ltd, CIN:
U7 2 2 00TN2 005 PTC05 7 1 2 8 , for m er ly kn ow n a s Tu tor V ista
Globa l Pv t. Ltd, licen see of Pea r son Edu ca tion in Sou th A sia .
Hea d Office: 1 5 th Floor , Tow er -B, Wor ld Tr a de Tow er , Plot No. 1 ,
Block-C, Sector 1 6 , Noida 2 01 3 01 , Utta r Pr a desh , In dia .
Reg ister ed Office: 4 th Floor , Softw a r e Block, Eln et Softw a r e City ,
TS 1 4 0, Block 2 & 9 , Ra jiv Ga n dh i Sa la i, Ta r a m a n i, Ch en n a i 6 00
1 1 3 , Ta m il Na du , In dia .
Fa x : 08 0-3 04 6 1 003 , Ph on e: 08 0-3 04 6 1 06 0
Website: in .pea r son .com . Em a il:
com pa n y secr eta r y .in dia @pea r son .com
Compos itor: Ma cr oTex Solu tion s, Ch en n a i.
Printed in India.

You might also like