Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
47 views850 pages

Introduction To Python by Rachna Verma

This document is an eBook titled 'Introduction to Python' authored by Dr. Rachna Verma and Dr. Arvind Kumar Verma, providing a comprehensive guide to the Python programming language. It covers fundamental to advanced concepts, including programming basics, data structures, object-oriented programming, and file handling, along with numerous examples and practice problems. The book is intended as a textbook for students learning Python and emphasizes practical applications in industrial and academic contexts.

Uploaded by

kharmukilan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
47 views850 pages

Introduction To Python by Rachna Verma

This document is an eBook titled 'Introduction to Python' authored by Dr. Rachna Verma and Dr. Arvind Kumar Verma, providing a comprehensive guide to the Python programming language. It covers fundamental to advanced concepts, including programming basics, data structures, object-oriented programming, and file handling, along with numerous examples and practice problems. The book is intended as a textbook for students learning Python and emphasizes practical applications in industrial and academic contexts.

Uploaded by

kharmukilan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 850

i

Introduction to Python

First Edition (eBook)

Rachna Verma
Professor of Master of Computer Application,
Faculty of Engineering and Architecure,
JNV University, Jodhpur, Rajasthan, India

Arvind Kumar Verma


Professor of Production and Industrial Engineering,
Faculty of Engineering and Architecture,
MBM University, Jodhpur, Rajasthan, India

ii
Introduction to Python
Copyright © 2024 Dr. Rachna Verma and Dr. Arvind Kumar Verma
ISBN:
First published in India by Dr. Rachna Verma and Dr. Arvind Kumar Verma
All rights reserved. No part of this publication may be reproduced or distributed
in any form or by any means, or stored in a data base or retrieval system, without
the prior written permission of the authors.
Cover (illustration) by Dr. Rachna Verma
Set by Dr. Rachna Verma
Published by https://kdp.amazon.com

This book provides a comprehensive, hands-on introduction to Python, a


powerful and one of the most widely used computer programming language.
Starting with basic concepts, the book lucidly builds advanced Python
programming concepts one needs for solving real-life industrial and academic
problems. The book contains a large number of illustrative examples and
practice problems. The book is well suited as a textbook for learning Python for
students. It is sold under the express understanding that the information
contained in this book is accurate to the best of authors’ knowledge. However,
the authors will not be held responsible for the consequences of any actions
based on the content of the book for any purpose.

iii
Introduction to Python
Table of contents

Preface xiii
1. Introduction to Computing 1
1.1 Components of a Computer 1
1.1.1 Input Devices 2
1.1.2 Output Devices 2
1.1.3 Central Processing Unit 2
1.1.4 Memory 4
1.2 Computer Software 4
1.2.1 Types of System Software 5
1.3 Programming Languages 7
1.3.1 Types of Computer Programming Languages 9
1.4 Algorithms and Flowcharts 12
1.4.1 Guidelines to Write Algorithms 13
1.4.2 Examples of Some Algorithms 14
1.4.3 Pseudocode 17
1.4.4 Flowchart 18
1.4.5 Examples of Flowcharts 19
1.4.6 Python Programs 25
2 Overview of Python 33
2.1 History of Python 33
2.2 Why Python? 34
2.3 Installing Python 35
2.4 Starting Python In Windows 39
2.4.1 Python Command Prompt 39

iv
2.4.2 Python IDLE 41
2.5 Structuring Python Programs 44
2.5.1 Python Statements 44
2.5.2 Line Continuation 45
2.5.3 Comments in Python 46
2.5.4 Proper Indentation 48
2.6 Structure of a Python Program 49
2.7 Coding Style 51
2.8 Identifier Naming Convention 52
2.9 Python Implementations 53
2.10 Python IDEs 54
2.11 Python Distributions 55
3 Basics of Python Programming 61
3.1 Character Set 61
3.2 Python Token 63
3.3 Keywords 63
3.4 Identifiers 66
3.4.1 Rules for Naming Identifiers 67
3.5 Literals and Datatypes 68
3.5.1 String Literals 68
3.5.2 Numeric Literals 75
3.5.2.1 Integer Literals 75
3.5.2.2 Floating-Point Literals 77
3.5.2.3 Complex Number Literals 78
3.5.3 Boolean Literals 79
3.5.4 Collection Literals 80
3.5.4.1 List Literals 80
3.5.4.2 Tuple Literals 81
3.5.4.3 Dictionary Literals 82
3.5.4.4 Set Literals 84

v
3.5.5 Special Literal None 85
3.6 Variables 86
3.7 Operators 87
3.8 Delimiters 88
3.9 Input and Output Functions 90
3.9.1 The Input Function 90
3.9.2 Reading Single Numeric Data 92
3.9.3 Reading Multiple Numeric Data Separated with a Delimiter 95
3.9.4 The Eval Function 97
3.9.5 The Print Function 100
3.10 Formatting Numbers and Strings 102
3.10.1 The Traditional % Formatting Operator 102
3.10.2 The Format Function 106
3.10.3 Formatting with the Format Method of the Str Object 109
3.10.4 F-String in Python 112
4 Operators and Expressions 123
4.1 Operators 123
4.1.1 Arithmetic Operators 123
4.1.2 Relational (Comparison) Operators 129
4.1.3 Logical Operators 130
4.1.4 Bitwise Operators 133
4.1.5 Assignment Operators 135
4.1.6 Membership Operators 139
4.1.7 Identity Operators 141
4.2 Expressions 143
4.2.1 Arithmetic Expressions 143
4.2.2 Logical Expressions 145
4.2.3 String Expressions 146
4.3 Operator Precedence and Associativity 147
4.4 Statements vs Expressions 150

vi
4.5 Python Built-in functions 150
4.6 Importing Mathematic Functions 167
5 Decision Making and Branching 189
5.1 if Statement 189
5.2 if-else Statement 193
5.3 Nested if Statement 195
5.4 Ladder if (if-elif-else) Statement 198
5.5 Ternary Operator 203
5.6 pass Statement 206
6 Loop Control Statements 219
6.1 while Loop 220
6.2 for Loop 224
6.3 break Statement 226
6.4 continue Statement 229
6.5 else Statement 233
6.6 Nested Loops 236
6.7 quit () and exit () Functions 236
7 User-Defined Functions 261
7.1 Introduction 261
7.2 Defining a User-defined Function 265
7.3 Parameters and Arguments in a Function 267
7.3.1 Positional Parameters 268
7.3.2 Parameters with Default Values 268
7.3.3 Keyword Arguments 269
7.3.4 Variable Number of Parameters 271
7.4 Calling a Function 273
7.5 Local and Global Functions 276
7.6 Scope and Life of a Aariable 277
7.6.1 Local Variables 277
7.6.2 Global Variables 278

vii
7.7 Passing Arguments to a Function 281
7.8 Return Values from Functions 285
7.8.1 Returning Multiple Values from a Function 286
7.9 Passing and Returning Function Objects to a Function 288
7.10 Recursive Functions 289
7.11 Lambda Function 290
7.12 Generator Functions 291
7.13 Command Line Arguments 293
8 Lists 315
8.1 List Creation 315
8.1.1 Lists from Data 315
8.1.2 Converting Other Data Types to Lists 316
8.1.3 List Comprehension to Create a New List 318
8.1.4 Split a String into a List of Words 321
8.2 Accessing an Element of a List 321
8.2.1 List Traversal 323
8.3 List Slicing 324
8.3.1 Traversing Sliced List 326
8.4 Commonly Used Built-in Function for Lists 327
8.4.1 The max() and min () Functions for a List of Lists or Iterables 330
8.4.2 The max () and min () Functions with a List of Complex 332
numbers
8.5 Creating Copies of a List 332
8.5.1 Reference Copy 334
8.5.2 Shallow Copy 336
8.5.3 Deep Copy 338
8.6 Methods of the list Class 338
8.7 Random Reshuffle of the Elements of a List 341
8.8 Using a List as a Matrix and an Array 343
8.8.1 Creating a Matrix from Data 343

viii
8.8.2 Creating an Array from data 345
8.8.3 Reading a Matrix from the Keyboard 349
8.8.4 Nested List Comprehension to Process Matrices 351
8.9 List Operators 353
9 Strings 377
9.1 Creating String Objects 377
9.1.1 Assigning a String Literal to a Variable 377
9.1.2 Using the Construction of the string Class 378
9.2 Built-in Functions for Strings 379
9.3 Accessing Characters in a String 379
9.4 Traversing a String 380
9.5 Slicing Operation with a String 381
9.6 String Operators 383
9.7 String Class Methods 383
10 Tuples, Sets and Dictionaries 403
10.1 Tuple 403
10.2 Create Tuples 404
10.2.1 From Data 404
10.2.2 From Other Iterables 404
10.2.3 Using Comprehension 405
10.3 Built-in Functions for Tuples 407
10.4 Indexing of Tuple Elements 409
10.5 Slicing of Tuples 410
10.6 Operations on Tuples 410
10.7 Traversing Tuples 411
10.8 Sorting a Tuple 413
10.9 Zipping Tuples Together 413
10.10 Tuple Methods 414
10.11 Lists and Other Mutable Sequences as Elements of Tuples 415
10.12 Tuple vs List 416

ix
10.13 Sets 417
10.14 Creating Sets 417
10.15 Built-in Functions for Sets 419
10.16 Membership Operators: in and not in 420
10.17 Set Methods 420
10.18 Traversing Sets 424
10.19 Frozenset 425
10.20 Dictionaries 426
10.21 Creating Dictionaries 426
10.22 Accessing a Dictionary Element 430
10.23 Nested Dictionary 430
10.24 Removing an Element from a Dictionary 431
10.25 Traversing a Dictionary 431
10.26 Built-in Functions for Dictionaries 432
10.27 Methods of the dict Class 433
11 File Handling 453
11.1 Types of Files 453
11.2 Steps in File Handling 454
11.3 Opening a File 455
11.4 Reading from a Text File 462
11.5 Writing into a Text File 465
11.6 Writing Numbers and Booleans in a File 467
11.7 Reading Numbers from a File 468
11.8 Seek and Tell Methods 469
11.9 Iterating Over Lines in a File 471
11.10 Accessing Binary Files 471
11.11 Serialization in Python 476
11.11.1 The pickle Module 477
11.11.2 The json Module 478
11.12 CSV Files 485

x
11.13 File and Directory Management 488
12 Object Oriented Programming in Python 513
12.1 Basic concepts of Object-Oriented Programming 514
12.1.1 Objects and Classes 514
12.1.2 Data Encapsulation 515
12.1.3 Inheritance 515
12.1.4 Polymorphism 518
12.1.5 Dynamic Binding 519
12.1.6 Message Passing 519
12.2 Define a Class in Python 520
12.3 Constructors and Destructor 524
12.4 Encapsulation in Python 528
12.5 Instance Methods 531
12.6 Name Mangling 533
12.7 Display Class Attributes and Instance Methods 534
12.8 Inheritance in Python 536
12.9 Types of Inheritance in Python 540
12.10 The object Class 543
12.11 Method Resolution Order in Python 544
12.12 Type and Class Membership Tests 548
12.13 Polymorphism in Python 550
12.14 Method Overloading 550
12.15 Operator Overloading 552
12.16 Overloading Built-in Python Functions 557
12.17 Decorator Classes 558
13 Exception Handling in Python 576
13.1 Python Built-in Exceptions 578
13.2 Handling a General Exception 581
13.3 Catching Specific Exceptions 582
13.4 Raising Exceptions 589

xi
13.5 User-defined Exception 590
13.6 Assertions 592
14 Introduction to NumPy 603
14.1 Introduction 603
14.2 NumPy Arrays 603
14.3 Data structure of NumPy arrays 605
14.4 Creating Arrays in NumPy 607
14.5 Attributes of the ndarray Class 618
14.6 Indexing and Slicing NumPy Arrays 620
14.7 Operations on NumPy Arrays 626
14.7.1 Element-wise Operations 626
14.7.2 Matrix and Linear Algebra Functions 629
14.7.3 Reduction Operations on Arrays 635
14.7.4 Broadcasting NumPy Arrays 637
14.7.5 Array Shape Manipulation 639
14.7.6 Sorting Data 643
14.8 Structured NumPy Arrays 644
15 Introduction to Matplotlib 663
15.1 Steps to Create a Plot in Matplotlib 663
15.2 The plot Method 666
15.3 Creating Sub-plots 670
15.4 Customizing a Plot 672
15.4.1 Adding Axis Labels and Plot Titles 672
15.4.2 Adding a Grid to a Plot 674
15.4.3 Adding Ticks and Tick-labels 676
15.4.4 Adding Legends 678
15.4.5 Twin Axis 680
15.5 Bar Charts 682
15.6 Histogram Plots 687
15.7 Pie Chart 689

xii
15.8 Scatter Plots 691
15.9 Contour Plots 692
15.10 Box Plots 694
15.11 Violin Plots 696
15.12 Quiver Plots 698
15.13 3D Plots 700
15.14 3D Contour Plots 703
15.15 Wireframe and Surface Plots 705
15.16 Animation using Matplotlib 707
15.16.1 Steps to Create an Animation Plot using FuncAnimation 708
15.16.2 Steps to Create Animation Plot using ArtistAnimation 710
16 GUI Applications using tkinter 727
16.1 Introduction to Graphics User Interface 727
16.2 Components of Event Driven Programming 729
16.2.1 Widgets 729
16.2.2 Events 731
16.2.3 Event Listener Functions 735
16.3 Creating a GUI Application using the tkinter Module 735
16.4 Creating and Customizing the Main Application Window 739
16.5 Creating Widgets 741
16.5.1 Standard Attributes of Widgets 742
16.5.2 Geometry Layout Manager 750
16.6 Button Widget 765
16.7 Canvas Widget 768
16.8 Checkbutton Widget 779
16.9 Entry Widget 783
16.10 Frame Widget 785
16.11 Label Widget 787
16.12 Listbox Widget 788
16.13 Menu Widget 795

xiii
16.14 Menubutton Widget 799
16.15 Message Widget 801
16.16 Radiobutton Widget 802
16.17 Scale Widget 804
16.18 Scrollbar Widget 806
16.19 Text Widget 808
16.20 Toplevel Widget 811
16.21 Spinbox Widget 812
16.22 Messagebox Widget 814
Index 824

xiv
Preface
Python is a very powerful and one of the most widely used computer programming
language for general purpose, scientific and technical computations. Its popularity is
due to a huge collection of library functions and very easy to learn. Further, a large
number of help material and forums are available for Python. Since it is freely available,
many commercial developers are also using it to reduce their project cost and has
reported many successful applications.

This book is written following several years of teaching the Python programming
course to our students. The basic objective to write this book is to teach Python in a
friendly, non-intimidating fashion to students who have no previous programming
knowledge and experience. Therefore, the book is written in simple language with many
sample problems in mathematics, science, and engineering. Starting from the basic
concepts, the book gradually builds advanced concepts, making it suitable for freshmen
and professionals. This makes this book unique among the many books available in the
market which assume previous knowledge of a programming language. The book deals
with the latest version of the language.

For promoting outcome-based learning, each chapter of the book starts with chapter
learning objectives and lucidly introduces the basic concepts, with sample examples, to
achieve those objectives. Each chapter concludes with a summary. Finally, the chapter
ends with multiple choice questions, review questions and programming assignments
so as students can apply the concepts learned in the chapter.

The book consists of sixteen chapters. Chapter 1 introduces the basic concepts of
Computing, algorithms, flowcharts and programming. Chapter 2 gives an overview of
Python programming language. Chapter 3 gives the basics of Python Programming.
Chapter 4 discusses the operators available in Python and concepts of expressions.
Chapter 5 introduces the basic concepts of decision making and branching constructs of
Python. Chapter 6 explains loop control statements. Chapter 7 discusses User-Defined
Functions. Chapter 8 introduces the basic concepts of Lists. Chapter 9 describes
Strings. Chapter 10 covers Tuples, Sets and Dictionaries. Chapter 11 describes File
Handling in Python. Chapter 12 presents the basic concepts of Object Oriented
Programming in Python. Chapter 13 briefly explains Exception Handling in Python.
Chapter 14 introduces NumPy forefficeint numerical computations. Chapter 15 gives
overview of Matplotlib to create charts. And Chapter 16 discusses GUI Applications
using tkinter.
xv
We hope that the book will be useful in lucidly building expertise in Python
programming to the readers. We sincerely welcome any suggestion to further improve
the book. Authors can be reached at [email protected], [email protected]
and [email protected] .

Rachna Verma

Arvind Kumar Verma

xvi
About the Authors

Dr. Arvind Kumar Verma is working as a Professor, Department of Production


and Industrial Engineering, MBM University, Jodhpur, Rajasthan, India. He
received his BE (Industrial Engineering) and ME (Production and Industrial
Systems Engineering) from IIT Roorkee, India and obtained his PhD in
CAD/CAM from MBM Engineering College, Jai Narain Vyas University,
Jodhpur, Rajasthan, India. He has 30 years of teaching experience. He teaches
numerical methods, CAD/CAM, robotics, and computer programming. He has
research interest in robotic vision, machining feature recognition and numerical
computation.

Dr. Rachna Verma is working as a Professor of Master of Computer Application,


Faculty of Engineering, Jai Narain Vyas University, Jodhpur, Rajasthan, India.
She received her BSc (Math Honours) form Delhi University, India and MCA
and PhD from JNV University, Jodhpur, India. She has 21 years of teaching
experience. She teaches numerical methods, computer programming and
computer graphics, visual computing, Machine learning and Data Science and
has research interest in deep learning, computer vision and image processing.

xvii
xviii
Chapter 1

Introduction to Computing
Learning outcomes
1. Describe computer, its components, and its functioning
2. Describe different types of software
3. Describe types of programming languages
4. Develop programming logic using flowcharts and algorithms

According to the Cambridge dictionary, a computer is an electronic machine used


to store, organize, and find words, numbers, and pictures, do calculations and control
other devices. It has a significant impact on every aspect of our life and profession.
Engineering, science, medicine, commerce, and even social sciences are widely using
computers. Hence, computer literacy and knowledge are now essential skills for every
profession. Computing is now one of the most sought-after careers that involve using
computers for data processing to efficiently and economically solving real-life problems.
To effectively use a computer, a basic understanding of various computer components
and computer programming are essential for students and professionals.

1.1 Components of a Computer


A computer system has two main components: hardware and software. The physical
parts, such as keyboard, mouse, display unit, CPU, associated with a computer system
is called hardware. On the otherhand, software is a set of instructions that tells the
hardware what to do. Figure 1.1 shows a block diagram of major hardware components
of a computer: input devices, central processing unit, memory, and output devices.
Arrows indicate the direction of the flow of data/information among different
components.

1
Input devices Central processing unit Output devices

Memory

Figure 1.1: Components of a computer

1.1.1 Input Devices

An input device reads data. The data can be in the form of numbers, texts,
images/videos, sound waves, etc. The read data can either be processed by the CPU or
stored in memory. The typical input devices are keyboards, mice, scanners, cameras,
joysticks, microphones.

1.1.2 Output Devices

An output device in a computer is a device that converts information produced by


the CPU into human-readable form. The outputs produced by these devices can be in the
form of texts/numbers, images/videos, audio. The typical output devices are visual
display units (monitors), printers, plotters, speakers.

1.1.3 Central Processing Unit

A central processing unit (CPU) is an electronic circuitry, usually a VLSI circuit, in a


computer that executes computer programs. It is responsible for all the data processing
and performs basic arithmetic, logic, controlling, and input/output (I/O) operations
specified by the instructions in a program. Primarily, a CPU consists of arithmetic and
logic unit (ALU), control unit (CU), internal memory (also called registers), instruction
decoder, and buses (set of wires to transfer data from one place to another). Figure 1.2
shows a detailed block diagram of a computer along with components of a CPU. Functions
of various components of a CPU are as given below:

Arithmatic and logic unit: The ALU unit consists of electronic circuits to perform addition,
subtraction, comparison, and other operations.

2
Instruction decoder: The instruction decoder unit decodes the instruction to be executed
by the processor.

Control Unit: The control unit generates required control signals to different components
for their operations. Due to this, CU is called the brain of a computer.

Registers and Cache memory: To efficiently perform various operations, the CPU has a
few high-speed internal memories, commonly known as registers. In addition to the above,
to further reduce the memory access time and enhance the computational speed of
computers, modern-day CPUs have additional high-speed memory called cache memory.

Busses: Busses, a bunch of wires, are used to exchange data and control signals among
various components. In figure 1.2, they are shown with lines.

Instruction decoder Data flow

Control unit

Input devices Arithmetic and logic unit Output devices

Registers

Memory

Figure 1.2: Detailed block diagram of a computer

3
1.1.4 Memory

Computer memory is a physical device where data/information and programs can be


stored and retrieved, such as RAM, ROM, hard disk, flash memory. Some computer
memories are high-speed but volatile (e.g., RAM), while others are slow but permanent
(e.g., hard disk). Figure 1.3 shows a classification of different types of memory: primary
and secondary. The CPU of a computer can directly interact only with the primary
memory. The primary memory is also known as the main memory. Examples of primary
memory are RAM, ROM, and Cache. Unlike the primary memory, the CPU cannot directly
interact with the data stored in a secondary memory. The data stored in a secondary
memory are first loaded into the primary memory for further processing. Examples of
secondary memory are hard disk, solid-state disk/drive, flash drive, magnetic tape. The
secondary memory is slower than the primary memory. Computer memories are also
classified as volatile and non-volatile memory. The volatile memory losses its data once
the computer power is turned off, for example, RAM. The non-volatile memory, such as
ROM, hard disk, and pen drive, is permanent and retains its data even after turning off a
computer.

Computer memory

Primary memory Secondary memory

Figure 1.3: Different types of computer memory

1.2 Computer Software


Computer software is a set of instructions to be executed on a computer to solve
problems. The software is classified as system software and application software,
4
depending on the type of task it performs. The system software is a computer program
designed to operate and manage computer hardware, and create and run application
programs, such as Linux, Windows, C++, Python. On the other hand, the application
software performs a specific type of task for the user. There is a vast list of application
software. Some common examples are image editing (Adobe Photoshop, MS Paint),
word processing (MS Word, Notepad), electronic spreadsheet (MS Excel), database
management (MySQL, Oracle, MS Access), accounting (Tally), creating engineering
drawings (AutoCAD, Solid work). Figure 1.4 shows the relationship between computer
hardware and software. Table 1.1 compares system software and application software.

1.2.1 Types of System Software

System Software can be of the following types, based on the kind of work they perform:

(a) Operating systems: An operating system, commonly called OS, is computer


software that works as an interface between a computer user and computer
hardware. The operating system typically performs file management, memory
management, process management, handling input and output devices. Commonly
used operating systems are MS Windows, Linux, Unix.

(b) Programming languages: A programming language is a program that provides


tools to develop/modify the software. As computers can process instructions given
as binary numbers (consisting of 1s and 0s), programming languages help to create
instructions in human-readable English-like languages (called source code) and
convert them into computer-understandable binary instructions (called executable
program). Some popular programming languages are C, C++, Java, Python, PHP,
JavaScript, C#, R, Swift, Kotlin.

(c) Utility programs: Utility programs help users in system maintenance tasks and
perform tasks of routine nature. Common utility tasks are disk defragmentation,
disk clean-up, compression, virus cleaning. Some examples are CCleaner,
Everything, Partition Wizard, WinZip.

5
User

Application Software

System Software

Hardware (CPU, Keyboard,


Mouse, Monitor, Printer, etc.)

Figure 1.4: Relationship of computer hardware and software

Table 1.1: Comparison of system and application software

S. No. System Software Application Software

1. System software manages computer Application software is used to


hardware and application software. solve a specific task of the user.

2. System software, specifically an Application software is installed


operating system, is essential for as per the user’s requirements.
computer operations.

3. Usually, a user does not directly In general, a user directly interacts


interact with the system software as it with an application software and
works in the background. provides the necessary inputs.

4. A system software can run Application software requires an


independently. operating system to run.

1.3 Programming Languages


6
A computer is an electronic machine that processes a set of predefined binary codes,
called machine instructions. Each code drives the computer circuit to perform a particular
task. A program is a set of machine instructions and it can be written in different ways as
given below:

Machine level programming: For example, on the execution of the binary code 1010000
(equal to 80 in hexadecimal) on an 8085 microprocessor, the processor will add the number
stored in register B with the number stored in register A and store the result back in register
A. A computer program is a set of such binary codes written in a particular sequence to
solve a problem. However, it is incredibly tedious and cumbersome to write instructions
manually in binary codes (called machine-level programming) even for simple tasks.
Further, each different type of CPU has its unique machine codes, making programming
more complex.

Assembly-level programming: To overcome the above difficulties, programmers started to


use symbolic codes (called mnemonics) in place of binary codes. This programming style is
called assembly-level programming. For example, instead of writing code 1010000 (or 80),
an assembly program uses ADD B. Each machine instruction is mapped to a unique
mnemonic. A computer program, called assembler, is used to covert an assembly program
into an equivalent machine code program. The assembly programming made the life of a
programmer a bit easier, but it is still a very tedious task to write complex programs.

High-level languages: To make programming easier, many human-readable English-like


languages (called high-level languages) are now widely used. Again, with the help of
compilers/interpreters, programs written in high-level languages are converted into
machine code programs. Please note, even a modern computer still understands machine
codes only. Figure 1.5 shows levels of computer programming based on the ease of
programming.

7
Ease of programming
Python, Java, C++, C,
FORTRAN, JavaScript
High Level Languages

Assembly code

Machine code

Computer hardware

Figure 1.5: Levels of computer programming

A programming language uses a predefined vocabulary, and grammatical and


syntax rules for creating instructions for a computer or computing device to perform
specific tasks. A programming language provides facilities to create/modify a program and
convert the program into executable codes. Usually, the term programming language refers
to a high-level programming language, such as BASIC, C, C++, Java, FORTRAN, Python.
Each programming language has a unique set of vocabulary (keywords) and a special
syntax for organizing program instructions.

Every language has its strengths and weaknesses. For example, FORTRAN is
suitable for scientific data processing but has no mechanism to organize and manage large
programs. C++ and Java have powerful object-oriented features, but it is complex and
challenging to learn. Python is suitable for interactive programming but slower in
comparison to C.

According to IEEE Spectrum's interactive ranking of programming languages,


Python is the top programming language of 2020, followed by C, Java, and C++. However,
the choice of a programming language depends on the nature of the task in hand, the target
computer, and the programmer's expertise.

8
1.3.1 Types of Computer Programming Languages

A computer program, called source code, can be written any plain text editor, such
as Notepad, Notepad++. However, most modern programming languages have their
integrated development environments (IDE) to create/edit, compile and run a program. A
computer program written in any programming language is finally converted into machine
codes so that the computer can understand and process it. Based on the ways high-level
programs are converted into machine codes, a programming language can be classified as
a compiled, interpreted, or intermediate programming language.

Compiled programming language: In a compiled programming language, the complete


source code of a program is directly converted into an executable machine code in one go.
Examples of compiled languages are C, C++, Erlang, Haskell, Rust, and Go.

A source code passes through several steps before it is converted into an executable
program. Figure 1.6 shows the major steps of this conversion. The basic steps to generate
an executable program are:

• In the first step, the compiler checks syntax errors in the source code, and if there is no
error, it converts the high-level source code into an assembly code.

• In the second step, the assembler converts the assembly code into the native object code,
i.e. machine code of a particular machine.

• Finally, the linker combines the object code, libraries, and other object codes into an
executable program. Every language has libraries of commonly used tasks, such as to
find square root, sine of an angle, etc. Other object codes are precompiled user defined
sub-programs.

Interpreted programming language: In an interpreted programming language, the


interpreter checks for the syntax errors and executes the program line-by-line. After running
a statement, it moves to the following statement of the program. If there is a syntax error in
a statement, the program's execution stops; otherwise, the execution will continue until the
program's end.

Figure 1.7 shows a block diagram of an interpreted programming language.


Interpreted languages are generally slower than compiled languages, but with just-in-time
compilation, the interpreted languages have comparable performance compared to

9
compiled languages. Examples of popular interpreted languages are PHP, Ruby, Python,
and JavaScript.

Intermediate programming language: In an intermediate programming language, the


high-level source code is first converted into a machine and platform-independent byte
code. Finally, a virtual machine (a virtual machine is a software) interprets the byte code
instructions and translates them into computer-specific machine codes. Figure 1.8 shows a
block diagram of an intermediate programming language. The major advantage of this
approach is that the same byte code can be executed on different types of CPUs and
operating systems without needing recompilation. However, this approach requires a
virtual machine for each type of computer and operating system. Due to one extra step, it
is a bit slower than purely compiled languages. A popular example of the intermediate
language is Java. Table 1.2 compares compiled and interpreted languages.

Source code

Specific Compiler

Assembly code

Assembler

Object code

Other object
Libraries Linker codes

Executable code

Figure 1.6: Block diagram of a compiled language

10
Source code

Runtime libraries Specific interpreter

Executable code

Figure 1.7: Block diagram of an interpreted programming language

Source code

Generic compiler

Byte code

Virtual Virtual Virtual


machine machine machine
Linux Windows Mac OS

Executable code Executable code Executable code

Figure 1.8: Block diagram of an intermediate language

11
Table 1.2: Comparison of compiled and interpreted languages

S.No. Compiled language Interpreted language

1 A compiled language uses a An interpreted language uses an


compiler to convert source codes into interpreter to convert source codes
machine codes. into machine codes.

2 In a compiled language, the complete In an interpreted language, the


program is compiled and converted source code is converted into
to machine codes in one go. machine code line-by-line.

3 Compiled programs run faster than Interpreted programs run slower


interpreted programs. than compiled programs.

5 A single error in the source program Execution of the program halts at the
stops the whole compilation process. occurrence of the first error.

6 The executable code is self-sufficient The interpreter is required on the


to execute and does not require the target machine to execute the
compiler on the target machine. program.

8 Examples of compiled language are Examples of Interpreted language are


C, C++, C#, COBOL, FORTRAN. JavaScript, Perl, Python, PHP,
BASIC.

1.4 Algorithms and Flowcharts

Before writing a computer program for a problem, the programmer should


understand the logic and steps to solve the problem. However, as the complexity of a task
increases, the complexity of the logic and steps also increases. The solution of a complex
real-life problem invariably involves a large number of arithmetic and logical operations.
Further, it is essential to execute these operations in a particular sequence to achieve the
desired results. To develop proper flow and write error-free programs, programmers
frequently use algorithms and flowcharts to visualize the logic and steps of complex tasks.
Hence, algorithms and flowcharts are very powerful tools for developing good

12
programming skills. It is strongly recommended that a learner should master to use these
tools.

An algorithm is a step-by-step problem-solving steps of a task, whereas a flowchart


is a graphical representation of the same. Both algorithms and flowcharts are very helpful
and productive tools to clarify the steps to solve a complex problem. These tools do not
depend on any programming language, computer system, or operating system. Hence, they
are very versatile in nature.

Irrespective of the complexity, size, and nature of a computer programming task,


we can group instructions used to solve the task into three categories: (1) imperative
statements, (2) conditional statements, and (3) iterative statements.

1. Imperative statements: Imperative statements are result-producing action


statements, i.e., they take some data, process them, and return some results, for
example, the addition of two numbers.

2. Conditional statements: Conditional statements help in choosing the execution


flow branches based on some condition. They help in implementing statements like,
do this if this condition is true or do that if some other condition is true. For example,
for an integer value x, if x is divisible by 2, x is an even number; else, x is an odd
number.

3. Iterative Statements: Iterative statements help in repeating the execution of a set of


instructions many times. For example, to print numbers between 1 and 100, we
repeat the statement print (x) for the value of x starting with 1 and increment it by 1
till x reaches 100.

This classification of instructions helps to use standard constructions and symbols


to write algorithms and create flowcharts. Students are encouraged to use these planning
tools to develop logic to solve problems instead of directly jumping to start writing
computer programs. In the long run of their career, this habit is very valuable and
productive.

1.4.1 Guidelines to Write Algorithms

An algorithm is a finite set of steps designed to solve a task. There are no defined rules
to write algorithms, but the following are some guidelines that help in writing practical
algorithms:

13
• Identify the input and output required to solve a task.

• Break the tasks into precise and small steps to easily convert them into statements
of a target programming language. Each step in the algorithm should be clear and
unambiguous.

• Use pseudocodes or a natural language to write an algorithm. An algorithm should


avoid using computer codes of a particular programming language.

• Algorithms should use the most effective and efficient way out of the different ways
to solve a problem.

• Use proper indentations to effectively implement and visualize different


programming constructs, such as looping and branching.

1.4.2 Examples of Some Algorithms

Following are some examples of algorithms.

Example 1.1: An algorithm to add two numbers entered by the user.

Step 1: Start
Step 2: Read num1 and num2.
Step 3: Calculate sum = num1+num2
Step 4: Print sum
Step 5: Stop

Example 1.2: An algorithm to find the largest number among three different
numbers.

Step 1: Start
Step 2: Input a, b and c.
Step 3: If a > b

14
If a > c
x=a
Else
x= c
Else
If b > c
x=b
Else
x=c
Step 4: Print x
Step 5: Stop

Example 1.3: An algorithm to find roots of a quadratic equation ax2 + bx + c = 0.

Step 1: Start
Step 2: Read coefficients a, b and c of the equation
Step 3: Calculate discriminant D = b2 - 4ac
Step 4: If D ≥ 0
r1 = (-b+√D)/2a
r2 = (-b-√D)/2a
Print Real roots are: r1 and r2.
Else
Calculate real part rp = -b/2a
Calculate imaginary part ip = √(-D)/2a
Print Complex roots are: rp+j(ip) and rp-j(ip)

15
Step 5: Stop

Example 1.4: An algorithm to calculate the factorial of a number entered by


the user.

Step 1: Start
Step 2: Read n
Step 3: Initialize factorial =1 and i=1
Step 4: Repeat the steps until i = n
factorial = factorial*i
i = i+1
Step 5: Print factorial
Step 6: Stop

Example 1.5: An algorithm to check whether a given number is a prime


number or not.

Step 1: Start
Step 2: Read n
Step 3: Initialize flag = 1 and i = 2
Step 4: Repeat the following steps until i <=(n/2)
If remainder of n/i equals 0
flag = 0
go to step 5
i= i+1
Step 5: If flag == 0

16
Print n is not prime
else
Print n is prime
Step 6: Stop

1.4.3 Pseudocode

Some programmers use pseudocode to write algorithms. It is written using plain


language describing implementation of an algorithm. In computer programming,
pseudocode is a more structured convention to write algorithms than simple algorithms. It
is intended for human reading and does not use strict programming constructs and
syntaxes. Since pseudocodes are not specific to any programming language, a programmer
with a different programming background can easily understand it. Example 1.6 uses
pseudocode to write an algorithm.

Example 1.6: A pseudocode to check whether a given number is a prime


number or not.
Pseudocode PRIME
{
print “Enter a number”
read n
flag= 1
i=2
while i <= n/2
{
if remainder of n/i == 0
{
flag = 0
exit loop
}
i= i+1
}
If flag == 0
{
print “The given number is not a prime number.”

17
}
Else
{
print “The given number is a prime number.”
}
}

1.4.4 Flowchart

A flowchart is a graphical representation of an algorithm using a set of standard


symbols. It helps in the visualization of steps to solve a problem. Based on the fact that a
picture is worth a thousand words, we quickly grasp the information presented to us in a
graphical form compared to the text form. Programmers widely use flowcharts to crystalize
the logic of a program before writing the program. Table 1.3 lists the commonly used
symbols in flowcharts with a brief description of each.

Table 1.3: Commonly used flowchart symbols

Symbol Name Description


(Shape)
Flowline It shows the sequence/flow of execution of connected
(Arrow) blocks. Execution flows in the direction of the
arrowhead.

Terminal It represents the start or the end of a flowchart.


(Oval)
Process It represents imperative statements, i.e.,
(Rectangle) programming statements which processes data and
produces results.

Decision It shows a decision point at which the execution flow


branches in different flow directions based on some
(Diamond) condition. It is also called branching operation, where
the execution flow can choose a path out of different
paths based on some criterion.

18
Input-Output It represents input or output operations, i.e., reading
(Parallelogram) or writing data from/to input/output devices.

On-page A pair of on-page connectors remotely connect two


Connector blocks on the same page of a flowchart. It reduces the
clutter of flowlines.
(Circle)

Off-page A pair of off-page connectors connect two blocks on


Connector two different pages of a long multipage flowchart.

1.4.5 Examples of Flowcharts

Following are the flowcharts of the algorithms given in section 1.5.2.

19
Example 1.7: A flowchart to add two numbers entered by the user.

Start

Read num1, numb2

Sum=num1 + num2

Print sum

Stop

20
Example 1.8: A flowchart to find the largest number among three different
numbers.

Start

Read a, b, c

yes no
a>b
no no
a>c b>c
yes yes
x=c
x=a x=b

Print x

Stop

21
Example 1.9: A flowchart to find roots of a quadratic equation ax2 + bx + c = 0.

Start

Read a, b, c

d = b2-4ac

yes no
d >= 0
r1 = (-b+√d)/2a rp = -b/2a
r2 = (-b-√d)/2a ip = √(-d)/2a

Print rp, ip
Stop

Stop

22
Example 1.10: A flowchart to calculate the factorial of a number entered by
the user.

Start

Read n

factorial=1
i=1

factorial= factorial * i
i=i+1

yes
i<n
no
Print
factorial

Stop

23
Example 1.11: A flowchart to check whether a given number is a prime
number or not.

Start

Read n

flag=1
i=2

reminder= mod (n, i)


i=i+1

yes
Is reminder =0?
no flag=0
yes

Is i<=n/2?
no

no yes
Is flag =1?

Print “Not Prime” Print “Prime”

Stop

24
1.4.6 Python Programs

Following is a Python program that finds out whether a given number is a prime
number or not. The program implements the flowchart shown in example 1.11. Readers
may skip this section as the basic syntaxes of Python are introduced in chapter 2. However,
it shows that a Python program is easy to understand as it is very near to a natural language.
This feature makes Python a popular programming language.

Example 1.12: A Python program to test a given number whether it is prime


or not.
#Find out if the given number is a prime or not
#Read the number to be tested
n =int(input("enter an integer number:"))
#Initialise the variables
flag=1
i=2
while(i<n//2):
if n%i == 0: #Test for divisibility
flag=0
break
i=i+1
if flag== 1: #Prime, if no divisor is found
print(n, " is a prime number ")
else:
print(n, " is not a prime number")

Output

enter an integer number:20


20 is not a prime number

enter an integer number:31


31 is a prime number

25
Chapter Summary

1. A computer is an electronic machine used for storing, organizing, and finding


words, numbers, and pictures, doing calculations, and controlling other
devices.
2. A computer system has two main components: hardware and software
3. Input devices are used to read data
4. Output devices are used to display information
5. The central processing unit (CPU) is the brain of a computer. It consists of
ALU, CU, and memory.
6. Computer memory is any physical device where data/information and
programs are stored and retrieved when required.
7. Computer software is an ordered set of instructions executed on a computer
to perform a particular task or function.
8. The software is classified as system software or application software.
9. System software is used to operate and manage a computer, such as file
management and memory management, executing a program, managing
input and output devices.
10. Application software is used to perform a user's specific task, such as writing
a letter, designing an image, and creating a drawing.
11. A computer programming language is used to create/modify programs.
12. A compiler is a program that converts the complete source code written in a
high-level language into an executable program.
13. An interpreter is a program that converts and executes a high-level source code
into executable codes, line-by-line.
14. An algorithm is the problem-solving steps of a task written in a natural
language, whereas a flowchart is a graphical representation of the problem-
solving steps.
15. A program consists of imperative statements, conditional statements, and
iterative statements.

Multiple Choice Questions

1. Which of the following cannot be performed by a computer?


(a) Store information
(b) Perform calculation
(c) Control other machines
(d) None of the above

26
2. Which of the following is not a part of a computer?
(a) CPU
(b) Memory
(c) Input device
(d) None of the above
3. Which of the following is an input device?
(a) Printer
(b) Speaker
(c) joystick
(d) Monitor
4. Which of the following is not an output device?
a) Printer
(b) Speaker
(c) Camera
(d) Monitor
5. Which of the following is not a part of the CPU of a computer?
(a) ALU
(b) CU
(c) Register
(d) RAM
6. Which of the following is not a permanent memory?
(a) RAM
(b) ROM
(c) Hard disk
(d) Flash memory
7. Which of the following is not a system software?
(a) Windows
(b) Linux
(c) Notepad
(d) Unix
8. Which of the following is an application software?
(a) MS Word
(b) Tally
(c) AutoCAD
(d) All of the above

27
9. Which of the following is not performed by the operating system of a
computer?
(a) File management
(b) Memory management
(c) Handling input devices
(d) Write a letter
10. Which of the following is not a programming language?
(a) C++
(b) Java
(c) Python
(d) Linux
11. Which of the following is not an operating system?
(a) Linux
(b) Windows
(c) Unix
(d) None of the above
12. Which of the following is a utility software?
(a) WinZip
(b) CCleaner
(c) Partition wizard
(d) All of the above
13. Which of the following is not a high-level programming language?
(a) C++
(b) Python
(c) Java
(d) None of the above
14. Which of the following is a low-level program?
(a) Python program
(b) BASIC program
(c) Java program
(d) Assembly program
15. Which of the following is a compiled programming language?
(a) C++
(b) Python
(c) PHP

28
(d) None of the above
16. Which of the following is not an interpreted Programming language?
(a) C++
(b) Python
(c) Java
(d) Ruby
17. Which of the following is an intermediate programming language?
(a) C++
(b) Java
(c) Python
(d) FORTRAN
18. Addition of two numbers is _____________.
(a) an imperative statement
(b) a conditional statement
(c) an iterative statement
(d) None of the above
19. Choosing a flow path based on the comparison of two numbers is
_____________.
(a) an imperative statement
(b) a conditional statement
(c) an iterative statement
(d) None of the above
20. Repeating a block of code for n times is _____________.
(a) an imperative statement
(b) a conditional statement
(c) an iterative statement
(d) None of the above

Review Questions

1. State whether the following statements are true or false:


a. A computer is an electric machine.
b. CPU is a hardware.
c. Registers are part of a CPU.
d. A scanner is an output device.
e. The CPU consists of ALU, CU, and registers.
29
f. RAM is a volatile memory.
g. MS Word is a system software.
h. Python is a compiled programming language.
i. Java is a compiled programming language.
j. Linux is a programming language.
k. Python is a low-level programming language.
l. Circles are used as on-page connectors in a flowchart.
m. Ovals are used as terminals in flowcharts.
n. Rectangles are used as input in flowcharts.
2. Draw a block diagram of a computer and discuss the roles of its various
components.
3. Describe different types of computer software.
4. Compare application and system software.
5. Describe types of system software.
6. Describe levels of computer programming languages.
7. Describe the advantages and disadvantages of machine language.
8. Describe the advantages and disadvantages of a high-level language.
9. Differentiate between an Interpreter and a Compiler.
10. Describe commonly used symbols in flowcharts.

Programming Exercises

1. Write an algorithm and draw a flowchart to input two numbers, a and b,


and print any one of the following string based on the values of the
numbers: (i) “a is greater than b”, (ii) “a is equal to b”, and (iii) “b is greater
than a”.

2. Write an algorithm and draw a flowchart to find the volume of a cuboid.

3. Write an algorithm to find the sum of digits of a number.

4. Write an algorithm and draw a flowchart to calculate the hypotenuse of a


right-angled triangle.

5. Write an algorithm and draw a flowchart to calculate the distance


between two points, p1(x1, y1) and p2(x2,y2).

30
6. Write an algorithm and draw a flowchart to read the distance d (in
kilometer) traveled by a vehicle in time t ( in minutes) and calculate the
vehicle's speed in m/s.

7. Write an algorithm and draw a flowchart to find the minimum of three


given numbers.

8. Write an algorithm and draw a flowchart to print a multiplication table of


a given number.

9. Write an algorithm and draw a flowchart to read marks obtained in three


subjects by a student and the maximum mark in each subject. Calculate
the student's total marks and percentage.

10. Write an algorithm and draw a flowchart to find the sum of the first N
natural numbers.(Hint: sum=n*(n+1)/2)

11. Write an algorithm and draw a flowchart to find the last digit of a number.
(Hint: divide the given number by 10 and multiply the quotient by 10 and
subtract the original number).

31
32
Chapter 2

Overview of Python
Learning Outcomes
1. Identify some domains where Python is widely used.
2. Install and run the Python interpreter.
3. Create and execute Python programs using IDLE
4. Describe the basic structure of a python program

Python is an interpreted, object-oriented, high-level, general-purpose programming


language. It is very popular due to its simple programming syntax, and English-like
programming statements. Further, due to fewer syntactical constructions and the use of
common English words, Python codes are easy to understand, learn, and maintain. It
does not use complex punctuations as compared to other languages. Further, it has high-
level built-in data structures, such as lists, sets, dictionaries, and it supports dynamic
typecasting and dynamic binding. These features make it an attractive option for rapid
application development, scripting, and automation. Python supports modular
programming through packages. Packages also help reuse the codes.

Python is a free and open-source programming language available for all major
computing platforms and operating systems. Further, it has a large set of free standard
libraries. Since it is an interpreted language, the edit-test-debug cycle is incredibly fast.
Easy debugging of Python programs is also another significant advantage of Python.
Python supports source-level debugging that allows inspection of local and global
variables, evaluation of arbitrary expressions, setting breakpoints, stepping through the
code a line at a time, and so on. Due to these features, Python is the widely used
programming language.

2.1 History of Python


Python is conceptualized and developed by Guido van Rossum at the National
Research Institute of Mathematics and Computer Science, the Netherlands, in the late

33
1980s. It is designed as a sequel to the ABC programming language, with exception
handling capability. The name Python is taken from the British TV show Monty Python.

Similar to other languages, Python evolves through several versions. In 1991, the
first version of Python, Python 0.9.0, was released. The first version included features
such as exception handling, classes, lists, and strings. In addition, it had lambda, map,
filter, and reduce, which made it suitable for functional programming.

In 2000, the second version, Python 2.0, was released as an open-source project and
included list comprehensions, a full garbage collector, and support for Unicode.

In 2008, Python 3.0 was released. The major noticeable change was the way the print
statement works in Python 3.0. The print statement of Python 2.0 was replaced with the
print () function in Python 3.0.

2.2 Why Python?


There are many languages, such as C, C++, C#, Java, Visual Basic, JavaScript, PHP,
Python, currently available for various programming tasks. Each language has its own
strength and is suitable for different programming tasks. The popularity of Python is
due to the following major reasons:

1) Easy to learn and use

Python is one of the easiest programming languages to learn and use due to:

• its simple syntaxes and punctuations.

• its use of constructions similar to the English language.

These features also make the Python code readable and easy to maintain and reuse.

2) Support from large software companies and academics

Python Programming language is supported by many large software companies,


such as Facebook, Amazon Web Services, and Google. Python is also widely used as the
core programming language in schools and colleges across the globe. Most universities
use Python for research in Machine learning, Artificial Intelligence, Deep Learning, and
Data Science.

34
3) Maturity and vast support of libraries

Python is a very mature language as it is widely used for more than 30 years.
Further, over the years, a large collection of libraries is now available at no cost. Plenty
of learning materials, such as documentation, guides, and video tutorials for Python
language, are available to programmers. Hundreds of Python libraries and popular
frameworks are available due to corporate sponsorship and a large community of
Python developers. These libraries and frameworks save time and efforts in the software
development cycle. In addition, many specialized libraries, such as nltk for natural
language processing, scikit-learn for machine learning applications, are available for
research in emerging areas of development. Further, there are libraries for the
commonly used tasks, such as Matplotib for plotting charts and graphs, SciPy for
engineering, scientific and mathematical applications, BeautifulSoup for HTML and
XML parsing, NumPy for scientific computing, and Django for server-side web
development.

4) Portability and Versatility

Python is platform-independent, i.e., the same program runs on all operating


systems and different types of machines. It is also very versatile, i.e., it can be used for
developing different types of software, such as mobile applications, desktop
applications, web development, hardware programming.

5) Support for emerging research areas

Python is widely used in the emerging areas of computer science, such as cloud
computing, machine learning, neural network, data science, and big data. Leading
universities and research centers use Python to carry out research and development in
the above emerging areas.

6) Software integration

Python code can easily use libraries developed in other programming languages,
such as C, C++, and Java. This feature makes it very easy to extend the capabilities of a
python program and reduces the development cycle.

2.3 Installing Python

35
Python is available for almost all operating systems, such as Windows, Linux, Mac.
We can download the latest version and older versions of Python for any platform freely
from www.python.org/downloads. Python is preinstalled on most Linux distributions.
Following is a step-by-step instruction to install the latest version of Python on the
Windows operating system.

Step 1: Download the latest version of Python for windows from the
www.python.org/downloads website. The older versions of Python are also available
on the same website.

Step 2: Double click the downloaded installer (such as python-3.7.4-amd64.exe) to start


the installation process. A pop-up window of the installer will appear, as shown in
figure 2.1. Next, check the two checkboxes given at the bottom of the pop-up (install
launcher for all users (recommended), and Add Python 3.7 to PATH) to ensure
availability of Python to all the users, and the PATH environment variable is modified
to access Python from anywhere.

Figure 2.1: Python Installer pop-up window

36
If the Python Installer finds an earlier version of Python installed on your computer,
the installer will give the option to upgrade to the latest version or install the latest
version separately.

Step 3: Click the Install Now (or Upgrade Now) message to start the installation. Click
Yes to the message "Do you want to allow this app to make changes to your device" to
begin the installation. Figure 2.2 shows the installation progress window. It will show
the various components it is installing, and finally, a pop-up window will appear saying
that "Setup was successful", as shown in figure 2.3.

To verify that Python is installed on your computer, open the command prompt and
type python; you will see a window, as shown in figure 2.4, telling the version and other
details. We can open a command prompt window by any one of the following options:

(1) Right-click the Start button and choose Command Prompt (or PowerShell)
(2) Press Windows key + X, followed by C (non-admin) or A (admin)).

Figure 2.2: Python installation progress window

37
Step 4: Click the close button. Python is now installed on your system.

Figure 2.3: Python installation successful window

Figure 2.4: Running Python from the command prompt

38
2.4 Starting Python in Windows
Once Python is installed, we can use Python in two ways: Python command prompt
and Python IDLE.

2.4.1 Python Command Prompt

The Python interpreter starts running when we enter python at the window’s
command prompt. Figure 2.5 shows the Python command prompt window. The Python
command prompt (>>>) is ready to execute Python codes. We can directly type a Python
statement at the prompt, and by pressing the enter key, the interpreter runs the
statement and produces the results. This interactive mode of the Python interpreter can
be used as a very powerful scientific calculator. For example, figure 2.5 shows how to
use the Python command prompt to evaluate the expression 10+15*3+2/3, and write a
program to add two numbers. However, the Python command prompt is not widely
used for writing programs in this fashion.

In practice, we write a Python program in an editor and run it to solve a problem. A


Python program (also called script) is a text file, and it can be created in any plain text
editor, such as notepad. We can run a program by passing the name of the program as
an argument to the interpreter. For example, the command to execute a Python program
(test.py) saved in the folder c:\users\MBM is C:\Users\MBM>python
c:\users\MBM\test.py. Figure 2.5 shows the program and its output. If the file is in the
current folder from where the Python interpreter is executed, the command becomes
C:\Users\MBM>python test.py.

If the Python interpreter is not included in the PATH environment variable, we have
to specify the complete address of the interpreter, and the above command becomes as
given below:

C:\>C:\Users\MBM\AppData\Local\Programs\Python\Python39\python
c:\users\mbm\test.py.

Here, C:\Users\MBM\AppData\Local\Programs\Python\Python39\ is the


path of the Python interpreter, i.e., python.exe and c:\users\mbm\ is the path of the
program.

39
Figure 2.5: Writing Python program at the command prompt

Program test.py

Figure 2.6: Executing a Python program at the windows command prompt

40
2.4.2 Python IDLE

A Python program can be written in any text editor, such as notepad, and can be
executed directly from the command prompt, but it is not a very convenient way to
write large programs. Therefore, most programmers use integrated development
environments (IDE), such as IDLE, VS code, Spyder, PyCharm. These IDEs provide
integrated facilities to create, edit, debug and execute a program. Most of the IDEs are
freely available. We can download an IDE of our choice from its website and install it
on our computer (More information about IDE is given in section 2.10).

In this book, we are using IDLE for creating and testing Python programs. Python's
Integrated Development and Learning Environment (IDLE) is installed by default when
we install Python. IDLE can create, modify, and execute Python programs and executes
a single statement in the interactive mode.

We can start IDLE like any other windows program from the start menu or search it
and click its icon. Figure 2.7 shows an IDLE window and it is called the IDLE Shell. The
IDLE Shell is similar to the Python command prompt and allows users to run Python
statements at its prompt. The interactive mode of IDLE is suitable for small Python
programs. But as the complexity and size of a program increases, it becomes difficult
and cumbersome to work in this mode. Therefore, for writing large programs, IDLE
provides an integrated programming editor. We can start the editor from the File menu
of the IDLE shell (File->New File) or using the shortcut command Ctrl + N, as shown
in figure 2.8. Creating a program in the editor is called script mode programming.

The IDLE editor has all the facilities to create, edit, save, open, run and debug a
program in an integrated environment. Figure 2.9 shows an editor window. The default
name of the new program is untitled. It is recommended to give a suitable name to a
program and save it before executing it.

To run the current program from the editor, use Run->Run Module, or F5 key, from
the drop-down menu of the editor (figure 2.10). The output of the program is shown in
the Python Shell, as shown in figure 2.11.

41
Figure 2.7: IDLE Shell

Figure 2.8: Starting the script editor in IDLE

42
Figure 2.9: Script editor

Figure 2.10: Running a script in the editor

Figure 2.11: Output of the script shown in IDLE Shell

43
2.5 Structuring Python Programs
One of the main reasons for Python's popularity is the simple syntaxes and
structures used to create Python programs. This section describes the proper structuring
and formatting of python programs.

2.5.1 Python Statements

It is a common practice to write one python statement in one line, and the 'new line
character' terminates the statement. However, it is possible to write more than one python
statement in a single line separated by semicolons, but it is not recommended, as it reduces
the program's readability. Example 2.1 shows a simple program that uses multiple
statements in a single line. Example 2.2 shows a preferred way of writing the previous
program.

Example 2.1: Multiple statements in a single line

# It is a bad Practice to write multiple lines in a single line


a = 10; b = 20; c = b + a
print(a); print(b); print(c)

Example 2.2: A preferred way of writing Example 2.1

# It is a good Practice to write one statement in one line


# It increases the readability of a code
a = 10
b = 20
c = b + a
print(a)
print(b)
print(c)

44
2.5.2 Line Continuation

Some statements may be very long, and to view them, the programmer has to scroll
the screen left and right frequently. A lengthy statement can be broken into multiple lines
using line continuation to avoid scrolling and enhance readability. Python supports two
types of line continuation: implicit and backslash.

The implicit line continuation is automatically used in a statement containing


opening parentheses ('('), brackets ('['), or curly braces ('{'). In such a statement, the Python
interpreter treats the statement incomplete till it finds the matching closing bracket
corresponding to an opening bracket, even if the statement spreads across multiple lines. In
this situation, newline characters before the closing bracket are not treated as the statement
terminators, and the statement may continue to many lines. The same is true for
parentheses, square brackets, and curly braces, also. Example 2.3 demonstrates some multi-
line statements written at the IDLE command prompt. The implicit line continuation can be
used in scripts also.

Example 2.3: Implicit line continuation

>>> a=(1+
2+
3+
4)
>>> print(a)
10
>>> b=[1,
2,
3,
4,
5]
>>> print(b)
[1, 2, 3, 4, 5]
>>> c={'a':1,
'b':2,
'c':3

45
}
>>> print(c)
{'a': 1, 'b': 2, 'c': 3}

In explicit line continuation, a backslash (\) at the end of a line indicates that the
current statement is incomplete and continues to the next line. The explicit line continuation
is typically used when implicit line continuation is not applicable, such as a long expression
without brackets. Example 2.4 shows an example of explicit line continuation.

Example 2.4: Explicit line continuation

>>> a=1\
+2\
+3\
+4
>>> print(a)
10

2.5.3 Comments in Python

Comments are lines in a program that the interpreter ignores and are primarily used
to document the code properly. They greatly help in code readability and make code
maintenance and reuse very easy. In addition, we can use a comment to explain the purpose
and logic of a statement or a block of code. We can write comments throughout a program.

Python supports both line comment and block comment. To comment a single line
of text till the end of the line, we put a hash (#) character at the beginning of the text. The
line comment can begin from the start of a line (for example, #This whole line is a
comment) or start after a statement (for example, x=10 #This part of the line is a comment)
and continues until the end of the line. If we want to comment more than one line as
comments, we have to put a hash character at the beginning of each line. Please note that a
hash (#) inside a string does not make the text after it a comment, for example, x="In this
string, #this part is not a comment".

46
Python uses a pair of triple-double quotation marks (""") to create a multi-line string
literal. If we do not assign such a string to a variable, it can be used as a multi-line block
comment. Instead of a pair of triple-double quotation marks, we can also use a pair of triple-
single quotation marks (''') to create a block comment.

Please note, we begin a block comment from a line without any indentation, i.e.,
before the beginning triple-double quote, nothing is allowed, not even white spaces. In
contrast, a line comment can begin anywhere in a line and can have white spaces or any
other Python statement before the # mark.

Example 2.5: Comments in Python

# This is a line comment as it starts with #.


# Comments will be ignored by the interpreter
#Initialize a with 10
a=10
#Initialize b with 20
b=20

"""Start of a block comment


Anything written up to the next triple quotation marks
will be ignored by the interpreter.
End of the block comment"""
#Sum a and b
c=a+b

#Show result
print(c)
x="The part after # is not a comment as it is\
inside a string"
y='The portion between """ is not a comment """" \
as it is inside a string'
print(x)# print the value of x

47
print(y) # print the value of y
#End of program

Output
30
The part after # is not a comment as it is inside a string
The portion between """ is not a comment """" as it is inside a string

2.5.4 Proper Indentation

Python has straightforward syntaxes and uses indentations to form blocks.


Indentation is the process of adding white spaces before a statement. Python uses spaces
and tabs for indentation and newline characters as line terminators. Tabs and spaces can be
mixed to give indentation, but all the statements in a block must have an identical and
consistent indentation. The first executable block (the block of a program from where the
execution begins, also called the main block) cannot have any indentation. Adding
indentation to the main block will raise an indentation error, "Syntax error: unexpected
indentation". At the command prompt, no white spaces are allowed at the beginning of a
statement. Again, attempting to give white spaces at the beginning of a statement will raise
the error "Syntax error: unexpected indentation". However, whitespaces may be included
inside a statement. The inside and trailing spaces in a statement are not an error and are
ignored by the Python interpreter. For example, the statement a=10 + 20 * 5 has a few
spaces inside it. The interpreter removes these spaces, and the previous statement is
equivalent to a=10+20*5. Programmers are encouraged to use white spaces freely to
increase the readability of programs. Example 2.6 shows some uses of correct and incorrect
indentations in a program.

Example 2.6: Indentation in Python

a=10 #Error: as the first block cannot have any indentation


b=20
c=int(input("Enter a number"))
if c <10:
print(a+b) #Properly indented block

48
print(a*b)
else:
print(a-b)
print(a/b)

#The following indentation will raise error


if c <10:
print(a+b) #incorrect indentation
print(a*b)
else:
print(a-b)
print(a/b) #incorrect indentation

2.6 Structure of a Python Program


A typical Python program consists of many sections: documentation sections,
import sections, function definitions, and the main program. Figure 2.4 shows a typical
structure of a Python program. All sections may not be present in every program. Though
documentations are not an essential part of a program, it is considered an important part of
it as it enhances the readability and comprehension of a program. The inclusion of
documentation is in line with the famous quote, "Codes are more often read than written".
This quote highlights the importance of documentation. Documentation becomes more
important in open source development as many people across the globe will use your code.

A Python program can seamlessly include and use the codes written in other python
programs. The import statement is the primary mechanism to include codes from other
Python scripts. Though import statements can be written anywhere in the program, they
must be written before using the imported code. However, writing import statements at the
top of a program tells the program's dependencies on other modules. Hence, it is a
recommended approach.

The function declaration section defines functions used in a program. A function


definition must appear before the use of the function.

49
The main block of a program is coded with no indentation. The program execution
begins from the first statement of the main block. The main block codes may not be
contiguous. It can be written in many segments. For example, we can write a function block,
then a part of the main block, another function block, and the other part. Example 2.7 shows
the above concepts with an example.

Documentation section

Import section

Function definitions

Main program

Figure 2.4: Typical structure of a Python program

Example 2.7: Typical structure of a Python program

#Documentation section
"""
Script Author: Arvind
Organization: MBM Engineering College, Jodhpur, India
Date: 10 December 2020
Version: 1.0
Purpose: Print the largest of three randomly generated numbers
"""

#import section
#importing the random module to include random number
#generator functions
import random

#Function section

50
#Function to find the largest of three numbers

def largest(a, b, c):


if a> b :
if a> c:
large=a
else:
large=c
else:
if b > c:
large=b
else:
large=c
return large
#End of the function

#main program section

x=random.randint(10,100)
y=random.randint(10,100)
z=random.randint(10,100)
print("The largest of (",x,",",y,",",z,") is ",largest(x,y,z))

2.7 Coding Style


A program implements logic and steps to solve a problem and can be written in various
ways. If each programmer follows a different style to write a program, it becomes
challenging to maintain the program in the long run. Further, it reduces the readability of a
program. To overcome these difficulties, the Python coding style PEP 8 is widely used by
most Python programmers. This style is not a set of rules but a set of customs that help write

51
more readable and consistent codes. Following are the most important points of the PEP 8
style:

• Use 4-space indentation. Use of tabs is not recommended.

• Use docstrings. A docstring is the first block comment string written after the function
header or written at the beginning of a module. Python uses the docstring of a
module/function for automatically generating the help of the function/module.

• Limit the number of characters in a line to less than 80 characters. This limit helps view
a program without using a horizontal scroll and correctly print a program on a paper.
To meet the 80 characters’ limit, a program line can be broken into multiple lines using
line continuation mechanisms.

• Use comments to explain the purpose and logic of the code. Comments should form
complete sentences and should be meaningful to the code.

• Use Python’s default UTF-8 or ASCII encodings for writing programs. These encodings
make programs portable internationally. UTF-8 is a Unicode-based encoding system to
accommodate characters of most of the natural languages.

• Use spaces around operators and after commas to enhance readability.

• Use a consistent naming convention. For example, refer to the naming convention
section 2.8 below, which describes a widely used naming convention.

• Don’t use non-ASCII characters in identifiers, as this reduces code reusability and
creates problems in code maintenance.

2.8 Identifier Naming Convention


Identifiers are names used to identify different entities in a program, such as variables,
functions, classes, constants, modules. Following are the general recommendations to name
identifiers in Python:

• Use relevant names instead of generic names. For example, use student_list,
class_list instead of list1, list2.

52
• Avoid using similar-looking characters as single-characters identifier names. For
example, ‘l’ (lowercase letter el) and ‘I’ (uppercase letter eye) confuse with 1.
Similarly, ‘O’ (uppercase letter oh) confuses with zero.

• Avoid using very wordy names, such as


dictionary_for_the_purpose_of_storing_data. The wordy names increase typing
time and cause errors.

Following are the specific conventions to be used to name different types of objects in
Python:

• Packages and modules: Use all lower case letters to name a package/module. For
multiple words package names, use an underscore to separate each word. However,
a single-word package/module name is preferable, for example, numpy, sklearn,
sklearn.linear_model.

• Classes: Use camelCase to name a user-defined class. In camelCase, the first letter
of the first word in the identifier name is in the lower case, while the first letter of
every subsequent word is in the uppercase. Further, use only the English alphabets
in a class name; avoid using numerals, underscore, and special symbols. In Python,
all the built-in classes are in lowercase words, except the Error class.

• Variables and methods: Use lowercase to name variables/methods. A multiple


word variable/method name should be separated by an underscore (_). Private
variables/methods begin with a single underscore. A double underscore prefix is
used to name attributes/methods in a class.

• Constants: In Python, there is no symbolic constant. However, we use variables


with all capital letter names to indicate that these variables be treated as constants
by programmers, such as PI=3.14. Use a single underscore to separate multi-word
constants, such as GRAVITY_CONSTANT=9.81.

2.9 Python Implementations


Another reason for the popularity of Python is that it is available for almost all digital
devices, from computers to micro-controllers, through its various implementations. Various
implementations are implemented differently as per the requirements but use the same
syntax. Following is a brief description of major implementations of Python. Interested
readers can explore the website of a particular implementation for a detailed description.
53
• Cpython: The default implementation of Python is CPython. CPython, written in a
mixture of C and Python, has a large standard library. As a result, CPython is the
most popular and widely used implementation. It is also called traditional Python.
CPython can be defined as both an interpreter and a compiler as it compiles Python
code into bytecode before interpreting it.

• IronPython: IronPython is an open-source Python implementation using C# and is


integrated with the .NET Framework. This integration helps use of .NET Framework
and Python libraries and facilitates other .NET languages to use Python code easily.

• Jython: Jython is a Java implementation of Python and can be used on any platform
with a JVM installed. Jython has an interactive interpreter that can interact with Java
packages as well as running Java applications. This interactive interpreter makes it
a rapid application development tool and helps seamless interaction between
Python and Java.

• PyPy: PyPy is another Python implementation using Python itself and uses just-in-
time (JIT) compilation. It is said to be 7.5 times faster than CPython. In JIT
compilation, the source codes are compiled directly to the native machine code,
making it very fast.

• Stackless Python: Stackless Python is another implementation of Python that does


not use the C call stack for its own stack. This change in stack management strategy
allows the main thread to run hundreds of thousands of tiny tasks, called tasklets.
Tasklets run completely decoupled and communicate through channels. Thus,
Stackless Python allows thread-based programming without compromising
performance and complexity problems as found in conventional thread
programming.

2.10 Python IDEs


Python programs can be written in any text editor. However, many integrated
development environments (IDEs) have been developed that make writing Python code
and its maintenance much easier. The commonly used IDEs are IDLE, Spyder, PyCharm,
Sublime, Emacs, Atom, and VS Code. These IDEs provide facilities to write, edit, format,
debug, execute, and test programs. However, it is strongly recommended to use IDLE for
beginners. Interested readers can explore the respective websites for detailed features of
various IDEs. All codes in this book are written in IDLE. IDLE is installed by default with

54
standard Python. The two popular editors are described next, for others, refer their websites
for their features.

PyCharm, developed by JetBrains, is another popular IDE used for the Python
programming language. It provides code analysis, a debugger, and supports web
development with the Django web framework. It is cross-platform and available for
Windows, MacOS, and Linux. The Community Edition is freely available and can be
downloaded from the link https://www.jetbrains.com/PyCharm/download/.

Jupyter Notebook is a browser-based web application that can be used as an IDE


for Python programming. It provides facilities to create, modify and execute Python
programs. A unique feature of Jupyter is mixing of formatted text and mathematical
expressions with the programming codes. For mixing, it uses two types of cells: code cell
and text cell. Code cells are used to write codes, whereas text cells are used to write plain
texts. On executing a code cell, the output is written just below the cell. This integration of
code, plain text, and output in a single page is very convenient for scientific computing. The
Jupyter notebook is installed with the Anaconda Python distribution.

2. 11 Python Distributions
As already stated, Python is a general-purpose programming language that is
widely used for many tasks, such as data science, machine learning. However, the standard
Python installation may not be suitable for different tasks as it frequently requires installing
dependent packages from scratch. Several tools and utilities are freely available to manage
packages easily, called distributions. A Python distribution is a bundle that contains a
Python implementation along with a bunch of libraries, tools, and IDEs. Popular Python
distributions are Anaconda, Enthought Canopy, ActiveState, and Intel. We can install
multiple Python distributions on a single system and use them independently as per our
requirements.

Anaconda is a free and open-source Python distribution widely used for data science
and machine learning applications. It uses conda as its package manager. Anaconda is pre-
bundled with popular data science and machine learning software libraries, such as Scikit-
learn, Keras, PyTorch, TensorFlow, SciPy, and many other popular data science packages
suitable for Windows, Linux, and MacOS. It also includes two popular IDEs, namely,
Spyder and Jupyter notebook for writing and executing Python programs. We can
download the Anaconda Individual Edition distribution from
https://www.anaconda.com/download. For other distributions, interested readers may
refer to their websites.
55
Chapter Summary

1. Python is an interpreted, object-oriented, high-level, general-purpose


programming language.
2. Python is a free and open-source programming language available for all major
computing platforms and operating systems.
3. Guido van Rossum developed Python at National Research Institute of
Mathematics and Computer Science, the Netherlands.
4. Python supports both line and block comments. A line comment begins with #
and continues till the end of the line. A block comment begins with a triple-double
quote and ends with a triple-double quote. A block comment can contain multiple
lines. We can also use triple-single quotes in place of triple-double quote.
5. Python uses indentation to create a block inside another block.
6. IDLE, PyCharm, Jupyter, VS Code, and Spyder are popular integrated
development environments for Python programming.
7. A Python distribution is a bundle that contains a Python implementation and a
bunch of libraries, tools, and IDEs. Popular Python distributions are Anaconda,
Enthought Canopy, ActiveState, and Intel.
8. Anaconda is a free and open-source Python distribution widely used for data
science and machine learning applications.

Multiple Choice Questions

1. Which of the following is not true about Python?


(a) It is an object-oriented programming language.
(b) It is a high-level programming language.
(c) It is a compiled programming language.
(d) It is a general-purpose programming language.
2. Python is popular because of the following reason:
(a) Simple syntax
(b) Built-in high-level data structures
(c) Support for Unicode characters
(d) All of the above

56
3. Python is initially developed by
(a) Charles Babbage
(b) Guido van Rossum
(c) Dennis Ritchie
(d) Larry Wall
4. Which of the following can be used to write a Python program?
(a) IDLE
(b) PyCharm
(c) Spyder
(d) All of the above
5. Which of the following is not a Python distribution?
(a) Anaconda
(b) Enthought Canopy
(c) ActiveState
(d) None of the above
6. The default package manager of Anaconda distribution is
(a) conda
(b) Spyder
(c) Jupyter
(d) pip
7. Which of the following IDE is installed by default with Python?
(a) IDLE
(b) VS Code
(c) Spyder
(d) Jupyter
8. Which of the following character is used to start a line comment?
(a) #
(b) /
(c) %
(d) “
9. Which of the following is valid to start a block comment?
(a) """
(b) %
(c) #
(d) None of the above

57
10. Which of the following character is used to separate multiple statements in a
line?
(a) comma
(b) Semi-colon
(c) Colon
(d) Space
11. Which of the following character is used to separate multiple expressions?
(a) comma
(b) Semi-colon
(c) Colon
(d) Space
12. Which of the following character is used to continue a statement to the next
line?
(a) Backslash
(b) Forward slash
(c) Colon
(d) Space
13. Which of the following function key is used to run a script in IDLE?
(a) F5
(b) F6
(c) F7
(d) F8
14. Which of the following shortcut key is used to open a new script?
(a) Ctrl+O
(b) Ctrl+S
(c) Ctrl+N
(d) Ctrl+P
15. Which of the following is the default name of a script in IDLE?
(a) script
(b) noname
(c) untitled
(d) None of the above

58
Review Questions

1. State whether the following statements are true or false:


a. Python is an interpreted programming language.
b. Python does not support object-oriented programming.
c. Python supports high-level data structures, such as lists, sets.
d. Python uses curly brackets to form blocks.
e. The name Python is taken from the British TV show Monty
Python.
f. In Python 3, print is a function, not a statement.
g. Python supports garbage collection.
h. Python does not support Unicode.
i. PyCharm is an IDE.
j. The default name of the new program is untitled.
k. F2 is the shortcut key to run a Python program in IDLE.
l. Jupyter is a Python distribution.
m. A Python statement must be written in only one line.
n. We can write more than one statements in a line.
o. A semi-colon is essential at the end of each line.
p. Hash character is used to write a comment.
q. Python does not support block comments.
2. Briefly describe the history of Python.
3. Describe the reasons for the popularity of Python.
4. Describe steps to install Python on your computer.
5. Describe the typical structure of a Python program.
6. Describe the coding style used for Python programs.
7. Discuss various Python implementations.
8. Discuss Python distributions.

59
60
Chapter 3

Basics of Python Programming


Learning Outcomes
1. Describe the Python character set, keywords, and datatypes
2. Explain tokens, identifiers, and delimiters in Python
3. Distinguish various types of literals
4. Perform input and output operations
5. Perform formatting of output
6. Perform conversion of one literal type into another type

Like any other high-level programming language, Python uses a set of symbols,
such as a, b, +, /, 1, 2, and keywords along with a set of syntax rules to write computer
programs. However, Python is very close to the English language in constructing its
statements, making it one of the most widely used programming languages. Further, it
uses fewer syntactic constructions and uses common English keywords, making Python
programs highly readable, easy to comprehend, and economical to maintain.

3.1 Character Set


Python 3.0 and newer versions support Unicode characters to name identifiers.
Unicode character encoding standard assigns a unique code to every character and
symbol of most human languages. Hence, a Python code and strings can have characters
from any combination of languages. However, it is strongly recommended to use ASCII
code characters to write a Python program to make it more portable and re-usable across
the globe. ASCII stands for American Standard Code for Information Interchange and
is a subset of Unicode. Example 3.1 shows a valid Python program that uses Unicode
characters (from Hindi and Greek letters) to name variables and functions. Although
Python allows Unicode to name identifiers, the character set (primarily based on the
English language) given in table 3.1 is preferred to write Python programs to promote
international portability, ease of maintenance, and reuse.

61
Most of the IDEs used to write programs using English keyboards do not have direct
facilities for typing all the Unicode characters. However, any Unicode character can be
easily included in a string using the escape character sequence “\u+Unicode of the
character”. For example, to create a string a=”αβγ”, in Python code, it is coded as
a=”\u03b1\u03b2\u03b3”, where 03b1, 03b2, and 03b3 are the Unicode of α, β, and γ,
respectively.

Example 3.1: Use of Unicode(from Hindi and Grrek letters) in a Python program

>>> def β(अ, ब):

return अ + ब

>>> क=10

>>> ख=20

>>> print("क और ख का जोड़ :", β(क,ख))

क और ख का जोड़ : 30

Table 3.1: Preferred character set for writing Python programs

Character types Description

Letters All English alphabets, both lower and upper case, i.e., A, B, C,
…X, Y, Z, and a, b, c, … x, y, z.

Digits 0,1,2,3,4,5,6,7,8,9

Special Symbols Comma (,), period (.), semicolon (;), colon (:), question mark
(?), apostrophe ('), quotation mark ("), exclamation mark (!),
vertical bar (|), slash (/), backslash (\), tilde(~), underscore(_),
dollar($), percent sign(%), ampersand (&), caret (^), asterisk
(*), minus sign(-), plus sign (+), opening angle bracket or less
than sign (<), closing angle bracket or greater that sign (>), left
parenthesis ((), right parenthesis ()), left bracket ([), right
bracket (]), left brace ({), right brace ( }), number sign (#).

62
White spaces Blank space, horizontal tab, newline, carriage return, form
feed.

3.2 Python Token


A token is the smallest unit of a computer program. They are the building blocks of
computer instructions and statements. Python tokens can be grouped into six categories
based on their purpose in forming statements(figure 3.1): keywords, identifiers, literals,
special symbols, and operators. Keywords are reserved words; identifiers are names of
variables, constants, functions, and packages; special symbols are delimiters; operators are
symbols to perform specific operations on data; and literals are fixed values used in the
source code. These are discussed in more detail later in the chapter.

Python Token

Keywords Identifiers Literals Operators Delimiters

Figure 3.1: Python tokens

3.3 Keywords
Keywords are reserved words for specific purposes to write Python statements, and they
can’t be used for any other purpose, such as naming variables, functions, or any other
identifier. They are the building blocks of Python and are used to define the syntax and
structure of the Python language. Keywords are case sensitive in Python, and there are 33
keywords in Python 3. Table 3.2 lists all the keywords of Python 3.10 with a brief description
of each. In all, there are 35 keywords in Python 3.10. Please note, the number of keywords
may be different in different versions of Python. You can use the help () function in your
Python shell without any argument and then type a keyword to list the keywords in your
Python installation, as illustrated below.

63
>>> help()

Welcome to Python 3.9's help utility!

If this is your first time using Python, you should definitely check out
the tutorial on the Internet at https://docs.python.org/3.9/tutorial/.

Enter the name of any module, keyword, or topic to get help on writing
Python programs and using Python modules. To quit this help utility and
return to the interpreter, just type "quit".

To get a list of available modules, keywords, symbols, or topics, type


"modules", "keywords", "symbols", or "topics". Each module also comes
with a one-line summary of what it does; to list the modules whose name
or summary contain a given string such as "spam", type "modules spam".

help> keywords

Here is a list of the Python keywords. Enter any keyword to get more help.

False break for not


None class from or
True continue global pass
__peg_parser__ def if raise
and del import return
as elif in try
assert else is while
async except lambda with
await finally nonlocal yield

Table 3.2: Python keywords

Keyword Description

and To perform logical AND operation

64
as To create an alias

assert To debug a code using an assertion condition.

async To declare an asynchronous function

await To asynchronously wait for a task to complete.

break To break further execution of a loop

class To define a class

continue To skip the remaining portion of the body of a loop and continue the
next iteration of the loop

def To define a function

del To delete an object

elif To form an else-if portion of a ladder if conditional statement

else To specify a block of codes to be executed when all specified


conditions are false in a conditional statement. It is also used in a
loop to execute a block of code on the normal termination of the loop.

except To specify what to do when an exception occurs

False To represent the Boolean FALSE value

finally To create a block of code that will always execute in a try-except


block

for To create a for loop

from To import specific parts of a module

global To declare a global variable

if To make a conditional statement

65
import To import a module

in To check if a value is present in a collection

is To test if two variables are referring to the same object

lambda To create an anonymous function

None To represent a null value

nonlocal To declare a non-local variable

not To perform logical NOT operation

or To perform logical OR operation

pass To create a null statement, i.e., a statement that will do nothing

raise To raise an exception

return To exit a function and return a value

True To represent the Boolean TRUE value

try To make a try-except statement for catching exceptions

while To create a while loop

with To automatically manage resources, such as files.

yield To write a generator function

3.4 Identifiers
An identifier is a sequence of characters used to name a variable, function, class,
module, or other objects. In Python, an identifier starts with an alphabet, preferably an
English letter, A to Z or a to z or an underscore (_), followed by zero or more letters,
underscores, and digits (0 to 9). Python is a case-sensitive language, i.e., upper case letters
66
are different from the lower case letters. Hence, Name, NAME, and name are different
identifiers.

3.4.1 Rules for Naming Identifiers

Following are the rules to name identifiers in Python 3.0:

1. An identifier name must contain only letters, digits, and underscore. The letter can
be from any human language. However, English letters are widely used and highly
recommended.
2. The first character of an identifier name must be a letter or underscore, i.e., an
identifier name can’t start with a digit.
3. A Python keyword cannot be used as an identifier name.
4. An identifier cannot have space or special characters, such as $, +, -, %.
5. An identifier can be of any length.

Examples of some valid identifier names are: a, B, Abc, var1, var_1, _var, _1var, my_list,
name_of_student. Please note, an underscore ( _ ) is a valid identifier name. Non-English
alphabets/words such as क, ख, कमल, जोड़, are some Hindi valid identifier names, and a,
b. d, m, l, p, ab are some Greek valid identifier names. Table 3.3 gives examples
of some invalid identifier names along with reasons.

Table 3.3: Examples of invalid identifier names

Invalid Identifier Description


names

1abc An identifier name cannot start with a digit (rule 2)

Sum of a and b An identifier name cannot have spaces (rule 4)

Sum$ An identifier cannot have special characters(rule 4)

lambda An identifier name cannot be a keyword (rule 3).


lambda is a keyword.

67
3.5 Literals and Their Types
A literal in a program is a constant value, such as 10, 25.5, 'abc', (1,2,3), that does not
change during the execution of a program. Python supports the following literal types: int,
float, complex, str, bytes, bool, NoneType, list, tuple, dict and set. Figure 3.2 shows a
classification of literal types of Python.

Python literals

String Numeric Boolean Collection None

Integer Float Complex

string bytes

List Tuple Set Dictionary

Figure 3.2: Python literals

3.5.1 String Literals

A string literal is a fixed text. In Python, a string literal is written using a pair of single
quotes ('), double quotes ("), triple single quotes ('''), or triple double quotes ("""), for
example,

• 'This is a single quote string literal',


68
• "This is a double quote string literal",
• ''This is a triple single quote string literal''', and
• """This is a triple double quote string literal""".

There is no difference between a single quote and double quote literals. However, we
cannot start a literal with a single quote and end with a double quote, i.e., mixing single and
double quotes is invalid. Hence, an attempt to define a string literal as ‘Mixing of single and
double quotes is an error” will generate an error. Triple single/double quotes are used to
create formatted multiline strings. Python ignores a string literal that is not assigned to a
variable. Hence, triple quote multiline literals can be used to write comments in Python.
Example 3.2 illustrates the above concepts.

Example 3.2: Creating string literals

>>> a='This is an example of a single quote string literal'


>>> print(a)
This is an example of a single quote string literal
>>> b="This is an example of a double quote string literal"
print(b)
>>> print(b)
This is an example of a double quote string literal
>>> c='''This is an
example
of
multiline and formatted triple single quote
literal'''

>>> print(c)
This is an
example
of
multiline and formatted triple single quote
literal
>>> d=""" This is a

69
triple double
quote string literals"""

>>> print(d)
This is a
triple double
quote string literals

Python 3 literals, by default, use Unicode. Hence, Python can create string literals
containing any character from most human languages (e.g., English, Spanish, Japanese,
Arab, Hebrew, Hindi). Contrary to Python 2, Python 3 string literals are Unicode. Hence
there is no requirement of prefixing u before a string literal to make it a Unicode string
literal. For example, the Python 2.0 Unicode string literal u'abc' is written in Python 3 as
'abc'.

Any Unicode character can be inserted in a string literal by using escape sequence
\u followed by the four-digit hexadecimal code of the character. For example, The Python
equivalent of the string αβγ is "\u03b1\u03b2\u03b3", where 03b1, 03b2, and 03b3 are
Unicodes of α, β, and γ, respectively. Example 3.3 illustrates the above concepts.

Example 3.3: Unicode characters in string literals

>>> s1="Python 3 strings use Unicode by default. No need to prefix u"


>>> s2=u"Python 3 strings use Unicode by default. No need to prefix u"
>>> print(s1==s2)
True
>>> s3="\u03b1\u03b2\u03b3"
>>> print(s3)
αβγ

70
By default, Python 3.0 string literals use the UTF-8 encoding system, and the literals
created are of type str. However, a string literal can be made byte string (uses only ASCII
characters) by prefixing it with b. The object type of byte string literals is bytes. We can get
the type of an object by the type () built-in function. For example, b"My String" is a byte
string. An str object can be converted into a byte object by the encode () method of the str
object. And, a byte object can be converted into an str object by the decode () method of the
byte object. String literals can be encoded using other encoding systems, such as UTF-16,
and decoded back by explicitly passing the coding system in the encode () and decode ()
functions. Example 3.4 illustrates the above concepts.

Example 3.4: String literals coding systems

>>> s1="Python 3 strings use UTF-8 coding for string literals"


>>> type(s1)
<class 'str'>
>>> s2=b"String literals can be made byte strings by prefixing with
b."
>>> type(s2)
<class 'bytes'>
>>> s3=s1.encode()
>>> type(s3)
<class 'bytes'>
>>> print(s3)
b'Python 3 strings use UTF-8 coding for string literals'
>>> s4=s2.decode()
>>> type(s4)
<class 'str'>
>>> print(s4)
String literals can be made byte strings by prefixing with b.
>>> s5=s2.decode('UTF-16')
Traceback (most recent call last):
File “<pyshell#10>", line 1, in <module>
s5=s2.decode('UTF-16')

71
UnicodeDecodeError: 'utf-16-le' codec can't decode byte 0x2e
in position 60: truncated data
>>> s5=s2.decode('UTF-8')
>>> print(s5)
String literals can be made byte strings by prefixing with b.
>>> s6=s1.encode('utf-16')
>>> print(s6)
b'\xff\xfeP\x00y\x00t\x00h\x00o\x00n\x00 \x003\x00 \x00s\x00t\x00r
\x00i\x00n\x00g\x00s\x00\x00u\x00s\x00e\x00 \x00U\x00T\x00F\x00\x008
\x00 \x00c\x00o\x00d\x00i\x00n\x00g\x00 \x00f\x00o\x00r\x00 \x00s
\x00t\x00r\x00i\x00n\x00g\x00
\x00l\x00i\x00t\x00e\x00r\x00a\x00l\x00s\x00'
>>> s7=s6.decode('utf-16')
>>> print(s7)
Python 3 strings use UTF-8 coding for string literals

By default, a backslash (\) character and a few characters after it have special
meaning in a string literals. Table 3.4 lists commonly used such combinations along with
their brief descriptions. The backslash (\) is called the escape character.However, to change
this default behavior of backslash characters in string literals, Python supports the concept
of a raw string. In a raw string, Python treats a backslash (\) as a simple character instead
of an escape character. A raw string literal is created by prefixing a string literal with 'r' or
'R'. It is useful when we don’t want to give special meaning to the backslash character.
Example 3.5 illustrates escape sequences, and Example 3.6 shows the concept of raw string.

Table 3.4: Escape sequences

Escape Description
Sequence
\\ To include a backslash (\) in a string
\' To include a single quote (') in a string
\" To include a double quote (") in a string
72
\a To include a bell sound in a string
\b To include a backspace character in a string
\f To include a form feed character in a string
\n To include a line feed character in a string.
\r To include a carriage return character in a string.
\t To include a horizontal tab character in a string.
\v To include a vertical tab character in a string.
\ooo To include a character with an octal value ooo in a string.
\xhh To include a character with a hex value hh in a string..
\N{name} To include a character that is identified by a name in the
Unicode database in a string.
\uxxxx To include a character with 16-bit hex value xxxx. Exactly
four hexadecimal digits are required in a string.
\Uxxxxxxxx To include a character with 32-bit hex value xxxxxxxx.
Exactly eight hexadecimal digits are required in a string.

Example 3.5: Python escape sequences

>>> print("\\ This is a backslash character")


\ This is a backslash character
>>> print("This string includes a single quote(\') character")
This string includes a single quote(') character
>>> print("This string includes a double quote(\") character")
This string includes a single quote(") character
>>> print("This string includes a bell sound(\a) character")
This string includes a bell sound() character
>>> print("This string includes a back space(\b) character")
This string includes a back space( ) character
>>> print("This string includes a form feed(\f) character")

73
This string includes a form feed() character
>>> print("This string is \nprinted in two lines")
This string is
printed in two lines
>>> print("This string is \rprinted in two lines")
This string is
printed in two lines
>>> print("In this string, a tab\tis inserted")
In this string, a tab is inserted
>>> print("This string is \vprinted in two lines")
This string is
printed in two lines
>>> print("Print ABC using octal codes \101\102\103")
Print ABC using octal codes ABC
>>> print("Print ABC using hexadecimal codes \x41\x42\x43")
Print ABC using hexadecimal codes ABC
>>> "Delta symbol is \N{GREEK CAPITAL LETTER DELTA}"
'Delta symbol is Δ'
>>> "Alpha symbol is \N{GREEK SMALL LETTER ALPHA}"
'Alpha symbol is α'
>>> print("Print omega using 16-bit Unicode \u03A9")
Print omega using 16-bit Unicode Ω
>>> print("Print omega using 32-bit Unicode \U000003A9")
Print omega using 32-bit Unicode Ω

Example 3.6: Python raw strings

>>> print("This\tis\ta\tnormal\nPython string")


This is a normal
Python string

74
>>> print(r"This\tis\ta\traw\nPython string")
This\tis\ta\traw\nPython string
>>> print(r"In raw strings,\\ has no special meaning")
In raw strings,\\ has no special meaning

A string literal is stored in memory as an array of characters. Individual characters


can be extracted by using an index. For example, the expression 'abc' [0] will return the first
character of the literal. In Python, literals are immutable, i.e., once a literal is created, it
cannot be modified in the program. However, we can extract a part of the literal using the
indexing mechanism. Example 3.7 extracts a character from a string using an index.

Example 3.7: Extracting characters of a string

>>> print("The fourth character of the string ABCDEF is","ABCDEF"[3])


The fourth character of the string ABCDEF is D

3.5.2 Numeric Literals

Numeric literals are fixed numerical values. Python has many types of numeric
literals: integer number, floating-point number, and complex number.

3.5.2.1 Integer Literals

Integer literals represent whole numbers. In Python, integer literals can be classified
as decimal integer, octal integer, hexadecimal integer, and binary integer. There is no limit
on the number of digits in an integer literal. Further, we can use an underscore (_) to
separate the two adjacent digits of an integer literal for better clarity and readability. The
underscore is ignored when processing an integer literal. For example, 100 can be written
as 1_0_0. However, we cannot use more than one underscores to separate two consecutive
digits. For instance, 1__0_0 will raise the invalid decimal literal error. Also, note that leading
zeros in decimal integer literals are not allowed. For example, the statement a=0100 will
raise an error.

A hexadecimal integer literal begins with 0x, an octal integer literal begins with 0o,
and a binary integer literal begins with 0b. For example, the decimal literal 100 can be

75
represented in hexadecimal, octal, and binary integer literals as 0x64, 0o144, and 0b1100100,
respectively. Irrespective of the types of integer literals used to assign a value to a variable,
Python’s print () function will always print the variable's value as a decimal integer only.
To print the integer literal in the hexadecimal, octal, or binary format, we have to convert
an integer literal to an equivalent string using the built-in functions hex (), oct (), and bin (),
respectively. For example, hex (100) will return '0x64', oct (100) will return '0o144', and bin
(100) will return '0b1100100'. The returned string literals can be converted back to integers
with the help of the int () function. A proper base value should be used for the correct
conversion. For example, to convert ‘0x64’ into an equivalent integer, use int ('0x64', 16).
Similarly, to convert '0o144', use int ('0o144', 8) and for '0b1100100', use int('0b1100100', 2).
The second parameter in the function int () is the base value of the number system of the
first parameter. However, we can use any form of integer literals in calculations directly.
For example, the expression 100+0x64+0o144+0b1100100 is a valid Python expression and
evaluates to 400. Example 3.8 shows the above concepts.

Example 3.8: Various types of integer literals

>>> a=100 #This will store integer literal 100 in variable a


>>> b=0100 #This will generate an error due to the leading zero
SyntaxError: leading zeros in decimal integer literals are not
permitted;
use an 0o prefix for octal integers
>>> b=1_0_0 #Underscores are ignored
>>> print(b)
100
>>> b=1__0_0
SyntaxError: invalid decimal literal
>>>#Print function prints different types of int as decimal int
>>> c=0x64 #Create a hexadecimal integer literal
>>> print(c)
100
>>> d=0o144 #Create an octal integer literal
>>> print(d)
100

76
>>> print(hex(c)) #Print a hexadecimal equivalent string
0x64
>>> print(oct(c)) #Print an octal equivalent string
0o144
>>> e=0b1100100 #Create a binary integer
>>> print(e)
100
>>> print(bin(e)) #Print a binary equivalent string
0b1100100
>>> print(int('0x64' ,16))#Convert a hexadecimal integer string into int
100
>>> print(int('0o144' ,8))#Convert an octal integer string into int
100
>>> print(int('0b1100100',2)) #Convert a binary integer string into int
100
>>> print(a+c+d+e)
400
>>> f=100+0x64+0o144+0b1100100 #Addition of different types of literals
>>> print(f)
400
>>>

3.5.2.2 Floating-point Literals

Any number with a fraction (fraction value may be zero) and a decimal point is a
floating-point literal, for example, 100.50, 31.4, 0.0012, -10.25. A floating-point literal can
also be written in the exponent form, using the character ‘e’, for example, 1.0050e2, 3.14e1,
1.2e-3, -1.025e1. Like integer literals, an underscore can also separate consecutive digits of a
float literal for enhanced readability. For example, 1.23_4e1_2 is a valid float number.
Python float literals are 64-bit double-precision values. The maximum value of a float literal
is approximately 1.8 x 10308. Example 3.9 shows the above concepts.

77
Example 3.9: Floating-point literals

>>> a=3.14
>>> b=3.12e2
>>> print(a,b)
3.14 312.0
>>> a=1.23_4e1_2 #underscores are ignored
>>> print(a)
1234000000000.0
>>> c=1.0e-2
>>> print(c)
0.01
>>> import sys #import sys module
>>> sys.float_info #shows the information of float literals.
Sys.float_info(max=1.7976931348623157e+308, max_exp=1024,
max_10_exp=308,
min=2.2250738585072014e-308, min_exp=-1021,
min_10_exp=-307, dig=15, mant_dig=53,
epsilon=2.220446049250313e-16, radix=2, rounds=1)

3.5.2.3 Complex Number Literals

Mathematically, a complex number has two parts: real and imaginary. It is


expressed in the form a + bi, where a and b are real numbers, and i represents the imaginary
unit, satisfying the equation i2 = −1. Because no real number satisfies this equation, i is called
an imaginary number. Python creates a complex number by adding a floating literal with
an imaginary literal. An imaginary literal is created by suffixing the letter j to a floating
literal, for example, 2.5j. Some examples of complex numbers in Python are 10+5j, 2.5-3.5j,
1.2e2-1.3e3j. We can also write the imaginary part before the real part of a complex number.
For example, 5j+4 is a valid complex literal.

A complex number can also be created using the complex () function, which takes
either two real numbers or a string as its parameters. For example, to create the complex

78
number 10+20i, we can use the expressions complex(10,20) or complex(‘10+20j’). We can
obtain the real and imaginary parts of a complex number using real and imag attributes of
the number, respectively. For example, c.real will return the real part of a complex number
c, and c.imag will return the imaginary part. The abs () function returns the absolute value
of a complex number. Example 3.10 illustrates the above concepts.

Example 3.10: Complex numbers

>>> a=3.5j #Create an imaginary literal


>>> type(a)
<class 'complex'>
>>> b=2.5+3.6j #Create a complex number
>>> type(b)
<class 'complex'>
>>> c=complex(3,4) #Create a complex number
>>> d=complex('4-5j') #Create a complex number
>>> print(a,b,c,d)
3.5j (2.5+3.6j) (3+4j) (4-5j)
>>> c.real #get the real part of a complex number
3.0
>>> c.imag #get the imaginary part of a complex number
4.0
>>> abs(c) #get the absolute value of a complex number
5.0

3.5.3 Boolean Literals

There are only two Boolean literals in Python: True and False. True represents true
logical value, and False represents false logical value. Boolean literals is of the bool type.
Hence, type(True) will return 'bool'. In python, the numerical value of True is 1 and of
False is 0, when used in arithmetic expressions. For example, the expression 2+False is equal
to 2, and the expression 2+True is equal to 3. A relational expression, such as a>b, will return
True if it satisfies the given condition; else, it will return False. For example, 10<20 will

79
evaluate to True, whereas 10>20 will evaluate to False. Example 3.11 illustrates the above
concepts.

Example 3.11: Boolean literals

>>> a=True #Create a Boolean variable from a Boolean literal


>>> type(a) #Get the type of an object
<class 'bool'>
>>> type(True)
<class 'bool'>
>>> b=False
>>> print(a,b)
True False
>>> c=10>20 #Create a Boolean variable from a relational expression
>>> d=10<20
>>> print(c,d)
False True
>>> e=2+True #Using a Boolean literal in an arithematic expression
>>> f=2+False
>>> print(e,f)
3 2

3.5.4 Collection Literals

Python has four different types of collection literals: List, Tuple, Dict, and Set. They
are briefly discussed in the following sections but are discussed in greater detail in later
chapters, as they are vital in Python programming.

3.5.4.1 List Literals

A list literal is a collection of literals of different data types. The values stored in a
list literal are separated by comma (,) and enclosed within square brackets ([]). For example,
a=[1,2,3, 'Four', 'Five']. We can access an individual item in a list using an index. For
example, a[2] will return 3. A list literal can contain other list literals or any other collection

80
literals. The variable created by assigning a list literal is mutable, i.e., we can modify the
contents of a list variable. Example 3.12 illustrates the above concepts.

Example 3.12: List literals

>>> a=[1,2,3,'four','five']#Create a list variable from a list literal


>>> type(a) #Get the type of a variable
<class 'list'>
>>> a[2] #Access an item of a list
3
>>> a[4]
'five'
>>> b=[1,2,3,[4,5,6],'Seven'] #A list containing another list
>>> b[3]
[4, 5, 6]
>>> a.append('six') #Add an item to a list
>>> a
[1, 2, 3, 'four', 'five', 'six']
>>> a[2]
3
>>> a[2]=4 #Modify an element of a list
>>> a
[1, 2, 4, 'four', 'five', 'six']

3.5.4.2 Tuple Literals

Similar to a list literal, a tuple literal is also a collection of literals of different data
types, but it is immutable. It means that once a tuple is assigned to a variable, the content
of the variable cannot be modified. However, we can assign a new tuple to the variable. A
tuple literal is enclosed in parenthesis, (), and each element is separated by a comma (,). For
example, a = (1,2,3, 'Four', 'Five'). Like a list, we can access an individual item of a tuple
using indexing. For example, a[2] will return 3. An attempt to modify a will result in an
error. Example 3.13 illustrates the above concepts.

81
Example 3.13: Tuple literals

>>> a=(1,2,3,'Four','Five')#Create a tuple variable using a tuple


>>> a
(1, 2, 3, 'Four', 'Five')
>>> a[2] #Accessing an item of a tuple
3
>>> a[2]=4 #Error: Cannot modify the content of a tuple
Traceback (most recent call last):
File "<pyshell#97>", line 1, in <module>
a[2]=4
TypeError: 'tuple' object does not support item assignment

3.5.4.3 Dictionary Literals

A dict literal (dict stand for dictionary) uses a pair of curly brackets to store a
collection of data in the form of key: value pairs. A key and its value are separated by a
colon (:). It uses curly-braces '{}' to enclose key: value pairs and the consecutive pair is
separated by a comma (,). The key values are distinct and unique in a dict literal. If we repeat
a key in a dict literal, the last key: value pair will overwrite the previous one.

We can use only an immutable object/literal, such as a string, tuple, integer, as a


key. However, the value of a key can be any mutable or immutable object/literal. For
example, we cannot use a list object/literal as a key, but we can use it as a value. The keys
in a dict object can be of different types of data. The same is also valid for values. The dict
is a mutable data type; hence it cannot be used as a key in a dictionary. Example 3.14
illustrates the above concepts.

Example 3.14: Dict literals

>>> a={1:'One',2:'Two',3:'Three'} #Integers are used as keys.


>>> print(a)
{1: 'One', 2: 'Two', 3: 'Three'}
>>> b={'name':'Ram','age':23} #Strings are used as keys.

82
>>> b['name']
'Ram'
>>> a[1]
'One'
>>> c={1.2:'Float',1:"Integer",'abc':'String'}
>>> c[1.2]
'Float'
>>> a={1:'One',2:'Two',1:'Three'} #Duplicate key, last one is
retained.
>>> a
{1: 'Three', 2: 'Two'}
>>> a[1]
'Three'
>>> b={[1,2,3]:'123', (1,2,3):'One'}#Error: Lists cannot be used as
keys.
Traceback (most recent call last):
File "<pyshell#105>", line 1, in <module>
b={[1,2,3]:'123', (1,2,3):'One'}
TypeError: unhashable type: 'list'
>>> b={(1,2,3):'123', (1):'One'}#Tuples are used as keys
>>> b
{(1, 2, 3): '123', 1: 'One'}
>>> b={(1,2,3):[1,2,3], (1):'One'}
>>> b
{(1, 2, 3): [1, 2, 3], 1: 'One'}
>>> b[(1,2,3)]
[1, 2, 3]
>>> b[1]
'One'
>>> b[0] #Error: Undefined keys will generate the KeyError
Traceback (most recent call last):

83
File "<pyshell#112>", line 1, in <module>
b[0]
KeyError: 0
>>> c={(1,2,3):'1,2,3',(4,5,6):'4,5,6'}
>>> c[(1,2,3)]
'1,2,3'

3.5.4.4 Set Literals

Set is an unordered collection of unique items of immutable and hashable types. An


object is said to be hashable if it has a hash value that remains the same during its lifetime.
A hash algorithm calculates the hash value of an object. A list, dictionary, and set cannot be
members of a set as they are mutable and not hashable. Duplicate items are automatically
removed. In a set, items are enclosed within a pair of curly braces, {}, and each element is
separated by a comma (,). An important thing to note about a set is that we cannot access
individual items using indexing. However, we can access items through iteration. Since a
set is an unordered collection of items, the items of a set may not be returned in the same
sequence as used to define the set during the iteration. Example 3.14 illustrates set literals.

Example 3.14: Set literals

>>> s={1,2,3,6,5,4} #Order of items may change


>>> s
{1, 2, 3, 4, 5, 6}
>>> print({1,2,3,4,1,2,4}) #Duplicate items are removed
{1, 2, 3, 4}
>>> s1={1,2,'Three', 'Four', (5,6,7)} #Items can be of different
types
>>> print(s1)
{(5, 6, 7), 1, 2, 'Three', 'Four'}
>>> s2={1,2,[3,4,5]}#Error: Lists and other mutable items are not
allowed
Traceback (most recent call last):

84
File "<pyshell#24>", line 1, in <module>
s2={1,2,[3,4,5]}
TypeError: unhashable type: 'list'
>>> s1[0] #Error: Indexing not allowed
Traceback (most recent call last):
File "<pyshell#25>", line 1, in <module>
s1[0]
TypeError: 'set' object is not subscriptable
>>> for a in s1: #Items can be accessed through iteration
print(a)

(5, 6, 7)
1
2
Three
Four

3.5.5 Special Literal None

Python has a special literal, None, to represent nothing or a null value. 'None' is
used to define a null variable. It is not the same as an empty string, False, or a zero. It is a
data type of the class NoneType. If we assign None to a variable, the variable contains
nothing. In Python, if a function does not return anything, it returns None. Example 3.15
illustrates the above concepts.

Example 3.15: Special literal None

>>> a=None #Create an empty variable


>>> print(a)
None
>>> type(a)
<class 'NoneType'>

85
>>> if a== None:
print('A is empty')

A is empty
>>> def fun(a,b): #Function that return nothing, returns None
c=a+b

>>> print(fun(10,20))
None
>>> print(False==None) # None is not equal to false
False
>>> print(''==None) # None is not equal to an empty string
False
>>> print(0==None) # None is not equal to zero
False
>>> print(None=={}) # None is not equal to an empty set
False
>>> print(None==[]) # None is not equal to an empty list
False
>>> print(None==dict()) # None is not equal to an empty dictionary
False
>>> print(None==()) # None is not equal to an empty tuple
False
>>> print(None==None) #None is only equal to None
True

3.6 Variables
A variable is a data that permits the modification of its value during the execution
of the program. In Python, we create a variable by assigning a value to an identifier. For
example, the statement x=10 creates the variable x in the memory. The type of value hold

86
by a variable decides the type of the variable. Python does not support explicit type
declaration of a variable. A variable can hold different types of data at different times during
the execution of a program. Hence, the type of a variable is dynamic. For example, the type
of the variable x is int, as currently, it is holding an integer, i.e., 10. The type of a variable
can be checked by the function type (). Hence, the statement type(x) will return int. The type
of a variable is dynamic in nature as the type of a variable will change when we assign a
different type of data to it. For example, the statement x=10.5 will change the data type of
the variable x to float. Example 3.16 illustrates the above concepts.

Example 3.16: Dynamic type of a variable

>>> x=10
>>> type(x)
<class 'int'>
>>> x=10.5
>>> type(x)
<class 'float'>

3.7 Operators
Operators are special symbols or reserved words used to perform various
operations on data. For example, in the expression s= 10 + 20, the character + is an operator
and performs the addition operation on data 10 and 20. The data are called operands.
Python has a rich set of operators for performing arithmetic, relational, logical, bitwise,
assignment, membership, and identity operations. Table 3.5 lists all the built-in operators
of Python. Example 3.17 illustrates some arithmetic operators. Chapter 4 describes these
operators in detail.

Table 3.5: List of Python operators


Operators Description
+, -, *, /, //, %, ** Arithmetic Operators
<, <=, >, >=, ==, != Comparison operators
and, or, not Logical operators

87
&, |, ^ Bitwise operators
=, +=, -=, /=, //=, Assignment Operators
is, is not Identity operators
in, not in Membership operators

Example 3.17: Simple arithmetic and relational operations

>>> a,b=19,7
>>> print(a+b, a-b, a*b, a/b, a**b,a//b, a%b)
26 12 133 2.7142857142857144 893871739 2 5
>>> a,b=5.5,2.2
>>> print(a+b, a-b, a*b, a/b, a**b,a//b, a%b)
7.7 3.3 12.100000000000001 2.5 42.540042248725975 2.0
1.0999999999999996
>>> print(a==b, a<b, a>b, a!=b)
False False True True

3.8 Delimiters
In Python programs, some special characters are used as punctuation marks, such
as separating data, assigning special meaning to the next character or a group of characters,
grouping data. Table 3.6 lists commonly used delimiters. Example 3.18 illustrates the uses
of some of the delimiters.

Table 3.6: Delimiters in Python

Symbol Description
Comma ( , ) To separate data items, variables, expressions.
Colon ( : ) • Used as the slice operator for a sequence.
• To create a new block in a conditional statement, a looping
statement, or function definition.
• To create a key and value pair in a dictionary.
88
Dot ( . ) To access an attribute or a method of an object.
Single quote (') • A pair of single quotes are used to create a string literal.
• A pair of triple single quotes are used to create a multiline
preformatted string literal.
Double quote(") • A pair of double quotes are used to create a string literal.
• A pair of triple-double quotes are used to create a multiline
preformatted string literal.
Semi colon ( ; ) • To separate statements which are written in a single line.
• To end a line.
Parentheses ( ) • To enclose items of a tuple.
• To enclose arguments/ parameters in a function.
• To change the order of evaluation of operators in an
expression.
Brackets [ ] • To create a list.
• To access items in a collection.
Curly Brackets { } • To create a dictionary or a set.
• To format strings.

Example 3.18: Delimiters

>>> a,b,c = 10,20+30,40 # Use comma to separate two variables and


data
>>> print(a,b,c)
10 50 40
>>> def sum(a,b): # Use a colon to create a new block
return a+b

>>> list1=[1,2,3,4,5,6,7,8]
>>> list1[2:4] # Use a colon to slice a collection
[3, 4]
>>> dict1={1:'One',2:'Two'} # Use a colon to link key and value pair
>>> string1='I love Python'
>>> string1.upper()# Use a dot to access a member function

89
'I LOVE PYTHON'
>>> a='This is a single line string using single quote'
>>> b="This is also a single line string using double quote"
>>> c="""This
is
a multiline string"""
>>> d='''This is also a multiline string
using triple single quote'''
>>> a=10; b=20; c=30; # Use a semicolon to separate two statements
>>> b=(1,2,3) # Use parentheses to create a tuple
>>> sum(10,20) # Use parentheses to call a function
30
>>> c=[1,2,3] # Use square brackets to create a list
>>> b[1],c[1] # Use square brackets to access items in collections
(2, 2)
>>> set1={1,2,3,4} # Use curly brackets to create a set
>>> dict1={1:'one',2:'two'} # Use curly brackets to create a dict

3.9 Input and Output Functions


The three essential operations in any useful program are reading, processing, and
writing operations. A program takes some data as input, performs some operations on
them, and produces some output. Python has two built-in input and output functions: input
() and print (), for reading from the keyboard and writing on the console (Python shell),
respectively.

3.9.1 The input () Function

The input () function is used to read data from the keyboard up to the newline
character and returns the read data as a string. It is important to remember that the input ()
function returns the input line as a string, and we have to explicitly convert the returned
string into desired data types, such as integer, float, as per our requirement. The syntax and
parameters of the input function are given in table 3.7.

90
Table 3.7: The input function

Syntaxes:

1. variable = input ()

2. variable = input(prompt)

Where the parameter prompt is a string, which is a message to be displayed


on the console.

In the second format, the input function first prints the string prompt on the console
and then takes the input. Example 3.19 illustrates the uses of both forms of the input ()
function. We cannot read integers, floats, complex numbers, lists, tuples, sets, and
dictionaries data directly. The input function reads everything as a string, and we have to
convert the returned string into the desired data types explicitly.

Example 3.19: The input function

>>> a=input() # Reads data from the keyboard without a prompt. Not
preferred.
10
>>> type(a) # Note the return type. It is always the string type.
<class 'str'>
>>> print(a)
10
>>> b=input("Enter a number") # Reads data with a prompt. Preferred.
Enter a number10
>>> type(b) # Note the return type.
<class 'str'>
>>> print(b)
10
>>> c=input("Enter a string: ")

91
Enter a string: Python is a very powerful language
>>> print(c)
Python is a very powerful language
>>> d=input("Enter numbers: ")
Enter numbers: 1,2,3
>>> print(d)
1,2,3
>>> type(d) # Note the return type.
<class 'str'>
>>> e=input ("Enter a list: ")
Enter a list: [1,2,3,4,5]
>>> print(e)
[1,2,3,4,5]
>>> type(e) # Note the return type.
<class 'str'>

3.9.2 Reading a Single Numeric Data

As we have already discussed, the input () function returns an input line as a single
string. However, we can easily convert the returned string into its equivalent numeric data
by using int (), float (), and complex () functions. For example, to convert a string of digits
into an integer number, we use the int (str_data, [base]=10) function. For example, the
expression int ('123') converts the string '123' into the decimal integer 123.

We can also use the int() function to convert a string containing an integer in the
binary, octal, and hexadecimal forms using a suitable base value, i.e., 2, 8, or 16, for binary,
octal, and hexadecimal, respectively. For example, the expression int('1010',2) evaluates to
10; the expression int('1010',8) evaluates to 520; and the expression int('1010',16) evaluates
to 4112. Please note, the parameter str_data must be valid for the specified base value;
otherwise, an error is generated. For example, int('123',2) results in an error, as the string
'123' is not a valid binary number string.

Similarly, the float (str_data) function converts a string containing a float number
into a float number. For example, the expression float('123.45') evaluates to 123.45. The

92
str_data parameter may contain a float number in the scientific notation. For example, the
expression float('12.345e1') evaluates to 123.45.

We use the complex (str_data) to convert a string containing a complex number into
a complex number. For example, the expression complex('3+4j') evaluates to (3+4j).

If the str_data parameter is not a valid string for the desired data type, an error is
raised. For example, the expressions int('123.45'), int('abc123'), int("12 22"),
float('abc123.45'), complex('3+4i') result in errors.

Example 3.20 illustrates some uses of the int () function for reading various types of
integer data, and example 3.21 illustrates uses of the float () and complex () functions.

Example 3.20: Reading an integer from the console

>>> a=input("Enter an integer:") # Read the input string


Enter an integer:10
>>> b=int(a) # Convert a string into its equivalent decimal integer
>>> type(b)
<class 'int'>
>>> c=int(input("Enter an integer:")) # Combine reading and
conversion
Enter an integer:20
>>> print(b+c)
30
>>> a=int(input("Enter a binary number:"),2) # Read a binary integer
Enter a binary number:1011
>>> b=int(input("Enter a binary number:"),2)
Enter a binary number:1001
>>> print(bin(a+b)) # Print a number in binary format using the bin
function
0b10100
>>> a=int(input("Enter an octal number:"),8) # Read an octal number
Enter an octal number:12342

93
>>> print(a, oct(a))
5346 0o12342
>>> a=int(input("Enter a hexadecimal number:"),16) #Read a
hexadecimal number
Enter a hexadecimal number: FF
>>> a # By default, a number is printed in decimal format
255
>>> a=int(input("Enter an integer number:")) #Invalid integer string
Enter an integer number:12a
Traceback (most recent call last):
File "<pyshell#109>", line 1, in <module>
a=int(input("Enter an integer number:"))
ValueError: invalid literal for int() with base 10: '12a'
>>> a=int(input("Enter a binary integer number:"),2)#Invalid binary
Enter a binary integer number:123
Traceback (most recent call last):
File "<pyshell#110>", line 1, in <module>
a=int(input("Enter a binary integer number:"),2)
ValueError: invalid literal for int() with base 2: '123'

Example 3.21: Reading float and complex numbers from the console

>>> a=float(input("Enter a float number:")) #Read a float number


Enter a float number:12.5
>>> b=float(input("Enter a float number (Scientific format):"))
Enter a float number (Scientific format):1.25e1
>>> print(a,b)
12.5 12.5
>>> a=float(input("Enter a float number:")) #Error: spaces are not
allowed

94
Enter a float number:1.2e 2
Traceback (most recent call last):
File "<pyshell#111>", line 1, in <module>
a=float(input("Enter a float number:"))
ValueError: could not convert string to float: '1.2e 2'
>>>
>>> a=complex(input("Enter a complex number:"))
Enter a complex number:2+7j
>>> a
(2+7j)
>>> a=complex(input("Enter a complex number:")) #Error: spaces are
not allowed
Enter a complex number:2 + 3j
Traceback (most recent call last):
File "<pyshell#112>", line 1, in <module>
a=complex(input("Enter a complex number:"))
ValueError: complex() arg is a malformed string

3.9.3 Reading Multiple Numeric Data Separated with a Delimiter

We can use the int (), float (), and complex () functions to convert a string consisting
of a single numeric data, but these functions cannot convert a string that consists of more
than one numeric data separated by delimiters. To convert such a string into a set of
numbers, we first split the string into its substrings with the help of the split () method of
the string class, and then we convert each substring into its equivalent number using an
appropriate conversion function. By default, the split () function uses white space as a
delimiter, but any other character can be passed as a delimiter. The split () function returns
substrings as a list of strings. The generated set of numbers can also be stored in a list of
numbers and processed further. Example 3.22 illustrates the above.

Example 3.22: Reading multiple numeric data from the console

>>> s=input("Enter numbers separated by spaces:") #Read string

95
Enter numbers separated by spaces:1 2 3 4 5
>>> print(s)
1 2 3 4 5
>>> s1=s.split() #Split the string into substrings
>>> print(s1)
['1', '2', '3', '4', '5']
>>> a=[] #Initialise an empty list
>>> for x in s1:#Convert each substring into an integer and add to
list
a.append(int(x))
>>> print(a) #Print numeric list
[1, 2, 3, 4, 5]
>>> type(a)
<class 'list'>
>>> s=input("Enter numbers separated by comma:")#Use a comma as the
delimiter
Enter numbers separated by comma:1,2,3,4,5
>>> s1=s.split(',') #Split into substrings using comma as a delimiter
>>> a=[]
>>> for x in s1:
a.append(int(x))
>>> print(a)
[1, 2, 3, 4, 5]
>>> s=input("Enter real numbers separated by commas:") #Read floats
Enter real numbers separated by commas:1.2, -0.3, 2.3e2, 4
>>> s1=s.split(',')
>>> a=[]
>>> for x in s1:
a.append(float(x))
>>> print(a)
[1.2, -0.3, 230.0, 4.0]

96
>>> s=input("Enter complex numbers separated by commas:") #Read
complex
Enter complex numbers separated by commas:1+2j,3-5j,1,-4j,1.2e2+3j
>>> s1=s.split(',')
>>> a=[]
>>> for x in s1:
a.append(complex(x))
>>> print(a)
[(1+2j), (3-5j), (1+0j), -4j, (120+3j)]

3.9.4 The eval Function

The eval (string) function is a powerful built-in function that can execute valid
Python expressions stored in a string. For example, the statement x =eval ('10+20') will
execute the expression '10+20' and assign the result 30 to x. Similarly, the statement x,
y=eval ('10+20, 20*3') will execute the expressions 10+20 and 20*3 and assigns the results to
x and y. The syntax and parameters of the eval () function are given in table 3.8. Please note
that the eval () function cannot evaluate statements. Hence, the statement eval ('x=10,
y=5+10') will generate error. This ability to dynamically execute expressions in a string and
assign results to variables can be used, along with the input function, to read multiple data
from the console.

We can use the eval () function to parse a string containing every type of literals,
including list, tuple, set, and dict. Example 3.23 illustrates some uses of the eval () function
to convert the string returned by an input function into different data types.

Since the eval () function can execute any valid Python expression, such as deleting
files from the computer, its use to read from the console may be dangerous as an illegitimate
user may input malicious codes that may harm your computer. A malicious code is an
expression/command intended to cause undesired effects, security breaches, or damage to
a system. This danger can be reduced through the additional parameters (globals and locals)
but cannot be ruled out. Hence, it is strongly recommended not to use the eval () function
for reading data from the console when the safety and security of the system are a concern.

97
Table 3.8: The eval function

Syntax:

eval(string, globals=None, locals=None)

Parameters:

1. string: the string to be parsed and evaluated as Python expressions

2. globals: This parameter specifies a dictionary of the global methods and


variables allowed to be used in the eval function.

3. locals: This parameter specifies a dictionary of the local methods and


variables allowed in the eval function.

Example 3.23: Reading multiple numeric data from the console

>>> a=10; b=20; c= eval('a+b') #Evaluate an expression


>>> c
30
>>> eval('10+20')
30
>>> a,b= eval('4+6, 7-2') #Evaluate multiple expressions
>>> print(a,b)
10 5
>>> a,b=eval(input("Enter two numbers:")) #Read multiple numbers
Enter two numbers:10,20
>>> print(a,b)
10 20
>>> a,b=eval(input("Enter two complex numbers:"))#Read complex
numbers
Enter two complex numbers:1+2j, 4-3j

98
>>> print(a,b)
(1+2j) (4-3j)
>>> a,b=eval(input("Enter two strings:")) #Read strings
Enter two strings:'Python', 'Programming'
>>> a,b,
('Python', 'Programming')
>>> print(a,b)
Python Programming
>>> a,b=eval(input("Enter two strings:"))#Error: undefined variables
Enter two strings:abc , xyz
Traceback (most recent call last):
File "<pyshell#165>", line 1, in <module>
a,b=eval(input("Enter two strings:"))
File "<string>", line 1, in <module>
NameError: name 'abc' is not defined
>>> a=eval(input("Enter a list:")) #Read a list
Enter a list:[1,2,3,4,5]
>>> print(a)
[1, 2, 3, 4, 5]
>>> a=eval(input("Enter a tuple:")) #Read a tuple
Enter a tuple:(1,2,3)
>>> print(a)
(1, 2, 3)
>>> a=eval(input("Enter a set:")) #Read a set
Enter a set:{1,2,3,2,3}
>>> print(a)
{1, 2, 3}
>>> a=eval(input("Enter a dictionary:")) #Read a dictionary
Enter a dictionary:{1:'One',2:'Two'}
>>> print(a)
{1: 'One', 2: 'Two'}

99
3.9.5 The print Function

The print () function writes the data on the console or other output device, such as
a printer. However, we will limit our discussion in this section to print only on the console.
The syntax and its parameters are given in table 3.9. The print () function can have zero or
more expressions separated by commas. The output can be formatted using the additional
parameters. Example 3.24 illustrates some uses of the print () function.

Table 3.9: The print function

Syntax:

print (expressions, sep= ‘ ‘, end = ‘\n’, file=file, flush=flush)

Parameters:

1. expressions: any number of valid Python expressions, each separated by a comma.

2. sep: it specifies the character to be used to separate the outputs of the expressions. It
is optional, and the default separator is a space character.

3. End: it specifies what to print at the end of the last expression output. It is optional,
and the default setting is to print a newline character, '\n', at the end.

4. file: It specifies the output device where the output is written. It is optional, and, by
default, the output is written on the console, i.e. sys.stdout.

5. flush: The flush parameter is a Boolean. If flush = True, the output is flushed; else,
the output is buffered. It is optional, and the default value is False.

Example 3.24: print function

>>> print("Hello World") #Print a string


Hello World
>>> print(10+20) #Evaluate the expression before printing
30

100
>>> print(1+2,3*4,'Hello',[1,2,3]) #Print different types of data
3 12 Hello [1, 2, 3]
>>> #Print with a specified separator
>>> print(1+2,3*4,'Hello',[1,2,3], sep=',')
3,12,Hello,[1, 2, 3]
>>> a,b,c=1,{1,2,3},{1:"One",2:"Two"}
>>> print(a,b,c,sep=':') #Print variables
1:{1, 2, 3}:{1: 'One', 2: 'Two'}
>>> #Print with the default end character, i.e. a newline character.
>>> print("Hello");print("World"); print("I like Python")
Hello
World
I like Python
>>> #Print the specified character at the end
>>> print("Hello World.", end=' ');print("I like Python.")
Hello World. I like Python.
>>> x=print("Hello") #The print function returns nothing.
Hello
>>> print(x)
None

3.10 Formatting Numbers and Strings


By default, the number of digits printed after the decimal point in a float number by a
print () function is dependent on the value of the number. Similarly, an integer value and a
string are also printed based on their values. Hence, the outputs are not properly aligned
and justified. Example 3.25 shows the default unformatted and formatted output in Python.
As seen from the output, the unformatted zig-zag printing of values is not very presentable
and elegant. Instead, we can use the following methods to format the output:

1. the traditional % formatting operator


2. the built-in format () function,

101
3. the format () method of the str class, and
4. Python’s f-string.

Example 3.25: Unformatted and formatted outputs

>>> for i in range(1,5): #Unformatted output


print(i, bin(i),1/i)
1 0b1 1.0
2 0b10 0.5
3 0b11 0.3333333333333333
4 0b100 0.25
>>> for i in range(1,5): #Formatted output
print("%3d"%i,"%6s"%bin(i),"%8.3f"%(1/i))

1 0b1 1.000
2 0b10 0.500
3 0b11 0.333
4 0b100 0.250

3.10.1 The Traditional % Formatting Operator

The % operator is used to format a Python data item as a string. For example, the
expression "%8.2f"%(1/3) will convert the value of the expression 1/3 into an equivalent
string of 8 characters with two digits after the decimal point, i.e., ' 0.33', in place of its
default value of 0.3333333333333333. In this way, we can control the printing width,
alignment, and the number of digits after the decimal point, i.e., precision. The syntax of the
% format operator is given in table 3.10.

Table 3.10: The traditional % formatting operator

Syntax:

102
"%Formatting string"% expression

Parameters:

1. The parameter Formatting string contains instructions to controls the alignment,


field width, precision, and type of data item to be formatted.

2. The parameter expression is the value to be formatted.

The structure of the formatting string is "%[flags][width][.precision]type". The


formatting string begins with a % symbol. The formatting string has four parameters: flags,
width, precision, and type. The first three parameters are optional, hence enclosed within
square brackets. The flags parameter controls the alignment; the width parameter sets the
total number of characters (digits) the output string should contain, including the decimal
point; the precision parameter sets the number of decimal digits in a floating-point number,
and the type parameter decides the datatype. For example, "%8.2f" is a format description
for a float number (as type= f stands for the float type). Here, width=8, i.e., the formatted
output string will have 8 characters, and precision=2, i.e., the string will have two digits
after the decimal point. Hence, the output string for the expression "%8.2f"%23.1254 is '
23.13', and the output of the expression "%08.2f"%23.1254 is '00023.13' as flag=0 means pad
the leading blank spaces with zeros. Table 3.11 describes the commonly used values for the
type parameter, and table 3.12 describes the commonly used values of the flags parameter.
Example 3.26 shows some examples of the traditional formatting.

Table 3.11: The commonly used values of the type parameter

Type Description

d To convert an integer into an equivalent decimal integer string.

i The same as d.

o To convert an integer into an equivalent octal integer string.

103
x To convert an integer into a lowercase hexadecimal integer string.

X To convert an integer into an uppercase hexadecimal integer string.

e To convert a floating-point number into an exponential float string. It uses


lowercase e.

E To convert a floating-point number into an exponential float string. It uses


uppercase E.

f To convert a floating-point number into a decimal float number string.

g To convert a float number into a decimal float string using either the
decimal notation or the exponential notation, depending on the exponent
value. If the exponent value is >6 or < -4, it uses the exponential format
(using small case e); else, it uses the decimal form.

G To convert a float number into a decimal float string using either the
decimal notation or the exponential notation, depending on the exponent
value. If the exponent value of the number is >6 or < -4, it uses the
exponential format (using capital case E); else, it uses the decimal form.

c To convert a Unicode (given as a decimal integer) into the equivalent


symbol or format a single character string.

R To convert any python object into the equivalent string using the repr()
function.

S To convert any python object into the equivalent string using the str()
function.

% To include a % in the formatted string.

Table 3.12: Values of the flags parameters

Flag Description

104
# It is with the type parameters o, x, or X to include 0o, 0x, or 0X,
respectively, as a prefix in the converted string

0 By default, when we format a number as a string, the leading empty fields


in the converted string are filled with spaces. However, the 0 flag fills the
leading empty fields with zeros. This parameter is used only with numeric
values, including decimal, octal, hexadecimal integers, and floats.

- By default, the converted string is the right justified in the specified width.
The – flag forces the converted string to be left-justified.

+ By default, when we convert a number into an equivalent string, no + sign


is prefixed before a positive number, but a – sign is prefixed. However, the
+ flag forces to prefix a + sign for a positive number and a – sign for a
negative number.

Example 3.26: Formatting using the traditional method

>>> a,b,c,d=10,-10,22/7,"Python"
>>> print(a,b,c,d) #Default
10 -10 3.142857142857143 Python
>>> print("%5d"%a,"%5d"%b,"%8.3f"%c,"%8s"%d) #Formatted
10 -10 3.143 Python
>>> print("%-5d"%a,"%-5d"%b,"%-8.3f"%c,"%-8s"%d) #Left justified
10 -10 3.143 Python
>>> print("%+5d"%a,"%#5X"%b,"%8.3e"%c,"%8s"%d) #Include + sign
+10 -0XA 3.143e+00 Python
>>> print("%#05o"%a,"%05d"%b,"%08.3f"%c,"%8s"%d) #Octal, binary
0o012 -0010 0003.143 Python
>>> print("%G"%1234,"%G"%1234567) #Auto choose e or f
1234 1.23457E+06
>>> print("%G"%(1/1234),"%G"%(1/1234567)) #Auto choose e or f
0.000810373 8.10001E-07

105
>>> print("%s"%[1,2,3,4,5]) #Convert list to a string
[1, 2, 3, 4, 5]

3.10.2 The format Function

The format () function can be used to format only a single numeric or string data.
The syntax of the format function is given in table 3.13.

Table 3.13: The format function

Syntax:

format(expression, "formatting string")

Parameters:

1. expression: It is an expression that evaluates to a single numeric or string


value, which we want to format.

2. “formatting string”: a string that describes how to format the value of the
expression.

Return value:

A formatted string.

The structure of the formatting string parameter is


"[options][width][.precision]type". Contrary to the traditional formatting string, the
formatting string in the format function does not begin with a % symbol. Here, the
formatting string takes four parameters: options, width, precision, and type. The first three
parameters are optional. The options parameter controls the alignment and padding; the
width parameter sets the total number of characters (digits) the output string should
contain, including the decimal point; the precision parameter sets the number of decimal
digits in a floating-point number, and the type parameter decides the datatype. For
example, " 8.2f" is a format description for a float number (as type= f stands for the float
type). Here, width=8, i.e., the formatted output string consists of 8 characters, including a
decimal point, and precision=2, i.e., the formatted string will have two digits after the
decimal point. Hence, the output string for the expression format (23.1254, " 8.2f") is ' 23.13'
106
and the output of the expression format (23.1254, "08.2f") is '00023.13' as options=0 means
pad leading blank spaces with 0.
The type parameter values are identical to the values of the type parameters (Refer
to table 3.11, above) of the traditional methods, except additional types b, %, and n. type =
b is used with integer data to convert an integer value to an equivalent binary value string.
For example, the expression format (23, “08b”) will return the string ‘00010111’, which is
the binary representation of 23 in 8 digits. The leading spaces are padded with zeros. type
= % is used to print the percentage equivalent of a float or integer numeric value. For
example, the expression format(0.25, "%") will return '25.000000%'. type = n is used as a
general format for numeric data including complex numbers. For example, the expression
format(12,'n') produces the output string '12', the expression format(1.2,'n') produces the
output string '1.2', and the expression format(1.2+1.5j,'n') produces the output string
'1.2+1.5j'.
Table 3.14 describes the commonly used values of the options parameter. Example
3.27 shows some examples of the format function with various options.

Table 3.14: The options parameter of the formatting string

Option Description

< The output string is left-aligned within the specified width. By default, string
data are left-aligned and numeric data are right aligned.

> The output string is right-aligned within the specified width.

0 The leading spaces in the output string of a numeric value is padded with 0.

, A comma will separate the output string of a numeric value at thousandth


positions, such as 12,345,678,910 and 12,345,678.123456. Commas separate
only the integral part.

^ The output string is centered within the specified width.

Example 3.27: The format function

>>> a,b,c,d=10,-10,22/7,"Python"

107
>>> print(a,b,c,d)
10 -10 3.142857142857143 Python
>>> print(format(a,"5d"),format(c,"8.3f"),format(d,"8s"))
10 3.143 Python
>>> print(format(a,"<5d"),format(b,"05d"),format(c,"<8.3f"))
10 -0010 3.143
>>> print(format(a,"5x"),format(b,"5o"),format(a,"8b"))
a -12 1010
>>> print(format(a,"05x"),format(b,"05o"),format(a,"08b"))
0000a -0012 00001010
>>> print(format(a,"#5x"),format(b,"#5o"),format(a,"#8b"))
0xa -0o12 0b1010
>>> print(format(a,"#05x"),format(b,"#05o"),format(a,"#08b"))
0x00a -0o12 0b001010
>>> a,b=12345678, 123456789.12345
>>> print(format(a,",d"),format(b,",f"))
12,345,678 123,456,789.123450
>>> c="Python"
>>> print(format(c,"<15s"),format(c,">15s"),format(c,"^15s"),
sep=':')
Python : Python: Python
>>> print(format(-123,"010d"))
'-000000123'

3.10.3 Formatting with the format Method of the str Object

From Python 2.6, Python added the format () method to the str class to format
different types of data as a string object more elegantly and conveniently. The syntax of the
format () method is given in table 3.15.

Table 3.15: The format method of the str class

108
Syntax:

template.format(p0, p1, …, k0=v0, k1=v1, …)

Parameters:

1. template: a string object or a string literal which is used as a formatting string. The
template string contains fields that are replaced by the corresponding arguments
in the format method. A field is defined by enclosing the position index of a
positional argument or the key value of a key-value argument within a pair of curly
brackets. A field also contains formatting instruction separated by a colon with the
filed label.

2. p0,p1, …, positional arguments, which will replace the corresponding fields in the
template string.

3. k0=v0, k1=v1, …, key=value pairs are for the additional arguments. The key=value
arguments can be referred to in the template by their key values. Please remember,
key-value arguments will appear only after all the positional arguments.

Return value:

A formatted string.

The template string used for formatting purposes has special structures called fields.
Fields are embedded at various locations where we want to insert the formatted data. A
field is created by a pair of curly braces {}, and it contains a reference to an argument of the
format method and its formatting codes. A field in a template string has the following two
formats: {index: formatting code}, or {key: formatting string}, where the index is the
position index (reference) of the positional arguments in the format function, the key is the
key of a key-value argument, and the formatting code is the formatting instructions. Both
the reference and formatting codes are optional.

Consider the formatting expression "{0},{1},{2}".format(12,34.5,"Python") which


contains three fields. When this expression is executed, the references 0, 1, and 2 are
replaced by the corresponding arguments 12, 34.5, and "Python", respectively. Please note,
the index of the first argument is 0, not 1. The output of the expression is '12,34.5,Python'.

109
The expression "{name} is {age} years old".format(name="John", age=10) produces the
output 'John is 10 years old'. Here, the keys are replaced by the corresponding values.

We can specify references in any order in a template string. For example, the
expression "{2},{0},{1}".format(12,34.5,"Python") produces the output 'Python,12,34.5'. We
can repeat a reference. For example, the expression "{2},{2},{2}".format(12,34.5,"Python")
produces the output 'Python,Python,Python'. When we give argument references in the
fields, it is called manual referencing. The above examples use manual referencing.

If references in fields are not given, the first field is mapped to the first argument;
the second field is mapped to the second argument, and so on. This referencing style is
called automatic referencing. For example, the expression "{},{},{}".format(12,34.5,"Python")
produces the output '12,34.5,Python'. Please note, we cannot mix the manual and automatic
referencing. This mixing is an error. However, we can mix the automatic referencing of the
positional arguments and the key referencing. For example, in the expression
"{},{key1},{},{key2},{}".format(1,2,3,key1=4, key2=5), the blank fields are automatically
mapped with the positional arguments, in sequence and the key references are mapped to
the key arguments. The expression produces the output '1,4,2,5,3'. Similarly, we can mix the
manual referencing with the key referencing. For example, the expression
"{1},{key1},{2},{key2},{0}".format(1,2,3,key1=4, key2=5) produces the output '2,4,3,5,1'.

The parts of the string outside the fields are included in the output string without
any change. So, for example, the expression "I love {} programming".format("Python")
produces the output 'I love Python programming'.

A brace character is included in the output string by doubling it, i.e. {{ or }}. For
example, the expression "{{I love {}}}".format("Python") produces the output '{I love
Python}'.

The structure of the formatting in a field is [options][width][.precision]type, where


the meanings of the options, width, precision, and type parameter values are identical to
the corresponding parameters of the format function discussed in section 3.8.2. Example
3.28 illustrates some uses of the format method of the str object.

Example 3.28: The format method of the str class

>>> "{0},{1},{2}".format(12,34.5,"Python") #Positional arguments


'12,34.5,Python'

110
>>> "{},{},{}".format(12,34.5,"Python") #Auto indexing
'12,34.5,Python'
>>> "{2},{1},{0}".format(12,34.5,"Python") #Randomised
'Python,34.5,12'
>>> "{0:4d},{1:8.3f},{2:10s}".format(12,34.5,"Python") #Formatting
code
' 12, 34.500,Python '
>>> "Value of {0} in binary:{0:04b}, in
hexadecimal:{0:#04X}".format(23)
'Value of 23 in binary:10111, in hexadecimal:0X17'
>>> "Value of {0} in binary:{0:08b}, in
hexadecimal:{0:#08X}".format(23)
'Value of 23 in binary:00010111, in hexadecimal:0X000017'
>>> "Left:{0:<15s}, Center:{0:^15s} and
Right:{0:>15s}".format("Python")
'Left:Python , Center: Python and Right:
Python'
>>> "{},{key1},{},{key2},{}".format(1,2,3,key1=4, key2=5)
'1,4,2,5,3'

3.10.4 f-string in Python

Python introduced a new string literal formatting mechanism, called f-string, by


prefixing a string literal with the letter f. It formats a string literal in the same way as the
str.format () method but is more convenient and compact. In an f-string, an expression and
variable, and their formatting strings are included in the string by enclosing them within a
pair of curly brackets, {variable or expression: formatting string}. Expressions and variables
in a string literal are replaced by their values during execution. Expressions in an f-string
are evaluated at run-time. For example, the string literal f"The value of 5/2 is {5/2}" is
formatted as 'The value of 5/2 is 2.5'. Example 3.29 illustrates how to embed variables and
expressions in a string literal.

111
Example 3.29: f- strings

name = 'John'
height = 1.72
weight = 75
#Embedding variables and expressions in a string literal
print(f"Hello, I am {name}. My BMI is {weight/(height*height)}")
Output
Hello, I am John. My BMI is 25.351541373715524

We can include a formatting instruction for a variable or an expression for properly


formatting its output value, using a colon (:), for example, f"Float:{1/3:8.2f}, Integer:{123:6d}
and String:{ 'xyz':>10s}". All the formatting string options discussed in section 8.3.2 for
built-in data types are used in f-strings also. Example 3.30 illustrates formatting a float, an
integer, and a string in an f-string literal. We can also call functions inside an f-string.
Example 3.31 illustrates this.

Example 3.30: Formatting a float number in an f- string

a=10.2 #A float
b=20 #An integer
c="abc" #A string
#Formatting a float, an integer and a string in an f-string
print(f"Float:{a:8.2f}\nInteger:{b:6d}\nString:{c:>10s}")
Output
Float: 10.20
Integer: 20
String: abc

Example 3.31: Including a function call in an f-string

112
import math
x=3
#Calling a function inside a f-string
print(f"The sqrt of {x} is {math.sqrt(x):8.3f}")
Output
The sqrt of 3 is 1.732

We can include symbols such as a double quotation mark ("), a single quotation
mark ('), a slash (\) by using the escape sequence, and a curly bracket is included by
doubling it. Other brackets require no special treatment. Example 3.32 illustrates this.

Example 3.32: Including special symbols in an f-string

#An f-string with special symbols


s=f"This string includes special symbols: \', \",{{curly}},(,),[,]
and \\."
print(s)
Output
This string includes special symbols: ', ",{curly},(,),[,] and \.

When using dictionary elements in an f-string, we must use proper quotation marks
to begin and end an f-string. If dictionary keys and values are defined using single quotation
marks, we must begin and end an f-string with a double quotation mark and vice versa.
Example 3.33 illustrates this.

Example 3.33: Including dictionary elements in an f-string


#Create a dictionary
d={'Name':'John', 'Age':50}
#Include dictionary elements in an f-string
s=f"I am {d['Name']}. My age is {d['Age']}."
print(s)

113
Output
I am John. My age is 50.

Chapter Summary

1. Python 3.0 and newer versions support Unicode characters to name identifiers.
2. A token is the smallest unit of a computer program. Tokens are the building blocks
of computer expressions and statements.
3. Keywords are reserved words and have predefined meaning in programs.
4. Python identifiers can be of any length and can include Unicode characters.
5. A literal in a program is a fixed value that does not change during the execution of
a program. Python supports the following literal types: int, float, complex, str,
bytes, bool, NoneType, list, tuple, dict, and set.
6. A Python string literal can be created by enclosing characters in a pair of single
quotes, double quotes, triple single quotes, or triple-double quotes. However, if we
start with a single quote, it must end with a single quote.
7. Python supports the processing of integers, floats, and complex numeric values.
8. A Python integer can have any number of digits.
9. We can directly use binary, octal, decimal, and hexadecimal integers and their
combinations in an expression.
10. Python creates a complex number by adding a floating literal with an imaginary
literal.
11. Python has four different types of collection literals: List, Tuple, Dict, and Set.
12. A list is a mutable collection, whereas a tuple is an immutable collection
13. Lists, sets, and dictionaries cannot be used as a key in a dictionary.
14. A set is an unordered collection of items.
15. Python has operators to perform arithmetic, relational, logical, bitwise,
assignment, membership, and identity operations.
16. The input function always returns the read data as a string.
17. The eval function is used to execute Python commands contained in a string.
18. The print function is used to print data on the console.
19. We can format the output of an expression by the % operator, format function,
format method of the str class, and f-string.

114
Multiple Choice Questions

1. Which of the following is not a valid character in Python?


(a) $
(b) #
(c) β
(d) None of the above
2. Which of the following is a token in Python?
(a) Keywords
(b) Identifiers
(c) Operators
(d) All of the above
3. Which of the following are valid identifiers in Python?
(a) Integer
(b) Float
(c) αβγ
(d) All of the above
4. Which of the following is not a keyword in Python?
a) Int
(b) float
(c) None
(d) True
5. What is the maximum permissible length of an identifier in Python?
(a) 32 characters
(b) 64 characters
(c) 128 characters
(d) none of the above
6. Which of the following is an invalid identifier name in Python?
(a) _
(b) _x
(c) __str__
(d) None of the above
7. Which of the following is not a core data type in Python?
(a) List
(b) Dictionary

115
(c) Tuple
(d) Class
8. Which of the following is a literal in Python?
(a) String
(b) Complex
(c) Tuple
(d) All of the above
9. Which of the following is not a valid string literal in Python?
(a) 'This is a string literal.'
(b) "This is a string literal."
(c) """This is a string literal."""
(d) None of the above
10. Which of the following escape sequence is used to include a Unicode in a
string? Here, x is a hexadecimal digit.
(a) \N{name}
(b) \uxxxx
(c) \Uxxxxxxxx
(d) All of the above
11. Which of the following is an invalid integer literal in Python?
(a) 100
(b) 1_0_0
(c) 0100
(d) 0o100
12. Which of the following literals can be directly used in a Python expression?
(a) 0x100
(b) 100
(c) 0b100
(d) All of the above
13. Which of the following is an invalid float literal in Python?
(a) 1.23_4e1_2
(b) 1.234e12
(c) 1.234e 12
(d) None of the above
14. Which of the following is an invalid complex literal in Python?
(a) 4+5j
116
(b) 5j+4
(c) 4+j5
(d) 4-3j
15. Which of the following is not a Boolean literal?
(a) True
(b) False
(c) None
(d) None of the above
16. Which of the following is a valid list literal?
(a) [1, 2, 3, 'Four', 'Five']
(b) [1, 2, 3, 4, 5]
(c) [[1,2,3], [4,5]]
(d) All of the above
17. Which of the following is an invalid tuple?
(a) (1, 2, 3, 4, 5)
(b) ([1, 2, 3], [4,5])
(c) ()
(d) None of the above
18. Which of the following cannot be used as a key in a dictionary?
(a) Tuple
(b) Integer
(c) List
(d) Complex
19. Which of the following is an invalid set?
(a) {1, 2, 3, 4}
(b) {[1, 2, 3], [4, 5]}
(c) {(1, 2, 3), (4, 5)}
(d) {True, False}
20. Which of the following is equal to None in Python?
(a) Zero
(b) ""
(c) [ ]
(d) None of the above
21. Which of the following is not an operator in Python?
(a) add

117
(b) and
(c) is
(d) in
22. Which of the following can be returned by the input function?
(a) Integer
(b) Float
(c) String
(d) All of the above
23. Which of the following can be printed by the print () function?
(a) Number
(b) String
(c) List
(d) All of the above
24. The number of digits after the decimal point in the output of the expression
"%8.2f"%(1/3) is ___.
(a) 3
(b) 2
(c) 0
(d) None of the above
25. Which of the following can be used to format the output of an expression?
(a) % operator
(b) f-string
(c) The format () method
(d) All of the above

Review Questions

1. State whether the following statements are true or false:


a. Python 3.0 supports Unicode characters.
b. Αβγ is a valid variable name.
c. A literal is not a token.
d. A keyword can be used as a variable name.
e. The identifiers Name and name are the same.
f. A string literal can be created by using triple double quotes.

118
g. There is no special meaning of a backslash character in a raw string.
h. Python does not support the processing of complex numbers.
i. There are only two Boolean literals in Python.
j. A list is an immutable data.
k. A set can be used as a key in a dictionary.
l. A set is an ordered collection of numbers.
m. The input () function can return an integer.
n. The eval () method can be used to execute any valid Python
command contained in a string.
o. f-string is used to format a string.
2. Describe various types of Python tokens.
3. What is the purpose of keywords? List ten keywords along with their uses.
4. Describe Python identifier naming rules.
5. Describe various types of integer representation supported by Python.
6. Describe methods to create complex literals.
7. Describe various collection literals available in Python.
8. Differentiate list and tuple.
9. Describe various delimiters used in Python.
10. Describe the input () function.
11. Describe how to read multiple integers separated by a delimiter using an
input function.
12. Describe the eval () function
13. Describe the print () function.
14. Describe different methods to format output in Python.
15. Describe the f-string in Python.
Programming Exercises

1. Write a program to read a number from the keyboard and calculate its inverse
and print the result that contains three digits after the decimal point.
2. Write a program to read three numbers (a, b, c) and evaluate the expression
X=a/(b**2 –c).
Print the output in the scientific notation.
3. Print Greek symbols (alpha, beta, gamma, and lambda) using Unicode.

119
4. Write a program to find the speed of a car when distance and time are given.
First, the program will read the distance (in meters) and the time (in seconds)
from the keyboard. Then, print the formatted output on the console with two
digits after the decimal point.
5. Write a program to display the following pattern using a single print
statement:
*****
*
*
*****
6. Write a program to compute x^y for x=3.5 and y=3.5. Print the formatted
output with four digits after the decimal.
7. Write a program, which asks a user to enter his name, age, address, and
hobby and print the following sentence:
My name is [name]. I am [age] old and live at [address]. I love [hobby].
8. Write a program to convert the temperature given in Fahrenheit to Celsius
(use the formula c=(F-32)/1.8.
9. Read an integer and print it in binary, octal, and hexadecimal format.
10. Write a program to read two integers and perform the following arithmetic
operations: addition, subtraction, multiplication, and division.
11. Write a program to read three numbers and find their average.
12. Write a program to convert meters into inches.
13. Write a program to calculate the surface area and volume of a cylinder with
the given height and radius values.
14. Write a program that calculate the number of seconds in a leap year.
15. Write a program to read two complex numbers from the keyboard and find
their sum and product.

120
121
Chapter 4

Operators and Expressions


Learning Outcomes

1. Describe built-in arithmetic operators of Python


2. Describe relational, logical, and bitwise operations
3. Perform bitwise operations
4. Understand operator precedence and associativity rules
5. Evaluate expressions
6. Describe common built-in functions and mathematical functions of the math module

4.1 Operators
Operators are symbols used to perform operations on variables and values. For
example, in the expression 10+20, the + sign is an operator and performs the addition of 10
and 20. The values 10 and 20 are called operands. Python has a rich set of operators for
performing various operations on data. It has built-in support for the following types of
operators for numeric data:

1. Arithmetic Operators
2. Comparison (Relational) Operators
3. Logical Operators
4. Bitwise Operators
5. Assignment Operators
6. Membership Operators
7. Identity Operators

4.1.1 Arithmetic Operators

Python has built-in operators to perform basic arithmetic operations, such as


addition, subtraction, multiplication, division, floor division, modulus, and exponent.
These are binary operations, which means that the operator has two operands. For
example, in the expression a+b, the + operator adds the operand a (typically called the left
operand) to the operand b (typically called the right operand). An operand can be a variable

122
or an expression. The operands can be integers, floats, complex numbers, and Booleans for
addition, subtraction, multiplication, division, and exponent operators. However, for the
floor division and modulus operators, complex numbers are not allowed. Python allows the
floor division and modulus operations with float operands. Table 4.1 lists all the arithmetic
operators along with their brief descriptions. Example 4.1 illustrates these operators.
Example 4.2 shows the arithmetic operators on float numbers, example 4.3 on complex
numbers, and example 4.4 on Boolean values.

In arithmetic operations, both operands need not be of the same numeric type, i.e.,
one operand can be an integer number while the other can be a float or complex or Boolean
number. In such a hybrid expression, the lower precision numeric operand is upgraded to
the higher precision operand, and the result is of the higher precision type. The order of
precision up-gradation in Python is Boolean, integer, float, and complex. For example, if we
add an integer with a float, the integer is upgraded to the float type, and the result is the
float type. Similarly, if we add a Boolean data with a float data, the Boolean is upgraded to
the float type, and the result is the float type. Example 4.5 shows the above concepts.

Table 4.1: Arithmetic operators

Operator Operation Description


+ Addition Adds the left and right operands. Operands can be
integer, float, complex, and Boolean. Boolean true is equal
to 1 and false equal to 0.
Besides the numeric addition, the + operator is also used
for strings, lists, tuples, sets, and dict. These are discussed,
in detail, later in the book.
- Subtraction Subtracts the right operand from the left operand.
Operands can be integer, float, complex, and Boolean.
* Multiplication Multiplies the left and right operands. Operands can be
integer, float, complex, and Boolean.
/ Division Divides the left operand (numerator) by the right operand
(denominator). Operands can be integer, float, complex,
and Boolean. However, the zero denominator raises the
division by zero error.

123
// Floor division Divides the left operand by the right operand and returns
the largest possible integer, but less than or equal to the
normal division result. The operands can be integer, float,
or Boolean. They can be positive or negative. However,
the zero denominator raises division by zero error.
Complex numbers are not allowed.
% Modulus Divides the left operand by the right operand and returns
the remainder of the division. The operands can be
integer, float, or Boolean. They can be positive or negative.
However, the zero denominator raises division by zero
error. Python uses the following mathematics to calculate
the modulus (a%b)= a-(a//b)*b. Complex numbers are not
allowed.

** Exponent Performs exponential operation (i.e., xy ) on operands.


Operands can be integer, float, complex, and Boolean.

Example 4.1: Arithmetic operators

>>> a=7 # Initialize variables


>>> b=3
>>> c=-7
>>> print(a+b) # Addition operation
10
>>> print(a-b) # Subtraction operation
4
>>> print(a*b) # Multiplication operation
21
>>> print(a/b) # Normal division. Returns a float number
2.3333333333333335
>>> print(a//b) # Floor division. Returns the largest integer, which is
either less than or equal to the normal division result.
2
>>> print(c/b)
-2.3333333333333335
>>> print(c//b) # Floor division. -3 is less than -2.33.
-3

124
>>> print(a%b) # Modulus division. Returns reminder.
1
>>> print(c%b)
2
>>> print(a**b) # Exponent operation.
343
>>>

Example 4.2 Arithmetic operators on float operands

>>> a=5.2
>>> b=2.2
>>> print(a+b)
7.4
>>> print(a-b)
3.0
>>> print(a*b)
11.440000000000001
>>> print(a/b)
2.3636363636363633
>>> print(a//b)
2.0
>>> print(a%b)
0.7999999999999998
>>> print(a**b)
37.601689251649596
>>>

Example 4.3: Arithmetic operators on complex operands

>>> a=2+3j
>>> b=3+5j
>>> print(a+b)
(5+8j)
>>> print(a-b)

125
(-1-2j)
>>> print(a*b)
(-9+19j)
>>> print(a/b)
(0.6176470588235294-0.02941176470588238j)
>>> print(a**b)
(-0.34349061841848877+0.022021533303860297j)
>>> print(a%b) # Error: Modulus operation is not defined for complex
Traceback (most recent call last):
File "<pyshell#153>", line 1, in <module>
print(a%b)
TypeError: can't mod complex numbers.
>>> print(a//b) # Error: floor division is not defined for complex
Traceback (most recent call last):
File "<pyshell#154>", line 1, in <module>
print(a//b)
TypeError: can't take floor of complex number.

Example 4.4: Arithmetic operators on Boolean operands

>>> a=True
>>> b=False
>>> print(a+b)
1
>>> print(type(a+b))
<class 'int'>
>>> print(a-b)
1
>>> print(a*b)
0
>>> print(a/b) # Error: The numeric value of False is zero.
Traceback (most recent call last):
File "<pyshell#161>", line 1, in <module>
print(a/b)
ZeroDivisionError: division by zero
>>> print(b//a)
0

126
>>> print(b%a)
0
>>>

Example 4.5: Arithmetic operators on hybrid operands

>>> a=3
>>> b=5.5
>>> c=2+3j
>>> d=True
>>> print(type(a+b),type(a+c), type(a+d)) # Note: Type conversion
<class 'float'> <class 'complex'> <class 'int'>
>>> print(c*a,c*b,c*d)
(6+9j) (11+16.5j) (2+3j)
>>> print(c**a,c**b,c**d)
(-46+9j) (739.1447590698494-890.1578370493768j) (2+3j)
>>> print(a**c,b**c,d**c)
(-8.893151344279719-1.38269995578789j) (11.83157699398098-
27.840191914487587j) (1+0j)
>>> print(b**c,d**c)
(11.83157699398098-27.840191914487587j) (1+0j)
>>> e=c//a # Error: Floor division note defined for complex
Traceback (most recent call last):
File "<pyshell#173>", line 1, in <module>
e=c//a
TypeError: can't take floor of complex number.
>>> e=c%b # Error: Modulus operation not defined for complex
Traceback (most recent call last):
File "<pyshell#174>", line 1, in <module>
e=c%b
TypeError: can't mod complex numbers.
>>>

127
4.1.2 Relational (Comparison) Operators
A relational operator compares the left operand with the right operand for the
specified condition and returns either True or False. For example, the expression 10<20
returns True, and the expression 10>20 returns False. Python has six relational operators:
less than (<), less than or equal to (<=), greater than (>), greater than or equal to (>=),
equal to (==), and not equal to (!=) (See table 4.2). For the >, <, >= and <= operators,
operands can be of integer, float, Boolean, string, list, tuple, set, and dict types. These
comparison operators are not defined for complex operands. However, the == and !=
operators are defined for all the Python data, i.e., operands can be integer, float, complex,
Boolean, string, list, tuple, dict, set, and NoneType. Comparison operators for string, list,
tuple, set, and dict types are discussed later in the book. Example 3.6 illustrates the
comparison operators for numeric and Boolean operands.

Table 4.2: Relational operators

Operator Operation Description

> Greater than Returns True if the left operand is greater than the right

< Less than Returns True if the left operand is less than the right

== Equal to Returns True if the left and the right operands are equal

!= Not equal to Returns True if the left operand is not equal to the right

>= Greater than Returns True if the left operand is greater than or equal to
or equal to the right

<= Less than or Returns True if the left operand is less than or equal to the
equal to right

Example 4.6: Comparison operators

>>> a=3
>>> b=4
>>> d=3
>>> e=2+3j

128
>>> f=3+2j
>>> print(a==b) # Equal to
False
>>> print(a==d)
True
>>> print(a<b) # Less than
True
>>> print(a>b) # Greater than
False
>>> print(a<=b) # Less than or equal to
True
>>> print(a<=d) # Less than or equal to
True
>>> print(a>=b) # Greater than or equal to
False
>>> print(True==False) # Comparing Boolean data
False
>>> print(a!=b) # Not equal to
True
>>> print(e==f) # Comparing complex numbers
False
>>> print(e!=f) # Comparing complex numbers
True
>>> print(2+3j==2+3j) # Comparing complex numbers
True
>>> print(2+3j <2+3j)#Error: < is not defined for complex numbers.
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
print(2+3j <2+3j)
TypeError: '<' not supported between instances of 'complex' and 'complex'

4.1.3 Logical Operators

Logical operators perform logical AND, OR, and NOT operations and are primarily
used for combining relational operations. For example, the expression 1<2 and 3<4 returns
True, whereas the expression 1>2 and 3>4 returns False. Table 4.3 lists the three logical
operators of Python and their truth table.

129
Logical operators can have operands of any datatype. In a logical Python expression,
the numeric value 0, the complex number 0+0j, an empty string "", empty list [], empty tuple
(), empty set {}, and empty dict dict() are treated as False, and all other values of these data
types are treated as True. For example, the expression bool ("") evaluates to False, and the
expression bool ("ABC") evaluates to True.

When we use expressions other than logical expressions as operands to logical


operators, the return value is as follows: For the and operator, if the overall result is True,
the right-hand operand is returned. However, if the result is False, the first operand
responsible for the false result is returned. Similarly, for the or operator, if the overall result
is False, the last operand responsible for the False result is returned, and for the True result,
the first operand responsible for the True result is returned. For example, the expression
1+2 and 3+4 evaluates to 7 as the overall result of the expression is true; hence the right-
hand operand is returned. Whereas the expression 0 and 3+4 returns 0. Similarly, the
expression 1+2 or 3+4 returns 3, and the expression 0 or 3+4 returns 7.

Chained Comparisons: We can chain together many comparison operators, for


example, 10 < 20 < 30. The expression x<y<z is equivalent to x<y and y < z. The chained
comparison f(x) < f(y) < f(z) is faster as compared to the longer expression f(x) < f(y) and
f(y) < f(z), as in the later one, f(y) is evaluated twice.

We can chain different relational operators to any length. For example, x1 op1 x2
op2 x3 … xn-1 opn xn is equivalent to x1 op1 x2 and x2 op2 x3 and … xn-1 opn xn, where
op1, op2…opn can be any relational operator.

Example 3.7 illustrates some uses of the logical operators.

Table 4.3: Logical operators

Operator Operation Description


and Logical AND Evaluates to True if both the operands are True, else False.
The truth table of the logical and operation is as given below:
Left operand Right operand result
False False False
False True False
True False False
True True True

130
or Logical OR Evaluates to True if either of the operand is True, else False.
The truth table of the logical or operation is as given below:

Left operand Right operand result


False False False
False True True
True False True
True True True
not Logical NOT Evaluates to True if the operand is False, else False.
The truth table of the logical not operation is as given below:

Operand result
False True
True False

Example 4.7: Comparison operators

>>> # and operator


>>> print( 2<3 and 3<4, 2<3 and 3>4, 2>3 and 3<4, 2>3 and 3>4)
True False False False
>>> # or operator
>>> print( 2<3 or 3<4, 2<3 or 3>4, 2>3 or 3<4, 2>3 or 3>4)
True True True False
>>> # not operator
>>> print( not 2<3, not 2>3)
False True
>>> # not operators with different types of data equal to False value
>>> print( not 0, not '', not [], not (), not {}, not dict())
True True True True True True
>>> # not operators with different types of data equal to True value
>>> print( not 1, not 'a', not [1], not(1), not{1}, not {1:'One'})
False False False False False False
>>> #Return values with different types of data with and operator
>>> print( 3 and 4, "hello" and "hi", [1,2] and [3,4,5], (1,2) and
(3,4))
4 hi [3, 4, 5] (3, 4)
>>> #Return values with different types of data with or operator
>>> print( 3 or 4, "hello" or "hi", [1,2] or [3,4,5], (1,2) or (3,4))
3 hello [1, 2] (1, 2)
>>> print( 0 and 4, type(4 and '')) # 0 and empty string are returned

131
0 <class 'str'>
>>> type(4 and '') #The second operand is returned
<class 'str'>
>>> type('' or []) #The second operand is returned
<class 'list'>
>>> 10<20<30 #Chained logical expression
True
>>> 10<20>15 #Chaining different relational operators
True
>>>

4.1.4 Bitwise Operators

Bitwise operators perform various operations at bit level on the integer and Boolean
operands. For bitwise operations, Boolean True is treated as 1, and Boolean False is treated
as 0. These operations are not defined for the float, complex number, string, list, tuple, set,
dict, and NoneType operands. Python supports the following bitwise operations: AND, OR,
NOT, XOR, left shift, and right shift, shown in Table 4.4. Table 4.5 shows the truth table of
various logical bitwise operations. Table 4.6 shows the concepts of bitwise shift operations.

Since Python does not use a fixed number of bits to store an integer, the bitwise left
shift will increase the number of bits in the result. For example, the expression
bin(0b111<<2) produces '0b11100', where the number of digits in the original number is 3,
whereas, in the output, it is 5. Similarly, the bitwise right shift will decrease the number of
bits. For example, the expression bin(0b11111>>2) produces '0b111', where the number of
digits in the original number is 5, whereas, in the output, it is 3.

Further, for bitwise logical operations, the number of bits in both the operands is
made equal before performing the operation by adding leading zeros to the shorter
operand. Finally, the leading zeros in the result are removed. Example 4.8 illustrates the
above concepts.

Table 4.4: Bitwise operators

Operator Operation Description


& Bitwise AND Performs bitwise logical AND operations on the
corresponding bits of the integer operands.

132
| Bitwise OR Performs bitwise logical OR operations on the
corresponding bits of the integer operands.
~ Bitwise NOT Performs bitwise logical NOT operations on the
individual bits of the integer operand.
^ Bitwise XOR Performs bitwise logical exclusive OR(XOR)
operations on the corresponding bits of the integer
operands.
>> Bitwise right shift Shifts the specified number of bits of the first operand
toward the right. The number of bits to be shifted is
defined by the second parameter.
<< Bitwise left shift Shifts the specified number of bits of the first operand
toward the left and adds the same number of trailing
zeros. The number of bits to be shifted is defined by
the second parameter.

Table 4.5: Truth table of bitwise logical operations

Left bit Right bit AND OR XOR NOT left bit


0 0 0 0 0 1
0 1 0 1 1 1
1 0 0 1 1 0
1 1 1 1 0 0

Table 4.6: Bitwise shift operations

Operation Example Result Explanation


Left shift 0b100001<<2 0b10000100 Adds the specified
number of trailing zeros
at the right end.
Right shift 0b100001>>2 0b1000 Truncates the specified
number of bits from the
right end.

133
Example 4.8: Bitwise operators

>>> a=7
>>> b=11
>>> print(bin(a), bin(b)) # The bin(x) function prints x as a binary
string
0b111 0b1011
>>> print(bin(a&b)) # Bitwise logical and operation
0b11
>>> print(bin(a|b)) # Bitwise logical or operation
0b1111
>>> print(bin(a^b)) # Bitwise logical exclusive or operation
0b1100
>>> #Note the result, it is negative as the sign bit is also flipped.
>>> print(bin(~a), bin(~b)) # Bitwise logical not operation
-0b1000 -0b1100
>>> print(bin(a<<2)) # Bitwise left shift operation
0b11100
>>> print(bin(b>>1)) # Bitwise right shift operation
0b101

4.1.5 Assignment Operators

The simple assignment operator ( = ) assigns values to variables. The values can be
literals, variables, or expressions. For example, in x=5, the value 5 is assigned to x. The
simple assignment operator can assign values to more than one variable. For example, in x,
y = 5, 3+4, the value 5 is assigned to x, and the output of 3+4, i.e., 7, is assigned to y. When
we assign more than one value to a variable, the values are assigned to the variable as a
tuple. For example, the statement x=1, 2, 3 is equivalent to x=(1, 2, 3). However, when we
assign multiple values to multiple variables, the number of variables must be equal to the
number of values; otherwise, an unpacking error will be generated. For example, the
statement x, y =1, 2, 3 will generate an error. The unpacking error can be avoided by using
dummy variables. For example, the statement x, y, _=1, 2, 3 sets x=1, y=2 and _=3. The
underscore ( _ ) is frequently used as a dummy variable. We can have any number of
dummy variables in a multiple assignment to avoid unpacking errors, for example, x, y, _,
_=1, 2, 3, 4.

In addition to the simple assignment operator (=) given above, Python has many
compound assignment operators that combine other operations with an assignment. For
example, in x+=5, the value 5 is added to the current value of x. Thus, the previous statement
134
is equivalent to x=x+5. Unlike the simple assignment operation, a compound assignment
operation can have one variable and one value. For example, the statement x, y += 2, 3 is
an error. Table 4.7 lists all the assignment operators that are available in Python. Example
4.9 and example 4.10 show some uses of various assignment operators.

Table 4.7: Assignment operators

Operator Operation Description


= Assignment The assignment operator can be used in the following
three forms:
1: x=b; in this, the value b is assigned to the variable
x.
2: x, y=c, d; in this, the value c is assigned to x, and
the value d is assigned to y. The number of
operands on both sides must be the same;
otherwise, it will raise the unpacking error.
3: x=a, b, c, d; in this, the values a, b, c, and d are
packed as a tuple, and the tuple is assigned to x.
+= Add and assign x+=y; It is equivalent to x = x+y.

For x and y of the numeric type, the + operator is


used as an arithmetic addition operator, and x must
be a predefined numeric variable.

For x and y of type string, list, tuple, set, or dict types,


the + operator is used as a concatenation operation
operator. This situation is discussed, in detail, later in
the book.
-= Subtract and assign x-=y, this is equivalent to x=x-y. Here, the – operator
is used as the arithmetic subtraction operator.
*= Multiply and assign x*=y, this is equivalent to x=x*y. Here, the * operator
is used as the arithmetic multiplication operator.
/= Divide and assign x/=y, this is equivalent to x=x/y. Here, the / operator
is used as the arithmetic division operator.

135
%= Modulus and assign x%y, this is equivalent to x=x%y. Here, the %
operator is used as the arithmetic modulus operator.

For the compound modulus operator, x and y


should only be int, float or Boolean types; Complex
operands are not permitted.
**= Exponent and assign x**=y, this is equivalent to x=x**y. Here, the **
operator is used as the arithmetic exponent operator.
//= Floor Division and x//=y, this is equivalent to x=x//y. Here, the //
assign operator is used as the arithmetic floor division
operator.

For the floor compound operator, x and y should


only be int, float or Boolean types; Complex
operands are not permitted.
&= Logical bitwise AND x&=y is equivalent to x= x & y. Here, the & operator
and assign is used as the bitwise AND operator.

For all Boolean type compound operators (given


below), x and y should only be an int or Boolean
types.
|= Logical bitwise OR x|=y is equivalent to x= x | y. Here, the | operator is
and assign used as the bitwise OR operator.
^= Logical bitwise XOR x^=y is equivalent to x = x ^ y. Here, the ^ operator
and assign is used as the bitwise XOR operator.
>>= Logical bitwise right x>>=y is equivalent to x=x >> y. Here, the >>
shift and assign operator is used as the bitwise right shift operator.
<<= Logical bitwise left x<<=y is equivalent to x=x << y. Here, the <<
shift and assign operator is used as the bitwise left shift operator.

Example 4.9: Assignment operators

>>> a=5 # Assign a single value


>>> b,c=6,7 # Assign multiple values to multiple variables

136
>>> d=1,2,3 # Assign multiple values to a single variable. d is a tuple.
>>> print(a,b,c,d)
5 6 7 (1, 2, 3)
>>> a+=b # Add and assign
>>> print(a)
11
>>> b-=2 # subtract and assign
>>> c*=3 # Multiply and assign
>>> print(b,c)
4 21
>>> a**=4 # Exponent and assign
>>> print(a) # a uses the latest value, i.e., a=11
14641
>>> c%=b # Modulo and assign
>>> print(c)
1
>>> a=5.5
>>> b=2.2
>>> a//=b # Floor division and assign
>>> print(a)
2.0
>>> e=2+3j
>>> f=3+7j
>>> e+=f # Add and assign complex numbers
>>> print(e) #Print the modified value of e
(5+10j)
>>> e-=f #Subtract and assign complex numbers
>>> print(e) #Print the modified value of e
(2+3j)
>>> e*=f #Multiply and assign complex numbers
>>> print(e) #Print the modified value of e
(-15+23j)
>>> e/=f #Divide and assign complex numbers
>>> print(e) #Print the modified value of e
(2.0000000000000004+3j)
>>> e%=f #Error: Complex numbers are not permitted in modulus
Traceback (most recent call last):
File "<pyshell#29>", line 1, in <module>
e%=f

137
TypeError: can't mod complex numbers.
>>> e//=f #Error: Complex numbers not permitted in floor division
Traceback (most recent call last):
File "<pyshell#30>", line 1, in <module>
e//=f
TypeError: can't take floor of complex number.
>>> a=True
>>> b=2
>>> a+=b #Boolean is permitted
>>> print(a)
3

Example 4.10: Assignment operators with bitwise operations

>>> a,b=3,7
>>> print(bin(a), bin(b)) #Print numbers in binary format
0b11 0b111
>>> a&=b #Bitwise logical AND and assign
>>> print(bin(a))
0b11
>>> a|=b #Bitwise logical OR and assign
>>> print(bin(a))
0b111
>>> a^=0b101 #Bitwise logical XOR and assign
>>> print(bin(a))
0b10
>>> b<<=2 #Bitwise left shift and assign
>>> print(bin(b))
0b11100
>>> b>>=1 #Bitwise right shift and assign
>>> print(bin(b))
0b1110

4.1.6 Membership Operators

Membership operators check the presence or absence of data in collections and


sequences, such as strings, lists, tuples, sets, dicts, and ranges. The range([start=0], end,

138
[step=1]) method generates a sequence of numbers starting from the start up to the end
with the step size of the step. The default values of start is 0 and step is 1. For example, the
expression range(1,10) returns the sequence 1,2,…,9.

There are two membership operators in Python: in and not in. The in operator
checks for the presence. For example, the expression 3 in [1,2,3] returns True, but the
expression 4 in [1,2,3] returns False. Whereas the not in operator checks for the absence.
For example, the expression 3 not in [1,2,3] returns False, but the expression 4 not in [1,2,3]
returns True. They are listed and explained in Table 4.8. Example 4.11 shows the uses of
these operators for various collections and sequences.

Table 4.8: Membership operators

Operator Operation Description


in Checks the presence of Evaluates to True if the left operand exists in the
an item in a collection right , and False otherwise.
not in Checks the absence of Evaluates to True if the left-hand operand does
an item in a collection not exist in the right-hand operand, and False
otherwise.

Example 4.11: Membership operators

>>> a="I love Python programming"


>>> b='love' in a #Check the existence of a string in the other string.
>>> print(b)
True
>>> print('love' in a, 'hate' in a)
True False
>>> b=[1,2,3,4,5,6]
>>> print(3 in b,7 not in b)#Check the existence of an item in a list
True True
>>> c=(1,2,3,4,5)
>>> print( 2 in c, 6 in c, 2 not in c, 6 not in c) #Check the existence
of an item in a tuple.
True False False True
>>> d={1,2,3,5,2,3}

139
>>> print(1 in d, 10 in d, 2 not in d, 10 not in d) #Check the
existence of an item in a set
True False False True
>>> e={1:'One',2:'Two', 3:'Three'}
>>> print(1 in e, 4 in e, 1 not in e, 4 not in e) #Check the existence
of a key item in a dict.
True False False True
>>> print( 'One' in e) #Cannot check the value items in a dict. Hence,
false.
False
>>> f=range(10) #Creating a range object.
>>> print(2 in f, 12 in f, 2 not in f, 12 not in f) #Check the
existence of an item in a range.
True False False True
>>> print([1,2,3] in b) #Cannot check a sub list. Hence, false.
False
>>> print((1,2) in c) #Cannot check a sub-tuple. Hence, false.
False
>>> print( {1,3} in d) #Cannot check a subset. Hence, false.
False

4.1.7 Identity Operators

In Python, we can refer to the same data with more than one variable. For example,
in the statements x=[1, 2, 3, 4] and y=x, both x and y refer to the same list in the memory,
i.e., it creates a shallow copy. Python does not allocate different memory in a shallow copy.
In shallow copy, modifying one variable will change the value of all other aliases as there is
only one copy of the actual data in memory. For example, in L1=[1,2,3], L2=L1, L1 and L2
refer to the same list, i.e. [1,2,3]. The same is true of other collection data types, such as tuple,
dict, set.

Further, the Python interpreter creates only one copy of data if we create two
identical literals of numeric, string, or Boolean types. For example, for x=5 and y=5, the
Python interpreter will create only one copy of the literal 5, and both x and y will refer to it.
However, the Python interpreter will create separate objects for the identical literals of list,
tuple, set, and dict types. For example, list1 = [1,2,3], list2 = [1,2,3] will create two separate
objects in memory. Similar is true for the other collection data types.

140
Identity operators check whether two variables refer to the same object in the
memory or not. There are two identity operators: is and is not. The is operator returns True
if both operands refer to the same object in the memory; otherwise, it returns False. For
example, with x=10; y=x, the expression x is y returns True. The is not operator does the
opposite of the is operator. For example, the expression x is not y returns False. Table 4.9
lists identity operators, and Example 4.12 illustrates some uses of the identity operators.

Table 4.9: Identity operators

Operator Description
is Returns True if both operands refer to the same object in the memory,
i.e., both operands are alias of each other, otherwise returns False.
is not Returns True if both operands refer to two different objects in the
memory, otherwise returns False.

Example 4.12: Identity operators

#For identical, atomic and string literal values, only one copy is
created in the memory
>>> x1, y1=5, 5
>>> x1 is y1
True
>>> s1, s2="Hello", "Hello"
>>> s1 is s2
True
>>> s3="hello"
>>> s1 is s3
False
>>> s1 is not s3
True
>>> #For collection literals, different objects are created in the
memory
>>> l1, l2 =[1,2,3], [1,2,3]
>>> l1 is l2
False
>>> l3=l1 #Shallow copy. No separate memory allocated.
>>> l1 is l3
True
>>> t1, t2 =(1,2,3), (1,2,3)
>>> t1 is t2

141
False
>>> t3=t1 #Shallow copy. No separate memory allocated.
>>> t1 is t3
True
>>> st1, st2 = {1,2,3}, {1,2,3}
>>> st1 is st2
False
>>> st3=st1 #Shallow copy. No separate memory allocated.
>>> st1 is st3
True
>>> d1, d2 = {1:'One',2:'Two'}, {1:'One',2:'Two'}
>>> d1 is d2
False
>>> d3=d1
>>> d1 is d3
True

4.2 Expressions
An expression is a combination of variables, functions, constants, and operators, as
per the programming language's syntax, and evaluates to a value. When we assign the
result of an expression to a variable, it is called a statement. For example, 10+20 is an
expression, whereas x=10+20 is a statement. Based on the type of the expression result, an
expression can be classified as an arithmetic expression, string expression, and logical
expression. An arithmetic expression returns a single numeric value; a string expression
returns a string value, and a logical (also called relational) expression returns a single logical
value. For example, 2+3 is an arithmetic expression, "Python"+" Programming" is a string
expression, and 2>3 is a logical expression, as they return a numeric (5), string ('Python
Programming'), and logical (False) values, respectively.

4.2.1 Arithmetic Expressions

An arithmetic expression combines numeric and Boolean values and arithmetic


operators and returns a numeric value. For example, the arithmetic expression 10+4/2-6
returns 6. The Boolean True and False are numerically equal to 1 and 0, respectively. Thus,
the expression 10+True returns 11. Numeric values could be integer, float, and complex
numbers. Python can handle any complex mathematical expression. Table 4.10 gives some
examples of mathematical expressions and their equivalent Python expressions. Example
4.13 gives some examples of arithmetic expressions. For evaluating complex expressions,

142
operator precedence and associativity rules are used, explained later in this chapter; see
section 4.3.

Table 4.10: Expressions

Mathematical expression Python expression


𝑎 + 𝑏 − 𝑐𝑑 a+b-c*d
(𝑎 + 𝑏)(𝑐 + 𝑑) (a+b)*(c+d)
𝑎+𝑏 (a+b)/(c-d)
𝑐−𝑑
4𝑥 2 + 2𝑥 − 3 4*x**2+2*x-3
𝑥 𝑎 x/y+a/b
+
𝑦 𝑏

Example 4.13: Arithmetic expressions

>>> a,b,c,d=1,2,3,4 #Integer operands


>>> a+b-c*d #Multiplication is evaluated first,then addition
and subtraction
-9
>>> (a+b)*(c+d)
21
>>> (a+b)/(c-d)
-3.0
>>> x,y=2,3
>>> x/y+a/b
1.1666666666666665
>>> a,b,c,d=1.1,2.5,3.3,4.7 #Float operands
>>> a+b-c*d
-11.91
>>> (a+b)*(c+d)
28.8

143
>>> (a+b)/(c-d)
-2.5714285714285707
>>> x,y=2.6,3.4
>>> x/y+a/b
1.2047058823529413
>>> a,b,c,d=2+3j,2-3j,3+5j,4+5j #Complex operands
>>> a+b-c*d
(17-35j)
>>> (a+b)*(c+d)
(28+40j)
>>> (a+b)/(c-d)
(-4-0j)
>>> x,y=2j,3+2j
>>> x/y+a/b
(-0.07692307692307693+1.3846153846153846j)

4.2.2 Logical Expressions

A logical expression, also called Boolean expression, is an expression that combines


relational expressions and other values with logical operators (and, or and not) and returns
either True or False. For example, the expression x>y and a>b is a logical expression. In
Python, 0, 0.0, 0+0j, an empty string, an empty list, an empty tuple, an empty set, and an
empty dict are considered False, and all non-zero and non-empty values are considered
True. Thus, in Python, the expression x>5 and y is a valid logical expression. This expression
returns true if x is greater than 5 and y is a non-zero or non-empty value. Table 4.11 gives
some examples of logical expressions and their equivalent Python expressions. Example
4.14 shows some examples of logical expressions.

Table 4.11: Logical expressions

Logical expression Python expression


𝑥≤𝑦 x<=y
𝑥 ≤ 𝑦 𝑎𝑛𝑑 𝑥 < 𝑧 x<=y and x<z
𝑥+𝑦 ≤ 𝑝+𝑞 x+y <= p+q
𝑥≤𝑦≤𝑧 x<=y<=z
𝑥 ≤ 𝑦 𝑜𝑟 𝑥 < 𝑧 x<=y or x<z

144
𝑥=𝑦 x==y
"ABC" < "𝑋𝑌𝑍" "ABC" < "XYZ"

Example 4.14: Logical expressions

>>> x,y,z=1,5,9
>>> x<=y
True
>>> x>y
False
>>> x<=y and x<z #True as both relational expressions are true
True
>>> x<=y and x> z
False
>>> x+y <=x+2 #Arithmetic expressions are evaluated first
False
>>> x+y >=x+2
True
>>> x<=y<=z
True
>>> x==y
False
>>> #Strings are compared based on their characters' Unicode values
>>> "abc"<"ABC"
False
>>> "abc">"ABC"
True
>>> "क"< "ख" #Strings can consist of any Unicode characters
True
>>> "क" > "ख"
False
>>> "α" <"β" #Strings can consist of any Unicode characters
True
>>> "α" > "β"
False

4.2.3 String Expressions

A string expression combines string literals, string variables, and functions using
string operators (concatenation (+) and product (*)) and returns a string. The concatenation
operator (+) combines the left and right strings. For example, the expression "Python" +

145
"Programming" returns 'PythonProgramming'. Please note that there is no separator used
during concatenation. To properly concatenate strings, add a separator if required; for
example, "Python" +" "+ "Programming" evaluates to 'Python Programming'.

The product operator (*) repeats a string by a specified time. For example, the expression
"Python" * 3 returns 'PythonPythonPython'. We can use both concatenation and product
operators in an expression. For example, the expression "Python is " + "very "*3 + " good."
returns 'Python is very very very good.' Example 4.15 shows some examples of string
expressions.

Example 4.15: String expressions

>>> s1,s2="Python", "Programming"


>>> s1+s2 #Concatenating two strings.
'PythonProgramming'
>>> s1+" "+s2 #Use a separator for readability
'Python Programming'
>>> "Python"*3 #Product operator
'PythonPythonPython'
>>> #Product and concatenation operators in an expression
>>> "Python is " + "very "*3 + " good."
'Python is very very very good.'

4.3 Operator Precedence and Associativity


As discussed earlier, an expression is a combination of values, variables, operators,
and functions. There can be more than one operator in an expression. For example, in the
expression 4 * 5 + 2, the result of the expression depends on the order in which we perform
operations. If the multiplication is performed before addition, the result is 22. However, if
the addition is performed before the multiplication, the result is 28. To resolve such
ambiguities, operators in an expression are evaluated in a predefined order. It is called
operator precedence rule or hierarchy of operators. The precedence rule is similar to the
BODMAS rule of evaluating arithmetic expressions, which guides the order in which these
operations are carried out. Table 4.12 shows the precedence order of Python operators. An
operator with a lower precedence level is evaluated before an operator with a higher
precedence level. For example, the precedence level of the multiplication operator is 4, and
that of the addition operator is 5. Hence, the multiplication operator is evaluated before the
addition operator in an expression. Applying the precedence rule, the expression 4 * 5 + 2
returns 22. Following is the sequence of evaluation of this expression:

146
Step 1: 4*5+2 (First operation: Multiplication (precedence level= 4))
Step 2: 20+2 (Second operation: Addition (precedence level = 5))
Step 3: 22

As can be seen from table 4.12, a group of operators has the same precedence level.
For example, the operators *, /, //, and % have the same precedence level. In this situation,
the order of evaluation of operators is decided by the associativity rule. The operator
associativity rule defines the direction of the evaluation of operators of a precedence level.
The direction of the evaluation of operators of the same level of precedence can be either
from left-to-right or from right-to-left. In the left-to-right associativity, the operator in the
left is evaluated first, whereas, in the right-to-left, the operator in the right is evaluated first.
The operators within the same precedence level will have the same associativity. The last
column of table 4.12 shows the associativity of the various precedence levels. For example,
in the expression 3 + 8 / 2 * 4, the precedence level of the division operator and the
multiplication operator is the same, but the associativity is from left to right. Hence,
division is performed before multiplication. The evaluation order of operators in the
expression is as given below:

Step 1: 3+8/2*4 (First: Division due to the left-to-right associativity)


Step 2: 3 + 4*4 (Second: Multiplication due to the higher precedence level)
Step 3: 3+ 16 (Third: Addition)
Step 3: 19

The evaluation order of the operators in an expression can be altered by using


parentheses. For example, in the expression 3+8/ (2*4), the evaluation order of the operators
is as given below:

Step 1: 3 + 8 / (2 * 4) (First: Parenthesis due to the higher precedence)


Step 2: 3+ 8 /8 (Second: Division due to higher precedence)
Step 3: 3+1 (Third: Addition)
Step 4: 4

The associativity can also to altered by using parentheses. For example, consider the
evaluation of the expressions 2**3**2 and (2**3) **2.

Step 1: 2**3**2 (First: The right exponent due the right-to-left associativity)
Step 2: 2**9 (Second: Exponent operator)
Step 3: 512

147
Step 1: (2**3)**2 (First: The left exponent operation due parenthesis)
Step 2: 8**2 (Second: Exponent operator)
Step 3: 64

Table 4.12: Python operator precedence and associativity

Precedence Operator Description Associativity


level
1. () Parenthesis left to right
2. ** Exponentiation right to left
3. +x, -x, ~x Unary positive and negative left to right
operations, bitwise not
4. *, /, //, % Multiplication, float division, left to right
integer division, modulus
5. +, - Addition, subtraction left to right
6. <<, >> Bitwise left and right shifts left to right
7. & Bitwise AND left to right
8. ^ Bitwise XOR left to right
9. | Bitwise OR left to right
10. in, not in, is, is Membership, Identity, left to right
not, <, <=, >, >=, comparison operators
!=, ==
11. not Boolean NOT left to right
12. and Boolean AND left to right
13. or Boolean OR left to right

Example 4.16 illustrates operator precedence with examples.

Example 4.16: Precedence and associativity

>>> 20-8*2 #Execution Order: * and –, due to precedence


4
>>> (20-8)*2 # Execution Order:-,*, due to parenthesis
24

148
>>> 5*2/3 #Order: *,/ due to the left to right associativity
3.3333333333333335
>>> 10 * 3 + (10 % 2) ** 3 #Order: %, **, *, +
30
>>> 45 % 2 - 5 / 2 + ( 9 * 3 - 2 ) #Order: *, -, %,/,-,+
23.5
>>> 5 + 24 / 2 * 4 #Order: /,*,+
53.0
>>> (2**3)**2 #Order: left ** and then right **
64
>>> 2**3**2 #Order: Right ** and then left **
512

4.4 Statements vs Expressions


A statement is a programming construct that does something, for example, an
assignment statement, conditional and branching statement, looping statements. Whereas
an expression is a combination of values and operators and always returns a value. In
simpler terms, we can say that anything that evaluates to some value is a Python expression,
while anything that does something is a Python statement.

4.5 Python built-in Functions


Python has a number of built-in functions. We can use the command dir('built_in')
at the command prompt to display the list of all the built-in functions and attributes.
Example 4.17 shows a list generated by the dir('built_in') command. These functions are
always available and do not require importing any module. Table 4.13 lists them in
alphabetical order, along with a brief description of each.

Example 4.17 : List built-in attributes and functions

>>> dir('built_in') #List all the built-in attributes and functions


['__add__', '__class__', '__contains__', '__delattr__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__',
'__init_subclass__', '__iter__', '__le__', '__len__', '__lt__',
'__mod__', '__mul__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__',

149
'__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold',
'center', 'count', 'encode', 'endswith', 'expandtabs', 'find',
'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii',
'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric',
'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust',
'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix',
'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition',
'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip',
'swapcase', 'title', 'translate', 'upper', 'zfill']
>>>

Table 4.13: Python built-in functions

Function Description
abs(num) It returns the absolute value of a number. It can be used for all numeric
data: integer, float, and complex numbers. For example, abs(-10)
returns 10, and abs(3+4j) returns 5.0.
all(itr) It returns True if all items in an iterable object are true. For example,
all([1,2,3,4,5]) returns True, whereas all([1,2,0,4,5]) returns False. It can
be used with all the collection data types: lists, tuples, sets, and
dictionaries.
any(itr) It returns True if any item in an iterable object is true, for example,
any([1,0,0,0,5]) returns True, whereas any([False,"",0,{}]) returns False.
It can be used with all the collection data types: lists, tuples, sets, and
dictionaries.
ascii(obj) It returns the readable ASCII version of any object, such as strings,
tuples, lists. The non-printable or invisible characters such as tab,
carriage return, form feed, and non-ASCII characters such as α, b, P
are replaced with equivalent escape sequence characters. For example,
ascii('α is a Greek symbol.') returns "'\\u03b1 is a Greek symbol.'",
where \\u03b1 is the escape sequence of α. Similarly, ascii(['α', 'β','γ'])
returns "['\\u03b1', '\\u03b2', '\\u03b3']" and ascii('\t\n\f\v\b')
returns "'\\t\\n\\x0c\\x0b\\x08'".
bin(num) It returns the binary representation of an integer number in a string
format. For example, bin(13) will return '0b1101'. The argument can be
given in any integer representation, such as decimal integer, octal

150
integer, hexadecimal integer, and binary integer. For example,
bin(0xFF) returns '0b11111111', bin(0o10) returns '0b1000', and
bin(0b1010) returns '0b1010'.
bool(obj) It converts an object into an equivalent Boolean value, i.e., True or
False. In python, 0, 0.0, 0+0j, an empty string, None, an empty list, an
empty tuple, an empty dictionary , an empty set and an empty range
are equivalent to False and all other values are True. Thus, bool(""),
bool(0), bool([]), bool(()), bool({}) and bool(None) all return False.
Whereas, bool("a"), bool(1), bool([1,2]), bool((1,4))and bool({1,2,3}) all
return True.
bytearray(obj) It returns an equivalent bytearray of an object. A bytearray is a mutable
array of bytes. In Python, the byte is an integer that can have a value
in the range 0 <= x < 256. Any value outside this range is an error.
The bytearray() method has the following three forms:
1. bytearray(integer): When we pass an integer argument, the
method returns a bytearray of the specified number of bytes and
the value of each byte is set to zero. For example, bytearray(4)
returns bytearray(b'\x00\x00\x00\x00'). The value of each byte is
shown in hexadecimal format.
2. bytearray(obj): When we pass a list, a tuple, a set, or a dict of
integer numbers, the method returns a bytearray of the items of
the object. For example, bytearray([1,2,3]) returns
bytearray(b'\x01\x02\x03').
3. bytearray(string, encoding): When we pass a string and its
encoding, the method returns a bytearray of the ASCII values of
the characters of the string. For example, bytearray('abcαβγ','utf-
8') returns bytearray(b'abc\xce\xb1\xce\xb2\xce\xb3')

A bytearray is mutable, i.e., we can assign a new value to elements of


a bytearray. See the following example:

>>> x=bytearray([1,2,3]) #Create a bytearray


>>> print(x) #Original content
bytearray(b'\x01\x02\x03')
>>> x[0]=10 #Assigning a new value to the first element
>>> print(x) #Modified value
bytearray(b'\n\x02\x03')

151
bytes(obj) It is similar to bytearray, but it returns an immutable array of bytes,
i.e., we cannot modify the returned array elements. However, we can
access individual items. Similar to the bytearray() method, the bytes()
method can also be used in the three forms. See the following
examples:

>>> #Create a bytearray with all elements set to 0.


>>> bytes(4)
b'\x00\x00\x00\x00'
>>> #Create a bytearray with given values.
>>> bytes([1,2,3,4])
b'\x01\x02\x03\x04'
>>> #Convert a string into a byte array.
>>> bytes('abc','utf-8')
b'abc'
callable(obj) Returns True if the specified object is callable, otherwise False. A
callable object accepts some arguments, processes the arguments, and
possibly returns some results, such as a function and a method. For
example, callable(10) returns False, but callable(print) returns True.
chr(code) It returns the character corresponding to a Unicode or ASCII code. For
example, chr(0x03B1) returns 'α'; chr(945) returns 'α'; chr(65) returns
'A', and chr(97) returns 'a'.
A character code can be given in any of the following formats:
hexadecimal, binary, octal or decimal integers. For example, chr(97),
chr(0x61) and chr(0b1100001) all returns 'a' as all the codes are for the
character 'a' in the different number systems.
complex(obj) It converts a compatible object, such as numbers and strings, to an
equivalent complex number. The method accepts either a number or a
string. See the following examples:

>>> complex(3) #Convert a number to a complex number


(3+0j)
>>> #The first number is the real part and the second is
the imaginary part.
>>> complex(3,4)
(3+4j)
>>> complex("3+4j") #Convert a string to a complex
number
(3+4j)
>>> complex('3+6J') #Capital J can be also used

152
(3+6j)
>>> #Error: the order of real and imaginary part is
important in case of string
>>> complex("4j+3")
Traceback (most recent call last):
File "<pyshell#148>", line 1, in <module>
complex("4j+3")
ValueError: complex() arg is a malformed string
>>> complex(3+4j) #Convert an expression to a complex
number
(3+4j)
>>> complex(4j+3) #The order of real and imaginary parts
is not important
(3+4j)
dict(data) It creates a dictionary object from data. The data can be given in the
form of a list (or a tuple) of tuples containing pairs of key-value pairs.
If there is no argument given, it returns an empty dictionary object. See
the following examples:

>>> dict() #Create an empty dictionary


{}

>>> #Create a dictionary from a list of tuples


>>> dict([(1,"One"),(2,"Two")])
{1: 'One', 2: 'Two'}
>>> #Create a dictionary from a tuple of tuples
>>> dict(((1,"One"),(2,"Two")))
{1: 'One', 2: 'Two'}
dir(obj) It returns a list containing all attributes, properties, and methods of the
argument object. For example, dir(tuple) returns all the methods and
the attributes of the tuple class, as given below:

>>> dir(tuple) #List attributes and methods of an object


['__add__', '__class__', '__class_getitem__',
'__contains__', '__delattr__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__',
'__getitem__', '__getnewargs__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__iter__', '__le__',
'__len__', '__lt__', '__mul__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__rmul__',
'__setattr__', '__sizeof__', '__str__',
'__subclasshook__', 'count', 'index']

153
divmod(arg1, Returns the quotient and the remainder when the first argument is
arg2) divided by the second argument. It can handle both real and integer
arguments. See the following examples:

>>> divmod(5,2) #Returns quotient and reminder of a


division
(2, 1)
>>> divmod(5.1,2.2) #Can handle real numbers
(2.0, 0.6999999999999993)
enumerate(itr) It converts a collection into an enumerated object. In an enumerated
object, a counter is added to each item of the collection. The counter,
by default, starts with zero, but it can be set to any other value. For
example:
>>> #The counter start with 0, by default
>>> for i in enumerate("Python"):
print(i)

(0, 'P')
(1, 'y')
(2, 't')
(3, 'h')
(4, 'o')
(5, 'n')
>>> #The counter starts from 5
>>> for i in enumerate("Python",5):
print(i)

(5, 'P')
(6, 'y')
(7, 't')
(8, 'h')
(9, 'o')
(10, 'n')
eval(string) Evaluates a string argument as python expressions and returns the
result. For example, eval("10+3*4-2") returns 20, x=2;
eval("2*x**2+2*x-3") returns 9, and eval("1+2,3+4,5*6") returns (3, 7,
30).

154
exec(string) Executes Python codes given as a string. For example,
exec("a=2;b=3;print(a+b)") creates variables a and b and print their
sum.
filter(fun, itr) It is used to select those items from a collection that returns True when
processed by a specified fun. The function can be used for every type
of collection and sequence, such as list, tuple, set, dictionary, string,
range. In the following example, vowels in a string and a list are
selected and printed.

>>> #Define a function to separate vowels and other


characters
>>> def isVowel(ch):
vowels = ['a', 'e', 'i', 'o', 'u']
if (ch in vowels):
return True #Return true when ch is a vowel
else:
return False

>>> #Create a filter to separate vowels in a string


>>> for ch in filter(isVowel,"Python Programming"):
print(ch)

o
o
a
i
>>> #Create a filter to separate vowels in a list
>>> for ch in filter(isVowel,['a','b','c','d','e','f']):
print(ch)

a
e
float(obj) Converts its argument to an equivalent floating point number. For
example, float("1231.4") returns 1231.4 and float(10) returns 10.0.
format(val) It is used to format a value as per a specified formatting string. See
chapter 3, section 3.8.2.
frozenset(itr) It converts an iterable data in a frozenset. A frozen set is similar to a
set, but it is immutable, i.e., it freezes the iterable objects and makes

155
them unchangeable. The function first removes duplicate items and
then converts the iterable in a frozen set. See the following example:

>>> frozenset((1,2,3,4,5,6)) #Covert a tuple to a


frozenset
frozenset({1, 2, 3, 4, 5, 6})
>>> #Covert a list to a frozenset. Duplicates are
removed.
>>> a=frozenset([1,3,2,5,4,6,2])
>>> a
frozenset({1, 2, 3, 4, 5, 6})
>>> a=frozenset("Python Programming")#Covert a string to
a frozenset
>>> a
frozenset({'g', ' ', 'a', 'P', 'm', 'h', 't', 'o', 'r',
'i', 'y', 'n'})
getattr(obj, It returns the value of the specified attribute of an object. It is similar
attrib) to obj.attrib. See the following example:

>>> class Person: #Create a class


age = 23
name = "John"

>>> person=Person() #Create an object


>>> getattr(person,'age') #Get the value of an attribute
23
>>> getattr(person,'name')
'John'
>>> person.age #Get the value of an attribute
(Preffered)
23
globals() It returns the current global symbol table as a dictionary. Symbol table
is a data structure created by the Python interpreter to store all the
information needed to execute a program. The local symbol table
stores all the information needed to the local scope of the program;
whereas the global symbol table stores global data. For example,
globals() returns:
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':

156
None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-
in)>, 'fruit': <class '__main__.fruit'>, 'a': 2, 'b': 3, 'i': (5, 'n'), 'x': 2}.
hasattr(obj, It returns True if the specified object has the specified attribute
attrib) (property/method). For example, hasattr(list(),"append") returns
True, whereas hasattr(tuple(),"append") returns False.
hash(obj) It returns the hash value of an immutable object, such as numeric
literals, strings, tuples, range. A hash value is a numeric value of fixed
length that uniquely identifies data. For example, hash("abc") returns
224187216707242117; hash(12.3) returns 691752902764109836, and
hash((1,2,3)) returns 529344067295497451. Hashing is widely used for
searching data in a collection.
help(obj) It is used to display the documentation of modules, functions, classes,
and keywords. See the following example:

>>> help('bin') #Get the help of the bin() method


Help on built-in function bin in module builtins:

bin(number, /)
Return the binary representation of an integer.

>>> bin(2796202)
'0b1010101010101010101010'

hex(num) It returns the hexadecimal representation of an integer as a string


object. It accepts an integer in decimal, octal, binary and hexadecimal
formats. See the following examples:

>>> hex(255) #Decimal integer to hexadecimal string


'0xff'
>>> hex(0b1010) #Binary integer to hexadecimal string
'0xa'
>>> hex(0o12) #Octal integer to hexadecimal string
'0xa'
>>> hex(0xff) #Hexadecimal integer to hexadecimal string
'0xff'

157
id(obj) It returns the id of an object in the memory. In Python, every created
object is assigned a unique integer ID. For example, a=10; id(a) returns
2213301873232.
input(string) Reads and returns a line of string from the console. For example,
>>>input("Enter a string:")
Enter a string: Python Program
The function returns 'Python Program'
int(arg, base) It converts the first argument to an integer. It accepts a number or a
string as its argument. The second parameter is the base of the number
system in which the first argument is given. The default base is 10, i.e.,
the decimal system. See the following examples:

>>> int(20.5) #Convert a float to an integer


20
>>> int('123') #Convert a string to an integer
123
>>> int('0b1010',2) #Convert a binary string to an
integer
10
>>>
>>> int('0xff',16) #Convert a hexadecimal string to an
integer
255
>>> int('0o10',8) #Convert an octal string to an integer
8
>>> int(0x10) #Convert an integer in hexadecimal to an
integer
16
isinstance(obj, It returns True if the first argument is an instance of a class given as
cls) the second argument. For example, isinstance("abc",str) returns True;
isinstance(1,str) returns False.
issubclass(cls1, It returns True if the first argument is a derived class of the second
cls2) argument. In Python, every class is derived from the object class. See
the following example:

>>> #The list class is derived from the object class


>>> issubclass(list,object)
True
>>> #The list class is not derived from the tuple class
>>> issubclass(list,tuple)

158
False
iter(obj) It creates an iterable object from a collection object, such as a list, tuple,
string, set, dictionary, range. For example, vowels_iter=iter("aeiou")
create an iterable object. It can be iterated using the function next ().
For example, next(vowels_iter) returns 'a' and the next time
next(vowels_iter) returns 'e', and so on.
len(obj) It returns the number of elements in a collection object, such as a string,
list, tuple, set and dictionary. For example, len("abc") returns 3 and
len([1,2,3,4]) returns 4.
list(obj) It creates a list from a collection object. The argument could be any
collection object, such as a tuple, string, set, dictionary, range. If no
argument is given, it creates an empty list. For example, list("abc")
returns ['a', 'b', 'c'], list((1,2,3)) returns [1, 2, 3] and list() returns [], i.e.
an empty list.
map(fun, itr) It evaluates the function specified as the first argument over a
collection object specified as the second argument. For example,
list(map(lambda x:x%2==0,[1,2,3,4,5])) returns [False, True, False,
True, False].
Also, see the following example:

>>> def fun(x): #Function definition


return x*x
>>> #Evaliuate the function fun at each list item
>>> a=map(fun,[1,2,3])
>>> for y in a:
print(y)

1
4
9
max(itr) It returns the largest item in an iterable object. For example,
max([1,2,4,3,5,0]) returns the element with the maximum value, i.e. 5,
max({1:1,2:4,3:9,4:16}) returns the maximum key value, i.e. 4, and
max("abc") returns the character with the maximum ASCII value, i.e.
'c'

159
min() It returns the smallest item in an iterable object. For example,
min([1,2,4,3,5,0]) returns the element with the smallest value, i.e. 0,
min({1:1,2:4,3:9,4:16}) returns the smallest key value, i.e. 1, and
min("abc") returns the character with the smallest ASCII value, i.e. 'a'
next() Returns the next item in an iterable object. See the following example:

>>> a=iter([1,2,3,4,5]) #Create an iterable object


>>> #Get the current element and move pointer to the
next item
>>> next(a)
1
>>> next(a)
2
object() It is used to create a new empty object of the object class. In Python,
every data and variable is an instance (object) of a class, and every class
is inherited from the object class. Thus, the object class defines the
properties and methods which are common to all classes. See the
following example, which creates an empty object and lists all the
attributes:

>>> obj=object() #Create an instance of the object class


>>> dir(obj) #List attributes of obj
['__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__']
oct(arg) It returns the octal representation of an integer as a string object. For
example, oct(255) returns '0o377'. The integer argument can be given
in any of the following formats: decimal, octal, hexadecimal, and
binary integer.
open() It opens a file for reading and writing. See the file handling chapter for
more detail.
ord() Returns the Unicode of a symbol. For example, ord('a') returns 97 and
ord('β') returns 946.

160
pow(x,y) It returns the value of x raised to the power of y, i.e., xy. For example,
pow(2,3) returns 8. It can handle complex arguments. For example,
pow(2+3j,3+4j) returns (-0.204552921794176+0.8966232598799766j).
print() It prints the value of arguments to the standard output device. For
example, print(10+2, 'ABC') prints 12 ABC on the console. See chapter
3.
property() It binds the getter, setter, and deleter functions of a class with a single
attribute name. Then, depending on the use of the attribute, the
corresponding function is called, automatically. For example, when
the attribute is assigned a value, the setter function is called, and if the
attribute is used in an expression, the getter function is called. See the
following example:

>>> class myClass: # Define a class


def __init__(self, value):
self._value = value
def getValue(self): #Define a getter
print('Getting value')
return self._value
def setValue(self, value): #Define a setter
print('Setting value to ' + value)
self._value = value
def delValue(self): #Define a deleter
print('Deleting value')
del self._value
#Convert the getter, setter and deleter
#functions as properties.
value = property(getValue, setValue, delValue)

>>> x=myClass('Python') #Create an object


>>> print(x.value) #Automatically call getter
Getting value
Python
>>> x.value="Programming" #Automatically call setter
Setting value to Programming
>>> del x.value #Automatically call the delete
Deleting value
range([start=0], It returns a range object. A range object is a sequence of numbers
end, [step=1]) between a start value (start) and an end value (end) with a step size
(step). The generated series includes the start value but excludes the

161
end value. By default, start=0 and step=1. All the arguments should be
integer only. Negative integers can be used. If we cannot reach from
start to end with the given step value, an empty range object is created.
The range function creates the definition of the range objet in the
memory. To get the individual item, we need to convert it to either into
a list or other collection. We can also get the individual item of the
range by iterating it using a for loop. See the following examples:

>>> a=range(0,6,2) #Create a range object


>>> print(a) #Print the range object
range(0, 6, 2)
>>> list(a) #Convert a range object to a list
[0, 2, 4]
>>> #A range with default start, i.e. 0, and step, i.e.,
1
>>> list(range(5))
[0, 1, 2, 3, 4]
>>> list(range(4,8)) # A range with default step, i.e.,
1
[4, 5, 6, 7]
>>> list(range(5,0,-1)) #A range with a negative step
value
[5, 4, 3, 2, 1]
>>> list(range(-10,-5)) # A range with a negative start
and end values
[-10, -9, -8, -7, -6]
>>> list(range(-2,2)) # A range with a negative start
and a positive end value
[-2, -1, 0, 1]
>>> list(range(5,1)) #An empty range
[]
repr(obj) It converts the argument to a string. The argument can by any valid
Python object. For example, repr(10) returns '10', repr(2+3j) returns
'(2+3j)' , repr([1,2,3,4]) returns '[1, 2, 3, 4]', and repr(range(10)) returns
'range(0, 10)'.
reversed(itr) It returns a reversed iterator of the argument. The argument can be any
collection object. However, in dict object, only the key values are used
to create a reversed iterator. A reverse iterator can be directly used, or
it can be converted to a list or other collection. See the following
example:

162
>>> list(reversed("abcd")) #String’s reversed iterator
['d', 'c', 'b', 'a']
>>> list1=reversed([1,2,3,4]) #List’s reversed iterator
>>> for x in list1:
print(x,end=' ')

4 3 2 1
>>> list(reversed({1:2,3:4})) #Dict’s reversed iterator
[3, 1]

round(x,d) It rounds off x (a float number) to the number of digits, d, after the
decimal point. For example, round(2.3123,2) returns 2.31. If the second
argument is negative, the decimal portion is discarded, and the whole
number portion is rounded off up to the given number of digits. For
example, -1 rounds off to the nearest tenth, and -2 rounds off to the
nearest hundredth. Thus, round(377.77,-1) returns 380.0 and
round(377.7717,-2) returns 400.0.
set(obj) It creates a set object from a collection object. Duplicate entries are
removed. For example, set([1,2,3,4,1,2,3]) returns {1, 2, 3, 4}. If no
argument is given, an empty set is created.
setattr() It sets the value of the specified attribute of an object with a given
value. It is similar to obj.attrib=value. See the following example:

>>> class Person: #Create a class


age = 23
name = "John"

>>> person=Person() #Create an object


>>> setattr(person,'age',30) #Set the value of an
attribute
23
>>> person.age #Get the value of an attribute
30
slice([start=0], It returns a slice object. The slice method has three integer parameters:
end, [step=1]) start, end, and step values. The slice object generates indices starting
from start up to end with a step size step. The end value is not included
in the slice object. For example, slice(1,5,2) generate index values 1 and
3. The default value of start is 0, and step is 1. For example, slice(5)
generates index values 0, 1, 2, 3, and 4. The arguments of the slice
163
method can be negative integers, also. A slice object is equivalent to a
slice operator. For example, slice(1,5,2) is equivalent to 1:5:2. The
returned slice object is used to select items of a collection. See the
following example:

>>> list1=[1,2,3,4,5,6,7,8] #A collection object


>>> x=slice(1,5,2) #Create a slice object
>>> list1[x] #Select values at index 1 and 3
[2, 4]
>>> #Create a slice with default values of start and
step
>>> x=slice(5)
>>> list1[x]
[1, 2, 3, 4, 5]
>>> x=slice(-1,-5,-1) #Create a slice with negative
values
>>> list1[x]
[8, 7, 6, 5]
>>> list1[-1:-5:-1] #A slice operator
[8, 7, 6, 5]
sorted(obj) It returns a sorted copy of a collection or an iterable object as a list.
However, the original collection remains the same. For a dict object, it
returns a sorted list of key values of the dict object. See the following
examples:

>>> sorted([1,4,2,3]) #Sorting a list


[1, 2, 3, 4]
>>> sorted((1,5,4,3)) #Sorting a tuple
[1, 3, 4, 5]
>>> sorted({1,5,4,3,2}) #Sorting a set
[1, 2, 3, 4, 5]
>>> sorted({1:10,3:30,2:20}) #Sorting a dictionary
[1, 2, 3]
>>> sorted("Python") #Sorting a string
['P', 'h', 'n', 'o', 't', 'y']
>>> sorted(range(5)) #Sorting a range
[0, 1, 2, 3, 4]
staticmethod() It converts a method into a static method. A static method is bound to
a class rather than its object and can be called from both the class or its
objects.

164
str(obj) It converts the argument to a string object. The argument can be any
Python object. See the following examples:

>>> str(10) #Convert an integer to a string


'10'
>>> str(12.5) #Convert a float to a string
'12.5'
>>> str([1,2,3]) #Convert a list to a string
'[1, 2, 3]'
>>> str((1,2,3)) #Convert a tuple to a string
'(1, 2, 3)'
>>> str({1,2,4,3}) #Convert a set to a string
'{1, 2, 3, 4}'
>>> str(range(10)) #Convert a range to a string
'range(0, 10)'
sum(obj) It returns the sum of the elements of a numeric collection object. See
the following example:

>>> sum([1,2,3,4,5]) #Sum elements of a numeric list


15
>>> sum((1,2,3,4,5)) #Sum elements of a numeric tuple
15
>>> sum({1,2,3,4,5}) #Sum elements of a numeric set
15
>>> sum({1:"One",2:"Two"}) #Sum key values of a dict
3
>>> sum(range(10)) #Sum elements of a range
45
super() It returns the base class of a class. It is discussed in more detail in
chapter 12.
tuple(obj) It creates a tuple from a collection. See the following example:

>>> tuple([1,2,3]) #Create a tuple from a list


(1, 2, 3)
>>> tuple({1,4,2}) #Create a tuple from a set
(1, 2, 4)
>>> tuple({1:10,2:20,3:30}) #Create a tuple from a dict
(1, 2, 3)
>>> tuple("Python") #Create a tuple from a string
('P', 'y', 't', 'h', 'o', 'n')
>>> tuple(range(5)) #Create a tuple from a range
(0, 1, 2, 3, 4)

165
type(obj) It returns the class of an object. The argument can by any Python object.
See the following examples:

>>> type(10) #Return the type of an object


<class 'int'>
>>> type(list)
<class 'type'>
>>> type(10.5)
<class 'float'>
>>> type(10+13j)
<class 'complex'>
>>> type([1,2,3])
<class 'list'>
>>> type(range(5))
<class 'range'>
vars() It returns the variables and its values of an object as a dict object. See
the following example:

>>> class Person: #Create a class


def __init__(self, name, age): #Constructor
self.age = age #Create a variable
self.name=name

>>> p=Person("John",45) #Create an object


>>> vars(p) #Get variables and its values as a dict
object
{'age': 45, 'name': 'John'}
zip() It combines two or more iterators into a single iterator. The new
iterator elements are of tuple type. Each element consists of
corresponding elements from each iterator. The smallest iterator
decides the length of the new iterator. See the following example:

>>> a=zip([1,2,3,4],[5,6,7]) #Create a zipped object


>>> a
<zip object at 0x0000014F6E5EE340>
>>> for x in a: #Iterate over a zipped object
print(x)

(1, 5)
(2, 6)
(3, 7)

166
4.6 Importing Mathematical Functions
Mathematical functions are common and frequently used in scientific and
engineering problems. Python has a built-in module, called math, that defines commonly
used mathematical functions and constants. To use the functions of a module, we have to
import the module into our programs, using the syntax import module_name. For example,
the statement import math will import the math module in the program. Once a module is
imported, its functions can be used using the dot notation. For example, to use the sin
function of the math module, we use the expression math.sin(x).

Alternatively, all the functions of a module can be imported into a program and
used directly without the module name, using the syntax form module_name import *. For
example, the statement from math import * imports all the functions of the math module.
These functions can be directly used without the object name, such as sin(x).

Instead of importing all the functions of a module, we can also import selected
functions from a module, using the syntax form module_name import fun1, …, fun2. For
example, the statement from math import sin, sqrt will import only two functions: sin and
sqrt, from the math module.

The math module consists of commonly used mathematical functions and accepts
only real and integer parameters. However, the equivalent functions that can handle
complex numbers can be imported from the cmath module. The functions of the math
module are listed in table 4.14, with their brief descriptions. Please note that all the
trigonometric functions of the math module accept angles in radians only. Table 4.15 lists
mathematical constants defined in the math module. The command dir(cmath) lists the
cmath module functions as given in example 4.18. Most of these functions are similar to
their corresponding functions in the math module but can process complex numbers and
return complex numbers. Table 4.16 discusses some of these functions, which are specific to
the cmath module.

If we import functions from two modules in a program, and there are functions with
the same name in both the modules, the functions of the last imported module will
overwrite the functions of the earlier imported modules. For example, if we write the
statement from cmath import * after the statement from math import *, the common
functions such as sin, cos, are available from the cmath module only.

167
Table 4.14: Mathematical functions

Function Description
math.ceil(x) It returns the smallest integer greater than or equal to x. For
example, math.ceil(5.3) returns 6.
math.copysign(x, y) It returns x with the sign of y. For example, math.copysign(3,-4)
returns -3.0.
math.fabs(x) It returns the absolute value of x as a float number. For example,
math.fabs(-5) returns 5.0
math.factorial(x) It returns the factorial of x. For example, math.factorial(5) returns
120.
math.floor(x) It returns the largest integer less than or equal to x. math.floor(5.7)
returns 5.
math.fmod(x, y) It returns the remainder when x is divided by y; x and y can be
real or float numbers. For example, math.fmod(7,3) returns 1.0
and math.fmod(5.5,2.5) returns 0.5.
math.frexp(x) It returns mantissa(m) and exponent(e) of a given value x such
that x== m*2**e. The mantissa is a floating point number, and the
exponent is an integer value. If x is zero, the mantissa=0,
otherwise 0.5 <= abs(m) < 1. For example, math.frexp(7.2) returns
(0.9, 3).
math.fsum(iterable) It returns the sum of values in an iterable. For example,
math.fsum([1,2,3,4,5]) returns 15.0.
math.isfinite(x) It returns True if x is neither an infinity nor a NaN (Not a
Number). For example, math.isfinite(10) returns True, whereas
math.isfinite(inf) and math.isfinite(nan) returns False.
math.isinf(x) It returns True if x is infinite. For example, math.isinf(10) returns
False and math.isinf(math.inf) returns True.

168
math.isnan(x) It returns True if x is a NaN. For example, math.isnan(math.nan)
returns True and math.isnan(10) returns False.
math.ldexp(m, e) It returns a number form mantissa (m) and exponent(e) using the
expression m * (2**e). For example, math.ldexp(0.9,3) returns 7.2.
math.modf(x) It returns the fractional and integer parts of x. For example,
math.modf(7.2) returns (0.20000000000000018, 7.0).
math.trunc(x) It returns the truncated integer value of x. For example,
math.trunc(7.8) returns 7.
math.exp(x) It returns the value of 𝒆𝒙 . For example, math.exp(.5) returns
1.6487212707001282.
math.expm1(x) It returns the value of 𝒆𝒙 -1. For example, math.expm1(0.5) returns
0.6487212707001282.
math.log(x, It returns the logarithm of x to the base b (the default base is e).
[b=math.e]) For example, math.log(10) returns 2.302585092994046 and
math.log(10,10) returns 1.0.
math.log1p(x) It returns the natural logarithm (i.e. the base is e) of 1+x. For
example, math.log1p(1) returns 0.6931471805599453.
math.log2(x) It returns the logarithm of x with base 2. For example,
math.log2(10) returns 3.321928094887362.
math.log10(x) It returns the logarithm of x with base 10. For example,
math.log10(10) returns 1.0.
math.pow(x, y) It returns x raised to the power y, i.e., xy. For example,
math.pow(2,3) returns 8.0.
math.sqrt(x) It returns the square root of x. For example, math.sqrt(4) returns
2.0.
math.acos(x) It returns the arc cosine of x in radians. For example,
math.acos(0)*180/math.pi returns 90.0.
math.asin(x) It returns the arc sine of x in radians. For example, math.asin(1)
returns 1.5707963267948966.
math.atan(x) It returns the arc tangent of x in radians. For example,
math.atan(1)*180/ math.pi returns 45.0.

169
math.atan2(y, x) It returns atan(y / x). For example, math.atan2(1,2)*180/ math.pi
returns 26.56505117707799.
math.cos(x) It returns the cosine of x. The x should be in radian. For example,
math.cos(math.pi/4) returns 0.7071067811865476.
math.hypot(x, y) It returns the length of the hypotenuse of a right-angle triangle,
i.e., Euclidean norm, sqrt(x*x + y*y). For example,
math.hypot(3,4) returns 5.0.
math.sin(x) It returns the sine of x. For example, math.sin(math.pi/2) returns
1.0.
math.tan(x) It returns the tangent of x. For example, math.tan(math.pi/4)
returns 0.9999999999999999.
math.degrees(x) It converts an angle x from radians to degrees. For example,
math.degrees(math.pi/2) returns 90.0.
math.radians(x) It converts an angle x from degrees to radians. For example,
math.radians(90) returns 1.5707963267948966.
math.acosh(x) It returns the inverse hyperbolic cosine of x; x must be greater
than or equal to 1. For example, math.acosh(1) returns 0.0.
math.asinh(x) It returns the inverse hyperbolic sine of x. For example,
math.asinh(1) returns 0.8813735870195429.
math.atanh(x) It returns the inverse hyperbolic tangent of x; x must lie between
-0.99 to 0.99. For example, math.atanh(.9) returns
1.4722194895832204.
math.cosh(x) It returns the hyperbolic cosine of x. Mathematically, cosh(𝑥) =
𝑒 𝑥 +𝑒 −𝑥
.
For example, math.cosh(1) returns 1.5430806348152437 ,
2
and (math.exp(1)+ math.exp(-1))/2 returns 1.5430806348152437.
math.sinh(x) It returns the hyperbolic sine of x, which is equivalent to sinh(𝑥) =
𝑒 𝑥 −𝑒 −𝑥
. For example, math.sinh(1) returns 1.1752011936438014.
2

math.tanh(x) It returns the hyperbolic tangent of x, which is equal to


sinh(x)/cosh(x). For example, math.tanh(1) returns
0.7615941559557649.

170
math.erf(x) It returns the value of the Gaussian error function at x.
2 𝑥 2
Mathematically erf(𝑥) = 𝜋 ∫0 𝑒 −𝑡 𝑑𝑡 . For example, math.erf(.5)

returns 0.5204998778130465.
math.erfc(x) It returns the complementary error function at x. Mathematically,
erfc(x) = 1-erf(x). For example, math.erfc(.5) returns
0.4795001221869534, and 1- math.erf(.5) returns
0.4795001221869535.
math.gamma(x) It returns the value of the Gamma function at x. For positive
integers, gamma(x)=factorial(x-1). For example, math.gamma(5)
returns 24.0, and math.factorial(5-1) returns 24.
math.lgamma(x) It returns the natural logarithm of the absolute value of the
Gamma function at x. For example, math.lgamma(5) returns
3.178053830347945, and math.log(24) returns
3.1780538303479458.

Table 4.15: Constants defined in the math module

math.pi Mathematical constant pi is defined as the ratio of the circumference of a


circle to its diameter. For example, math.pi returns 3.141592653589793.

math.e Euler's number e. For example, math.e returns 2.718281828459045.

math.tau Tau is a circle constant and is defined as the ratio of the circumference to
the radius of a circle. It is equal to 2π. For example, math.tau returns
6.283185307179586.

math.inf It is the floating-point positive infinity. The negative infinity is


represented as –math.inf. For example, 1/ math.inf returns 0.0; 1/-
math.inf returns -0.0 and math.inf/ math.inf returns nan.

math.nan It is a floating-point NaN value. NaN stands for not a number. It is used
to represent any value that is undefined or unpresentable as a real
number. For example, 0/0, ∞/∞, square root and log of a negative
number, inverse sine, and cosine of a number greater than 1 or less than
-1 are all undefined as a real number; therefore, they are represented as

171
NaN. All the functions of the math module will raise errors in such
situations. For example, math.inf/ math.inf returns nan; 1/ math.nan
returns nan; 1* math.nan returns nan.

Example 4.18: List of the cmath module functions

>>>dir(cmath)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh',
'asin', 'asinh', 'atan', 'atanh', 'cos', 'cosh', 'e', 'exp', 'inf', 'infj',
'isclose', 'isfinite', 'isinf', 'isnan', 'log', 'log10', 'nan', 'nanj',
'phase', 'pi', 'polar', 'rect', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau']

Table 4.16: Some commonly used functions of the cmath module

cmath.isclose() It checks whether two complex values are close or not, within a
specified tolerance values. This method uses a relative tolerance
(rel_tol) and an absolute tolerance (abs_tol) to determine the closeness
using the following formula: abs(a-b) <= max(rel_tol * max(abs(a),
abs(b)), abs_tol). The default value of rel_tol=1e-09 and abs_tol=0.

The syntax of the function is:


cmath.isclose(a, b, rel_tol = value, abs_tol = value)

Examples:
>>> cmath.isclose (2+3j,2+3.0001j)
False
>>> cmath.isclose (2+3j,2+3.0000000001j)
True
cmath.phase() It returns the phase angle of a complex number. The phase angle of a
complex number is the angle between the vector representing the
complex number and the positive x-axis. The returned value is
between -𝜋 and 𝜋.

Examples:
>>> cmath.phase(2+3j)
0.982793723247329

172
>>> cmath.phase(2-3j)
-0.982793723247329
cmath.polar() It converts a complex number to the polar coordinate form. In the
polar coordinate form, a complex number is defined by modulus and
phase angle. Thus, the function returns modulus and phase angle.

Example:
>>> cmath.polar(2+3j)
(3.605551275463989, 0.982793723247329)
cmath.rect() It converts a complex number given in the polar form into the
rectangular form. The parameters of the function are phase and
modulus. The method is equivalent to modulus * (math.cos(phase) +
math.sin(phase)*1j).
Syntax:
cmath.rect(modulus, phase)

Examples:
>>>cmath.rect(3.605551275463989, 0.982793723247329)
(2+2.9999999999999996j)

4.7 Solved Examples

Program 4.1: Read a float number from the keyboard and print the last two digits of the
integral part of the number.

Solution steps:
1. Read the input number and convert it to a float.
2. Convert the float into an integer.
3. Get the last digit using modulus operator.
4. Remove the last digit by floor division.
5. Get the last digit using the modulus operator.

Program

x=float(input("Enter a float number: "))#Read a float number


y=int(x) #Convert x to an integer

173
d=y%10 #Modulus with 10 returns the last digit of y
print("Original number: ",x)
print("The integral part of the number: ",y)
print("The last digit of the integral part: ",d)
y=y//10 #Floor division with 10 removes the last digit of y
d=y%10 #Get the last digit of y
print("The second last digit of the integral part: ",d)

Output

Enter a float number: 126534.453


Original number: 126534.453
The integral part of the number: 126534
The last digit of the integral part: 4
The second last digit of the integral part: 3

Program 4.2: Write a program to find the volume and surface area of a sphere. Print the
result up to only three decimal digits.

Solution steps:
1. Read the radius of the sphere.
4
2. Calculate the volume using the formula 𝑣 = 𝜋𝑟 3 .
3
3. Calculate the surface area using the formula 𝑠𝑎 = 4𝜋𝑟 2 .

Program

import math
r=float(input("Enter radius of the sphere:"))#Read radius
v=(4/3)*math.pi*r**3 #Calculate volume
sa=4*math.pi*r**2 #Calculate surface area
print("Volume={:8.3f}\nSurface area={:8.3f} ".format(v,sa))

Output

174
Enter radius of the sphere:3
Volume= 113.097
Surface area= 113.097

Program 4.3: Write a program to convert the body temperature given in Fahrenheit to
Celsius.

Solution steps:
1. Read the temperature in Fahrenheit (F).
5
2. Use the formula 𝐶 = 𝑥 (𝐹 − 32) to convert to Celsius.
9

Program

#Read the temperature from the keyboard


f=float(input("Enter temperature in Fahrenheit :"))
c=(f-32)*5/9
#00B0 is the Unicode of the degree symbol
print("{:8.3}\u00B0F = {:8.3f}\u00B0C ".format(f, c))

Output

Enter temperature in Fahrenheit :98.6


98.6°F = 37.000°C

Program 4.4: Write a program to find the roots of a quadratic equation 𝑎𝑥 2 + 𝑏𝑥 + 𝑐 =


0.

Solution Steps:
1. Read the coefficients a, b, and c.
−𝑏+√𝑏2 −4𝑎𝑐 −𝑏−√𝑏2 −4𝑎𝑐
2. Calculate roots using the formula 𝑥1 = and 𝑥2 = .
2𝑎 2𝑎

import cmath #Import complex number math module

175
#Read the coefficients a, b and c
a, b, c=eval(input("Enter the values of coefficients a, b, and c: "))
#The cmath.sqrt() function can process negative numbers
#Hence, the following formulas can find real and complex roots
x1=(-b + cmath.sqrt(b*b - 4*a*c))/(2*a)
x2=(-b - cmath.sqrt(b*b - 4*a*c))/(2*a)
print("x1=", x1)
print("x2=", x2)

Outputs

Enter the values of coefficients a, b, and c: 1,-4,4


x1= (2+0j)
x2= (2+0j)

Enter the values of coefficients a, b, and c: 1,3,6


x1= (-1.5+1.9364916731037085j)
x2= (-1.5-1.9364916731037085j)

Program 4.5: Write a program to calculate economic order quantity (EOQ), when
demand per unit time (D), unit holding cost per unit time (H) and setup cost per order
(S) are given.

Solution Steps:
1. Read D, H and S
2𝐷𝑆
2. Calculate EOQ using the formula 𝐸𝑂𝑄 =√
𝐻

from math import sqrt #Import the sqrt function from the math module
#Read D, H and S
d =float(input("Enter demand rate: "))
h =float(input("Enter unit holding cost per unit time: "))
s =float(input("Enter setup cost: "))

176
#Calculate EOQ
eoq = sqrt(2*d*s/h)
print("EOQ=", round(eoq,0))#Round to the nearest whole number

Outputs

Enter demand rate: 5000


Enter unit holding cost per unit time: 6
Enter setup cost: 30
EOQ= 224.0

Chapter Summary

1. Operators are symbols used to perform operations on variables and values.


Variables and values used in operations are called operands.
2. Python has built-in operators to perform arithmetic, comparison, logical,
bitwise, assignment, membership, and identity operations.
3. Python arithmetic operations can process integers, real and complex
numbers.
4. In a hybrid expression, operands are of different precision, and during
evaluation, the lower precision numeric operand is upgraded to the higher
precision operand, and the result is of the higher precision type. The order
of precision up-gradation in Python is Boolean, integer, float, and complex.
5. In Python, an integer can have any number of digits.
6. Bitwise operators perform various operations, such as AND, OR, and NOT,
at bit level on the integer and Boolean operands
7. Logical operators perform logical AND, OR, and NOT operations and are
primarily used for combining relational expressions.
8. A relational operator compares the left operand with the right operand for
the specified condition and returns either True or False.
9. The simple assignment operator assigns values to variables. It can assign
values to more than one variable.

177
10. A compound assignment operator combines another operation with an
assignment. For example, x+=5 is equivalent to x=x+5.
11. A membership operator checks the presence or absence of data in a
collection.
12. In Python, we can refer to the same data with more than one variable.
13. An expression is a combination of variables, functions, constants, and
operators that evaluates to a value.
14. An arithmetic expression combines numeric and Boolean values and
arithmetic operators and returns a numeric value.
15. A logical expression combines relational expressions and other values with
logical operators (and, or and not) and returns either True or False.
16. In Python, 0, 0.0, 0+0j, an empty string, an empty list, an empty tuple, an
empty set, an empty range, and an empty dict are considered False, and all
other values are considered True in a logical expression.
17. A string expression combines string literals, string variables, and functions
using string operators (concatenation (+) and product (*)) and returns a
string.
18. The precedence rule is similar to the BODMAS rule of evaluating arithmetic
expressions, which guides the order in which operations are processed in
an expression.
19. The direction of the evaluation of operators, called associativity rule, of the
same level of precedence can be either from left-to-right or right-to-left. In
the left-to-right associativity, the operator in the left is evaluated first,
whereas, in the right-to-left, the operator in the right is evaluated first.
20. A statement is a programming construct that does something, for example,
an assignment statement, conditional and branching statement, looping
statements. Whereas, an expression is a combination of values and
operators and always returns a value.

Multiple Choice Questions

1. Which of the following operators is not supported in Python?

178
(a) Relational
(b) Bitwise
(c) Increment
(d)Membership
2. Which of the following operation is not supported in Python?
(a) Addition of two complex numbers
(b) Addition of an integer and a complex number
(c) Addition of Boolean value and complex number
(d) None of the above
3. Which of the following cannot be an operand in an arithmetic expression?
(a) Boolean
(b) Integer
(c) Complex
(d) String
4. Which of the following is the correct order of precision up-gradation in
Python?
(a) Boolean, float, integer, and complex
(b) Boolean, integer, float, and complex
(c) Integer, Boolean, float, and complex
(d) Boolean, integer, complex, float
5. What is the type of the value of the expression True+10*2.5?
(a) bool
(b) int
(c) float
(d) None of the above
6. What is the type of the value of the expression True+10*2.5+ (3+4j) -(5+4j)?
(a) bool
(b) int
(c) complex
(d) float
7. Which of the following is the correct output of the expression -7//3?
(a) -2
(b) -3
(c) -2.33
(d) None of the above

179
8. Which of the following is the correct output of the expression -7%3?
(a) -1
(b) -2
(c) 2
(d) 1
9. Which of the following is the correct output of the expression 5.2%2.5?
(a) 0.0
(b) 0.2
(c) Invalid expression
(d) None of the above
10. Which of the following is the correct output of the expression 5.2//2.2?
(a) 2.0
(b) 2.3636363636363633
(c) Invalid expression
(d) None of the above
11. Which of the following is an invalid arithmetic expression?
(a) 2.3 % 1.3
(b) 2.3 // 1.3
(c) (2+4j) % (1+2j)
(d) All of the above
12. Which of the following is an invalid expression?
(a) 10+'10'
(b) (2+4j) // (1+2j)
(c) (2+4j) % (1+2j)
(d) All of the above
13. Which of the following is an invalid expression?
(a) 10+True
(b) (2+4j) * (1+2j)
(c) (2+4j) / (1+2j)
(d) None of the above
14. How many relational operators are there in Python?
(a) 7
(b) 6
(c) 5
(d) 4

180
15. Which of the following is the correct not equal to operator in Python?
(a) <>
(b) !=
(c) ~=
(d) ><
16. Which of the following is an invalid expression in Python?
(a) 2+3j==2+3j
(b) 2+3j !=2+3j
(c) 2+3j <=2+3j
(d) All of the above
17. Which of the following logical expression returns False?
(a) bool("")
(b) bool(set())
(c) bool(0)
(d) All of the above
18. What is the output of the expression 0 or 3+4 in Python?
(a) 0
(b) 7
(c) True
(d) None of the above
19. Which of the following is not a valid chained logical expression?
(a) x<y<z
(b) x<y>z
(c) x<=y!=z
(d) x<=y=z
20. The maximum number of bits to store an integer in Python?
(a) 16
(b) 64
(c) 128
(d) Not fixed
21. What is the output of the expression 7&11?
(a) 1
(b) 2
(c) 3
(d) 4

181
22. What is the output of the expression 7|11?
(a) 13
(b) 14
(c) 15
(d) 16
23. What is the output of the expression 7<<2?
(a) 14
(b) 28
(c) 1
(d) 15
24. Which of the following is an invalid assignment in Python?
(a) x, y, z=1, 2, 3
(b) x=1, 2, 3
(c) x, y, _=1, 2, 3
(d) x, y = 1, 2, 3
25. Which of the following is a valid expression in Python?
(a) "Python" + "Programming"
(b) "Python" + "Programming"*3
(c) "Python" + "Programming"*len("ABC")
(d) All of the above
26. Which of the following is the correct order of the evaluation of operators in
the expression 3 + 8 / 2 * 4?
(a) / , * ,+
(b) + , / , *
(c) +, *, /
(d) None of the above
27. What is the value of the expression 22 // 3 + 3 / 3?
(a) 8
(b) 8.0
(c) 8.333
(d) None of the above
28. What is the value of the expression 2 + 9 / 3 *3 - 8 / 4 ?
(a) 9.0
(b) 3.0
(c) 8.0

182
(d) None of the above
29. The operators is and is not are _______.
(a) Identity Operators
(b) Comparison Operators
(c) Membership Operators
(d) None of the above
30. What is the output the expression 0xD + 0xE + 0xF?
(a) Error: Invalid expression
(b) 0xDEF
(c) 0X22
(d) 42
31. Which of the following is not a complex number?
(a) 2 + 3j
(b) complex(2,3)
(c) 2 + 3i
(d) None of the above

Review Questions

1. State whether the following statements are true or false:


a) An expression consists of operators and operands.
b) A binary operator has two operands.
c) An expression always evaluates to a value.
d) Python arithmetic operators cannot process complex numbers.
e) X<y<z is a valid expression.
f) There are six relational operators.
g) The expression bool ("") evaluates to False.
h) The expression x+=5 is equivalent to x=x+5.
i) X, Y, Z =10,20,20 is a valid statement in Python.
j) "Python is " + "very "*3 + " good." is a valid expression.
k) In the expression 3 + 8 / 2 * 4, addition is performed first.
l) *, /, //, % operators have left to right associativity.
m) The exponential operator ** has the right to left associativity.
n) A bytearray object is mutable.
o) The expression bool("None") returns True.
p) The eval () method can only evaluate expressions given as a string.

183
q) The frozenset is mutable.
r) The statement from math import * imports all the functions of the math
module.
2. Describe various arithmetic operators.
3. Explain various membership and identity operators.
4. Outline various bitwise operators.
5. Discuss chaining of relational operators.
6. Describe truth tables of various logical operations.
7. Explain precedence and associativity rules of operators evaluation.
8. Describe string operators.
9. List 10 built-in methods and explain them with examples.
10. Write Python expressions for the following:
(a) 𝑥 − 𝑦 + 𝑥𝑦
(b) (𝑥 + 𝑦)(𝑥 − 𝑦)
𝑥𝑦
(c)
𝑥+𝑦
(d) 4𝑦 2 + 2𝑥𝑦 − 5
𝑥 𝑦
(e) 𝑦 + 𝑧
𝑧
(f) 𝑧 𝑥 +
𝑦
11. Write the Python statements for the following equations:
(a) 𝑎 = 𝜋𝑟 2 + 2𝜋𝑟ℎ
2𝑚𝑛
(b) 𝑇 = 𝑚+𝑛 𝑔
(c) 𝑠 = √𝑥 2 + 𝑦 2 + 2𝑥𝑦𝑐𝑜𝑠(𝑎)
𝑣2
(d) 𝐸 = 𝑚 [𝑎ℎ + ]
2
𝑋𝑌 𝑋
(e) 𝐴 = 𝐶+10 − 8(𝑍+𝑌)
12. Remove the unnecessary brackets from the following expressions and give
the values of the expressions:
(a) ((5-(7/5) + 8) %3) +25
(b) ((10-5)*4)+8
(c) (5*6) + (-5/2)
(d) 5/(3*6)

13. Find out the values of the following logical expressions, with x=2, y=3, and
z=-5:
(a) x>y and z<x
(b) x>y or z<x

184
(c) x<y>z
(d) x<y<z
14. Determine the values of the following expressions:
(a) 3 in [1,2,3,4,5]
(b) 3 not in [1,2,3,4,5]
(c) bin(10)
(d) hex(20)
(e) oct(10)
15. Determine the values of the following expressions, with a=65; b=65; c=97:
(a) a is b
(b) a is not c
(c) chr(a)
(d) ascii(a)
16. Determine the output of the following expressions, with a=3+4j and b=3-4j:
(a) a+b
(b) a-b
(c) a*b
(d) abs(a)
17. Determine the output of the following expressions:
(a) bool(None)
(b) bool(False)
(c) bool("ABC")
(d) bool(0x0)
(e) bool(set())
(f) bool([0,0,0])
(g) bool(range(6,3))
18. Determine the output of the following expressions, with a=5 and b=7:
(a) a&b
(b) a|b
(c) a^b
(d) ~a
(e) a<<2
(f) b>>2
19. Determine the value of x after the executing the following, with x=5:
(a) x+=3
(b) x-=3
(c) x%=3
(d) x&=3

185
(e) x>>=1
20. Determine the output of the following:
(a) bin(10)+bin(15)
(b) bool([1,2,3])+bool(-1)
(c) chr(945)
(d) complex(3,5)
(e) hex(255)
(f) len([1,2,3,4])
(g) max("Python")
(h) oct(20)
(i) ord('a')
(j) round(377.77,-1)
(k) sum([1,2,3,4])
21. Determine the output of the following:
(a) math.copysign(3,-4)
(b) math.fabs(-5)
(c) math.fmod(5.5,2.5)
(d) math.trunc(7.8)
(e) cmath.phase(2+3j)
(f) cmath.polar(2+3j)
(g) cmath.rect(3, 1)

Programming Exercises

1. Given two strings s1= “Python” and s2= “Programmers”, Print the length of s1
and s2, and display the output after concatenating the two strings s1 and s2.
2. Read a distance in meter and convert it into inch.
3. Input radius of a circle and compute radius and circumference of the circle.
4. Input an integer number and calculate its factorial using the library function.
5. Reads the sides (a, b and c) of a triangle. Calculate area of the triangle. (Hint:
𝑎+𝑏+𝑐
formula for area calculation is area= √𝑠(𝑠 − 𝑎)(𝑠 − 𝑏)(𝑠 − 𝑐) , and 𝑠 = 2
.

6. Read polar coordinates (r, θ) of a point and convert it to Cartesian coordinates


(x, y) (Use formula x=r cos(θ) and y=r sin(θ))

186
7. Read the initial velocity (u), acceleration (a) and time of travel (t) of a body. Then
calculate the distance (s) traveled by the body (Hint: use the formula s = ut +
at2
2
)

8. Read the principal amount (p), rate of interest (r) and period of investment (n).
𝑟
Calculate the amount (a) received at the maturity.(Hint: 𝑎 = 𝑝(1 + 1000)𝑛 )

9. Write a program to calculate the number of seconds in a leap year. (Hint: A leap
year has 366 days)
10. Read coordinates of two points and calculate the distance between them.
11. Read a complex number and calculate its magnitude and phase. (Hint: use
library functions)
12. Write a program to read a numeric list from the keyboard and find the sum of
its elements. (Hint: Use eval() function).

187
Chapter 5

Decision Making and Branching

Learning Outcomes:

1. Describe various decision-making constructions


2. Explain nesting of various decision-making constructs
3. Select an appropriate decision-making construct
4. Create programs using decision-making constructs

The normal order of execution of the statements of a program is in the order in which
they are written in the program, i.e., statements are executed sequentially from top to
bottom. However, there are many situations in a program where we need to alter this
normal execution sequence, such as choosing a different set of statements based on some
conditions or repeating a set of statements. For example, to find the roots of a quadratic
equation (𝑎𝑥 2 + 𝑏𝑥 + 𝑐 = 0), two situations can occur based on the values of its coefficients:
real roots or complex roots. Hence, after reading the values of the coefficients, a set of
statements are executed for real roots and another set of statements for complex roots.
Figure 5.1 shows a flowchart to find the roots of a quadratic equation. As shown in the
flowchart, two different execution paths are followed: (1) the left path for the real roots and
(2) the right path for the complex roots. In computer programming, choosing a different
execution sequence based on a specified condition is called decision making and
branching. Python has the following decision making and branching statements:

1. if statement
2. if-else statements
3. nested if statements
4. if-elif ladder
5. Conditional expression

5.1 if Statement
An if statement is used to execute a block of code if a specified condition evaluates to
True, otherwise the block is skipped. Figure 5.2 shows this situation with a flowchart. The
syntax of the if statement is given below:

188
if condition:
Statement 1
Statement 2

Statement n

Shorthand if statement: As a special case, if there is only one statement in the True
block, the following syntax may be used, also called a shorthand if statement:

if condition: Statement1

where condition can be a logical expression or a simple expression. A logical


expression always evaluates to either True or False. In the case of a simple expression,
if the expression evaluates to any of these values in Python: 0, 0.0, 0.0+0.0j, False, empty
list, empty tuple, empty set, empty dictionary, empty string, empty range, and None,
it is treated as logically False, for all other values, it is logically True. For example, 3 + 5
is logically True, but 5 - 5 is logically False. Hence the statement if 3+5: print("Hello")
prints Hello in the console, but if 3-3: print("Hello") prints noting in the console.

Also note, expressions 0 == False, 0.0 == False and 0.0+0.0j == False all returns True.
Thus, the statement if 0 == False: print("Hello") prints Hello in the console. However,
if we directly test for the equality of any empty value or None (given above) with False,
the result is False. For example, "" == False evaluates to False. Thus, the statement if
""==False: print("Hello") prints nothing. But if we convert an empty value to a Boolean
value and then equate, it returns True. For example, bool("")==False evaluates to True.
Thus, the statement if bool("")==False: print("Hello") prints Hello in the console.

Further, condition can be a simple relational expression, such as a>b, a==b, a<=b,
or can be a compound expression, such as a>b and a<c, a>b and c. The above points
about the condition expression are valid for all the decision and branching statements
in Python.

Example 5.1(a) uses an if statement and example 5.1(b) uses a shorthand if


statement.

189
Start

Read a, b, c

d = b2-4ac
Real root branch Complex root branch
yes no
d >= 0

r1 = (-b+√d)/2a rp = -b/2a
r2 = (-b-√d)/2a ip = √(-d)/2a

Print r1,r2 Print rp, ip

Stop Stop

Figure 5.1: Decision and branching

False
Condition

True

Body of true block

Figure 5.2: A flowchart of the if statement

190
Example 5.1(a): If statement

#Find the square root of a number. If the number is negative,


#first make it positive then find the square root.
import math
n=float(input("Enter a number: "))
if n<0:
n=-n
r=math.sqrt(n)
print("The square root of ", n , " = ",r)
Output

Enter a number: 12
The square root of 12.0 = 3.4641016151377544
Enter a number: -12
The square root of 12.0 = 3.4641016151377544

Example 5.1(b): Shorthand if statement

#Find the square root of a number. If the number is negative,


#first make it positive then find the square root.
import math
n=float(input("Enter a number: "))
if n<0: n=-n
r=math.sqrt(n)
print("The square root of ", n , " = ",r)
Output

Enter a number: 12
The square root of 12.0 = 3.4641016151377544
Enter a number: -12
The square root of 12.0 = 3.4641016151377544

191
5.2 if-else Statement
There are many situations where we want to execute a block of codes if a certain
condition evaluates to true, otherwise a different block of codes. The if-else statement is
used in such situations. Figure 5.3 shows a flowchart of the if-else statement. From the
flowchart, it is clear that when the specified condition evaluates to true, the true block is
executed; otherwise, the false block is executed. After executing one of the two blocks, the
statement written after the if-else block is executed. The syntax of the if-else block is given
below:

if condition:
Statement 1
Statement 2

Statement n
else:
Statement 1
Statement 2

Statement n

Shorthand if-else statement: As a special case, if the number of statements in the true
block and the false block is one, the following syntax can be used. This special case is called
the shorthand if-else statement.

if condition: Statement 1
else: Statement 1

Example 5.2(a) uses an if-else statement to find real and complex roots of a quadratic
equation, and example 5.2(b) uses a shorthand if-else statement to tell if the given number
is positive or negative.

192
False
Condition

True

The body of false block The body of true block

Next block to be executed

Figure 5.3: A flowchart of the if-else statement

Example 5.2(a): if-else statement

#Find the roots of a quadratic equation ax^2+bx+c=0


import math
#Read coefficients
a=float(input("Enter the value of a: "))
b=float(input("Enter the value of b: "))
c=float(input("Enter the value of c: "))
d=b*b-4*a*c
if d<0: #Complex roots
#True block
rp=-b/(2*a)
ip=math.sqrt(-d)/(2*a)
print("Complex roots")
print("Roots:{0:.3f}+{1:.3f}j and {0:.3f}-{1:.3f}j".format(rp,ip))
else: #Real roots
#False block
r1=(-b+math.sqrt(d))/(2*a)
r2=(-b-math.sqrt(d))/(2*a)
print("Real roots")
print("Roots:{0:.3f} and {1:.3f}".format(r1,r2))

193
Output

Enter the value of a: 1


Enter the value of b: 2
Enter the value of c: 3
Complex roots
Roots:-1.000+1.414j and -1.000-1.414j

Enter the value of a: 1


Enter the value of b: -4
Enter the value of c: 4
Real roots
Roots:2.000 and 2.000

Example 5.2(b): Shorthand if-else statement

#Find out whether the given number is positive or negative


import math
a=float(input("Enter a value: "))
if a<0:print("The given number is negative")
else: print("The given number is positive")
Output

Enter a value: 10
The given number is positive

Enter a value: -10


The given number is negative

5.3 Nested if Statement


If an if statement is written inside the body of another if statement, it is called a nested
if statement. An inner if statement, including its else part, must entirely lie inside either the
true block or the false block of the outer if statement. Any level of nesting of if statements
are possible in Python. Figure 5.4 shows a flowchart of a nested if statement. The syntax of
the nested if statement is as given below, and example 5.3 uses nested if statements to find
roots of a quadratic equation:

194
if condition:
#Level 1
Statement 1

if condition:
#Level 2
Statement 2

if condition:
#Level 3
Statement 1

Statement n
else:
Statement 1

Statement n

Statement n
else:
Statement 1

Statement n

Statement n
else:
#Level 1
Statement 1

if condition:
#Level 2
Statement 1

Statement n
else:
Statement 1

Statement n

Statement n
195
False
Condition

True

Statements Statements
Nested if

True
Condition

False Statements

Statements

Next block to be executed

Figure 5.4: A flowchart of the nested if statement

Example 5.3 Nested if-else statement

#Find the largest of three numbers, a, b, and c


a=float(input("Enter the value of a: "))
b=float(input("Enter the value of b: "))
c=float(input("Enter the value of c: "))
print("The largest of ", a,b,c, " is : ", end=' ')
#Nesting of if
if a>b: #Outer if
if a>c: #Inner if

196
print(a)
else:
print(c)
else:
if b> c: #Inner if
print(b)
else:
print(c)

Output

Enter the value of a: 4


Enter the value of b: 9
Enter the value of c: 2
The largest of 4.0 9.0 2.0 is : 9.0

5.4 Ladder if (if-elif-else) Statement


If multiple conditions are tested sequentially until a true condition is met, the
ladder-if is used. The ladder-if statement is also called a multi-way if statement. The ladder-
if starts by testing its first condition; if it is true, it executes the associated block and then
goes out of the ladder-if; else, it goes to test the second condition of the ladder-if. If the
second condition of the ladder-if is true, it executes the associated block and then goes out
of the ladder-if. This process is repeated until a true condition or the default block is
reached. Once a true condition is reached, the remaining part of the ladder-if is skipped. If
none of the conditions is true, then the else block statements are executed. The else block is
optional. The syntax of the ladder-if is given below, and its flowchart is shown in figure 5.5:

if condition1:
Statements
elif condition2:
Statements

else:
statement

197
Shorthand ladder-if statement: If there is a single statement in a block, the
shorthand form can be used. The shorthand form and standard form can be mixed as given
below:
if condition1: Statement1 #Shorthand form
elif condition2: #Standard form
Statements

else:
statement

As shown in the flowchart (figure 5.4), the conditions are tested sequentially from
the top to the bottom. Once a true condition is found, the remaining part of the ladder-if is
skipped. Hence, the sequence of the conditions in the if-elif-else statement is critical and
should be carefully chosen. Example 5.4(a) uses an if-elif-else ladder construct to predict the
grade of a student.
The ladder-if statement gives cleaner and more efficient code than the equivalent
nested if statement or the simple if statement. Example 5.4(b) and 5.4(c) use simple if and
nested-if statements, respectively, for the above student grading problem.

198
True
Condition Statements

False
True
Condition Statements

False

True
Condition Statements

False
Statements

Next block to be executed

Figure 5.5: A flowchart of the ladder if statement

Example 5.4(a): Student grading using the ladder if-elif-else statement

# Find the grade of a student based on the following conditions:


# Hons, if marks >=75
# First, if marks >=60
# Second, if marks >=45
# Third, if marks >=35
# Else, Fail

marks=float(input("Enter your marks: "))


#Ladder-if:Statements upto the first true condition are executed
if marks>=75:print("Your grade: Hons")
elif marks>=60:print("Your grade: First")

199
elif marks>=45:print("Your grade: Second")
elif marks>=35:print("Your grade: Third")
else:print("Your grade: Fail")
Output
Enter your marks: 65
Your grade: First

Enter your marks: 83


Your grade: Hons

Enter your marks: 49


Your grade: Second
Enter your marks: 42
Your grade: Third

Enter your marks: 30


Your grade: Fail

Example 5.4(b): Student grading using the simple if statement

# Find the grade of a student based on the following:


# Hons if marks >=75
# First if marks >=60
# Second if marks >=45
# Third if marks >=35
# Else Fail

#Simple if statement: All the statements are executed


marks=float(input("Enter the marks: "))
if marks>=75:print("Your grade: Hons")
if marks>=60 and marks<75:print("Your grade: First")
if marks>=45 and marks<60:print("Your grade: Second")
if marks>=35 and marks<45:print("Your grade: Third")
if marks <35 :print("Your grade: Fail")
Output

Enter the marks: 65


Your grade: First

Enter the marks: 81


Your grade: Hons

200
Enter the marks: 49
Your grade: Second

Enter the marks: 41


Your grade: Third

Enter the marks: 30


Your grade: Fail

Example 5.4(c): Student grading using the nested if-else statement

# Find the grade of a student based on the following:


# Hons if marks >=75
# First if marks >=60
# Second if marks >=45
# Third if marks >=35
# Else Fail

#Nested-if statement: Statements executed till the first true


condition
marks=float(input("Enter the marks: "))
if marks>=75:print("Your grade: Hons")
else:
if marks>=60:print("Your grade: First")
else:
if marks>=45:print("Your grade: Second")
else:
if marks>=35:print("Your grade: Third")
else :print("Your grade: Fail")
Output

Enter the marks: 65


Your grade: First

Enter the marks: 81


Your grade: Hons

Enter the marks: 49


Your grade: Second

201
Enter the marks: 41
Your grade: Third

Enter the marks: 30


Your grade: Fail

5.5 Ternary Operator


The ternary operator, also called conditional expression, implements a shorthand
if-else statement, which assigns different values to a variable based on the outcome of a
condition. It simply allows testing a condition and returning a value in a single line,
replacing a multiline if-else construction. This construct makes code more compact. The
ternary operator has three operands: condition, on_true_expression, and
on_false_expression. The syntax of the ternary operator is:
var = [on_true_expression] if [condition_expression] else [on_false_expression]

If condition_expression evaluates to True, var is set to on_true_expression;


otherwise, var is set to on_false_expression. Example 5.5(a) illustrates the ternary
operator. In a ternary operator, condition_expression, on_true_expression, and
on_false_expression can be a function, which returns a value. Example 5.5(b) illustrates
the above concepts.

Example 5.5(a): Ternary operator

# Find the minimum of two numbers using a ternary operator


a, b=eval(input("Enter numbers:"))
min_no=a if a<b else b #Ternary operator
print("The minimum of ", a, "and ", b, "is ", min_no)
Output

Enter numbers:3,4
The minimum of 3 and 4 is 3
Enter numbers:7,3
The minimum of 7 and 3 is 3

202
Example 5.5(b): Ternary operator with functions

# Functions in a ternary operator


# If the entered value is even, find its square else find its
cube
def cal_square(x): #Calculate square
return "Square of {} is {}".format(x,x*x)

def cal_cube(x): #Calculate cube


return "Cube of {} is {}".format(x,x*x*x)

def check_odd_even(x): #Test even and odd


if x%2==0:
return True
else:
return False

a=int(input("Enter an integer number: "))


print( cal_square(a) if check_odd_even(a) else cal_cube(a))
Output

Enter an integer number: 5


Cube of 5 is 125

Enter an integer number: 4


Square of 4 is 16

Nesting of ternary operators: Python allows nesting of ternary operators. We can write
another ternary operator in on_true_expression and/or on_false_expression. Example
5.5(c) illustrates the nesting of ternary operators.

Example 5.5(c): Nesting of ternary operators

# Return value as per the following rules:


# "Negative", if a<0
# "Zero", if a==0
# "Positive", if a>0
a=int(input("Enter an integer:"))
#Nested ternary operators.
#Parenthesis is not required but given for clarity
m= ("Negative" if a<0 else"Zero") if a<=0 else "Positive"

203
print(m)
Output

Enter an integer:20
Positive

Enter an integer:-20
Negative

Enter an integer:0
Zero

Implied ternary operator: The implied ternary operator (also called tuple ternary
operator) selects either the first item or the second item of a two-item collection, such as
a tuple, list, and dict, based on a condition. For example, (x, y)[condition] returns x if
condition is false; else returns y. In Python, True == 1 and False == 0, and Hence, (x,
y)[False] is equivalent to (x,y)[0] and (x, y)[True] is equivalent to (x,y)[1]. This
construction can be used with lists, strings, and dicts also. For example for x=2 and y=3,
[10,20][x<y] returns 20, "AB"[x<y] returns "B" and {0:"First",1:"Second"}[x<y] returns
"Second". For a dictionary, the keys should be 0 and 1.
However, this construction is not encouraged as it is slow and confusing. First, it is
slow as both the collection items are evaluated to create the collection before selecting.
Second, it is confusing as the true condition returns the second item, whereas the false
condition returns the first item. Therefore, we should carefully put the true value and
the false value correctly in the collection. Hence, it is recommended to use the if-else
ternary operator as in this, only one value is evaluated depending on the condition.
Example 5.5(d) illustrates the above concepts.

Example 5.5(d): Tuple ternary operator

# Implied ternary operator to find the max of two numbers


a, b = eval(input("Enter two numbers: "))

#Using tuple
# (if_test_false,if_test_true)[test]
# Note the order of true and false values.

204
print(f"Tuple: The maximum of {a} and {b} is ", (a, b) [a < b] )

#Using list
# [if_test_false,if_test_true][test]
# Note the order of true and false values.
print(f"List: The maximum of {a} and {b} is ", [a, b] [a < b] )

#Using Dictionary.
#Order of elements is not important as indexing is through keys
print(f"Dictionary: The maximum of {a} and {b} is ",{1: a, 0: b}
[a > b])

Output

Enter two numbers: 4,9


Tuple: The maximum of 4 and 9 is 9
List: The maximum of 4 and 9 is 9
Dictionary: The maximum of 4 and 9 is 9

5.6 pass Statement


In Python, an empty code block is not allowed as the body of a loop, function
definition, class definition, or if statement. Therefore, a pass statement is used to avoid
errors in such situations. The pass statement is a placeholder statement and does
nothing. It is commonly used as a placeholder where actual code may be written later.
The Python interpreter executes a pass statement and does nothing, and moves on to
the next statement. Example 5.6 illustrates a pass statement.

Example 5.6: pass statement

# Swap a and b, if a > b


a, b = eval(input("Enter two numbers: "))
print(f"Original order{a},{b}")
if a<b:
pass #Do nothing. Move to the nest statement
else: #Swap the numbers to arrange in ascending order.
t=a
a=b
b=t

205
print(f"Ascending order:{a},{b}")
Output

Enter two numbers: 6,2


Original order6,2
Ascending order:2,6

Enter two numbers: 3,7


Original order3,7
Ascending order:3,7

5.7 Solved Examples

Problem 5.1: Write a program to read three numbers and arrange them in ascending
order.

Solution Steps:
1. Read numbers
2. Swap the first two number if they are not in ascending order. Then, swap the last
two numbers if not in the ascending order
3. Swap the first two numbers if they are not in the ascending order.
x = int(input("Enter the first number: "))
y = int(input("Enter the second number: "))
z = int(input("Enter the third number: "))

if x>y: #Swap x and y


t=x
x=y
y=t
if y>z: #Swap y and z
t=y
y=z
z=t
if x>y: #Again, swap x and y
t=x
x=y
y=t
print("Ascending order:",x, y, z)
Output
Enter the first number: 3

206
Enter the second number: 7
Enter the third number: 1
Ascending order: 1 3 7

Enter the first number: 7


Enter the second number: 4
Enter the third number: 2
Ascending order: 2 4 7

Problem 5.2: Write a program to read X and Y coordinates of a point and determine
in which quadrant the point lies

Solution Steps:
1. Read x and y
2. Use for following decision matrix:
Second quadrant: First quadrant:
x<0 and y>0 x>0 and y>0
Third quadrant: Fourth quadrant:
x>0 and y<0 x>0 and y<0

x = int(input("Enter the x coordinate of the point: "))


y = int(input("Enter the y coordinate of the point: "))

if x>0 and y>0: #Condition for the first quadrant


print(f"The point{(x,y)} is in the first quadrant")
elif x<0 and y>0:#Condition for the second quadrant
print(f"The point{(x,y)} is in the second quadrant")
elif x>0 and y<0:#Condition for the third quadrant
print(f"The point{(x,y)} is in the third quadrant")
elif x>0 and y<0:#Condition for the fourth quadrant
print(f"The point{(x,y)} is in the first quadrant")
elif x==0: #Condition for the y-axis
print(f"The point{(x,y)} is on the y-axis")
elif y==0: #Condition for the x-axis
print(f"The point{(x,y)} is on the y-axis")
else : #Only option left is origin
print(f"The point{(x,y)} is on the origin")
Output
Enter the x coordinate of the point: 1
Enter the y coordinate of the point: 2
207
The point(1, 2) is in the first quadrant

Enter the x coordinate of the point: -3


Enter the y coordinate of the point: 5
The point(-3, 5) is in the second quadrant

Enter the x coordinate of the point: -3


Enter the y coordinate of the point: -6
The point(-3, -6) is on the x-axis

Enter the x coordinate of the point: 4


Enter the y coordinate of the point: -4
The point(4, -4) is in the third quadrant

Enter the x coordinate of the point: 0


Enter the y coordinate of the point: 2
The point(0, 2) is on the y-axis

Problem 5.3: Write a program to determine if the given year is a leap year or not.

Solution Steps:
1. Read the year.
2. If the year is divisible by 4 but not by 100 or is divisible by 400, it is a leap year;
otherwise it is not a leap year.
years= int(input("Enter the year to check: "))#Read year

div_by_4 = years % 4 == 0 #Test divisibility by 4


div_by_100 = years % 100 == 0 #Test divisibility by 100
div_by_400 = years % 400 == 0 #Test divisibility by 400

if (div_by_4 and not div_by_100) or (div_by_400):


print(f"{years} is a leap year")
else:
print(f"{years} is not a leap year")
Output
Enter the year to check: 1900
1900 is not a leap year

Enter the year to check: 2000


2000 is a leap year

208
Problem 5.4: Write a program to read the number of units consumed by a consumer
and calculate the amount to be paid by the consumer as per the following tariff plan:

Units Rate of charge


0-200 Rs. 2.00 per unit
201-400 Rs. 400 + Rs. 1.50 per unit for the units above 200
401-600 Rs. 700 + Rs. 3.00 per unit for the units above 400
601- above Rs. 1300 + Rs. 4.00 per unit for the units above 600

Solution Steps:
1. Read the unit consumed
2. Find out the slab in which the consumed unit fall, using a ladder-if statement
3. Calculate the billing amount
units= int(input("Enter the consumed units: "))

if units < 0: #Invalid data: Consumed units < 0


print("Invalid Entry")
else:
if units <= 200: #Slab-1
bill_amount = units * 2
elif units <= 400: #Slab-2
bill_amount = 400 + (units - 200) * 1.5
elif units <= 600: #Slab-3
bill_amount= 700 + (units - 400) * 3.0
else: #Last slab
bill_amount = 1300 + (units - 600) * 4.00
print("Billing amount: ", bill_amount)

Output
Enter the consumed units: 150
Billing amount: 300

Enter the consumed units: 450


Billing amount: 850.0

Enter the consumed units: 600


Billing amount: 1300.0

209
Enter the consumed units: 854
Billing amount: 2316.0

Enter the consumed units: -100


Invalid Entry

Problem 5.5: Write a program to read an integer number between 0 and 99 and print
the number in word.

Solution steps:
1. Read and validate the number
2. Create the following three dictionaries:
dict_ones={0:"Zero",1:"one",2:"Two",3:"Three",4:"Four",5:"Five",6:"Six",7:"Seve
n",8:"Eight",9:"Nine",10:"Ten"}

dict_tens={20:"Twenty",30:"Thirty",40:"Forty",50:"Fifty",60:"Sixty",70:"Seventy
",80:"Eighty",90:"Ninty"}

dict_special={11:"Eleven",12:"Twelve",13:"Thirteen",14:"Fourteen",15:"Fifteen"
,16:"Sixteen",17:"Seventeen",18:"Eightteen",19:"Ninteen"}
3. if the number is less than 11, use the number as a key to get the corresponding word
from the dictionary dict_ones.
4. if the number is between 11 and 19, use the number to get the corresponding word
from the dictionary dict_special.
5. for the number between 20 and 99, get the digit at the ones position and then floor
the number to the nearest tens. Use the floored number as key to get the
corresponding words from the dictionary dict_tens and then get the corresponding
word for the digit at one’s position.

#Number to word conversion


x = int(input("Enter an integer between (0 and 99): "))

dict_ones={0:"Zero",1:"one",2:"Two",3:"Three",4:"Four",5:"Five",6:"S
ix",7:"Seven",8:"Eight",9:"Nine",10:"Ten"}

dict_tens={20:"Twenty",30:"Thirty",40:"Forty",50:"Fifty",60:"Sixty",
70:"Seventy",80:"Eighty",90:"Ninty"}

210
dict_special={11:"Eleven",12:"Twelve",13:"Thirteen",14:"Fourteen",15
:"Fifteen",16:"Sixteen",17:"Seventeen",18:"Eightteen",19:"Ninteen"}

if x<0 or x>99: #Check validity of the input


print("Invalid number")
elif x <=10: #Processing the number <= 10
print(dict_ones[x])
elif x<20: #Processing numbers between 10 and 19
print(dict_special[x])
else: #Processing numbers above 20
d1=x%10 #Get the last digit
y=x//10*10 #Floor the number to the nearest ten
print(dict_tens[y], end=" ")
if d1>0: print(dict_ones[d1])
Output
Enter an integer between (0 and 99): -10
Invalid number

Enter an integer between (0 and 99): 100


Invalid number

Enter an integer between (0 and 99): 5


Five

Enter an integer between (0 and 99): 13


Thirteen

Enter an integer between (0 and 99): 25


Twenty Five

Enter an integer between (0 and 99): 30


Thirty

Chapter Summary
1. The normal order of execution of the statements of a program is in the order
in which they are written in the program, i.e., statements are executed
sequentially from top to bottom.
2. Choosing a different execution sequence based on a specified condition is
called decision making and branching.
211
3. An if statement is used to execute a block of code if a specified condition
evaluates to True, otherwise the block is skipped
4. Shorthand if statement is a special case of if statement where there is only
one statement in the True block and the complete statement can be written
in one line.
5. The if-else statement is used when we want to execute different blocks of
codes depending on the outcome of a condition.
6. If an if statement is written inside the body of another if statement, it is called
a nested if statement.
7. If multiple conditions are tested sequentially until a true condition is met,
the ladder-if is used.
8. The ternary operator, also called conditional expression, implements a
shorthand if-else statement, which assigns different values to a variable
based on the outcome of a condition.
9. The pass statement is a placeholder statement and does nothing.

Multiple Choice Questions

1. The symbol that is placed at the end of if condition is


a. ;
b. :
c. &
d. ~

2. Which of the following is not a branching statement?


(a) if statement
(b) if-else statement
(c) if-elif-else statement
(d) while statement

3. Which of the following is not equivalent to Boolean False?


(a) 0
(b) []
(c) None
(d) [0]

212
4. Which of the following is equivalent to False?
(a) set()
(b) list()
(c) tuple()
(d) All of the above

5. Which of the following expression evaluates to true?


(a) 0 == False
(b) ""==False
(c) []==False
(d) All of the above

6. Which of the following statement will print Hello in the console?


(a) if 0.0+0.0j == False: print("Hello")
(b) if bool("") == False: print("Hello")
(c) if bool(range(5,2)) == False: print("Hello")
(d) All of the above

7. For a=3, b=4, and c=5, which of the following statement will print Hello
in the console?
(a) if a<b<c: print("Hello")
(b) if b<c>a: print("Hello")
(c) if a<b and b<c: print("Hello")
(d) All of the above

8. Which of the following statement is true?


(a) if statements can be nested
(b) if-else statements can be nested
(c) if-elif-else statements can be nested.
(d) All of the above

9. The maximum number of nesting levels permitted in if-else statements


is
(a) 1
(b) 2
(c) 3
(d) None of the above

213
10. Which of the following statement is not true about an if-elif-else
statement?
(a) conditions are evaluated sequentially from the top
(b) else block is essential
(c) all the conditions may not be evaluated
(d) if-elif-else statements cannot be nested.

11. For a=2, what is the value of x after executing the statement x= 1 if a>2
else 2 if a<3 else 3
(a) 1
(b) 2
(c) 3
(d) None of the above

12. With a =2 and x = (1,2), What is the output the expression x[a<2]?
(a) 1
(b) 2
(c) It is an error
(d) None of the above

13. What is the output of the following program?


a=0
b=0
if a>b:
b=b+5
else:
if a<b:
b=b+10
else:
b=b+20
print(b)

(a) 0
(b) 5
(c) 10
(d) 20

14. What is the output of the following program?

214
a=int(True)
b=int(False)

if a+b==0:
n=1
elif a+b==1:
n=2
else:
n=3
print(n)

(a) 1
(b) 2
(c) 3
(d) None of the above

15. With a =2 and x = {1: "One", 0: "Zero"}, What is the output the
expression x[a<=2]?
(a) One
(b) Zero
(c) It is an error
(d) None of the above

16. What is the value of the expression bool ("1") + bool ("2") + bool ([1]) +
bool (None)?
(a) 3
(b) 4
(c) It is an error
(d) None of the above
Review Questions

1. State whether the following statements are true or false

a. By default, statements are executed sequentially from top to bottom


in a program.
b. Nesting is not allowed in fi-statements.
c. Shorthand if statement can have only one statement in a true block.
d. The expression 0.0+0.0j == False evaluates to false.
215
e. The expression bool(range(1,4))==False evaluates to false.
f. The expression a<b and b > c can also be written as a<b>c.
g. Any number of nesting of if-else statements is permitted.
h. In a ladder-if, sometimes all the conditions are evaluated.
i. In a ladder-if, conditions are randomly evaluated.
j. We cannot nest ladder-if statements.
k. The statement print( 3 if 3<2 else 2) prints 2 in the console.
l. We can nest ternary operators.

2. Briefly explain the conditional statements available in Python.


3. Describe and compare the if-else and if-elif-else statements with
examples.
4. Describe Boolean equivalent of different types of Python data.
5. Describe nesting of conditional statements.
6. Describe the conditional expression.
7. Describe the pass statement
8. Find the syntax errors in the following program

year == int.input("Greetings! Enter a year of your choice: '))

if year <= 1950


print ('That's great. It is quite past!')
elif year > 1950 && year < 2020:
print ("It's the present era!")
elif:
print ("Far out, that's the future!!")

Programming Exercises

1. Write a program to read three numbers and their minimum.


2. Write a program to read two number. If the first number is larger than the second,
swap them.
3. Write a program to read three numbers and print them in ascending order. Do not
use loops and library functions.
4. Write a program to read two numbers, if both numbers are positive, print Positive,
else if both are negative, print Negative, otherwise print Positive-Negative. Also
write this program using ternary operators.
216
5. Write a program to read a number. If the number is negative, calculate its cube
otherwise calculate its square, using Ternary operator.
6. Write a program to read a month number between 1 and 12 and print the
corresponding month name, using a ladder if statement.
7. Write a program to read three positive numbers from the keyboard. Find out
whether they form a right angle tringle or not. (Hint: Use Pythagoras theorem)
8. A college gives scholarship to students who have secured marks in 12th class
according to the following table:

Marks Scholarship(in
obtained (in % of tuition fee)
percentage)
95% and 100%
above
85% to 95% 90%
75% to 85% 75%
70% to 75% 25%
Below 70% 0

If the tuition fee is Rs 50000, write a program to read the marks obtained out of 500
and compute the net fee to be paid by a student.
9. Read the net taxable salary of an employee and compute his income tax according
to the following table:
Annual Salary Income tax percentage
Below 2.5 lakh 0
Between 2.5 to 5 10
Between 5 to 8 15
Above 8 20%

217
218
Chapter 6

Loop Control Statements


Learning Outcomes:

1. Describe various looping constructs


2. Explain nesting of looping constructs
3. Select an appropriate looping construct
4. Control premature exit in looping constructs
5. Create programs using various looping constructs

As discussed in the previous chapter, in general, statements are executed


sequentially from top to bottom, i.e., the first statement in a program is executed first,
followed by the second, and so on. However, there may be a situation where we need to
execute a statement or a block of statements several times. This repetitive execution of a
code block is called looping. In other words, a loop control statement allows us to execute
a block of statements multiple times or until a specified condition is met. The looping is also
called iterative flow control statement. Figure 6.1 shows flowcharts of looping processes.
Figure 6.1(a) shows a bottom-controlled looping process, and figure 6.1(b) shows a top-
controlled looping process. In a bottom-controlled looping, the loop control condition is
the last statement in the block. Whereas in the top-controlled looping, the looping control
statement is written at the top. Further, in the bottom-controlled loop, the loop's body
executes at least once, but the body may never execute in the top-controlled looping.

A loop has two parts: header and body. The header of a loop consists of a looping
construct and the loop control condition. It controls the number of iterations a loop
performs. The body of a loop is a block of code that is repeated during the looping.

Python has the following two looping constructs: while loop and for loop. The
while loop executes the loop's body till the specified looping condition is true. In contrast,
the for loop iterates over each collection item. Both the while loop and the for loop are the
top-controlled looping. There is no built-in statement for the bottom controlled looping in
Python.

219
Condition
Body of the loop
False
True

Body of the loop


Condition
True
False

(a) Bottom controlled loop (b) Top controlled loop

Figure 6.1: Loops

6.1 while Loop


The while loop repeatedly executes a block of codes till the given looping condition is true.
The syntax of the while loop is as given below:

while condition: #Header of the loop


statement1 #Body of the loop begins from here
statement2

Statementn #Body of the loop ends from here

Here, condition may be any expression that evaluates to True or False. In Python, any non-
zero value and any non-empty collection are considered True. The body of a loop may
consist of a single statement or a block of statements. When the looping condition evaluates
to False, the looping process ends, and the statement written below to the loop's body is
executed. Figure 6.2 shows a flowchart of a while loop. Here, it is important to note that the
body of a while loop may never execute if the condition evaluates to False on the very first
time. Example 6.1(a) finds the sum of digits of an integer number using a while loop.

220
Shorthand while loop: As a special case, when there is only one statement in the body of a
while loop, the statement can be written in the same line after the colon of the loop. This
special case of a while loop is called a shorthand while loop and has the following syntax:

while condition: statement

We can combine many statements with a semi-colon (;) to make a single compound
statement. The Python interpreter treats a compound statement as a single statement.
Example 6.1(b) illustrates a shorthand while loop.

False
Condition

True

Body of the loop

Statements

Figure 6.2: Flowchart of a while loop

Example 6.1(a): The sum of the digits of a number using a while loop

#Print the digits of an integer number and their sum


n=int(input("Enter an integer number:"))
if n<0: n=-n #convert a negative number into the positive number
s=0
#while loop

221
while n>0:
#Start of the body of the loop
d=n%10
print(d)
s=s+d
n=n//10
#End of the while loop
#The statement to be executed at the end of the loop
print("The sum of digits is",s)
Output

Enter an integer number:16501


1
0
5
6
1
The sum of digits is 13

Example 6.1(b): Shorthand while loop

#Print 1,2,3, ...,n


n=int(input("Enter a positive integer number:"))
count=0
#while loop
while count<n: count+=1; print(count)
Output

Enter a positive integer number:3


1
2
3

Infinite while loop: An infinite loop is a loop that never terminates. A while loop can be
made to loop infinitely by using a conditional expression that always evaluates to true, such
as any non-zero constant, non-empty collection, or True. However, there should be some
mechanism to break such loops to make them useful in practice. Example 6.1(c) uses an
222
infinite loop to read numbers from the console, print their squares and terminate the
program when a negative number is given (the break statement is discussed later in the
chapter).

The infinite while loop with a termination condition at the bottom of the loop body
can be effectively used to substitute the do-while loop of many programming languages.
Python does not have the do-while type construct. Example 6.1(d) illustrates the above.

Example 6.1(c): infinite while loop

#Print squares of numbers till a negative number is entered


#Infinite while loop
while(True):
n=float(input("Enter a number:"))
if n<0:
print("Aborting the loop: a negative number entered")
break
print(n, n*n)
Output

Enter a number:2
2.0 4.0
Enter a number:3
3.0 9.0
Enter a number:5
5.0 25.0
Enter a number:-1
Aborting the loop: a negative number entered

Example 6.1(d): Simulating do-while loop

#Simulate do-while in Python


i = 1
while True: #equivalent to do
print(i, sep=",", end=",")
i = i + 1
if(i > 3): #equivalent to while
break
Output

223
1,2,3,

6.2 for Loop


A for loop iterates over each item of a collection or a sequence. It takes one item of the
collection, processes it, takes the next item, and processes it. The loop repeats this process
for all the items one by one. The syntax of the for loop is:

for item in items: #Loop header


statements(s) #Loop body

Where items is a collection, such as a list, tuple, string, set, dictionary, or range, and item is
a variable that holds the current item of the sequence. By default, the for loop starts with
the first item in the collection and terminates after processing the last item.

Figure 6.3 shows a flowchart of the for loop. Example 6.2 for loops to traverse
various collection objects of Python.. It is important to note that the set object may return
items in a different order than the order in which they are created.

Is any item left in


the sequence ?
False
True

Process the body of the loop with the


current item

Statements

Figure 6.3: Flowchart of a for loop

224
Blank loop: It is syntactically valid to have only the pass statement in the body of a loop,
called a blank loop. For example, the following for loop is valid:
for items in [1,2,3,4,5]:
pass #Doing nothing

Example 6.2: for loop

#Iterating items in various types of collection objects using the


for loop
print("Iterating a string")
string = "Python"
for ch in string:
print(ch, end=", ")

print("\nIterating a list")
mylist = [1,2,3,4,5]
for item in mylist:
print(item*item,end=", ")

print("\nIterating a tuple")
mytuple = (1,2,3,4)
for x in mytuple:
print(1/x, end=", ")

print("\nIterating a set")
myset = {1,3,2,5,4}
for x in myset:
print(x, end=", ")

print("\nIterating a dictionary")
mydict = {1:"One",2:"Two",3:"Three"}
for key in mydict:
print(key,":",mydict[key], end=", ")
Output

Iterating a string
P, y, t, h, o, n,
Iterating a list
1, 4, 9, 16, 25,

225
Iterating a tuple
1.0, 0.5, 0.3333333333333333, 0.25,
Iterating a set
1, 2, 3, 4, 5,
Iterating a dictionary
1 : One, 2 : Two, 3 : Three,

6.3 break Statement


By default, a while loop ends when the looping condition evaluates to false, and a for loop
ends when it reaches the last item in the collection. These are called normal termination of
loops. However, in some situations, we want to end the execution of a loop before it reaches
the normal termination. It is called premature exit from a loop. For example, we are
processing a list, and we found an invalid entry in the list, which makes further processing
of list elements irrelevant. The break statement is used for premature exit from a loop. The
break statement is used to prematurely exit from a while loop and a for loop. We can use
more than one break statement in a loop. Figure 6.4 shows a while loop with a premature
exit. The following is the syntax of a while loop with a break statement.

while condition1:
statement1

if condition2:
statements
break #Premature exit from the loop

Statementn

When condition1 evaluates to False, the loop terminates normally, but when condtion2
evaluates to True, the loop terminates prematurely. The statements written after the break
statement will not be executed. Writing a break statement without a condition is possible,
but that is meaningless as the loop breaks in the first iteration. Example 6.3(a) uses a break
statement to find the sum and average of positive numbers entered by the user until he
enters a negative number.

226
Normal exit Condition

False True

Statements

True
Premature exit Condition

False

Statements

Statements

Figure 6.4: Premature exit of a loop

Example 6.3(a): A while loop with a break statement

#Find the sum and average of numbers entered by the user.


#Terminate the loop when the user enters a negative number.
count=0
total=0
while(True):
n=float(input("Enter a number. To terminate, enter a -ve number: "))
if n <0: break # The loop will terminate if the condition is true
total+=n
count+=1

if count==0:

227
print("You have not entered any positive number")
else:
print("Sum=", total , " and average=", total/count)
Output

Enter a number. To terminate, enter a -ve number: 2


Enter a number. To terminate, enter a -ve number: 5
Enter a number. To terminate, enter a -ve number: 2
Enter a number. To terminate, enter a -ve number: -3
Sum= 9.0 and average= 3.0

We can also prematurely exit from a for loop using a break statement (see figure
6.5). Following is the syntax of a for loop with a break statement.

for item in items:


statements
if condition:
statements
break
statements

Example 6.3(b) uses a for loop with a break statement to iterate characters of a string till it
finds a digit in it. The program uses the isdigit() method of the string object to test the
presence of a digit.

Example 6.3(b): Loop with a break statement

#Iterating a string till a digit is found in it


string=input("Input a string containing digits: ")
for ch in string:
if ch.isdigit(): # Checking the presence of a digit
print("\nA digit found")
break #Premature exit from the loop
print(ch, end="")
Output

Input a string containing digits: Python 3 Programming


Python
A digit found
228
Normal exit Is any item left in
the sequence ?
False
True

Statement2

True
False
Premature exit Condition

Statements

Figure 6.5: Flowchart of a for loop with a break statement

6.4 continue Statement


Normally, in each iteration of a loop, all the statements in the loop's body are executed from
top to bottom, and then the next iteration starts called the normal next iteration. However,
due to a certain condition, we need to skip the execution of the remaining part of the body
of a loop and start the next iteration of the loop, called the early next iteration. For example,
we are processing a list, and we found an invalid entry, such as 0, and we want to skip
further processing with this entry and start the next iteration of the loop with the next entry
in the list. In such a situation, a continue statement is used to skip the remaining part of
the loop's body for both a while loop and a for loop. There may be more than one continue
statement in a loop. A flowchart of a while loop with a continue statement is shown in
figure 6.6. The following is the syntax of a while loop with a continue statement.
229
while condition1:
statement1

if condition2:
statements
continue

Statementn

When condtion2 evaluates to True, the loop starts the next iteration without executing the
remaining statements of the loop, i.e., the statements written after the continue statement
are skipped. Writing a continue statement without a condition is valid, but this will make
the statements written after it irrelevant and never get executed. Example 6.4 (a) uses a
continue statement to find the sum and average of only positive numbers entered by the
user. The negative numbers are ignored. Example 6.4 (b) prints a pattern shown in figure
6.7, using a single loop.

Condition

False True
Statements Early next
iteration

True
Condition

False
Statements Normal next
iteration

Statements

Figure 6.6: Skipping the remaining part of a loop

230
Example 6.4(a): continue statement

#Find the sum and average of the first three positive numbers
#entered by the user, in a list of positive and negative numbers
count=0
total=0
while(count<3):
n=float(input("Enter a number: "))
if n <0: continue #Skip the statements below, if the condition is true

total+=n
count+=1

if count==0:
print("You have not entered any positive number")
else:
print("Sum=", total , " and average=", total/count)
Output

Enter a number: 2
Enter a number: -1
Enter a number: 5
Enter a number: -2
Enter a number: 2
Sum= 9.0 and average= 3.0

*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
Figure 6.7: A triangular pattern

231
Example 6.4(b): Printing a patter using continue statement

#Generate the pattern shown in figure 6.7, using a single while loop
n=int(input("Enter the number of lines in the pattern:"))
col_no = 0
row_no = 1
while(row_no <= n ):
if col_no < row_no: #Print stars in the same line
print("* ", end = "")
col_no += 1
continue
if (col_no == row_no): #Start a new line
print("")
row_no += 1
col_no = 0

Output

Enter the number of lines in the pattern:5


*
**
***
****
*****

By default, a for loop executes the complete body of the loop, starting with the first
statement to the last statement. However, there may be a situation when we need to skip
the remaining statements of the loop's body and begin executing the next iteration of the
loop. The continue statement is used for such a situation in a for loop. There can be more
than one continue statement in a for loop. Following is the syntax of a for loop with a
continue statement.

for item in sequence:


statements
if condition:
statements
continue
statements
232
6.5 else Statement
As discussed earlier, a loop may terminate normally or prematurely. Therefore, there are
some situations where we want to execute some additional statements at the normal
termination of a loop and want to do nothing at the premature exit from the loop. An else
statement is used in both a while loop and for loop to execute additional statements on the
normal termination of the loop. Figure 6.8 shows a flowchart of a while-else loop. Following
is the syntax of the while-else statement:

while condition1:
statement1

if condition2:
statements
break

Statementn
else:
Statements

The else part of the loop is only executed on the normal termination of the loop; otherwise,
this part is skipped. Example 6.5(a) uses a while-else loop to print all the prime numbers
between a given range of positive integers.

Example 6.5 (a): while-else loop

#Print all the prime numbers between n1 and n2. n1<n2, n1>0
n1=int(input("Enter the value of n1:"))
n2=int(input("Enter the value of n2:"))
print("Prime numbers between", n1, " and ", n2, ":")
while n1 <= n2:
c=2
m=n1//2

while c <= m:
if n1%c==0: #Check divisibility
break

233
c+=1
else:
print(n1, sep=" ", end=" ") #Print in case no divisor found
n1=n1+1
Output

Enter the value of n1:10


Enter the value of n2:50
Prime numbers between 10 and 50 :
11 13 17 19 23 29 31 37 41 43 47

Condition1?

False
True

Statement2

False
Condition2

True Premature
termination
else block: Statements
Normal
termination

Statements

Figure 6.8: Flowchart of a while-else statement

234
for-else loop: Similar to the while loop, a for loop can also have an else statement, which
will be executed only when the loop terminates normally. The else block is not executed if
the loop terminates prematurely. Figure 6.9 shows a flowchart of the for-else loop statement.
The syntax of the for loop with an else statement is as follows:

for item in sequence:


statements
if condition:
statements
break
statements
else:
Statements

Is any item left in


the sequence?
False
True

Statement2

False

Condition

True

Premature
Normal else block: Statements termination
termination

Statements

Figure 6.9: Flowchart of a for loop with an else statement

235
Example 6.5(b) uses a for loop with an else block to test whether a string contains a digit or
not.

Example 6.5(b): for loop with else

#Check the presence of a digit in a string


string=input("Input a string: ")
for ch in string:
if ch.isdigit(): # Checking the presence of a digit
print("There is a digit in the string:",string)
break
else:print("There is no digit in the string:",string)
Output

Input a string: Python3


There is a digit in the string: Python3

Input a string: Python


There is no digit in the string: Python

6.6 Nested Loops


Python allows using a loop inside another loop, called the nesting of loops. Both for
loops and while loops can be mixed and nested. We can write a for loop inside another for
loop, a while loop inside another while loop, or a while loop inside a for loop, or vice versa.

(a) Nested for loops (b) Nested while loops


for item in items: while condition:
statements statements
for item in items: while condition:
statements
statements
Statements
Statements
(c) Nesting of a while loop inside a for loop (d) Nesting of a for loop inside a while loop
for item in items: while condition:
statements statements
while condition: for item in items:
statements statements
Statements Statements
236
Loops can be nested to any level; however, any inner loop must entirely lie inside
the immediate outer loop. For every iteration of the outer loop, each inner loop completes
all its iterations. The statement written just after the inner loop is executed at the end of the
inner loop or the premature exit from the inner loop. After this, the next iteration of the
outer loop begins. Figure 6.10 shows a flow chart of nested loops. Example 6.6 uses nested
loops to print a multiplication table of numbers between n1 and n2.

6.7 quit () and exit () Functions


When we execute a program in Python, the Python interpreter starts executing the
program from top to bottom. The program execution typically ends when the interpreter
reaches the end of the program. However, we can terminate the execution of a program
after any statement by using the quit () or exit () methods. The exit () or quit () functions
immediately terminate the execution, ignoring the remaining part of the program. Example
6.7 illustrates the exit () function. We can use the quit () function in place of the exit ()
function.

237
Outer loop

Is any item left in


the sequence?
False
True
Statements

Inner loop False

Condition

True
Body of the inner loop

Statements

Statements

Figure 6.10: Flowchart of for nested loops

Example 6.6: nested loops

#Print the multiplication table of numbers between n1 and n2


n1,n2=eval(input("Enter multiplication table range (n1 and n2):"))
#Outer loop starts
while n1 <= n2:
i=1

#inner loop starts

238
while i<=10: #Generate a multiplication table row
print("{0:5d}".format(n1*i), end=" ") #Print a table element
i=i+1
#inner loop ends
n1=n1+1
print() #Go to a new line
#Outer loop ends

Output

Enter multiplication table range (n1 and n2):2,6


2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60

Example 6.7: The exit () function

for i in range(5):
for j in range(5):
print(i*j, end=" ")
if i*j == 8:
print("\nProgram terminated by the exit() method.")
exit() #Terminate the program execution
print("")
Output

00000
01234
02468
Program terminated by the exit() method.
6.8 Solved Examples

Program 6.1: Write a program to read an integer number from the keyboard and reverse
its digits.

Solution Steps:
1. Read the number and initialize the reversed new number with 0

239
2. Get the last digit of using modulus with 10
3. Remove the last digit using floor division by 10
4. Multiply the new number by 10 and add the last digit
5. Repeat the above process till the original number is greater than 0.

n=int(input("Enter an integer number: "))


m=0 #Initialise the new reversed number
n1=n #Create a copy of the original number
while n>0:
d=n%10 #Extract the last digit
m=m*10+d #Move the digits to left and add the extracted digit
n=n//10 #Remove the last digit
print(f"The original number: {n1} , and the reversed number: {m}")

Output

Enter an integer number: 365479


The original number: 365479, and the reversed number: 974563

Program 6.2: Write a program to generate the following Fibonacci series up to the nth
term and also find the sum of the series:
1, 1, 2, 3, 5, 8, 13, 21, …

Solution Steps:
1. Read the number of terms
2. Initialize the first two terms, say t1=1 and t2=1 and s=2 (sum of the first two terms)
3. Calculate the next term using t3=t1+t2
4. Update the last two terms using t1=t2 and t2=t3
5. Add the new term to the previous sum
6. Repeat the steps from step 3 and stop if the desired number of terms is generated.

n=int(input("Enter an integer number: "))


t1=t2=1 #Initialise the first two terms of the series
s=2 #Initialise sum
print("Series:",t1, t2, end=' ') #Print the first two terms
i=2
while i< n:
t3=t1+t2 #Calculate the next term
s=s+t3 #Update the sum
print(t3, end=' ') #Print the new term

240
t1=t2 #Update the second last terms
t2=t3 #Update the last term
i=i+1 #Increment the loop control variable
print("\nSum of the series: ",s) #Print the final sum

Output

Enter an integer number: 10


Series: 1 1 2 3 5 8 13 21 34 55
Sum of the series: 143

Program 6.3: Write a program to generate the following pattern, up to the specified
number of rows (The column width for both the columns is 10. The first colum left
justified and the second column right justified).
1 1
22 21
333 321
4444 4321
55555 54321

Solution Steps:
1. Read the number of rows
2. For each row, initialize the left and right numbers with the current row number.
3. Start a decreasing counter from the current row number till 1, and for reach counter,
perform the following:
Left_number=Left_number*10+Row_number
Right_number=Right_number*10+counter
4. Print the left and right numbers. Use the left alignment for the left number and the
right alignment for the right number.

n=int(input("Enter a digit(1-9): "))


if 1<=n<=9: #Invalidate input
for x in range(1,n+1): #Outer loop, repeat for each row
s1=x #Initialise the left number for the current row
s2=x #Initialize the right number for the current row
for y in range(x-1,0,-1):
s1=s1*10+x #Add the new digit at the end
s2=s2*10+y #Add the new digit at the end

241
print(f"{s1:<10d}{s2:10d}")#Left-align s1 and right-align s2
else:
print("Invalid entry")

Output

Enter a digit(1-9): 9
1 1
22 21
333 321
4444 4321
55555 54321
666666 654321
7777777 7654321
88888888 87654321
999999999 987654321

Program 6.4: Write a program to calculate the value of sin(x), accurate up to three
decimal places, using the following sine series:
sin(x) = x – x3/3! + x5/5! – x7/7! …

Solution Steps:
1. Read the value of the angle, x, and convert it to radian
2. Initialise the sum, s=x, and the first term Tn=x
3. Calculate the next term using the following formulae
Tn+1 = - Tn * x * x / ((2n+1) * 2n)
4. Add the new term to the s
5. Repeat steps 3 and 4 till the desired accuracy is attained.

import math
x=float(input("Enter angle, in degree:"))
xd=x
x=x*math.pi/180 #Convert into radian
i=1
tn=x #Initialise the first term of the series
s=x
if x !=0:

while True: #Infinite while loop

242
tnp=-tn*x*x/((2*i+1)*(2*i)) #Calculate the next term of the
series
if abs(tnp/s) < 0.000005: break #Check accuracy
s=s+tnp #Add the new calculated term to the previous sum
tn=tnp #Update the current term for the next iteration
i=i+1 #Increment the loop counter
print(f"Calculated using the series: sin({xd})={s}")
print(f"Calculated using math.sin(): sin({xd})={math.sin(x)}")
else:
print(x)

Output

Enter angle, in degree:30


Calculated using the series: sin(30.0)=0.5000021325887924
Calculated using math.sin(): sin(30.0)=0.49999999999999994

Program 6.5: Write a program to print the binomial coefficients table. The formula for
the binomial coefficients is
𝑛!
𝐵(𝑛, 𝑚) =
(𝑛 − 𝑚)! 𝑚!

Solution Steps:
1. Read the number of rows, r.
2. Print the heading
3. For each n in the range 0 to r, repeat the following:
3.1 Initialise the binomial coefficient, b=1, and print it.
3.2 For each m in the range 1 to n, repeat the following:
3.2.1 Calculate the next coefficient using the formula b = b(n-m+1)/m
3.2.2 print the next coefficient
3.3 Print a line break

import math
r=int(input("Enter the value of rows(<=10):"))
print(" n\m", end='')
for n in range(r+1): #Print heading
print(f"{n:4d}",end='')
print("")
for n in range(r+1): #Iterate over each row

243
b=1 #Initialize the binomial coefficient for the row
print(f"{n:4d}{b:4d}",end='')
for m in range(1,n+1): #Iterate over each coefficient in the row
b=int(b*(n-m+1)/m) #Calculate the next coefficient
print(f"{b:4d}", end='') #Print
print("")

Output

Enter the value of rows(<=10):10


n\m 0 1 2 3 4 5 6 7 8 9 10
0 1
1 1 1
2 1 2 1
3 1 3 3 1
4 1 4 6 4 1
5 1 5 10 10 5 1
6 1 6 15 20 15 6 1
7 1 7 21 35 35 21 7 1
8 1 8 28 56 70 56 28 8 1
9 1 9 36 84 126 126 84 36 9 1
10 1 10 45 120 210 252 210 120 45 10 1

Program 6.6: Write a program to print a histogram using asterisks to visualize the
following employee's data.
Group No. of employees
Group-1 10
Group-2 15
Group-3 25
Group-4 20
Group-5 12

Solution Steps:
1. Read the histogram data
2. Normalise the histogram data on a scale of 50. For this, divide the histogram data by
the maximum value into the data and then multiply by 50.
2. Generate a string containing asterisks in proportion to the value of the group.
3. Print the histogram strings

244
#Read the number of groups
g=int(input("Enter the number of groups:"))
list1=[]
m=-1
#Read the histogram data
for n in range(g):
x=int(input(f"Enter the number of employees in Group-{n}: "))
list1.append(x)
if m<x: m=x
list2=[]
#Normalise the histogram data
for n in range(g):
list2.append(int(list1[n]*50/m))

print("\nHistogram of the employee strength:")


for n in range(g):
print(f"Group-{n}: ",end='')
#Generate and print histogram string
print(f"{'*'*(list2[n]+1)}", list1[n])

Output

Enter the number of groups:5


Enter the number of employees in Group-0: 10
Enter the number of employees in Group-1: 20
Enter the number of employees in Group-2: 30
Enter the number of employees in Group-3: 25
Enter the number of employees in Group-4: 15

Histogram of the employee strength:


Group-0: ***************** 10
Group-1: ********************************** 20
Group-2: *************************************************** 30
Group-3: ****************************************** 25
Group-4: ************************** 15

Program 6.7: Write a program to graphically print the shape of a sine wave, a sin(t), for
0<=t<=2p in a step 0.25, in the console.

Solution Steps:
1. Read the sine wave amplitude, a, and initialise time, t=0

245
2. Repeat till t <= 2p
2.1 Calculate the value of wave, y, at time t
2.2 If y > 0
2.2.1 Add spaces up to the center line
2.2.2 Add a center mark, #
2.2.3 Add a hyphon up to the wave value
2.2.4 Add an asterisk at the value of the wave
2.3 Else
2.3.1 Add spaces up to the wave value
2.2.2 Add an asterisk at the wave value
2.2.3 Add a hyphon up to the center line
2.2.4 Add a center line mark, #
2.4 Increment t

#Sine wave y = a * sin(t)


import math
a=int(input("Enter amplitude: "))
t=0 #Initialize time, t
while t <= math.pi*2:
y = int(a*math.sin(t)) #Calculate the value of the wave at t
if y>=0: #Process the positive part of the sine wave
s = ' '*a #Add spaces upto the center line
s = s + "#" #Add a center line mark
s = s + '-'*y #Add a hyphon up to the wave value
s = s +'*' #Add an asterisk to mark the wave value
else: #Process the negative part of the sine wave
s = ' '*(a+y) #Add spaces up to the sine wave value
s = s + '*' #Add an asterisk to mark the wave value
s = s + '-'*(abs(y)-1) #Add a hyphen up to the center line
s = s + '#' #Add a center line mark
print(s) #Print the wave
t=t+0.25 #Increment time

Output

246
Program 6.8: Write a program to read a list of numbers from the console and find their
mean, µ, and standard deviation, s, using the following formulae:
𝑛

𝜇 = ∑ 𝑥𝑖
𝑖=0

∑(𝑥𝑖 − 𝜇)2
𝜎=√
𝑛

Solution steps:
1. Read the total number of data and read them and store them in a list.

247
2. Calculate the sum and mean
3. Calculate standard deviation

import math
n=int(input("Enter number of data: "))
data=[]
for i in range(n): #Read data
x=float(input("Enter data: "))
data.append(x)
s= sum(data) #Find the sum
avg = s/n #Find mean
sd=0
for i in range(n):
sd=(data[i]-avg)**2
sd=sd/n
sd=math.sqrt(sd) #Find standard deviation
print("Mean=",avg,"Standard deviation=", sd)

Output

Enter number of data: 5


Enter data: 2
Enter data: 6
Enter data: 3
Enter data: 6
Enter data: 3
Mean= 4.0 Standard deviation= 0.4472135954999579

Chapter Summary

1. The repetitive execution of a code block is called looping.


2. A loop has two parts: header and body. The header of a loop consists of a
looping construct and the loop control condition. It controls the number of
iterations a loop performs. The body of a loop is a block of code that is repeated
during the looping.
3. Python has the following two looping statements: while loop and for loop. The
while loop executes the loop's body till the specified looping condition is true.
In contrast, the for loop iterates over each collection item.

248
4. The number of iterations in a while loop depends on the looping condition. In
contrast, the number of iterations in a for loop is decided by the number of
elements in the collection.
5. In Python, any non-zero value and any non-empty collection are considered
True. Otherwise, it is deemed to be False.
6. When there is only one statement in the body of a while loop, the statement can
be written in the same line after the colon of the loop. This form of the for loop
is called the shorthand while loop.
7. We can combine many statements with a semi-colon (;) to make a single
compound statement. The Python interpreter treats a compound statement as
a single statement.
8. An infinite loop is a loop that never terminates. For example, a while loop can
be made to loop infinitely by using a conditional expression that always
evaluates to true, such as any non-zero constant, non-empty collection, or True.
However, there should be some mechanism to break such loops to make them
useful in practice.
9. A for loop iterates over each item of a collection or a sequence.
10. The break statement is used for premature exit from a loop.
11. The continue statement is used in a loop to skip the remaining part of the loop's
body
12. We can write the pass statement to create a blank loop body.
13. Both while loop and for loop can have an else block that executes when the loop
ends normally. In other words, the else block does not execute if the loop
terminates prematurely by a break statement.
14. Python allows using a loop inside another loop, called the nesting of loops.

Multiple Choice Questions

1. ____ control statement repeatedly executes a block of statements.


a. Iterative
b. Conditional

249
c. Multi-way
d. All of these

2. The symbol that is placed at the end of the header of a loop is


a. ;
b. :
c. -
d. ,

3. Which of the following is equivalent to False in Python?


(a) [0]
(b) {}
(c) "0 "
(d) All of the above

4. With x=1, which of the following is not an infinite loop?


(a) while x: x+=1
(b) while x:x+1
(c) while x: x=x//2
(d) None of the above

5. Which of the following statement is used to start the next iteration of the loop?
a. next
b. break
c. continue
d. None of these

6. Which of the following statement is used to terminate a loop ?


a. break
b. return
c. continue
d. exit

7. Which of the following is an invalid nesting of loops?


(a) a for loop inside a while loop
(b) a while loop inside another while loop
(c) a for loop inside another for loop
(d) None of the above

250
8. Which of the following terminates the execution of a program?
(a) break
(b) pass
(c) exit
(d) None of the above

9. The statement for x in range (5): print ("Hello") will print Hello how many
times?
(a) 4
(b) 5
(c) 0
(d) None of the above

10. What is the output of the statement for x in range (1,5): print (x, end=" ")?
(a) 1 2 3 4
(b) 1 2 3 4 5
(c) 0 1 2 3 4
(d) None of the above

11. What is the output of the following program?


x = -1
d = {-1:-1, 0:0, 1:1, 2:2}
while d[x]:
print(d[x], end = " ")
x=x+1

(a) -1, 0, 1, 2
(b) -1
(c) -1 0 1 2
(d) None of the above

12. What is the output of the following program?


a=10
for x in range (10):
a=a-x
if x==3: break
print(a)
(a) 4

251
(b) 5
(c) 6
(d) 7

13. What is the output of the following program?


a=15
for x in range(10):
a=a-1
else:
print(x, end=",")
print(a)

(a) 5
(b) 4
(c) 9, 5
(d) 10, 5

14. What is the output of the following program?


x=1
while x < 5:
if x % 3 == 0: break
x=x+2
else: print(x)

(a) 5
(b) 4
(c) 3
(d) None of the above

15. What is the output of the following program?


x=1
while x < 5:
x=x+2
if x % 3 == 0: continue
x=x-1
else: print(x)

(a) 4

252
(b) 5
(c) 6
(d) None of the above

16. What is the output of the following program?

i=1
for x in range(1,3):
for y in range(1,3):
i=i*2
print(i)
(a) 8
(b) 16
(c) 32
(d) None of the above

17. What is the output of the following program?


x=5
while x <= 5:
if x < 5:
x= x + 1
print(x)

(a) The value of x will be printed an infinite number of times


(b) The value of x will be printed exactly once
(c) The value of x will never be printed
(d) The value of x will be printed exactly five times

18. How many asterisks will be printed by the following program?


for x in [0, 1, 2, 3]:
for y in [0, 1, 2, 3, 4]: pass
print ('*')

(a) 4
(b) 5
(c) 20
(d) None of the above

253
19. What is the output of the following program?
for x in range(10):
for y in range(2,x//2):
if x%y==0 : break
else: print(x)
(a) 0,1,2,3,4,5,7,
(b) 0,1,2,3,5,7,
(c) 1,2,3,5,7,
(d) None of the above

20. To traverse each item of a list containing ten items, which of the following
range() expression would generate the correct list indices?

(a) range(1,10)
(b) range(10)
(c) range(0,9)
(d) range(1,11)

21. How many iterations the for loop in the following program will perform?
a=[1,2,3,4]
i=4
for x in a:
print(x)
i=i+1
a.append(i)

(a) 4
(b) infinite
(c) 3
(d) None of the above

Review Questions

1. State whether the following statements are true or false


a. The iterative flow control statements repetitively execute a block of code
several times.
b. In a for loop, the number of iteration of the loop is not known in advance.
254
c. The loop header and body of a while loop cannot be in the same line.
d. In a while loop, if the expression evaluates to a non-empty list, the loop
terminates.
e. The looping statement while 1: print("Hello") is an infinite loop.
f. The for loop is primarily used to iterate over the elements of a collection.
g. The statement for x in [1,2,3]: pass is a valid for loop.
h. A break statement written inside an inner loop of nested loops ends all the
nested loops.
i. A pass statement is used to do nothing.
j. We cannot write more than one continue statement in a loop.
k. The else block of a loop is executed when the loop terminates prematurely.
l. We cannot nest a for loop inside a while loop.
m. The exit () function is used to terminate a program.
2. Describe the syntax of a for loop with an example.
3. Explain the purpose of using break and continue.
4. Describe the syntax of a while loop with an example.
5. Discuss the purpose of else in a for loop with an example.
6. Compare for and while loops.
7. Describe shorthand while and for loops
8. Explain nesting of loops
9. Draw a flowchart of a for loop with a break and an else statement.
10. Draw a flowchart of a while loop with a continue statement and a break
statement.
11. Write an equivalent while loop for the following for loop:

for i in range(1,50,3):
print(i)
12. Replace the inner for loop with an equivalent while loop in the following
program

for x in range(10):
if x==0: continue
for y in range(2,x//2+1):
if x%y==0 : break
else: print(x, end=',')
13. Write the outputs of the following program:
numbers = [2, 3]
items = ["Chair", "Table"]

255
for x in numbers:
for y in items:
print(x*y)
14. Write the outputs of the following program:
for c in 'Python':
if c == 'o':
pass
print(c, end=", ")
15. Write the outputs of the following program:
for num in range(5, 10):
for i in range(2, num):
if num%i == 1:
print(num)
break
16. Write the outputs of the following program:
x=0
while (x < 20):
x+=2
print(x)
17. Write the outputs of the following program
x=5
for i in range(5):
for j in range(2, 10, 1):
if x % 2 == 0:
continue
x += 1
x+=1
else:
x+=1
print(x)
18. What is the output of the following program?
x=0
for i in range(10):
for j in range(-1, -10, -1):
x += 1
print(x)
19. There are five syntax errors in the following program. Find these errors.

256
x=5
for i=0 in range(5)
for j in range(2, 10, 1);
if x % 2 = 0:
continue
x += 1
x+=1
else:
x+=1
print(x)
20. There is a logical error in the following prime number generation program. Find
the error.

for x in range(1,20):
for y in range(2,x//2):
if x%y==0 : break
else: print(x)

Programming Assignments

1. Write a program to read a list of numbers and create and print another list containing numbers
divisible by ten from the original list.
2. Write a program to read a tuple of numbers. Iterate over the tuple and stop printing numbers on
the first occurrence of 7 in the tuple.
3. Write a program to display characters present at the even positions of the string "Wonderful
World". (Note: a space is a character in a string.)
4. Write a program to find the factorial of a number using a loop.
5. Write a program to read a string and print the count of character 'a' in the string ( For example,
if the input string is 'alphabet', the count of 'a' is 2)
6. Write a program to read a string consisting of capital letters, small letters, numbers, and other
characters and print their counts.
7. Write a program to read a list of n numbers. Iterate over the list and print the division of
consecutive numbers of the list. However, if the division by zero occurs, break the loop.
8. Print the following pattern:
54321
4321

257
321
21
1

9. Write a program to print the following pattern:


1
22
333
4444
55555

10. Write a program to sum the following series


(a) S = 1 + 1/2 + 1/3 + ¼ + …
(b) S = 1 – 1/2 +1/3 – 1/4 + …
(c) e = 1 + 1/1! + 2/2! + 3/3! + …
(d) cos(x) = 1 - x2/2! + x4/4! - x6/6! + ...
11. Write a program to generate a compound interest table for an investment of 1000 for a period
ranging from 1 to 10 years in a step of 1 and interest rates ranging from 4% to 12%, in a step of
1.

12. Write a Python program to generate the following pattern:


1
AB
234
CDEF
56789
13. Write a program to convert a decimal integer into its binary, octal and hexadecimal integer
without using the built-in functions.
14. Write a program to generate the following pattern:
1
01
101
0101
258
10101
15. Write a program to print a positive integer (maximum 8 digits) into words, such as 125 is to be
printed as one hundred and twenty five.

259
260
Chapter 7

User-defined Functions
Learning Outcomes

1. Describe user-defined functions


2. Identify the elements of a user-defined function
3. Define global and local functions
4. Explain value passing mechanisms in Python functions
5. Understand the concept of recursive functions
6. Explain lambda functions
7. Explain generator functions

7.1 Introduction
Certain operations or calculations, such as finding factorials of a number, are
repeatedly used at different points in a program, and it is valid that we can repeat the same
code at different places. However, a better design approach is writing functions and calling
them at places where they are needed. Example 7.1(a) shows a program to find the value of
nCr for given values of n and r, without using a function, whereas example 7.1(b) shows a

program to find nCr using a function. As can be seen from these two programs, the program
using a function is more compact and modular than the program without a function.

Example 7.1(a): Program to calculate nCr without using a function

#Calculate the value of nCr without using functions


#nCr =n!/(r!*(n-r)!)
n,r=eval(input("Enter values of n and r"))

#Calculate n!
factn=1
for i in range(1,n+1):
factn=factn*i

#Calculate r!
factr=1

261
for i in range(1,r+1):
factr =factr*i

#Calculate (n-r)!
factn_r=1
for i in range(1,n-r+1):
factn_r =factn_r*i

#Calculate nCr
ncr=factn/(factr*factn_r)

print("nCr=", ncr)
Output

Enter values of n and r5,2


nCr= 10.0

Example 7.1(b): Program to calculate nCr using a function

#Calculate the value of nCr using a function


#nCr =n!/(r!*(n-r)!)

#function to calculate the factorial of a number


def fact(n):
r=1
for i in range(1,n+1):
r=r*i
return r

#main program
n,r=eval(input("Enter values of n and r"))

#Calculate nCr by calling the fact function


ncr=fact(n)/(fact(r)*fact(n-r))

print("nCr=", ncr)

Output
Enter values of n and r5,2

262
nCr= 10.0

A function is defined as a self-contained subprogram called to perform a specific


task in a program. A function is also known as subprogram, procedure, routine. A function
takes some data through its arguments, processes them, and returns results to the calling
program. Once a function is defined in a program, it can be called (used) several times at
different places in the program. Further, we can save related functions as a module that can
be imported and used in any program, i.e., we can create a library of functions. Hence,
functions are widely used to promote modularity and reusability of codes in programs.

One of the main reasons for the popularity of Python is the availability of many
built-in functions and a large number of functions in the form of modules that can be
imported and used. We have already used functions from the math and cmath modules in
chapter 4. Despite a huge collection of Python functions, sometimes we need to create our
functions, called user-defined functions. Functions are classified as built-in functions,
module functions, and user-defined functions.

Built-in functions: Built-in functions, such as print (), range (), int (), are part of the Python
interpreter, and they do not require importing any module. They are available in every
program.

Module functions: Module functions are defined in modules, and the respective module
must be imported into a program before using these functions. Examples of module
functions are math.sqrt(), math.sin().

User-defined functions: User-defined functions are written by the programmer in the


program itself, for example, the fact () function as defined in example 7.1(b).

Figure 7.1 shows a flowchart of the program given in example 7.1(b). As shown in
the flowchart, on a function call, the program flow control goes to the function (shown in
dashed curves) and executes it. After completing the function execution, the program
control returns back to the calling program's next instruction.

263
fact(n)
Start

r=1
Input n, r i=2

factn=fact(n)
If i<=n
No
factr=fact(r) Yes
r=r*i
Factn_r=fact(n-r)

i=i+1
nCr=factn /(factr * factn_r)

Input n, r Return r

Stop

(a) Flow chart for nCr (main program) (b) Flow chart for factorial (Called function)

Figure 7.1: Flow of execution in function calls

Figure 7.2 shows the modular programming approach using functions, where a
large program uses many small functions. In figure 7.2, the program is divided into six
modules: the main program and five functions. In this approach, a function can be called
by different functions; for example, function 4 is being called by the main program and
function 3. When a function calls itself, it is called a recursive function. Following are some
advantages of using functions in computer programming:

1. It promotes the modular programming paradigm. In modular programming, a


computer program is divided into separate self-contained sub-programs (functions).

264
Since the code in a sub-program is short, it is simple and easy to understand. Further, it
is easy to maintain such programs. It is also easy to identify errors as they are localized
to a function.
2. Since the code of a function is not repeated in the calling program, the overall size of the
program is smaller.
3. Once a function is defined and tested, it can be reused in other programs also.

However, the main disadvantage of function-oriented programming is that it makes the


program slower and requires more memory due to the calling overheads of functions.

Main program

Function 1

Function 2 Function 3

Function 5

Function 4

Figure 7.2: Modular approach using functions

7.2 Defining a user-defined Function


A user-defined function is defined using the following steps:

1. Function definition begins with the def keyword followed by the function name
followed by parentheses ( ). After the parentheses, a colon (:) is written. The
statement starting from def and up to the colon is called the header of the function.
2. A function can have zero or more input parameters. The input parameters of the
function are written inside a parenthesis, separated by commas.

265
3. The statements below the function header are known as the body of the function.
All the statements of the body are indented.
4. It is a good programming practice to document the basic details of a function.
Python uses the first string literal written just below the function header as a
docstring. This docstring is shown when a user seeks help for a function. However,
the docstring is optional.
5. Normally, the last statement of a function body is return [expression], which ends
the function and returns the expression value to the calling program. The expression
in a return statement is optional. If no expression is given, the function returns None.
The return statement is optional. In this situation, the function automatically returns
None. Further, we can have more than one return statement in a function. The
execution of a function will end at the first return statement.

Following is the syntax for creating a user defined function in Python:

def function_name (parameters): #Header of the function


"function documentation string" #Body of the function begins here
Statements
return [expression] #Body of the function ends here

In Python, a function can be defined anywhere in a program, but the function must
be defined before its first use (call). A function can also be defined on the command prompt.
Example 7.2(a) shows a function to sum two numbers on the prompt. Example 7.2(b) shows
a function to print "Hello World. I love Python" five times on the console.

Example 7.2(a): Defining functions at the command prompt

>>> def mysum(a,b): #Header of the function


"mysum(a,b) returns total of two numbers" #Docstring
return a+b #Body of the function

>>> mysum(2,3)
5
>>> help(mysum)
Help on function mysum in module __main__:

mysum(a, b)
mysum(a,b) returns total of two numbers
>>>

266
Example 7.2(b): Defining and using a function

#A function to print "Hello World. I love Python" five times

#Defining the function


def print_hello(): #Function header
print("Hello World. I love Python") #Function body
return #Exitng the function

#Main program
for i in range(5):
print_hello() # Calling the function

Output
Hello World. I love Python
Hello World. I love Python
Hello World. I love Python
Hello World. I love Python
Hello World. I love Python

7.3 Parameters and Arguments in a Function


A function accepts input data through its parameters. The parameters are specified
in the parentheses used in the function header. There can be zero or more parameters in a
function. For a function with no parameter, the parentheses are empty. If there is more than
one parameter, they are separated by commas.

The term parameter is used when defining a function and is the name of an input
variable of a function. On the other hand, the term argument is used when we call a function
in a program, i.e., arguments are the values passed to the function during calls. For example,
in example 7.2 (a), the function has two parameters, namely a and b. When we call the
function, the arguments are 2 and 3, corresponding to the parameters a and b. In example
7.2(b), the function has no parameter and no argument. However, in most of the text, the
terms parameter and argument are used interchangeably, including this book. Python
supports the following types of input parameters to a function:

1. Positional parameters
2. Parameters with default values
3. Keyword arguments
267
4. Variable number of parameters

7.3.1 Positional Parameters

Positional parameters are the parameters that are mapped to the arguments
according to their positions. There is one to one mapping between the parameters and
arguments in order of their positions, i.e., the first argument's value is assigned to the first
parameter, the second argument's value to the second parameter. In other words, the
arguments passed to a function are in the same order as they are defined in the function. If
the number of parameters does not match the number of supplied arguments, an error is
generated. Example 7.3(a) illustrates the concept of positional parameters. The missing
positional argument error is generated in case of a mismatch between parameters and
arguments.

Example 7.3(a): Defining functions at the command prompt

>>> def myfun(a,b,c):


return a*b+c

>>> myfun(2,3,4)
10
>>> myfun(2,3)
Traceback (most recent call last):
File "<pyshell#18>", line 1, in <module>
myfun(2,3)
TypeError: myfun() missing 1 required positional argument: 'c'
>>>

7.3.2 Parameters with Default Values

Python allows assigning default values to parameters of a function. Therefore, it is


not necessary to pass arguments corresponding to the default value parameters. In this
situation, the function uses the default values to the missing arguments. Example 7.3(b) uses
the default value parameters to generate greetings.

Example 7.3(b): Default value parameters

#Defining default values to parameters

268
>>> def greet(name="Ram", msg="Hello"):
print(msg,",",name)
return

>>> greet() #Calling without arguments


Hello , Ram
>>> greet("Shyam") #Calling with only one arguments
Hello , Shyam
>>> greet("Ravi", "Good Morning") #Calling with both arguments
Good Morning , Ravi
>>>

It is valid to assign default values to only some parameters of a function. In such


situations, the default value parameters must be placed after all the non-default value
parameters. Violation of this rule will generate the SyntaxError: non-default argument
follows default argument error. Example 7.3(c) illustrates the above concept.

Example 7.3(c): Mixing default value and positional parameters

>>> def greet(name, msg="Good morning"):


print(msg,name)
return

>>> greet("Ram")
Good morning Ram
>>> greet("Ram", "Good Afternoon")
Good Afternoon Ram
>>> def greet1(msg="Good morning", name):

SyntaxError: non-default argument follows default argument


>>>

7.3.3 Keyword Arguments

The values to the positional arguments of a function are passed on in the sequence
they are written in the function definition. However, Python allows to call a function to pass
arguments in any order by using the name of the function parameters as keywords and
assigning values to them during function calling. For example, consider the header of a
function def myFun(a, b):, the parameters a and b of the function are keywords and the
function can be called as myFun(b=10, a=5), which is equivalent to myFun(5, 10). This way
of calling a function is called key-value pair mechanism to call a function.
269
This key-value pair mechanism to call a function can be used for parameters with or
without default values. The key-value and positional arguments can also be used together,
but key-value arguments must follow all the positional arguments. It is valid to pass values
some as positional arguments, some as keyword arguments, and remaining with default
values. Example 7.3(d, and e) shows some examples of keyword arguments.

Example 7.3(d): Keyword arguments

>>> def fun(a,b,c=10,d=20):


print("a=",a,"b=",b,"c=",c,"d=",d)
return

>>> fun(1,2,3,4) #positional arguments


a= 1 b= 2 c= 3 d= 4
>>> fun(a=1,d=4,c=3,b=2) #keyword arguments
a= 1 b= 2 c= 3 d= 4
>>> fun(a=1,b=2) #Keyword arguments and default values
a= 1 b= 2 c= 10 d= 20
>>> fun(1,2,d=4,c=3) #positional and keyword arguments
a= 1 b= 2 c= 3 d= 4
>>> fun(1,c=3, b=2) #positional, keyword arguments and default values
a= 1 b= 2 c= 3 d= 20

Example 7.3(e): Error: Duplicate arguments to a parameter

>>> def myFun(a):


print(a)

>>> myFun("I love Python") #Called using positional argument


I love Python
>>> myFun(a="I love Programming") #Called using keyword argument
I love Programming
>>> #Error: Tried to use positional and keyword together in a call
>>> myFun("I love Python", a="I love programming")
Traceback (most recent call last):
File "<pyshell#82>", line 1, in <module>
myFun("I love Python", a="I love programming")
TypeError: myFun() got multiple values for argument 'a'

270
7.3.4 Variable Number of Parameters

In Python, it is possible to define a function that accepts a variable number of


arguments, similar to the print function, which accepts any number of arguments. Such
functions are defined using the following two syntaxes:

Syntax 1:

def function_name([formal_args,] *var_args):


"function docstring"
Statements
return [expression]

Syntax 2:
def function_name([formal_args,] **var_kargs):
"function docstring"
Statements
return [expression]

Here, formal_args are the positional arguments, and they must precede the variable
number arguments. In syntax 1, the parameter *var_args accepts a variable number of
arguments and converts them into a tuple. It is similar to positional arguments, and the
values of the arguments are available in the order they are given in the function call.
Whereas, in syntax 2, the parameter **var_kargs accepts a variable number of keyword
arguments and converts them into a dict object. It is similar to the key-value pair
arguments, and the values of the arguments can be accessed as key-value pairs. Please note
the use of single and double asterisks in variable number arguments. Example 7.3(f)
illustrates the concepts of the variable number of positional arguments, and example 7.3(g)
shows the variable number keyword arguments. It is valid to combine formal positional
arguments, variable arguments, and variable keyword arguments in a function definition.
However, we have to give arguments in the following sequence: (1) formal arguments, (2)
variable number positional arguments, and (3) variable number keyword arguments.
Example 7.3(h) illustrates the above.

271
Example 7.3(f): Variable length positional arguments

>>> def mySum(*argv):


s=0
for arg in argv:
s=s+arg
return s

>>> mySum(1,2)
3
>>> mySum(1,2,3,4)
10
>>> mySum(1,2,3,4,5,6,7)
28

Example 7.3(g): Variable number keyword arguments

>>> def myFun(**kwargs): #Variable number keyword arguments


for key, value in kwargs.items():
print ("%s == %s" %(key, value))

>>> myFun(name="Ram")
name == Ram
>>> myFun(name="Ram",age="10")
name == Ram
age == 10
>>> myFun(name="Ram",age=10)
name == Ram
age == 10
>>> myFun(FirstName="Ram", SecondName="Singh", age=20, weight=60.5)
FirstName == Ram
SecondName == Singh
age == 20
weight == 60.5
>>>

272
Example 7.3(h): Using different types of arguments together

#Using formal, variable positional and keyword arguments together


ef myFun(x, *y, **z):
print("The value of formal argument:",x) #Accessing formal argument
print("Values of variable number positional arguments")
for a in y: #Accessing variable number positional arguments
print(a)
print("Values of variable number keyword arguments")
for k in z: #Accessing variable number keyword arguments
print("Key:", k, ", Value:",z[k])
myFun(1,2,3,4,5,6, a=7,b=8,c=9)
Output
The value of formal argument: 1
Values of variable number positional arguments
2
3
4
5
6
Values of variable number keyword arguments
Key: a , Value: 7
Key: b , Value: 8
Key: c , Value: 9

7.4 Calling a Function


Once a function is defined, it can be called in the main program or any other function
or the function itself (recursive function) by specifying its name and parameter values. A
function or program that calls another function is known as the calling function or program,
and the function which is being called is known as a called function.

In Python, we can pass any data type, such as float, int, complex number, string, list,
tuple, dict, as arguments to a function, and it will be available as the same type in the
function. Example 7.4(a) illustrates this.

273
Example 7.4(a): Calling a function with different types of data

>>> def myFun(a,b,c,d):


print(type(a),":",a)
print(type(b),":",b)
print(type(c),":",c)
print(type(d),":",d)
return

>>> myFun([1,2,3],(4,5,6),{"a":7,"b":8},{1,2,3})
<class 'list'> : [1, 2, 3]
<class 'tuple'> : (4, 5, 6)
<class 'dict'> : {'a': 7, 'b': 8}
<class 'set'> : {1, 2, 3}
>>>

Expanded arguments: In Python, it is possible to unpack (expand) a list, a tuple, or a dict


(dictionary), and pass each element of the collection to a function as a separate argument by
adding * to a list or a tuple and ** to a dictionary when calling a function. When using an
expanded dict as an argument, the key name of the dict object must match with the
parameter name in the function definition. This unpacking of arguments facilitates the use
of the same function for simple arguments and collection arguments. For example, consider
the header of a function def myFun(a,b,c):, we can call this function as myFun(1,2,3) or
myFun( *[1,2,3]). The later one unpacks the list and passes the list elements as simple
arguments. We can also call the function as myFun(*(1,2,3)) and
myFun(**{"a":1,"b":2,"c":3}). It is also possible to mix simple and unpacked collections as
function arguments. For example, we can also call the function as myFun( 1, *(2,3)) or
myFun( *(1,2),3). Example 7.4(b) illustrates the above concept.

In a variable-length parameter function, the simple and expanded arguments are


mapped first to the positional parameters, and then the remaining arguments are treated as
variable-length arguments. Example 7.4(c) shows a function with two positional parameters
and one variable-length parameter and is called with a few simple arguments and one
expanded argument. Simple and expanded arguments can be given in any order. It is
possible to use more than one expanded arguments.

When a function has only positional arguments without default values, the number
of simple and expanded arguments passed must match the number of parameters of the
function; otherwise, an error will be generated (see example 7.4(d).
274
Example 7.4(b): Expanded list, tuple, and dictionary as function arguments

>>> def myFun(a,b,c): #Function definition


print(a+b+c)
return

>>> myFun(1,2,3) #Calling with simple arguments


6
>>> myFun(*[1,2,3]) # Calling with an expanded list
6
>>> myFun(*(1,2,3)) #Calling with an expanded tuple
6
>>> myFun(**{"a":1,"b":2,"c":3}) #Calling with an expanded dictionary
6
>>> myFun(**{"b":2,"a":1,"c":3}) #Expanded dictionary in random order
6
>>> >>> myFun(1,*[2,3])
6
>>> myFun(*[1,2],3)
6
>>>

Example 7.4(c): A function with a few positional parameters and a variable number
parameter

# A function with two positional and one variable length parameters


>>> def myFun(a,b,*arg):
print(a,b)
for x in arg:
print(x,end=" ")
return

>>> myFun(1,2,3,4,5) #Calling with simple arguments


1 2
3 4 5
>>> myFun(*[1,2,3,4,5]) #Calling with expanded arguments
1 2
3 4 5
>>> myFun(1,*[2,3,4,5]) #Calling with simple and expanded arguments
1 2
3 4 5
>>> myFun(*[1,2,3],4,5) #Calling with expanded and simple arguments
1 2
3 4 5

275
>>> myFun(*[1,2,3],*(4,5),6,7)
1 2
3 4 5 6 7
>>>

Example 7.4(d): A function with only positional parameters and function calling with
simple and expanded arguments

>>> def myFun(a,b,c):


print(a,b,c)

>>> myFun(*[1,2,3])
1 2 3
>>> myFun(1,*[2,3])
1 2 3
>>> myFun(*[1,2])#Error due to less number of arguments
Traceback (most recent call last):
File "<pyshell#53>", line 1, in <module>
myFun(*[1,2])
TypeError: myFun() missing 1 required positional argument: 'c'
>>> myFun(*[1,2,3,4]) #Error due to excess number of arguments
Traceback (most recent call last):
File "<pyshell#54>", line 1, in <module>
myFun(*[1,2,3,4])
TypeError: myFun() takes 3 positional arguments but 4 were given
>>>

7.5 Local and Global Functions


In Python, a function can be defined anywhere in the code, even inside another
function. When a function is defined inside another function, it is called a local or nested
function. However, a local function can only be called within the function where it is
defined, and it is not available outside that function. Hence, the scope of a local function is
limited to the domain where it is defined. A function defined outside any other function is
called a global function and is available throughout the code. In other words, a local
function has a local scope, and a global function has a global scope. Also note, if there are
local and global functions with the same name, the local function is called. Example 7.5
illustrates the above.

276
Example 7.5: Local and global functions

#Local and global functions


def fun2(x): #a global function
print("Using global function")
return x*x

def fun1(a,b,c):# a global function


def fun2(x): #A local function
print("Using local function")
return x*2 # End of local function
d=fun2(a)+fun2(b)+fun2(c) # Calls local function
return d # End of global function

print(fun1(1,2,3))
print(fun2(4)) #Calls global function
Output
Using local function
Using local function
Using local function
12
Using global function
16

7.6 Scope and Life of a Variable


The variable's scope refers to the parts of a program where the variable is accessible,
and the lifetime of a variable is the period between the time of variable creation and its
killing. In Python, a variable is created by assigning a value to it. Based on the accessibility
of a variable, it is classified as a local or global variable.

7.6.1 Local Variables

A variable created in a function is a local variable, and its accessibility is limited to


the function codes. Parameters of a function are local variables. A local variable is created
when a function is executed and is destroyed on returning from the function. Outside the
function, the local variable does not exist and is inaccessible. Example 7.6(a) illustrates the
concept of local variables. A local variable created in a block inside another block of a
function is accessible in the outer block after its point of creation. In example 7.6(b), a local
variable declared at a deeper indentation in a function is available at a lesser indentation in
the function.

277
Example 7.6(a): Local Variables

>>> def myFun(a): #Parameters are local variables


x=10 #x is a local variable to this function
print(a+x) # a and x are accessible here

>>> myFun(5)
15
>>> print(a) #a is not available here
Traceback (most recent call last):
File "<pyshell#98>", line 1, in <module>
print(a)
NameError: name 'a' is not defined
>>> print(x) #x is not available here
Traceback (most recent call last):
File "<pyshell#99>", line 1, in <module>
print(x)
NameError: name 'x' is not defined

Example 7.6(b): Local Variables

>>> def myfun(a):


x=10
if a > 10:
b=20 #Defining a local variable at a higher indentation
print(x,b)
print(x,b) #Variable b is accessible here at lesser indentation

>>> myfun(20)
10 20
10 20

7.6.2 Global Variables

A variable declared outside any function is a global variable, and it is accessible


(below the point of definition) throughout the program and every function (see example
7.6(c).

278
Example 7.6(c): Global Variables

>>> a=10 #Declaring a global variable


>>> def myFun(b):
print(a+b) # Accessing a global variable in the function

>>> myFun(5)
15
>>> print(a) #Using a global variable in the main program
10

However, to change the value of a global variable inside a function, we need to use
the global keyword (see example 7.6(d).

Example 7.6(d): Changing a global variable inside a function

>>> a=10 #Creating a global variable


>>> def myFun(b):
global a #Declaring a global variable
print(a+b)
a=20 #Modifying a global variable

>>> print(a) #Print the initial value


10
>>> myFun(5)
15
>>> print(a) #Print the modified value
20
>>>

Without the global keyword, the interpreter will create a new local variable with the
same name, which will shadow the global variable in the function, and any change in the
variable will not affect the global variable. Further, once a local variable is created in a
function, a global variable with the same name cannot be used directly, even before the
point of creation of the local variable (see example 7.6(e)).

279
Example 7.6(e): Global Variable

>>> a=10 #Creating a global variable


>>> def myFun(b):
print(a+b) #Error: Try to access before declaration
a=20 #Creates a local variable

>>> print(a)
10
>>> myFun(5)
Traceback (most recent call last):
File "<pyshell#132>", line 1, in <module>
myFun(5)
File "<pyshell#129>", line 2, in myFun
print(a+b)
UnboundLocalError: local variable 'a' referenced before assignment

However, we can access and modify a global variable and a local variable with the
same name in a function using the globals() built-in method simultaneously. The globals()
method returns all the global variables as a dictionary. The global variable is used as a global
directory item, and the local variable is used directly. After returning from the function, the
global variable can be used directly (see example 7.6(f)).

Example 7.6(f): Local and global variables with the same name

>>> def myFun(b):


a=20 # Creating a local Variable
#Using the local and the global variables simultaneously
print(a+b+globals()['a'])
globals()['a']=100 #Modifying a global variable

>>> a=10 #Creating a global variable


>>> myFun(5)
35
>>> print(a) #Print the modified value
100

Normally, a global variable once created remains in the memory until the program's
execution. However, we can delete a variable using the del keyword. Once a variable is
deleted, it is no more available in the program; see example 7.6(g)

280
Example 7.6(g): Deleting a global variable

>>> def myFun(b):


global a #Declaring a variable to be global
print(a+b)
del a #Deleting a variable

>>> a = 10 #Creatig a global variable


10
>>> myFun(5)
15
>>> print(a) #Trying to use a deleted variable
Traceback (most recent call last):
File "<pyshell#165>", line 1, in <module>
print(a)
NameError: name 'a' is not defined
>>>

7.7 Passing Arguments to a Function


In general, we can pass a value to a function by using the following two mechanisms:
pass-by-value or pass-by-reference.

In pass-by-value, an independent copy of the argument is passed to the function.


Any changes made to that copy have no impact on the original argument variable. There
are separate memories for the argument and the parameter variables.

In pass-by-reference, the memory reference of the argument variable is passed to


the function. Any changes made to it in the function are available in the calling function. In
other words, the argument variable and the parameter variable refer to the same data in the
memory.

In Python, arguments to a function are passed as pass-by-object-reference. In the


pass-by-object-reference, the behavior of the argument changes with context. The same
argument behaves like pass-by-value or pass-by-reference depending on the way argument
is used in the function or the type of the argument value. For example, when we pass an
argument of the immutable data types, such as integer, string, tuple, it behaves like a pass-
by-reference argument (no separate memory is allocated to it) till it is assigned a new value.
It behaves like a pass-by-value argument on the assignment of a new value, and a separate

281
memory is allocated to it. Thus, a variable with an immutable value passed as an argument
of a function will never change its original variable in the calling program. See example
7.7(a), where an immutable argument is passed to a function. Please note the ids of the
argument and its corresponding variable in the function. As can be seen, the ids of the
arguments and the related variables are the same before the assignment (behaves like pass-
by-reference), but after the assignment, they are different (behaves like pass-by-value).

Example 7.7(a): Calling a function with immutable type arguments

>>> def myFun(a,b,c):


#Ids of arguments and parameters are the same
# till new assignments
print("Values and ids before assignment:")
print(a,id(a),"\n", b,id(b),"\n", c, id(c))
a=20
b=(1,2,3)
c="John"
#New Ids are created as new local variables are created
#These local variables have no link with the original arguments
print("\nValues and ids after assignment:")
print(a,id(a),"\n", b,id(b),"\n", c, id(c))

>>>
>>> x,y,z=10,(1,1,1),"David"
>>> print(x,id(x),"\n", y,id(y),"\n", z, id(z))
10 2105591622224
(1, 1, 1) 2105632687232
David 2105632753904
>>> myFun(x,y,z)
Values and ids before assignment:
10 2105591622224
(1, 1, 1) 2105632687232
David 2105632753904

Values and ids after assignment:


20 2105591622544
(1, 2, 3) 2105632724736
John 2105632725104
>>> #The new assignments have no effect on the original arguments
>>> print(x,id(x),"\n", y,id(y),"\n", z, id(z))
10 2105591622224
(1, 1, 1) 2105632687232
David 2105632753904

282
When we pass a mutable object, such as a list, a dictionary, and a set, it is treated as
a pass-by-reference argument. If the function modifies its parameters, the corresponding
argument in the calling program is also updated with the new value; see example 7.7(b).

Example 7.7(b): Calling a function with a list object

>>> def myFun(myList):


print(myList, id(myList))
myList.append(4) #Appending an element to the list
print(myList, id(myList))

>>> a=[1,2,3]
>>> print(a,id(a))
[1, 2, 3] 2422402427904
>>> myFun(a)
[1, 2, 3] 2422402427904
[1, 2, 3, 4] 2422402427904
>>> print(a,id(a))
[1, 2, 3, 4] 2422402427904
>>>

However, if we assign a new mutable object to the passed argument in the function,
the corresponding calling variable is unaffected. Hence, it behaves like a call-by-value
argument; see example 7.7(c).

Example 7.7(c): Calling a function with a list and performing assignment operations

>>> def myFun(myList):


print(myList, id(myList))
myList=[4,5,6] #Assignment creates a new object
print(myList, id(myList))

>>> a=[1,2,3]
>>> print(a, id(a))
[1, 2, 3] 2422407557824
>>> myFun(a)
[1, 2, 3] 2422407557824
[4, 5, 6] 2422407690112
>>> print(a, id(a))
[1, 2, 3] 2422407557824
>>>

283
Further, if we are using a compound assignment operator, the behavior of the
passed argument is again like a pass-be-reference, and changes are available in the calling
program; see example 7.7(d). The same is true for sets and dictionaries; see example 7.7(e).
The set and dictionary do not support compound assignment operators.

Example 7.7(d): Calling a function with a list and performing compound assignment
operations

>>> def myFun(myList):


print(myList, id(myList))
myList+=[4,5,6] #Compound assignment, the original list is modified
print(myList, id(myList))

>>> a=[1,2,3] #Initial list


>>> print(a, id(a))
[1, 2, 3] 2422407688704
>>> myFun(a)
[1, 2, 3] 2422407688704
[1, 2, 3, 4, 5, 6] 2422407688704
>>> print(a, id(a)) #Modified list available in the main program
[1, 2, 3, 4, 5, 6] 2422407688704
>>>

Example 7.7(e): Passing sets and dictionary to a function

>>> def myFun(set1,dict1):


print(id(set1), set1, id(dict1), dict1)
set1.add(4)
dict1[3]="Three"
print(id(set1), set1, id(dict1), dict1)

>>> s={1,2,3}
>>> d={1:"One",2:"Two"}
>>> print(id(s),s,id(d),d)
2422407519808 {1, 2, 3} 2422407726784 {1: 'One', 2: 'Two'}
>>> myFun(s,d)
2422407519808 {1, 2, 3} 2422407726784 {1: 'One', 2: 'Two'}
2422407519808 {1, 2, 3, 4} 2422407726784 {1: 'One', 2: 'Two', 3:
'Three'}
>>> print(id(s),s,id(d),d)
2422407519808 {1, 2, 3, 4} 2422407726784 {1: 'One', 2: 'Two', 3:
'Three'}

284
The change in a calling variable by a function is known as the function side effect.
If it is not desirable, we can pass a shallow copy of a variable to a function. A shallow copy
of a variable can be created using a colon operator; for example, for a list variable x=[1,2,3,4],
a shallow copy of x is created as x[:]. Example 7.7(f) illustrates the above concepts.

Example 7.7(f): Passing a shallow copy to a function to avoid the function side effect

>>> def myFun(myList): #Receiving a shallow copy


print(myList, id(myList))
myList+=[4,5,6]
print(myList, id(myList))

>>> a=[1,2,3]
>>> print(a, id(a))
[1, 2, 3] 2930492433344
>>> myFun(a[:]) #Passing a shallow copy of a list
[1, 2, 3] 2930487176512
[1, 2, 3, 4, 5, 6] 2930487176512
>>> print(a, id(a)) #The original list is not affected
[1, 2, 3] 2930492433344
>>>

7.8 Return Values from Functions


A function may return one or more values to the calling function. Normally, a return
statement is used to terminate the execution of a function, and the values of the expressions
written with the return statement are returned to the calling program (see example 7.8(a)).

Example 7.8(a): Returning values from a function

>>> def mySum(a,b):


return a+b #Returning a single value

>>> s=mySum(10,20)
>>> print(s)
30

>>> def swap(a,b):


return b,a #Returning multiple values

>>> a,b=10,20
>>> a,b= swap(a,b)

285
>>> print(a,b)
20 10

If no expression is written with the return statement, the None value is returned to
the calling program (see example 7.8(b)). Even if we are not writing a return statement in a
function, the function returns the None value to the calling function (see example 7.8(c)).

Example 7.8(b): A return statement with no expression

>>> def myFun(msg):


print(msg)
return #No return expression

>>> a=myFun("Greetings") #Function returning None


Greetings
>>> print(a)
None
>>>

Example 7.8(c): A function without a return statement

>>> def myFun(msg):


print(msg) #A function without a return statement

>>> a=myFun("Greetings") #Function returning None


Greetings
>>> print(a)
None
>>>

7.8.1 Returning Multiple Values from a Function

As stated earlier, a function may return multiple values to the calling program. The
returned values may be of any data type and may be assigned to variables in the calling
functions or ignored. If multiple returned values are assigned to a single variable, the values
are stored as a tuple. However, if returned values are assigned to different variables, the
number of variables should be equal to the number of returned values. The miss-match in
numbers (either less or more) raises unpacking errors. The unpacking error is avoided using

286
dummy variables (typically, an underscore, _ , is used as a dummy variable name) to match
the number of returned values and the variables. Example 7.8(d) illustrates various
situations of multiple values returned from a function.

Example 7.8(d): A function returning multiple values

>>> def cycle(a,b,c):


return b,c,a #Returning multiple values

>>> a,b,c=10,20,30
>>> x=cycle(a,b,c) #Returned as a tuple
>>> print(x, type(x))
(20, 30, 10) <class 'tuple'>

>>> a,b,c=cycle(a,b,c) #Returned as individual items


>>> print(a,b,c,type(a),type(b),type(c))
20 30 10 <class 'int'> <class 'int'> <class 'int'>

>>> #Error: mismatch in numbers of returned and collected values


>>> a,b=cycle(a,b,c)
Traceback (most recent call last):
File "<pyshell#288>", line 1, in <module>
a,b=cycle(a,b,c)
ValueError: too many values to unpack (expected 2)

>>> #Error: mismatch in numbers of returned and collected values


>>> a,b,c,d=cycle(a,b,c)
Traceback (most recent call last):
File "<pyshell#289>", line 1, in <module>
a,b,c,d=cycle(a,b,c)
ValueError: not enough values to unpack (expected 4, got 3)

>>> #Using a dummy variable to match returned values and variables


>>> a,b,_=cycle(a,b,c)
>>> print(a,b)
30 10
>>>

A function can return any data type, such as numbers, strings, lists, tuples, sets,
dictionaries. Example 7.8(e) illustrates returning values of various data types by a function.

287
Example 7.8(e): Returning different types of values from a function

>>> def myFun():


mylist=[1,2,3]
mytuple=(1,2,3)
myset={1,2,3}
mydict={1:"One",2:"Two"}
mystr="Python"
#Returning different types of data
return mylist, mytuple,myset,mydict,mystr

>>> a,b,c,d,e=myFun()
>>> print(a,type(a))
[1, 2, 3] <class 'list'>
>>> print(b,type(b))
(1, 2, 3) <class 'tuple'>
>>> print(c,type(c))
{1, 2, 3} <class 'set'>
>>> print(d,type(d))
{1: 'One', 2: 'Two'} <class 'dict'>
>>> print(e,type(e))
Python <class 'str'>
>>>

7.9 Passing and Returning Function Objects to a Function


In Python, a function is also an object. Hence, we can pass a function as an argument
in another function. A function that accepts other functions as its arguments is called a
higher-order function. Example 7.9(a) illustrates the above. Similarly, we can return
function objects from a function. In this way, a local function defined inside a function can
be returned to the calling program and used outside the function; see example 7.9(b).

Example 7.9(a): Passing function objects to a function

>>> def mySum(a,b):


return a+b

>>> def myProd(a,b):


return a*b

>>> def compute(fun, a,b):#The first parameter is a function object


return fun(a,b)

288
>>> a,b=10,20
>>> compute(mySum, a,b) #The first argument is a function object
30
>>> compute(myProd, a,b)#The first argument is a function object
200

Example 7.9(b): Returning a function object from a function

>>> def myFun(): #Global function


def myFun2(a,b):# Local function
return a+b
return myFun2 #Returning the local function object

>>> fun=myFun() #Calling a function which returns a function object


>>> fun(2,3) #Calling the returned function, i.e., myFun2
5
>>>

7.10 Recursive Functions


When a function calls itself, it is called a recursive function. It can be very useful if a
problem can be defined in terms of itself. For example, factorial(n)=n*factorial(n-1).
However, every recursive function should have a base condition at which the recursion
should end; otherwise, the recursion will continue infinitely and ultimately will lead to out
of stack error. By default, the Python interpreter limits the number of recursion to 1010 to
help avoid infinite recursions. If the above limit is crossed, it results in the Recursion Error.
Example 7.10 shows a recursive function to calculate the factorial of a number. In the
calculation of factorial, the base condition occurs when n reaches 1.

Example 7.10: A recursive function

>>> def fact(n): #Function definition


if n==1: #Base condition at which recursion stops
return 1
else:
return n*fact(n-1) #Calling itself, a recursive call

>>> fact(5)
120

289
When we call the fact function (example 7.10) with a positive integer, it calls itself
recursively. Each time argument is decreased by 1. The recursive call ends when the
argument reaches 1. There is no further recursive call at the base condition, and the function
starts to return value to its previous call and reaches the first call, and returns the factorial
value of the passed number. The whole process is illustrated below:

factorial(3) # First call with n=3


3 * factorial(2) # Second call with n=2
3 * 2 * factorial(1) # Third call with n=1, the base condition reached
3*2*1 #The return value from the third call is 1
3*2 # The return value from the second call is 2*1, i.e., 2
6 # The return value from the first call is 3*2, i.e., 6

The recursive function has many advantages, such as reducing a complicated task
into simpler repetitive subtasks, which reduces the requirement of nested iterations. The
recursion makes codes simpler and compact. However, a recursive function takes a lot of
memory and has a significant function calling overheads. A recursive function usually is
challenging to debug.

7.11 Lambda Function


An anonymous function, a function without a name, is created with the lambda
keyword in Python. A lambda function can take any number of arguments but can have
only one expression in its body. Following is the syntax of a lambda function:

lambda p1, p2, …, pn: expression

where p1, p2, …, pn are the function parameters, and expression is a valid python
expression. Example 7.11(a) creates a lambda function to evaluate the expression
𝑓(𝑥, 𝑦) = 𝑥 2 + 𝑦 2 + 𝑥𝑦

Example 7.11(a): A lambda function

>>> f=lambda x,y:x*x+y*y+x*y


>>> f(1,1)
3
>>> f(2,2)
12

290
As can be seen from Example 7.11(a), there is no function name in a lambda function,
and there is no return statement. Since only one expression is permitted in a lambda
function, its value is returned. A lambda function can be used anywhere a function is
required. They are frequently used with built-in functions, such as filter, map, and reduce.

A lambda function can be used with the filter function to select the elements of a list
which returns a true value from the lambda function. For example, to get all the even
numbers from a list of integers, see example 7.11(b). The filter function evaluates the
specified Lambda function iteratively for each element of the list and returns the true
elements as a filter object. The list function can be used to convert a filter object back into a
list.

Example 7.11(b): A lambda function with the filter function

>>> a=[1,2,3,4,5,6,7,8,9] #Original list


>>> b=list(filter(lambda x: x%2==0,a))
>>> b # Filtered list
[2, 4, 6, 8]

Similarly, a Lambda function can also be used with the map function to evaluate the
function for all the elements of lists. For example, to get a list that consists of the sum of the
corresponding elements of two lists (See example 7.11 (c)).

Example 7.11(c): A lambda function with the map function

>>> a=[1,2,3,4,5]
>>> b=[6,7,8,9,10]
>>> #Calling the function for each pair of the lists
>>> c=list(map(lambda x,y:x+y, a,b))
>>> c
[7, 9, 11, 13, 15]
>>>

7.12 Generator Functions


A generator function generates a series of outputs. The function maintains its last
state and, in the next call, continues from there. In other words, it behaves like an iterator.
A generator function uses the keyword yield instead of the return keyword to return a value
to the calling program. When we call a generator function, it returns a generator object. The
291
next () built-in function is used to get elements from a generator object. Each call of the next
() method returns the next generator element. On reaching the last element of a generator
object, further call of the next () method results in the StopIteration error. Example 7.12(a)
illustrates a simple generator function.

Example 7.12(a): A generator function

# A simple generator function


def my_gen(n):

print('This is printed first')

yield n #The first call returns from here

n += 1
print('This is printed second')
yield n #The second call returns from here

n += 1
print('This is printed at last')
yield n #The Last call returns from here

gen_obj = my_gen(10) # The main call of the generator function


print(next(gen_obj)) #Getting the first value
print(next(gen_obj)) #Getting the second value
print(next(gen_obj)) #Getting the last value
print(next(gen_obj)) #Error: Trying to access beyond the last element

Output
This is printed first
10
This is printed second
11
This is printed at last
12
Traceback (most recent call last):
File "D:/akv/akv/Python_book/Chapter 4/se5.py", line 20, in <module>
print(next(gen_obj)) #Error: Trying to access element beyond the
last element
StopIteration

292
The generator function differs from the normal function in the following ways:

i. When we call a normal function, it starts executing its code immediately; whereas a
generator function only creates a generator object. On calling the next method, the
code of the generator function gets executed.
ii. The normal function returns values using the return statement; whereas the
generator function uses a yield statement to return value. A generator function can
have more than one yield statement. We can iterate from one yield to the next yield
statement using the next () method. Once a generator function yields a value, the
function is paused and the control is transferred to the calling program.
iii. Local variables and their states are remembered between successive calls in a
generator function; whereas a normal function kills its local variables on returning
from the function.

We can use a generator function in a for loop to directly get the values generated by the
function. The next () method is automatically called during the looping. Example 7.12(b)
uses a generator function to generate a sequence of numbers.

Example 7.12(b): A generator function in a for loop

>>> def genFun(start, end, inc): #Generator function


i=start
while(i<end):
yield i #yield is used in place of return
i = i + inc

>>> for x in genFun(2,10,3):


print(x)

2
5
8
>>>

7.13 Command Line Arguments


We can pass some values to a Python program while executing it from the command line.
The values that are given after the name of the program in the command line shell of the

293
operating system are known as command line arguments. For example, the command
D:\>python test_program.py 1 2 3 4 5 runs the program test_program.py from the
command line and 1, 2, 3, 4 and 5 are the command line arguments.

We can access the command line arguments using the variable sys.argv of the sys
module. The sys.argv is a list and contains all the command line arguments, in the sequence
given at the command line. The first item, i.e., sys.argv[0], is the name of the python
program. Other items are the arguments. We can use len(sys.argv) to get the total number
of arguments including the name of the script. Example 7.13 illustrates the processing of
command line arguments of a program. The program prints the command line arguments
and find the sum of the arguments passed.

Example 7.13: Command line arguments

import sys #import the sys module

# total number of command line arguments


n = len(sys.argv)
print("Total number of arguments passed:", n)

# Arguments passed
print("\nName of Python program:", sys.argv[0])

print("\nArguments passed are:")


for i in range(1, n):
print(sys.argv[i])

# Addition of arguments
Sum = 0
for i in range(1, n):
Sum += int(sys.argv[i])

print("\nThe sum of arguments is:", Sum)

Output
D:\>python test_program.py 1 2 3 4 5
Total number of arguments passed: 6

Name of Python program: test_program.py

Arguments passed are:


1
2

294
3
4
5

The sum of arguments is: 15

7.14 Solved Examples


Program 7.1: Write a function to calculate surface area and volume of a solid cylinder.

Solution steps:
1. Define the function cyl_vol_sa (r, h):
1.1 Calculate volume, vol, using the formula 𝑣𝑜𝑙 = 𝜋𝑟 2 ℎ
1.2 Calculate surface area, sa, using the formula 𝑠𝑎 = 2𝜋𝑟(ℎ + 𝑟)
1.3 Return vol and sa
2. Read the radius, r, and height, h, of the cylinder.
3. Call the function cyl_vol_sa
import math
#Define function
def cyl_vol_sa (r, h):
""" The cyl_vol_sa(r,h) function calculates volume
and surface area of a solid cylinder"""

vol= math.pi*r*r*h #Volume calculation


sa = 2*math.pi*2*(r+h) #Surface area calculation
return vol,sa

#main program
r =float(input("Enter radius of the cylinder: "))
h =float(input("Enter height of the cylinder: "))

v,s = cyl_vol_sa(r,h)#Calling function


print(f"Volume ={v:8.3f} \nSurface area = {s:8.3f}")
Output
Enter radius of the cylinder: 3
Enter height of the cylinder: 4
Volume = 113.097
Surface area = 87.965

295
Program 7.2: Write a function to list all the prefect numbers up to a given number. A
perfect number is a positive integer that is equal to the sum of its proper positive divisors,
that is, the sum of its positive divisors excluding the number itself.

Solution steps:
1. Define the function perfect_numbers (n):
1.1 for each number x in the range 1 and n:
1.1.1 find the divisors of x and sum them
1.1.2 if x is equal to the sum, add number to the list of perfect numbers
1.2 return the list
#Function definition
def perfect_numbers(m):
if m < 0: return "Invalid number"
list_perfect=[]
for n in range(1,m):
sum = 0
for x in range(1, n):
if n % x == 0: #Evaluates to true if x is a factor of n
sum += x
#Add the prefect number into the list
if sum == n: list_perfect.append(n)

return list_perfect #Return the list of perfect numbers

#main program
n= int(input("Enter the upper limit:"))
print("Perfect numbers between 1 and ", n," are:", perfect_numbers(n))

Output
Enter the upper limit:1000
Perfect numbers between 1 and 1000 are: [6, 28, 496]

Program 7.3: Write a function isPalindrome(word) to check whether word is a


Palindrome.

Solution steps:
1. Define the function isPalindrome(word):
1.1 Convert all the characters of word to the lower case
1.2 Initialize the left index to 0 and the right index to the last character.
1.3 while left index < right index:

296
1.3.1 if characters at the left index is different than the character at the right index
Return False
Else
Increment the left index by one
Decrement the right index by one
1.4 Return True as no mismatch found
#Function definition
def isPalindrome(word):
word=word.lower()
left_pos = 0 #Index of the first character
right_pos = len(word) - 1 #Index of the last character
while right_pos >= left_pos:
#Mismatch of characters means not a palindrome.
if not word[left_pos] == word[right_pos]:
return False
left_pos += 1 #Increment the left index
right_pos -= 1 #Decrement the right index
return True #No mismatch found, hence palindrome
#Main program
word=input("Enter the word to check for palindrome: ")
print(f"The word {word} is ", "a palindrome"
if isPalindrome(word)else "not a palindrome")
Output
Enter the word to check for palindrome: Madam
The word Madam is a palindrome

Enter the word to check for palindrome: Sir


The word Sir is not a palindrome

Program 7.4: Write a generator function, genFibonacci (t1, t2, n), to generate a Fibonacci
series starting with t1 and t2 up to the nth term.

Solution steps:
1. Define the function genFibonacci (t1, t2, n):
1.1 Yield the first and the second terms
1.2 while the number of terms < n:
1.2.1 Calculate the next term using t3= t1 + t2
1.2.2 Yield the new term
1.2.3 Update the last two terms using t1=t2 and t2 =t3
3. Call the function, such as genFibonacci (1, 1, 10)

297
#Function definition
def genFibonacci (t1,t2,n):
yield t1 #return the first term
yield t2 #return the second term
i=2
while i < n: #Repeat till nth term
t3=t1 + t2 #Calculate the next term
yield t3 #return the next term
t1=t2 #Update the last two terms
t2=t3
i=i+1 #Increment the loop counter

#Main program
print("Using the function as an iterator")
for x in genFibonacci(1,1,10): #Use the function as an iterator
print(x, end=' ')

#Use the function as a normal function


print("\nUsing the function as a normal function")
gen_obj = genFibonacci(2,5,10) #Creating a generator object
i=0
while i<10:
t=next(gen_obj) #Getting a term from the generator object
print(t,end=' ')
i+=1

Output
Using the function as an iterator
1 1 2 3 5 8 13 21 34 55
Using the function as a normal function
2 5 7 12 19 31 50 81 131 212

Program 7.5: Write a program using lambda function to segregate positive numbers from
a list of numbers and find their sum.

Solution steps:
1. Use the filter method and a lambda function to segregate the positive numbers.
list1= [2,-4,6,2,-6,3] #Original list
#A lambda function used in the filter method
list2 = list(filter( lambda x : x>0, list1)) #Segregated list
print("Original list: ", list1)
print("Segregated list: ",list2)
print("Sum of the positive numbers: ", sum(list2))
298
Output
Original list: [2, -4, 6, 2, -6, 3]
Segregated list: [2, 6, 2, 3]
Sum of the positive numbers: 13

Program 7.6: Write a recursive function to sum the first nth term of the following series:

𝑥 𝑥2 𝑥3 𝑥4
𝑒𝑥 = 1 + + + + +⋯
1! 2! 3! 4!

Solution steps:
1. Define the function myExp (x, n):
1.1 Declare num and denum as global variable
1.2 if n = 0, return 1
1.3 else
1.3.1 r = myExp(x,n-1)
1.3.2 num = num*x
1.3.3 denum = denum * n
1.3.4 return r + num/denum
2. Initialise variables num=1 and denum=1
3. Call the function myExp(3,15)
# Recursive Function to calculate e^x

def myExp(x, n) :
global num, denum #Global variables

if (n == 0) : #Termination condition of the recursion


return 1
r = myExp(x, n - 1) #Recursive call
num = num * x #Calculate the numerator of the nth term
denum = denum * n #Calculate the denominator of the nth term
return (r + num / denum)

#Main program
num = 1.0 # global variable num
denum = 1.0 # global variable denum
x = float(input("Enter value of x: "))
n = int(input("Enter the number of terms to sum: "))
print(f"Using the recursive function: exp({x})=",myExp(x, n))
import math
print(f"Using the math library function: exp({x})=",math.exp(x))

299
Output
Enter value of x: 3
Enter the number of terms to sum: 15
Using the recursive function: exp(3.0)= 20.08553443097081
Using the math library function: exp(3.0)= 20.085536923187668

Program 7.7: Write a function currency2words(currency) that convert the given currency
value (999999999.99) into words using the Indian system.

Solution steps:
1. Read the currency value
2. Separate whole and fraction parts
3. For the whole part, extract numbers at tens (last two digits), hundreds (next one
digit), thousands (next two digits), lakhs ((next two digits) and crores (next two digits).
4. Convert the extracted numbers into words.
5.

# Main Logic
#1 to 9
ones = ('Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven',
'Eight', 'Nine')
#10,11,12,...19
twos = ('Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen',
'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen')
#20,30,40, ...,100
tens = ('Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy',
'Eighty', 'Ninety', 'Hundred')

def getWord99(number): #Convert a two-digit number into words

if number == 0: word = "Zero" #Convert 0 into word


elif number < 10: word = ones[number] #Convert 1 to 9 into words
elif number>=10 and number <=19: word = twos[number-10] #Convert 10
to 19 into words
else:
n=number//10 #Get the digit at the tenth position
word=tens[n-2] #Convert 20, 30, 40... into words. 2 is
subtracted from the digit to adjust the index.

300
r=number%10 #Get digit at unit position
if r > 0:
word=word + "-" + ones[r] #Combine tens and unit position
words
return word

def currency2words(currency): #Convert a number up to 999999999.99 into


words

if currency > 999999999.99 : return "Error: The maximum currency


value permitted is 999999999.99"
whole =int(currency) #Get the whole part of the currency value
fraction =currency-whole #Get the fraction part of the currency
value
fraction = round(fraction*100) #Get the first two digits of the
fraction part

word=""
if whole == 0 : word = "Zero" #If the whole part is zero
else:
teens= whole%100 #Get the last two digits of the whole part
if teens : word= getWord99(teens) #Convert the last two digits
into words

hundreds=whole%1000//100 #Get the digit at the hundred position


if hundreds : word = getWord99(hundreds) + " Hundred " + word

thousands=whole%100000//1000 #Get the two digits at the


thousand position
if thousands : word = getWord99(thousands) + " Thousand " +
word

lakhs=whole%10000000//100000 #Get the two digits at the lakh


position
if lakhs : word = getWord99(lakhs) + " Lakh " + word

crore=whole//100000 #Get the two digits at the crore position


if crore : word = getWord99(lakhs) + " Crore " + word

word1 =getWord99(fraction)
return "Rs " + word + " and " + word1 + " Paisa" #Combine the whole
and fraction parts

#Main program

301
num = float(input("Enter the currency value : "))
print(currency2words(num))

Output
Enter the currency value : 99.23
Rs Ninety-Nine and Twenty-Three Paisa

Enter the currency value : 54236


Rs Fifty-Four Thousand Two Hundred Thirty-Six and Zero Paisa

Enter the currency value : 999999999.99


Rs Ninety-Nine Crore Ninety-Nine Lakh Ninety-Nine Thousand Nine Hundred Ninety-
Nine and Ninety-Nine Paisa

Chapter Summary

1. A function is a self-contained subprogram used to perform a specific task in a


program. A function is also known as subprogram, procedure, routine. A
function takes some data through its arguments, processes them, and returns
results to the calling program.
2. Built-in functions, such as print (), range (), int (), are part of the Python
interpreter, and they do not require importing any module. They are available
in every program.
3. Module functions are defined in modules, and the respective module must be
imported into a program before using these functions.
4. User-defined functions are written by the programmer in the program itself
5. In modular programming, a computer program is divided into separate self-
contained sub-programs (functions).
6. In Python, a function can be defined anywhere in a program, but the function
must be defined before its first use (call). A function can also be defined on the
command prompt.

302
7. In Python, functions support the following types of input parameters:
Positional parameters, Parameters with default values, Keyword arguments,
and a Variable number of parameters.
8. In Python, we can pass any data type, such as float, int, string, list, tuple, dict,
as arguments to a function, and it will be available as the same type in the
function.
9. When a function is defined inside another function, it is called a local or nested
function. A function defined outside any other function is called a global
function and is available throughout the code.
10. The variable's scope refers to the parts of a program where the variable is
accessible, and the lifetime of a variable is the period between the time of
variable creation and its killing.
11. A variable created in a function is a local variable, and its accessibility is limited
to the function codes. A variable declared outside any function is a global
variable, and it is accessible (below the point of definition) throughout the
program and every function
12. In pass-by-value, an independent copy of the argument is passed to the
function. Any changes made to that copy have no impact on the original
argument variable. There are separate memories for the argument and the
parameter variables.
In pass-by-reference, the memory reference of the argument variable is passed
to the function. Any changes made to it in the function are available in the
calling function. In other words, the argument variable and the parameter
variable refer to the same data in the memory.
13. In Python, arguments to a function are passed as pass-by-object-reference. In
the pass-by-object-reference, the behavior of the argument changes with
context. The same argument behaves like pass-by-value or pass-by-reference
depending on the way argument is used in the function or the type of the
argument value.
14. A function may return one or more values to the calling function.
15. When a function calls itself, it is called a recursive function
16. An anonymous function, a function without a name, is created with the lambda
keyword in Python. A lambda function can take any number of arguments but
can have only one expression in its body.

303
17. A generator function generates a series of outputs. The function maintains its
last state and, in the next call, continues from there. In other words, it behaves
like an iterator.

Multiple Choice Questions

1. Which of the following keyword is used to define a user-defined function in


Python?
(a) function
(b) subroutine
(c) def
(d) sub

2. Which of the following is the advantage of using functions in programs?


(a) Reduce duplication of code
(b) modular programming
(c) Reuse of code
(d) All of these

3. Which of the following is returned by a function when there is no return


statement in the function?
(a) NULL
(b) None
(c) void
(d) None of the above

4. Which of the following type of parameters is not supported in a Python function?


(a) Positional parameters
(b) Parameters with default values
(c) Variable number of parameters
(d) None of the above

5. Which of the following is the correct sequence of different types of parameters in


a function definition?
(a) formal arguments, variable number positional arguments, and variable
number keyword arguments.
(b) formal arguments, variable number keyword arguments, and variable
number positional arguments.

304
(c) Arguments can be given in any order
(d) None of the above

6. Which of the following type of object cannot be passed to a function?


(a) Mutable object
(b) Immutable object
(c) Function object
(d) None of the above

7. Which of the following is a correct header definition of a function?


(a) def myFun(a, b, c):
(b) def myFun(a, b, c = 10):
(c) def myFun(a, b=10, c=20):
(d) All of the above

8. Which of the following is an incorrect header definition of a function?


(a) def myFun(a, b, c):
(b) def myFun(a, b, c = 10):
(c) def myFun(a, b=10, c):
(d) None of the above

9. For the function def myFun (a, b, c): print (a, b, c), which of the following is an
incorrect way to call it?
(a) myFun (1, 2, 3)
(b) myFun (*[1, 2, 3])
(c) myFun (1, *(2,3))
(d) None of the above

10. For the function def myFun (a, b, c): print (a, b, c), which of the following is the
correct way to call it?
(a) myFun (a=1, c=3, b=2)
(b) myFun (*[1, 2, 3])
(c) myFun(**{"a":1,"b":2,"c":3}).
(d) All of the above

11. In Python, a function can be defined ______


(a) At the beginning of a program
(b) Outside any other function

305
(c) Inside a function
(d) All of the above

12. A variable defined outside any function is referred as


(a) static
(b) global
(c) public
(d) extern

13. In Python, objects are passed to a function using which of the following
mechanism
(a) pass by value
(b) pass by reference
(c) pass by object reference
(d) None of the above

14. Which of the following object cannot be returned by a function?


(a) Immutable objects
(b) mutable objects
(c) function objects
(d) None of the above

15. In Python, a function can return which of the following?


(a) a single value
(b) multiple values
(c) function objects
(d) all of the above

16. In Python, a lambda function cannot have


(a) multiple expressions
(b) multiple parameters
(c) a function call
(d) None of the above

17. A lambda function can be used with which of the following function?
(a) map
(b) filter
(c) reduce

306
(d) All of the above

18. Which of the following is not true for a generator function in Python?
(a) Can have multiple yield statements
(b) Can have a return statement at the end of the function
(c) Can be used with a for loop
(d) None of the above

19. The command-line arguments are stored in


(a) sys.arg
(b) sys.argv
(c) argv
(d) None of the above

20. What is the output of the following program?

def myFun(a):
a=100
a=50
print(myFun(a))

(a) 50
(b) 100
(c) None
(d) None of the above

21. What is the output of the following program?

def myFun(a):
a=100
a=50
myFun(a)
print(a)

(a) 50
(b) 100
(c) None
(d) None of the above

307
22. What is the output of the following program?

def myFun(x):
global a
a=100
a=50
myFun(a)
print(a)

(a) 50
(b) 100
(c) None
(d) None of the above

23. What is the output of the following program?

x=10
def myFun():
x=x+10
return x

print(myFun()

(a) 10
(b) 20
(c) Error: local variable 'x' referenced before assignment
(d) None of the above

24. What is the output of the following program?

def genFun(end):
i=0
while(i<=end):
yield i
i=i+1
for x in genFun(3):
print(x,end=' ')
(a) 0 1 2

308
(b) 1 2 3
(c) 0 1 2 3
(d) None of the above

25. Which of the following is the correct way to call the following function?

def myFun (a, b, c):


return a*b, b*c, c*a

(a) x=myFun (2, 3, 4)


(b) x, y, z=myFun (2, 3, 4)
(c) x, y, _=myFun (2, 3, 4)
(d) All of the above

Review Questions

1. State whether the following statements are true or false


a. A function is a self-contained subprogram that returns a value to the calling
program.
b. Built-in functions can be used without importing any module.
c. Functions make a program a bit slower.
d. We cannot write the header and the body of a function in the same line.
e. We can pass values to the parameters of a function in any order using
keyword arguments.
f. Python function does not support a variable number of parameters.
g. The default value parameters can be written anywhere in the parameter list.
h. The scope of a local variable is limited to the function where it is created.
i. A local variable created at a deeper indentation cannot be used in lower
indentation codes.
j. There is no mechanism to simultaneously use the local and global variables
with the same name in a function.
k. The local variables are killed automatically on returning from the function.
l. A global variable cannot be killed before the end of the program.
m. In Python, arguments to a function are passed through the pass-by-value
mechanism only.
n. We cannot modify a global variable in a function.
o. A python function can return only one value.

309
p. A Python function always returns a value.
q. We can pass a function as an argument to a function.
r. Python does not support recursive functions.
s. A lambda function can have only one parameter and one expression.
t. A generator function maintains its last state.
u. We can pass arguments to a program at the command line.

2. Describe the advantages and disadvantages of using functions in a program.

3. Draw a flowchart to show the flow of control in function calls.

4. Describe the structure of a function in Python.

5. Describe different types of parameters supported in Python functions.

6. Describe the procedure to write a function with a variable number of arguments.

7. Discuss local and global functions.

8. Discuss the scope and life of variables.

9. Discuss argument passing mechanisms in Python functions

10. What is a recursive function? Describe with an example.

11. Describe a lambda function with an example.

12. Describe a generator function with an example.

13. What are command-line arguments? Discuss.

14. What is the output of the following program?

z= lambda x: (x,2*x)
print(z(2))

15. What is the output of the following program?

z=lambda x: x, 2*x

310
print(z(2))

16. Find the errors in the following program:

x = 10
def f ():
x = x + 10
print(x)
f()

17. Find the errors in the following program:

def f (x = 10, y):


x = x + 10
y = y + 20
print (x + y)
f(5,10)

18. Find the output of the following program:

def myFun(*var):
return sum(var)
print(myFun(1,2,3,4,5))

19. Find the output of the following program:

def myFun(a, b, c):


return a * a + 2 * b + c
print(myFun(c=3,b=2,a=1))

20. Find the output of the following program:

def myFun(x):
while(1):
yield x
x=x+1

311
for a in myFun(2):
print(a)

Programming Assignments

1. Write a Python function to calculate the area of a hexagon with given side length.

2. Write a Python function to find the maximum of three numbers.

3. Write a Python function that takes 2 positive integer values and returns the
highest common factor of the numbers.

4. Write a Python function that takes two numbers as its arguments and returns
sum and multiplication of these numbers.

5. Write a Python function that calculates the compound interest of a given


principal amount, interest and period of investment. If the values of the interest
rate and period of investment is not given, a default values of interest rate = 7%
and period of investment = 5 years should be used.

6. Write a Python function to calculate the factorial of a positive.

7. Write a Python function to calculate nCr. Define an inner factorial function in the
function.

8. Write a recursive function to calculate factorial of a number.

9. Write a Python function to accept three arguments and check whether the last
argument falls within the range of the first two arguments.

10. Write a Python function that accepts a string and counts the number of upper-
case, lower-case letters, digits and other symbols.

11. Write a Python function that returns a new list with distinct elements from the
argument list.

12. Write a Python function to checks whether the given number is prime or not.

312
13. Write a Python function that returns all the prime numbers between a given
range.

14. Write a Python function to check whether a number is "Perfect" or not. A perfect
number is a positive integer that is equal to the sum of its factors excluding the
number itself.

15. Write a Python function that checks whether a given word is a palindrome or
not. A palindrome is a word that reads the same backward as forward, e.g.,
madam.

16. Write a Python function to check whether a given string is a pangram or not. A
pangram is a string that contains every letter of the alphabet at least once. For
example: "The quick brown fox jumps over the lazy dog.". It may contain other
symbols also.

17. Write a Python function that accepts variable number of arguments and find
their average.

18. Write a Python function that takes a string and check whether the given string is
a valid email address without using any library. Use the following check rules:
• Must contain at least 1 character before the @ symbol
• Must contain an @ symbol
• Must have at-least 1 character after the @ symbol and before the period(.)
• Must contain at least 1 character after the last period(.).
• Maximum 256 characters
• Must start with a letter or a number

313
314
Chapter 8

Lists
Learning Outcomes

1. Understand lists in Python.


2. Create and manipulate items in lists.
3. Describe Indexing and slicing in lists.
4. Describe list methods.
5. Discuss list comprehension.
6. Use lists to create matrices and arrays

A list is a built-in data structure used to store several Python objects, for example, list1=
[1, 2, 3, 4]. The individual item of a list can be of different types, for example, list2= [1,
"Python", [1,2,3], (4,5,6)], which consists of an integer, a string, a list, and a tuple. A list of
lists is called a nested list, for example, [ [1,2,3], [4,5,6], [7,8] ]. Since a list is an ordered
sequence of items, individual items can be accessed with an index. For example, list2[1] will
return the second element of the list, i.e., "Python". In Python, the index starts with zero,
i.e., the index of the first element of a list is 0. A list is dynamic and mutable in nature, as
items in the list can be inserted, deleted, and modified at any time in the program.

8.1 List Creation


Lists can be created in the following ways: lists from data, converting other sequence
data into lists, and list comprehension.

8.1.1 Lists from Data

Putting data/expressions separated by commas within a pair of square brackets


creates a list. The items of a list can be homogeneous, i.e., of the same data types, or
heterogeneous, i.e., of different data types. Items can also be expressions, which are
evaluated, and the results are stored in the list. A list can be an empty list, i.e., there is no
item in the list. Example 8.1(a) illustrates the creation of a few lists from data.

315
Example 8.1(a): Lists from data

>>> list1=[1,2,3,4] #Creating a list of homogeneous items


>>> print(list1, type(list1))
[1, 2, 3, 4] <class 'list'>
>>> list2=[] #Creating an empty list
>>> print(list2)
[]
>>> #Create a list with heterogeneous items
>>> list4=[1,2.25, 3+4j,"Four", None, False]
>>> print(list4)
[1, 2.25, (3+4j), 'Four', None, False]
>>> #Creating a list with lists, tuples, sets, etc. as items
>>> list5=[1,[2,3,4],(5,6,7),{1,2,3},{1:"One",2:"Two"}]
>>> print(list5)
[1, [2, 3, 4], (5, 6, 7), {1, 2, 3}, {1: 'One', 2: 'Two'}]
>>> list6=[1+2,3+4,5*6] #List items can be expressions
>>> print(list6)
[3, 7, 30]

8.1.2 Converting other Data Types to Lists

The built-in list () function converts sequence data, such as a string, a tuple, a range,
a set, into a list. The syntax of the function is as given below:

list_var=list(sequence)

where sequence is any iterable data or variable, such as a string, a tuple, a list, a set, a
dictionary, a range. When a string is passed to a list function, it returns a list of its characters.
When a tuple is passed as the argument of a list function, the function returns a list of its
items/elements. When a dictionary object is passed to a list function, the function returns a
list of the keys of the dictionary object, and the values are ignored. If we pass non-iterable
data, such as an integer, a float, a complex, an error is generated. For example, the

316
expression list(10) generates TypeError: 'int' object is not iterable. Example 8.1(b)
illustrates the list () function to convert the various types of iterable objects into lists.

Example 8.1(b): Convert the various types of iterable objects into lists

>>> string="Python"
>>> list1=list(string) #Convert a string into a list of its characters
>>> print(list1)
['P', 'y', 't', 'h', 'o', 'n']
>>> tuple1=(1,2,3)
>>> list2=list(tuple1) #Convert a tuple into a list
>>> print(list2)
[1, 2, 3]
>>> set1={1,2,3,4,1} #Convert a set into a list
>>> list1=list(set1)
>>> print(list1)
[1, 2, 3, 4]
>>> dict1={1:"One",2:"Two"} #Convert a dictionary into a list of its
keys
>>> list1=list(dict1)
>>> print(list1)
[1, 2]
>>> range1=range(1,5)
>>> list1=list(range1) #Convert a range object into a list
>>> print(list1)
[1, 2, 3, 4]
>>> list1=list(["One", "Two", "Three"]) #Convert a list into a list
>>> print(list1)
['One', 'Two', 'Three']
>>> c=2+3j
>>> c
(2+3j)

317
>>> list(c) #Error: cannot pass atomic data
Traceback (most recent call last):
File "<pyshell#37>", line 1, in <module>
list(c)
TypeError: 'complex' object is not iterable
>>>

8.1.3 List Comprehension to Create a New List

List comprehension is a concise way to construct a new list by selecting some


elements from an already defined sequence, such as creating a list of the even numbers from
a list of numbers. Such a list can be created using a for loop and a conditional expression,
as shown in example 8.1(c). However, the same can be achieved through the list
comprehension in a more compact form, as shown in example 8.1(d). Following is the
syntax of the list comprehension:

output_list = [exp_x for x in input_seq if (x_condition)]

where input_seq is the original collection of items, exp_x is an expression of x. The value of
exp_x is added to the new output_list only if the conditional expression x-condition
evaluates to true. The if condition block is optional. If it is not specified, then the values of
exp_x corresponding to all the elements of input_seq will be added to the output_list. In
example 8.1(e), a list is generated containing the squares of the elements of the given list.

Example 8.1(c): Selecting some elements from a list

list1=[1,2,3,4,5,6,7,8,9,10] #Given list


list2=[]
for x in list1:
if x%2==0:
list2.append(x)
print(list2)#List of even numbers
Output
[2, 4, 6, 8, 10]

318
Example 8.1(d): Selecting some elements from a list using the list comprehension

list1=[1,2,3,4,5,6,7,8,9,10]#The given list


list2=[x for x in list1 if x%2==0] #List comprehension
print(list2)
Output
[2, 4, 6, 8, 10]

Example 8.1(e): Generating a list consisting of the squares of the elements of a list

list1=[1,-2,3,-4,5] #Given list


#List consisting of the square of the elements of the given list
list2=[x*x for x in list1] #List comprehension
print(list2)
Output
[1, 4, 9, 16, 25]

The list comprehension can be used with other sequence data also. Example 8.1(f)
shows list comprehensions with different types of sequence data.

Example 8.1(f): List comprehensions with various sequences

#Generate a list of the ASCII codes of the characters of a string


string="Python"
list2=[ord(ch) for ch in string] # ord(ch) returns ASCII code of ch
print("A list from a string:", list2)

#Generate list of even numbers divisible by 5 upto 50

319
list3=[x for x in range(50) if x%2==0 and x%5==0]
print("A list from a range:", list3)

#Convert a tuple into a list using the list comprehension


tuple1=(1,4,2,5)
list4=[x for x in tuple1]
print("A list from a tuple:",list4)

#Convert a set into a list using the list comprehension


set1={1,2,6,5}
list5=[x for x in set1 if x%2==0]
print("A list from a set:",list5)

#Convert a dictionary into a list of key-value pair


dict1={1:"One",2:"Two"}
list6=[[k,dict1[k]] for k in dict1]
print("A list from a dictionary",list6)

Output
A list from a string: [80, 121, 116, 104, 111, 110]
A list from a range: [0, 10, 20, 30, 40]
A list from a tuple: [1, 4, 2, 5]
A list from a set: [2, 6]
A list from a dictionary [[1, 'One'], [2, 'Two']]

8.1.4 Split a String into a List of Words

A string can be split into a list of its word using the split method of the str object.
For example, the expression "I love Python".split() evaluates to a list ['I', 'love', 'Python'].
Example 8.1(g) reads a string from the keyboard and counts the number of words in it.

320
Example 8.1(g): Count the number of words in a text

#Count number of word in a string


s=input("Enter the string:")
a=s.split() #Split the string into a list of words
print("The number of words in the string is:", len(a))

Output
Enter the string:I love Python Programming. It is very simple but
powerful.
The number of words in the string is: 10

8.2 Accessing an Element of a List


An element of a list can be accessed through an index. Each element of a list has a
unique index. The index of the first element is 0, of the second element is 1, and so on. The
elements of a list can also be accessed backward from the end of the list by using a negative
index value. In the backward indexing, the index of the last element of a list is -1, of the
second last element is -2, and so on. Figure 8.1 shows the forward and backward indexing
for a list.

Forward index 0 1 2 3 4
List 10 20 30 40 50
Backward index -5 -4 -3 -2 -1

Figure 8.1: Forward and backward indexing of a list

The syntax of accessing an element of a list is as given below:

List_object[index]

321
Where List_object is a list object and index is an integer. If the index is a positive integer,
forward indexing is used; otherwise, backward indexing is used. Example 8.2(a) shows how
an element of a list is accessed. The number of elements in a list is obtained by the built-in
function len(list_obj). The maximum value of the valid index value is equal to
len(list_object) -1.

Example 8.2(a): Accessing list items

>>> list1=[10,20,30,40,50]
>>> list1[0] #Accessing the first element of a list
10
>>> list1[1] #Accessing the second element of a list
20
>>> list1[-1] #Accessing the last element of a list
50
>>> list1[-2] #Accessing the second last element of a list
40
>>> list1[-5] #Accessing the first element of a list
10
>>> list1[4] #Accessing the last element of a list
50
>>> list1[5] #Error: trying to access out of the range of a list
Traceback (most recent call last):
File "<pyshell#45>", line 1, in <module>
list1[5]
IndexError: list index out of range
>>> len(list1) #Number of elements in the list
5

8.2.1 List Traversal

322
We can traverse each element of a list using a for loop. Items are returned in
sequence from the list. In example 8.2(b), a list of numbers is traversed from the beginning
to the end, and the square of each number is printed in the console.

Example 8.2(b): Traversing list items

list1=[1,5,2,6,8,7]
for item in list1: #Traversing a list
print( f"The square of {item} = {item*item}")
Output
The square of 1 = 1
The square of 5 = 25
The square of 2 = 4
The square of 6 = 36
The square of 8 = 64
The square of 7 = 49

We can traverse a list in the reverse order by first reversing the list and then
traversing it. Example 8.2(c) illustrates the reverse traversal of a list.

Example 8.2(c): Reverse traversal of list items

list1=[1,5,2,6,8,7]
list1.reverse() #Reversing the order of list items
for item in list1: #Traversing a list
print( f"The square of {item} = {item*item}")
Output
The square of 7 = 49
The square of 8 = 64
The square of 6 = 36
The square of 2 = 4
The square of 5 = 25

323
The square of 1 = 1

We can also use a while loop to traverse a list. Example 8.2(d) illustrates the
traversal of a list using a while loop.

Example 8.2(d): Traversing list items using a while loop

list1=[1,5,2,6,8,7]
index=0 #Initialising index
while index < len(list1): #Traversing a list
print( f"The square of {list1[index]}={list1[index]*list1[index]}")
index+=1 #Incrementing index
Output
The square of 1 = 1
The square of 5 = 25
The square of 2 = 4
The square of 6 = 36
The square of 8 = 64
The square of 7 = 49

8.3 List Slicing


An index is used to get an individual element of a list. But, to get a sub-list of a list,
we use list slicing. The list slicing returns a sub-list but does not change the original list. We
use the slice operator to slice a list. The syntax of the slice operator, which has three
parameters, is as given below:

List_object [start_index: end_index: step_size]

Where List_object is a list, the slice starts from the start_index and ends at the end_index
with a step size of step_size. All the parameters are optional. If start_index is not specified,
zero is assumed. If end_index is not specified, the end index of the list is assumed. And if
step_size is not specified, a step size of 1 is used. Negative indices are allowed. If the

324
end_index cannot be reached from the start_index using the specified step_size, an empty
list is returned. Further, if the specified range is outside the size of the specified list, the
extra range is ignored. For example, for a list with ten elements, any end_index value
greater or equal to 10 is ignored. Similarly, any start_index value equal to -10 or less is
ignored. Example 8.3(a) illustrates various ways in which a slice operator can be used.

Example 8.3(a): List slicing

>>> list1=[1,2,3,4,5,6,7,8,9,10] #Initial list


>>> list1[2:7] #Sub-list from the third element to the seventh element
[3, 4, 5, 6, 7]
>>> list1[:7] #Sub-list from the start up to the seventh element
[1, 2, 3, 4, 5, 6, 7]
>>> list1[4:] #Sub-list from the fifth element to the end of the list
[5, 6, 7, 8, 9, 10]
>>> list1[:]#Sub-list from the start to the end
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> #Sub-list from the third element up to the ninth element, skipping
>>> alternate elements
>>> list1[2:9:2] #step size of 2
[3, 5, 7, 9]
>>> list1[::2] #Alternate elements from the start to the end of the
list
[1, 3, 5, 7, 9]
>>> #An empty list, as with step = 1, we cannot reach from -1 to -6
>>> list1[-1:-6]
[]
>>> # Sub-list starting from the end up to the 6th element from the end
>>> list1[-1:-6:-1] # Step size = -1
[10, 9, 8, 7, 6]
>>> list1[::]# All the elements from the start to the end of the list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

325
>>> #Sub-list from the start to the 5th from the end of the list
>>> list1[:-5]
[1, 2, 3, 4, 5]
>>> #Sub-list from the 5th from the end up to the end of the list
>>> list1[-5:] [6, 7, 8, 9, 10]
>>> list1[::-1]# All the elements in the reverse order of the list
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> a[-30:] #The start_index is out of range, in the lower side
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> #Start_index =-1. It means the last element of a list and the
default end-index is also the last element. Hence the last element.
>>> a[-1:]
[10]
>>> #The start_index and end_index both are more than the maximum
possible index value, i.e., 9. Hence an empty list.
>>> a[10:20] # This returns a blank list
[]
>>> a[-10:10] #Equal to a[0:10]as start index =-10 is equal to 0
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[-20:10] #Equivalent to a[0:10],i.e., an index < -10 is ignored.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[0:20] #Equivalent to a[0:10], i.e. index > 9 is ignored.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

8.3.1 Traversing Sliced List

Similar to the list traversal, we can traverse sliced list using a for loop. Example
8.3(b) illustrates traversing a list slice.

326
Example 8.3(b): Traversing a sliced list

list1=[1,5,2,6,8,7]
for x in list1[2:4]: #Traversing a sliced list
print(f"{x}:{x*x}", end=',')
print("\Traversing in reverse order")
for x in list1[-1:0:-1]: #Traversing in reverse order
print(f"{x}:{x*x}", end=',')
Output
2:4,6:36,
Traversing in reverse order
7:49,8:64,6:36,2:4,5:25,

8.4 Commonly used Built-in Function for Lists


Table 8.1 lists some commonly used built-in functions used with lists, with a brief
description of each. The functions max() and min() accept only a homogeneous list of real
numbers, strings, lists, sets, or dicts. For a list of real numbers, the maximum and the
minimum is based on the values of the numbers in the list.

For a list of strings, strings are compared in the alphabetic order, letter-by-letter from
the beginning, based on their ASCII values/ Unicode values. For example, in "abc" and
"abd", the second string is larger than the first string as "d" has a higher ASCII value (100)
than that of "c" (99). Also, note, up to the first two characters, both the strings are the same.
Hence they are differentiated based on the third character. Similarly, "Acd" is smaller than
"abc", as the ASCII value of "A" is 65 and that of "a" is 97. Strings are compared based on
the first mismatching character. Example 8.4(a) illustrates the use of the functions listed in
Table 8.1.

327
Table 8.1: Commonly used built-in function for lists

Function Description

len It returns the number of elements of a list.

max It returns the maximum value of a list consisting of homogeneous data only,
i.e., all real numeric elements or all string elements. For a heterogeneous list
or a list of iterables, we have to specify the second parameter of the function,
i.e., key.

min It returns the minimum value of a list consisting of homogeneous data only.
Similar to the max() function, for a heterogeneous list or a list of iterables,
we must specify the function's second parameter, i.e., key.

sum It returns the sum of all the list elements consisting of only numeric data,
both real and complex. If the list contains non-numeric data, an error is
raised.

Example 8.4(a): Built-in functions used with lists

>>> list1=[1,2,3,4,5] #List of numbers


>>> list2=["a","b","A","B"] #List of characters
>>> list3=["Abc","abc","abd"] #List of strings
>>> #Calculate the count of elements in lists
>>> print(len(list1),len(list2),len(list3))
5 4 3
>>> print(max(list1),max(list2),max(list3)) #Maximum of a list
5 b abd
>>> print(min(list1),min(list2),min(list3)) #Minimum of a list
1 A Abc

328
>>> print(sum(list1)) #Sum of all the elements of a numeric list
15
>>> print(sum(list2)) #Error: sum is not defined for non-numeric lists
Traceback (most recent call last):
File "<pyshell#14>", line 1, in <module>
print(sum(list2))
TypeError: unsupported operand type(s) for +: 'int' and 'str'
>>> list4=[{1:"One",2:"Two"},{3:"Three",4:"Four"}] #List of
dictionaries
>>> len(list4)
2
>>> max(list4) # Error: Max is defined only for numeric and string
lists
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
max(list4)
TypeError: '>' not supported between instances of 'dict' and 'dict'
>>> list5=[True, False, 1,2] #True and False are considered as numeric
>>> len(list5)
4
>>> max(list5)
2
>>> sum(list5) #True=1 and False=0 is used in calculations
4
>>> list6=[True, False, 1,2, None] #Heterogeneous list
>>> len(list6)
5
>>> max(list6) #Error: max not defined for heterogeneous lists
Traceback (most recent call last):
File "<pyshell#21>", line 1, in <module>
max(list6)

329
TypeError: '>' not supported between instances of 'NoneType' and 'int'
list7=[1,2,"Three",4,5] #Heterogeneous list
>>> max(list7) #Error: max, min and sum are not defined for
heterogeneous lists
Traceback (most recent call last):
File "<pyshell#27>", line 1, in <module>
max(list7)
TypeError: '>' not supported between instances of 'str' and 'int'

8.4.1 The max() and min () Functions for a List of Lists or Iterables

For a list of iterables, such as lists, tuples, we have to specify the second parameter
of the max() and min () functions, i.e., key. The parameter key accepts a function that
processes each inner list and returns a numeric or string value. These values are used to
decide the maximum or minimum of the outer list. For example, max( [[1, 8, 3],[4, 0, 6],[7, 2,
6]], key=sum) returns [7, 2, 6] as the sum of the elements of [7, 2, 6] is the maximum out of
the three inner lists. Here, the sum of each sublist is computed first and then max() is
applied. Similarly, max( [[1, 8, 3],[4, 0, 6],[7, 2, 6]], key=max) returns [1, 8, 3] as the
maximum value in [1, 8, 3] is the maximum of the three inner lists. Similarly, min( [[1, 8,
3],[4, 0, 6],[7, 2, 6]], key=sum) returns [4, 0, 6], as the sum of the elements of [4, 0, 6] is the
minimum out of the three inner lists.

The key parameter can also accept a user-defined function. For example, max( [[1, 8,
13],[4, 10, 6],[7, 2, 0]], key=lambda x: x[0]) returns [7, 2, 0] as the user-defined lambda
function returns the first element of each inner list. Similarly, min(["adc","abc","aBc"], key=
lambda x : x[1]) returns 'aBc', as the lambda function returns the second character of each
string, and 'B' is the smallest out of the second characters, 'd', 'b' and 'B'. The above concept
is valid for the list of tuples, sets, dictionaries, and other iterables. Example 8.4(b) illustrates
the above concept.

Example 8.4(b): The max() and min() functions with nested lists and lists of iterables

>>> list1=[[1,0,10],[5,4,7],[5,6,4]] #A nested list


>>> max(list1,key=sum) #The maximum based on the sum of elements
[5, 4, 7]

330
>>> max(list1,key=max) #The maximum based on the maximum of elements
[1, 0, 10]
>>> max(list1,key=min) #The maximum based on the minimum of elements
[5, 4, 7]
>>> max(list1,key=lambda x : x[2]) #The maximum based on the third
element of each sub list
[1, 0, 10]
>>> min(list1,key=sum) #The minimum based on the sum of elements
[1, 0, 10]
>>> min(list1,key=min) #The minimum based on the minimum of elements
[1, 0, 10]
>>> min(list1,key=max) #The minimum based on the maximum of elements
[5, 6, 4]
>>> min(list1,key=lambda x : x[2]) #The minimum based on the third
element of each sub list
[5, 6, 4]
>>> list2=[(4,2,6),(8,1,5),(3,7,9)] #A list of tuples
>>> max(list2, key=sum) #The maximum based on the sum of elements
(3, 7, 9)
>>> min(list2, key=sum) #The minimum based on the sum of elements
(4, 2, 6)
>>> list3=[{4,2,6},{8,1,5},{3,7,9}] #A list of sets
>>> min(list3, key=sum) #The minimum based on the sum of elements
{2, 4, 6}
>>> list4=[range(5),range(3,6),range(10)] #A list of ranges
>>> max(list4, key=sum) #The maximum based on the sum of elements
range(0, 10)
>>> list5=[(4,2,6),{8,1,5},[3,7,9]] #A list of heterogeneous iterators
>>> max(list5, key=sum) #The maximum based on the sum of elements
[3, 7, 9]

331
8.4.2 The max () and min () Functions with a List of Complex Numbers

Similar to the list of iterators, the max() and min() functions also require the key
parameter to handle a list of complex numbers. Without the key parameter, these functions
raise an error. A list of complex numbers can be compared based on their absolute values,
real parts, imaginary parts, or any other user-defined function. For example, max([2+3j, 4-
2j, 3+4j], key =abs) returns (3+4j), based on the absolute values of the complex numbers.
Example 8.4(c) illustrates the above.

Example 8.4(c): The max() and min() functions with lists of complex numbers

>>> #The maximum of a list of complex numbers based on the absolute


value
>>> max([2+3j, 4-2j, 3+4j], key =abs)
(3+4j)
>>> #The maximum of a list of complex numbers based on the real part
value
>>> max([2+3j, 4-2j, 3+4j], key =lambda x: x.real)
(4-2j)
>>> #The maximum of a list of complex numbers based on the imaginary
part value
>>> max([2+3j, 4-2j, 3+4j], key =lambda x: x.imag)
(3+4j)
>>> #The maximum of a list of complex numbers based on a user defined
function
>>> max([2+3j, 4-2j, 3+4j], key =lambda x: abs(x.real-x.imag))
(4-2j)

8.5 Creating Copies of a List


We frequently require to copy a list to another list to duplicate the list or modify/edit
or give another name to the original list. A list can be copied into another list at three levels
332
in Python: reference copy, shallow copy, and deep copy. Figure 8.2 shows the memory
model of various types of copy mechanisms for the list [1, 2, [3, 4, 5], 6], where R1, R2, R3,
R4, and R5 are the memory references of the lists and the nested elements.

• In the reference copy, the same memory references are used by the original list and
the copied list.
• In the shallow copy, the original and the copied lists use different memory
references, but their nested elements use the same memory references.
• In the deep copy, the original list and the copied list use different memory
references. The nested elements also use separate memory references.

Example 8.5(a) illustrates these concepts. Notice the IDs of the lists and nested lists.

R1
Original List 1 2 R2 6

R2
Reference Copied List
3 4 5
R3
Shallow Copied List 1 2 R2 6

Deep Copied List


R4
1 2 R5 6

R5
3 4 5

Figure 8.2: Memory model of reference, shallow and deep copy of a list

333
Example 8.5(a): Various methods to copy a list

>>> list1=[1,2,[3,4,5],6] #Original list


>>> list2=list1 #Reference copy
>>> list3=list1.copy() #Shallow copy
>>> import copy
>>> list4=copy.deepcopy(list1) #Deep Copy

>>> #Id of the list copied using the reference is same as that of
>>> #the original list but different for the shallow and deep copies.
>>> print(id(list1),id(list2),id(list3), id(list4))
2406062644096 2406062644096 2406103484224 2406103483712
>>> #Ids of a nested elements are same for reference and shallow copies
>>> #but different for a deep copy
>>> print(id(list1[2]),id(list2[2]),id(list3[2]), id(list4[2]))
2406071688256 2406071688256 2406071688256 2406103483520

8.5.1 Reference Copy

In a reference copy of a list, the copied list is an alias of the original list. Both the lists
refer to the same memory object. Any modification, addition, or deletion in the original list
is also reflected in the copied list and vice versa. A reference copy is created by using the =
operator (assignment). However, if we assign new data to the original list or the copied list,
the other list is unaffected. Hence, the reference copy should be used with care. Example
8.5(b) illustrates the above.

Example 8.5(b): Copy of a list using the reference copy

>>> list1=[1,2,3,4] #Original list


>>> list2=list1 #Aliasing a list. Both lists refer to [1,2,3,4]
>>> print(list1, list2)
[1, 2, 3, 4] [1, 2, 3, 4]
>>> list1[0]=5 #Editing the list elements

334
>>> print(list1,list2) #Changes are reflected to both.
[5, 2, 3, 4] [5, 2, 3, 4]
>>> list2=[1,2] #Assigning a new list will not affect the other list
>>> print(list1,list2)
[5, 2, 3, 4] [1, 2]

>>> list3=[[1,2],[3,4]] #Creating a nested list


>>> list4=list3 #Copy a nested list
>>> print(list3,list4)
[[1, 2], [3, 4]] [[1, 2], [3, 4]]
>>> #Editing an element will change the other list also
>>> list4[0][0]="Python"
>>> print(list3,list4)
[['Python', 2], [3, 4]] [['Python', 2], [3, 4]]
>>> list4[0]=(1,2) #Editing an element will change other list also
>>> print(list3,list4)
[(1, 2), [3, 4]] [(1, 2), [3, 4]]

>>> list5=[1,2,3] #Original list


>>> list6=list5 #Copied list
>>> print(list5,list6)
[1, 2, 3] [1, 2, 3]
>>> list5.append(4) #Elements appended to both the lists
>>> print(list5,list6)
[1, 2, 3, 4] [1, 2, 3, 4]
>>> list6.remove(1) # Elements removed from the both lists
>>> print(list5,list6)
[2, 3, 4] [2, 3, 4]
>>> list5.reverse() #Both the lists are reversed
>>> print(list5,list6)
[4, 3, 2] [4, 3, 2]

335
8.5.2 Shallow Copy

In the shallow copy of a list, the atomic items (such as integers and floats) and string
items are duplicated in the copied list, but collection items (such as lists, tuples, sets, and
dictionaries) are not duplicated, and their references are added. In other words, a new
memory is allocated to the new list in the shallow copy, but no separate memory is assigned
to the nested objects; only their references are added to the new list. Any change in a nested
object in the original list will also appear in the copied list. However, the changes in the
non-nested elements in one list do not affect the other list. Also, adding a new element
(either nested or non-nested) in one list does not affect the other. A shallow copy is created
using the copy method of the list or the copy method of the copy module. Example 8.5(c)
illustrates the behavior of shallow copies.

Example 8.5(c): Shallow copy of a list

>>> list1=[1,2,3] #List of non-nested elements


>>> list2=list1.copy() #Shallow copy. Separate memory is allocated.
>>> print(list1,list2)
[1, 2, 3] [1, 2, 3]

>>> #Any change in a non-nested element does not affect the copied list
>>> list2[0]=10
>>> print(list1,list2)
[1, 2, 3] [10, 2, 3]

>>> list3=[1,[2,3,4]] #A nested list, i.e., lists inside a list.


>>> list4=list3.copy()# Shallow copy
>>> print(list3,list4)
[1, [2, 3, 4]] [1, [2, 3, 4]]
>>> list4[0]=10 #Change in a non-nested element does not affect the
copied list
>>> print(list3,list4)
[1, [2, 3, 4]] [10, [2, 3, 4]]

336
>>> list4[1].append(10)# Changes in a nested element affect the other
list
>>> print(list3,list4)
[1, [2, 3, 4, 10]] [10, [2, 3, 4, 10]]
>>> #A new assignment to a nested element does not affect the other
list.
>>> list4[1]=[1,2]
>>> print(list3,list4)
[1, [2, 3, 4, 10]] [10, [1, 2]]

>>> list5=[1,[2,3,4]]
>>> list6=list5.copy()
>>> print(list5,list6)
[1, [2, 3, 4]] [1, [2, 3, 4]]
>>> #Appending an element does not affect the other list
>>> list5.append((5,6))
>>> print(list5,list6)
[1, [2, 3, 4], (5, 6)] [1, [2, 3, 4]]
>>> #Appending an element does not affect the other list
>>> list6.append([8,9])
>>> print(list5,list6)
[1, [2, 3, 4], (5, 6)] [1, [2, 3, 4], [8, 9]]
>>> list6.remove(1) #Removing an element does not affect the other list
>>> print(list5,list6)
[1, [2, 3, 4], (5, 6)] [[2, 3, 4], [8, 9]]
>>> #Removing an element does not affect the other list
>>> list6.remove([2,3,4])
>>> print(list5,list6)
[1, [2, 3, 4], (5, 6)] [[8, 9]]
>>>

337
8.5.3 Deep Copy

In a deep copy of a list, a completely independent copy of the original list is created.
All the nested elements are also duplicated in the new list and have their separate memory.
Once created, there is no link between the original list and the new list. Any change made
in one list does not affect the other. For the deep copy, we use the deepcopy method of the
copy module. Example 8.5(d) illustrates the above.

Example 8.5(d): Deep copy of a list

>>> import copy


>>> list1=[1,2,[3,4,5]] #Original list
>>> list2=copy.deepcopy(list1) #Deep copy
>>> print(list1,list2)
[1, 2, [3, 4, 5]] [1, 2, [3, 4, 5]]
>>> list2[0]=10 #Change the copied list
>>> list2[2].append(6) #Appending an element to the copied list
>>> print(list1,list2) #No effect of editing on the original list
[1, 2, [3, 4, 5]] [10, 2, [3, 4, 5, 6]]
>>> list2.remove(2) #Removing an element
>>> print(list1,list2) #No effect of remove on the original list
[1, 2, [3, 4, 5]] [10, [3, 4, 5, 6]]
>>>

8.6 Methods of the List Class


The list class has several built-in methods for performing common tasks, such as
appending new items, removing existing elements, sorting. Table 8.2 briefly describes some
list methods. The lists used to describe these methods are A=[3,2,4,2,1] and B=[7,8]. Each
method is explained with the original lists. Example 8.6 illustrates some of these methods.

338
Table 8.2: List methods

Method Description

append(value) Adds value as an element at the end of the list. For example,
print(A.append(10)) results in [3, 2, 4, 2, 1, 10].

clear() Removes all the elements from the list. For example,
print(A.clear()) results in [].

copy() Creates a shallow copy of the list. For example, C= A.copy();


print(C) results in [3,2,4,2,1].

count(value) Finds the number of occurrences of the specified value in the list.
For example, print( A.count(2)) results in 2.

extend(iterable) Adds each element of iterable at the end of the list as a separate
item. For example, A.extend(B); print(A) results in [3, 2, 4, 2, 1, 7,
8]

index(value) Returns the index of the first match of value in the list. For example,
print(A.index(4)) results in 2. If the specified value is not in the list,
a ValueError is generated.

insert(index, value) Adds the value as an element at the index position in the list. For
example, A.insert(1,20); print(A) results in [3, 20, 2, 4, 2, 1]. If the
index is more than the count of the list, the value is appended at the
end of the list. For example, A.insert(10,100); print(A) result in [3,
20, 2, 4, 2, 1, 100].

pop(index) Removes and returns the element at index position in the list. For
example, A.pop(2) results in 4, and the new A is [3, 2, 2, 1]. If the
specified index is more than the list length, an out-of-range error is
generated.

remove(value) Removes the first match of value from the list. For example,
A.remove(4); print(A) results in [3, 2, 2, 1]. If value is not in the list,
an error is raised.

339
reverse() Reverses the order of the list elements, i.e., the first element
becomes the last and vice versa. For example, A.reverse(); print(A)
results in [1, 2, 4, 2, 3].

sort() Sorts the elements of the list in ascending order. For example,
A.sort(); print(A) results in [1, 2, 2, 3, 4].

Example 8.6: Various methods of the list object

>>> list1=[1,2,3] #Original list


>>> list1.append(4)
>>> print(list1)#Appended list
[1, 2, 3, 4]
>>> list1.clear()
>>> print(list1)#Cleared list
[]

>>> list1=[1,2,3] #Original list


>>> list2=list1.copy()
>>> print(list1,list2) #Original and copied lists
[1, 2, 3] [1, 2, 3]
>>> print(list1.count(2)) #Count the number of 2 in the list
1
>>> list1.extend([4,5,6])
>>> print(list1) #Extended list
[1, 2, 3, 4, 5, 6]
>>> #The index of the first occurrence of 4 in the list
>>> print(list1.index(4))
3
>>> list1.index(100) #Value error
Traceback (most recent call last):

340
File "<pyshell#62>", line 1, in <module>
list1.index(100)
ValueError: 100 is not in list
>>> list1.insert(3,20) #insert 20 at index 3 in the list
>>> print(list1)
[1, 2, 3, 20, 4, 5, 6, 3]
>>> a=list1.pop(3) #Return the value of the element at index 3
>>> print(a)
20
>>> list1.pop(12) #Error, the specified index is out of range
Traceback (most recent call last):
File "<pyshell#59>", line 1, in <module>
list1.pop(12)
IndexError: pop index out of range
>>> list1.remove(4) #Remove the first occurrence of 4 from the list
>>> print(list1)
[1, 2, 3, 5, 6, 3]
>>> list1.reverse() #Reverse the list
>>> print(list1)
[3, 6, 5, 3, 2, 1]
>>> list1.sort() #Arrange the list in ascending order
>>> print(list1)
[1, 2, 3, 3, 5, 6]
>>>

8.7 Random Reshuffle of the Elements of a List


The random reshuffle of a list means placing the elements of the list at random
positions in the list. The following are the commonly used method to shuffle elements of a
list randomly:

341
(a) Using the random.shuffle method: The shuffle () method of the random module
shuffles the list elements in place, and the original list order is lost. Example 8.7(a) illustrates
the same.

(b) Using the random.sample method: The sample () method of the random module
returns a new list with shuffled elements, and keeps the original list order intact. The
sample () method takes two parameters: (1) the original list, and (2) the number of elements
to randomly draw from the original list, and returns the shuffled list. Example 8.7(b)
illustrates the above.

Example 8.7(a): Shuffle a list in place

>>> import random #Importing random library


>>> list1=[1,2,3,4,5,6,7,8,9,10]#Original list
>>> random.shuffle(list1) #shuffling the list
>>> print(list1)
[3, 10, 2, 9, 6, 7, 8, 1, 5, 4]
>>>

Example 8.7(b): Sampling a list to generate a shuffled list

>>> import random #Importing random library


>>> list1=[1,2,3,4,5,6,7,8,9,10]#Original list
>>> list2=random.sample(list1, len(list1)) #Random sampling
>>> print(list1) #Original list
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> print(list2) #Shuffled list
[3, 5, 2, 4, 10, 9, 1, 7, 8, 6]
>>> list3=random.sample(list1, 5)#Randomly select 5 elements from list1
>>> list3 #Sampled list
[6, 1, 8, 7, 9]

342
8.8 Using a List as a Matrix and an Array
A matrix is a rectangular arrangement of data or numbers. The horizontal entries in
a matrix are called rows, and the vertical entries are called columns. The size of a matrix is
specified as r x c, where r is the number of rows, and c is the number of columns. When the
number of dimensions of a grid of data is more than two, it is called an n-dimensional array
or simply an array. A matrix is a special case of it, with only two dimensions.

Python does not have built-in data structures for matrices and arrays, but lists can
be used to implement the concepts of matrices and arrays. The ability of a list to contain
another list as its elements is used to implement matrices and arrays. Further, Python has a
powerful module called NumPy(see chapter 14) to efficiently create and manipulate
matrices and arrays. However, in this section, we will discuss how lists are used to create
and process matrices and arrays.

8.8.1 Creating a Matrix from Data

A matrix is created as a nested list. The inner lists store the rows of a matrix. For
1 2 3
example, the list [ [1, 2, 3], [4, 5, 6], [7, 8, 9]] stores the following matrix: [ 4 5 6]. Example
7 8 9
8.8(a) shows how to create this matrix and perform some simple matrix operations. Figure
8.3 shows the memory model of how a matrix is constructed using lists:

Example 8.8(a): Creating a matrix from data

matrix=[]#Initialise matrix with a blank list


matrix.append([1,2,3])#Append a row
matrix.append([4,5,6])#Append a row
matrix.append([7,8,9])#Append a row
print(matrix)#Print the matrix as a list
#The above matrix can also be created directly.
matrix =[ [1, 2, 3], [4, 5, 6], [7, 8, 9]]
print("Diagonal elements of the matrix:")
for i in range(len(matrix)): #Print the diagonal
print(matrix[i][i], end=" ")

343
print("\nThe matrix in the matrix form:") #Print the matrix
for i in range(len(matrix)):
print()
for j in range(len(matrix[0])):
print(matrix[i][j],end=" ")

#Creating the transpose of the matrix


matrix_transpose=[]
for i in range(len(matrix[0])):

matrix_transpose_row=[]
for j in range(len(matrix)):
matrix_transpose_row.append(matrix[j][i])
matrix_transpose.append(matrix_transpose_row)

print("\nThe transpose of the matrix:")# Print the transpose


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

Output
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Diagonal elements of the matrix:
1 5 9
The matrix in the matrix form:

1 2 3
4 5 6
7 8 9

344
The transpose of the matrix:

1 4 7
2 5 8
3 6 9

List1
1 2 3 List2
R1

R2 4 5 6 List3

R3
7 8 9 List4

Figure 8.3: Creating a matrix using lists

8.8.2 Creating an Array from Data

Similar to matrix creation, higher-order arrays can be created using lists. Figure 8.4
shows the memory model of a 3D array with two planes, three rows and three columns.
Example 8.8(b) illustrates how to create a 3D array of size 3 x 3 x 3 which consists of a
number sequence starting from 1. The size of a 3D array is specified as p x r x c, where p is
the number of planes, r is the number of rows in each plane, and c is the number of columns
in each row. Another example where a small size array and matrices can be created directly
from the given data using a nested list is shown in example 8.8(c).

Example 8.8(b): Creation of a 3D array

array3d=[]#Initialise the array as a blank list


a=1 #Initialise the sequence
print("Enter size of the array(p,r,c):")
np,nr,nc=eval(input()) #input the size of the array

345
for p in range(np):
plane=[] #Initialise a plane
for r in range(nr):
row=[] #Initialize a row
for c in range(nc):
row.append(a) #Add a column to the row
a=a+1
plane.append(row)#Add a row to the plane
array3d.append(plane)#Add a plane to the array3d

print(array3d)
#Print the array in the grid format
for p in range(np):
print("plane:",p)
for r in range(nr):
for c in range(nc):
print(array3d[p][r][c], end=" ")
print()

Output
Enter size of the array(p,r,c):
3,3,3
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16,
17, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]]
plane: 0
1 2 3
4 5 6
7 8 9
plane: 1
10 11 12
13 14 15

346
16 17 18
plane: 2
19 20 21
22 23 24
25 26 27

List1
1 2 3 List3
R1

R2 4 5 6 List4
List0 R3
7 8 9 List5
P1

P2
List2 10 11 12 List6
R1

R2 13 14 15 List7

R3
16 17 18 List8

Figure 8.4: A memory model of a 3D array

Example 8.8(c): Creation of an array directly from data

#Initialise the array directly with the data


array3d=[
[#Plane 1
[1,2,3],

347
[4,5,6],
[7,8,9]
],
[#Plane 2
[10,11,12],
[13,14,15],
[16,16,18]
],
[#Plane 3
[19,20,21],
[22,23,24],
[25,26,27]
]
]

print(array3d)#Print the array in the list form

#Print the array in the matrix format


for p in range(3):
print("plane:",p)
for r in range(3):
for c in range(3):
print(array3d[p][r][c], end=" ")
print()

Output
[[[1, 2, 3], [4, 5, 6], [7, 8, 9]], [[10, 11, 12], [13, 14, 15], [16,
16, 18]], [[19, 20, 21], [22, 23, 24], [25, 26, 27]]]
plane: 0
1 2 3
4 5 6

348
7 8 9
plane: 1
10 11 12
13 14 15
16 16 18
plane: 2
19 20 21
22 23 24
25 26 27

8.8.3 Reading a Matrix from the Keyboard

A matrix can be read from the keyboard, element-by-element, using the input
function. Elements can be read row-wise or column-wise. Since the input () function returns
the read data as an str object, we have to convert the input data to the appropriate type.
Example 8.8(d) shows how to read two float matrices from the keyboard and find their sum.

Example 8.8(d): Reading matrices from the keyboard

#Read size of matrices


nr=int(input("Enter the number of rows:"))
nc=int(input("Enter the number of columns:"))
print("Read the matrix element-by-element:")
matrix1=[]
#Reading the first matrix from the keyboard
for r in range(nr):
row=[]
for c in range(nc):
print("Enter element matrix1[",r,"][",c,"]:", end=" ")
x=float(input())
row.append(x)
matrix1.append(row)

349
#Reading the second matrix from the keyboard
matrix2=[]
for r in range(nr):
row=[]
for c in range(nc):
print("Enter element matrix2[",r,"][",c,"]:", end=" ")
x=float(input())
row.append(x)
matrix2.append(row)

print("The First matrix:")


print(matrix1)
print("The Second matrix:")
print(matrix2)
#Sum the first and the second matrices
matrix3=[]
for r in range(nr):
row=[]
for c in range(nc):
row.append(matrix1[r][c]+matrix2[r][c])
matrix3.append(row)

print("The sum matrix:")


print(matrix3)

Output
Enter the number of rows:3
Enter the number of columns:3
Read the matrix element-by-element:
Enter element matrix1[ 0 ][ 0 ]: 1
Enter element matrix1[ 0 ][ 1 ]: 2

350
Enter element matrix1[ 0 ][ 2 ]: 3
Enter element matrix1[ 1 ][ 0 ]: 4
Enter element matrix1[ 1 ][ 1 ]: 5
Enter element matrix1[ 1 ][ 2 ]: 6
Enter element matrix1[ 2 ][ 0 ]: 7
Enter element matrix1[ 2 ][ 1 ]: 8
Enter element matrix1[ 2 ][ 2 ]: 9
Enter element matrix2[ 0 ][ 0 ]: 4
Enter element matrix2[ 0 ][ 1 ]: 2
Enter element matrix2[ 0 ][ 2 ]: 3
Enter element matrix2[ 1 ][ 0 ]: 4
Enter element matrix2[ 1 ][ 1 ]: 2
Enter element matrix2[ 1 ][ 2 ]: 5
Enter element matrix2[ 2 ][ 0 ]: 2
Enter element matrix2[ 2 ][ 1 ]: 3
Enter element matrix2[ 2 ][ 2 ]: 4
The First matrix:
[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]
The Second matrix:
[[4.0, 2.0, 3.0], [4.0, 2.0, 5.0], [2.0, 3.0, 4.0]]
The sum matrix:
[[5.0, 4.0, 6.0], [8.0, 7.0, 11.0], [9.0, 11.0, 13.0]]

8.8.4 Nested List Comprehension to Process Matrices

The list comprehension, as discussed in section 8.1.3, can be nested to process


matrices and arrays. The nesting of list comprehensions beyond two levels of nesting is
difficult to visualize. Hence, it is recommended that the nesting of the list comprehensions
should be limited to only two levels. The syntax of the two-level nested list comprehension
is given below, where for every outer list comprehension, the inner list comprehension is
repeated:

351
Output_list = [ [inner list comprehension] outer list comprehension]

Example 8.8(e) calculates the sum and multiplication of two matrices using list
comprehension. For calculating matrix multiplication, we first generate vectors of the
product of the pivot rows and columns and then, in the second step, the sum of these vectors
is calculated. We have to use two steps as an assignment is not permitted in the list
comprehension. The code using the list comprehension is very compact, but it is difficult to
understand.

Example 8.8(e): Sum and product of matrices using the list comprehension

A=[[1,2,3],[4,5,6],[7,8,9]] #Matrix A
B=[[4,2,3],[6,2,5],[6,1,2]] #Matrix B

#Sum of the first and the second matrices


S=[[A[i][j]+B[i][j] for j in range(3)] for i in range(3)]

#Product of the First and the second matrices


#Step 1: calculate vectors of products of pivot rows and columns
M=[[[A[i][k]*B[k][j] for k in range(3)] for j in range(3)] for i in
range(3)]
#Step 2: Sum of the vectors
M1=[[sum(M[i][j]) for j in range(3)] for i in range(3)]

print(A)
print(B)
print("Sum of A and B:")
print(S)
print("Product of A and B:")
print(M1)
Output
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[4, 2, 3], [6, 2, 5], [6, 1, 2]]

352
Sum of A and B:
[[5, 4, 6], [10, 7, 11], [13, 9, 11]]
Product of A and B:
[[34, 9, 19], [82, 24, 49], [130, 39, 79]]

8.9 List Operators


List object supports the following operators:

• concatenation operator (+)


• repetition operator (*)
• existence operator (in)
• identity operator(is)
• delete operator (del)

The concatenation operator combines the two lists. For example, the expression
[1,2,3] + [4,5] evaluates to [1,2,3,4,5]. The repetition operator returns the replicated list. For
example, the expression [1,2,3] * 2 evaluates to [1,2,3,1,2,3]. The existence operator checks
whether the specified value exists in the list or not. If it exists, it returns True, otherwise
False. The identity operator is used to check whether two list variables refer to the same
list in the memory or not. And, the delete operator deletes elements or a slice from a list.
Example 8.9 illustrates the above.

Example 8.9: The list operators

>>> a=[1,2,3]
>>> b=[4,5,6]
>>> c=a+b #Concatenate two lists
>>> print(c)
[1, 2, 3, 4, 5, 6]
>>> d=a*3 #Replicate the list three times
>>> print(d)
[1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 2 in a #Check the existence of a value in a list

353
True
>>> 5 in a #Check the existence of a value in a list
False
>>> a=[[1,2,3],[4,5,6],7,8]
>>> [1,2,3] in a #Check existence of a list in another list
True
>>> a=[1,2,3]
>>> b=a
>>> a is b #Check whether the two lists are the same object or not
True
>>> c=a.copy() #Shallow copy
>>> a is c
False
>>> del a[2] #Delete an element
>>> print(a)
[1, 2]
>>> del c[0:2] #Delete a slice of the list
>>> c
[3]
>>>

8.10 Solved Examples


Program 8.1: Write a program that creates a list of n random integers between 0 and 100.
Separate even and odd numbers in two different lists, and find sum of elements of each
list.

Solution steps:
1. Import the random module.
2. Read the size of the list.
3. Initialize the random number list.

354
4. Generate random numbers using the randint () function of the random module and
append them to the list.
5. Initialize the even and odd number lists.
6. Iterate the random number list, and append the even numbers to the even list and the
odd numbers to the odd list.
7. Find the sum of both lists and print them.

import random #Import random module


n=int(input("Enter the size of the random number list: "))

random_list=[] #Create an empty list


for i in range(n):
x=random.randint(0,100) #Generate a random number
random_list.append(x) #Add the random number to the list

even_list=[] #Create an empty list


odd_list =[] #Create an empty list
for x in random_list:
if x%2==0:
even_list.append(x) #Add even number to even_list
else:
odd_list.append(x) #Add odd number to odd_list

print("Random list:", random_list) #Original list


print("Even list:", even_list) #Even list
print("Odd list:", odd_list) #Odd list
print("Sum of even list:", sum(even_list)) #Sum of even list
print("Sum of odd list:", sum(odd_list)) #Sum of odd list
Output
Enter the size of the random number list: 10
Random list: [94, 75, 87, 37, 26, 84, 9, 76, 32, 70]

355
Even list: [94, 26, 84, 76, 32, 70]
Odd list: [75, 87, 37, 9]
Sum of even list: 382
Sum of odd list: 208

Program 8.2: Write a program to read a list of n integer numbers, and create the
frequency table of the list.

Solution steps:
1. Initialize the list.
2. Read numbers and add them to the list
3. Convert the list to a set to remove the duplicate entries.
4. Iterate over the set elements and get the count of each set element in the list using the
count () method.
#Read the number of data
n=int(input("Enter the number of items in the list "))
L1=[] #Create an empty list

for i in range(n): #Read the data one by one


x=int(input(f"Enter the value of element L[{i}]"))
L1.append(x) #Add an item to the list

s=set(L1) #Convert the list to a set. The duplicate entries are removed
print(format("Element", ">10s"),":", format("Frequency",">10s"))
for x in s: #Iterate the set and count the number of entries of an
element in the list
print(format(x,"10d"),":", format(L1.count(x),"10d"))
Output
Enter the number of items in the list: 10
Enter the value of element L[0]: 2
Enter the value of element L[1]: 1

356
Enter the value of element L[2]: 3
Enter the value of element L[3]: 1
Enter the value of element L[4]: 2
Enter the value of element L[5]: 5
Enter the value of element L[6]: 3
Enter the value of element L[7]: 2
Enter the value of element L[8]: 4
Enter the value of element L[9]: 6
Element : Frequency
1: 2
2: 3
3: 2
4: 1
5: 1
6: 1

Program 8.3: Write a program to read n integer numbers, and find their mean, median,
mode and standard deviation.

Solution steps:
1. Import the math module.
2. Read the numbers into a list.
3. Find the sum of list elements using the sum () method and find the mean.

(𝑥𝑖 −𝑥̅ )2
4. Find the standard deviation using the formula 𝜎 = √ 𝑛
.

5. Sort the list in the ascending order.

357
6. If the size of the list is odd, the median value is the middle value of the list, else the
median is the average of the two middle values.
7. To calculate the mode, convert the list into a set and find the set element which has
the maximum count in the list.
import math #Import math library
n=int(input("Enter the number of data: "))
data1=[] #Create an empty data list
for i in range(n):
x=int(input(f"Enter the value of element data[{i}]: "))
data1.append(x)

mean=sum(data1)/n #Calculate mean


data2=[]
for x in data1:
y=(x-mean)**2
data2.append(y)
sd = math.sqrt(sum(data2)/n) #Calculate standard deviation

data1.sort() #Sort the list


#Calculate median
if n%2: #For even number of data
median = (data1[n//2]+data1[n//2-1])/2
else: #For odd number of data
median = data1[n//2]

#Remove the duplicate entries


data3=list(set(data1))
mode=data3[0]
c= data1.count(mode)
for x in data3: #Calculate mode

358
if data1.count(x)> c:
c=data1.count(x)
mode=x

print("Sorted list:",data1)
print("Mean=", mean)
print("Standard deviation=", sd)
print("Mode=", mode)
print("Median=", median)
Output
Enter the number of data: 5
Enter the value of element data[0]: 1
Enter the value of element data[1]: 2
Enter the value of element data[2]: 3
Enter the value of element data[3]: 4
Enter the value of element data[4]: 2
Sorted list: [1, 2, 2, 3, 4]
Mean= 2.4
Standard deviation= 1.019803902718557
Mode= 2
Median= 2.0

Program 8.4: Write a program to read a list of n numbers and sort the list using the
bubble sort.

Solution steps:
1. Read the numbers into a list.
2. Repeat the following process n-1 times, where n is the number of elements in the list.
2.1 Iterate over the list items, if the adjacent items are not in order, swap them.

359
Step by step working of the bubble sort is illustrated below. The swapped items are
highlighted in red. As can be seen from the table, the largest element settles in its position
after the first outer iteration, the second largest after the second outer iteration and so on.
Hence, the span of the inner loop reduces after each outer loop iteration. The reduction
in the inner loop span is shown as gray color.

Outer Inner 6 2 4 3 1 Original List


loop loop
index index
0 0 2 6 4 3 1
0 1 2 4 6 3 1
0 2 2 4 3 6 1
0 3 2 4 3 1 6 The largest element at its final position.
1 0 2 4 3 1 6
1 1 2 3 4 1 6
1 2 2 3 1 4 6 The second largest element at its position.
2 0 2 3 1 4 6
2 1 2 1 3 4 6 The third largest element at its position.
3 0 1 2 3 4 6 Sorted list

n=int(input("Enter the number of data: "))


data=[] #Create an empty data list

for i in range(n):
x=float(input(f"Enter the value of element data[{i}: "))
data.append(x)
#Bubble sorting
for i in range(n):
for j in range(n-i-1):
if data[j] > data[j+1]:#swap items if not in order
t=data[j]
data[j]=data[j+1]
data[j+1]=t

360
print("Sorted list:", data)

Output
Enter the number of data: 5
Enter the value of element data[0: 6
Enter the value of element data[1: 2
Enter the value of element data[2: 4
Enter the value of element data[3: 3
Enter the value of element data[4: 1
Sorted list: [1.0, 2.0, 3.0, 4.0, 6.0]

Program 8.5: Write a program to read n numbers and insert them in a list in ascending
order.

Solution steps:
1. Read the number of elements in a list.
2. Read a list item
2.1 Locate its proper position in the list
2.2 Insert the item at its position

n=int(input("Enter the number of data: ")) #Read the number of data


ordered_list=[]#Create an empty list
for i in range(n):
x=float(input(f"Enter the data item[{i}]: "))#Read a data
m=0 #Initialize the index
for y in ordered_list: #Iterate the list
if x > y: #Skip all the smaller elements
m=m+1
else: #Insert the item just before the first larger value
ordered_list.insert(m,x)

361
break
else: #Append at the end of the list
ordered_list.append(x)
print("Sorted list: ", ordered_list)

Output
Enter the number of data: 5
Enter the data item[0]: 3
Sorted list: [3.0]
Enter the data item[1]: 1
Sorted list: [1.0, 3.0]
Enter the data item[2]: 6
Sorted list: [1.0, 3.0, 6.0]
Enter the data item[3]: 4
Sorted list: [1.0, 3.0, 4.0, 6.0]
Enter the data item[4]: 2
Sorted list: [1.0, 2.0, 3.0, 4.0, 6.0]

Program 8.6: Write a program to simulate push and pop operations of a stack.

Stack is a special type of queue where we can read and write data from the top only.
It uses the queue discipline last in fist out, LIFO. The pop operation removes one item
from the top of the stack, and the push operation writes one item at the top of the stack.

Solution steps:
1. Initialize the stack as an empty list.
2. Write an infinite loop:
2.1 Create the main menu - 1 for push, 2 for pop and 3 for ending simulation.

362
2.2 Get the choice of the user.
2.3 If choice is 1:
2.3.1 Read the item.
2.3.2 Add the item at the top of the stack.
2.3.3 Print the stack.
2.4 Else if choice is 2:
2.4.1 Get the last item of the stack, remove it from the stack and print it.
If there is no item in the stack, print the message that the stack is empty.
2.4.2 Print the stack.
2.5 Else if choice is 3:
2.5.1 break the infinite loop to end the simulation.
2.6 Else:
2.6.1 Print invalid choice, and show the main menu again.
stack=[] #Initialise the stack
while 1: #Infinite loop
#Show the main menu items
print("\n\n====== Main Menu =====\n1 for push an item\n2 for pop
an item\n3 end")
#Get the choice
choice=int(input("Enter your choice: "))
if choice == 1: #Implementing the push operation
x=input("Enter the item to push in the stack: ")
stack.append(x) #Add the new item at the end
print("\nStack values:", stack)
print("Item pushed successfully")
elif choice == 2: #Implementing the pop operation
if len(stack)==0: #There is no item in the stack
print("There is no item in the stack to pop.")
else:
#Remove the last item from the stack and return it.
x=stack.pop()
print("\nPopped item:",x)
print("Stack values:",stack)

363
elif choice ==3: #End the simulation
print("\nBreaking the simulation")
break
else: #Invlaid choice
print("\nInvalid choice")

Output
====== Main Menu =====
1 for push an item
2 for pop an item
3 end
Enter your choice: 1
Enter the item to push in the stack: 10

Stack values: ['10']


Item pushed successfully

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 2

Popped item: 10
Stack values: []

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 1
Enter the item to push in the stack: 20

Stack values: ['20']

364
Item pushed successfully

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 1
Enter the item to push in the stack: 30

Stack values: ['20', '30']


Item pushed successfully

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 2

Popped item: 30
Stack values: ['20']

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 2

Popped item: 20
Stack values: []

====== Main Menu =====


1 for push an item
2 for pop an item
3 end

365
Enter your choice: 2
There is no item in the stack to pop.

====== Main Menu =====


1 for push an item
2 for pop an item
3 end
Enter your choice: 3

Breaking the simulation

Chapter Summary

1. A list is a built-in data structure used to store several Python objects.


2. A list is a mutable collection of items. The individual items can be of different
types. We can add, delete, modify, sort and reverse list elements.
3. A list without any item in it is called empty list.
4. We can create a list by putting data/objects separated by commas within a pair
of square brackets. We can also convert other sequence data into a list using the
list () method.
5. We can also create a list by selecting few items from a collection using the list
comprehension.
6. Built-in functions include len(List) - returns the length of the list; max(List) -
returns the maximum element in the list; min(List) - returns the minimum
element in the list, and sum(List) - returns the sum of all the elements in the list.
7. We can access individual item of a list using indexing. Several items can be
selected using list slicing.
8. The index of the first item in the list is zero. A negative value of an index refers
items from the list end. The index -1 refers to the last item.
9. In the reference copy, the same memory references are used by the original list
and the copied list.

366
10. In the shallow copy, the original and the copied lists use different memory
references, but their nested elements use the same memory references.
11. In the deep copy, the original list and the copied list use different memory
references. The nested elements also use separate memory references.
12. Nested list means a list within another list. We can use nested lists to create
matrices and arrays.

Multiple Choice Questions

1. Which of the following is true for a list object in Python?


(a) it is mutable
(b) It can store heterogeneous data
(c) It can be nested with other lists
(d) All of the above

2. Which of the following is an incorrect way to create a list?


(a) L1 = list (1, 2, 3, 4)
(b) L2 = list ()
(c) L3 = "1,2,3,4".split(',')
(d) L4 = list([1, 2, 3, 4])

3. Which of the following is an error?


(a) L1 = list ("1234"]
(b) L2 = list(10)
(c) L3 = list((1,2,3,4))
(d) None of the above

4. What is the value of L1 after executing the following code snippet?


L1 = [x for x in "Python" if x not in "aeiou"]

(a) ['P', 'y', 't', 'h', 'n']


(b) ['P', 'y', 't', 'h', 'o', 'n']
(c) ['o']
(d) None of the above

5. What is the value of L1 after executing the following Python code snippet?
L1= [x for x in "hello"]

367
(a) [‘h’, ‘e’, ‘l’, ‘l’, ‘o’]
(b) ‘hello’
(c) [‘hello’]
(d) hello

6. What is the value of L1 after executing the following Python code snippet?
L1= [x+y for x in "abc" for y in "def"]

(a) ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']
(b) ['da', 'ea', 'fa', 'db', 'eb', 'fb', 'dc', 'ec', 'fc']
(c) [['ad', 'ae', 'af'], ['bd', 'be', 'bf'], ['cd', 'ce', 'cf']]
(d) None of the above

7. For the list A=[1,2,3,4,5], which of the following is incorrect way to get 3 from
the list?
(a) A[3]
(b) A[2]
(c) A[-3]
(d) None of the above

8. For the list A = [1,2,3,4], What is the value of A[-1]?


(a) 1
(b) 4
(c) It is an error
(d) None of the above

9. For the list L1= [1,2,3,4,5], which of the following is correct slicing operation?
(a) L1[0]
(b) L1[:2]
(c) L1[: -2]
d) All of the above

10. What is the value of L1 after executing the following code?


L1 = [0.5 * x for x in range (0, 4)]

(a) [0.0, 0.5, 1.0, 1.5]


(b) [0.0, 0.5, 1.0, 1.5, 2.0]

368
(c) It is an error
(d) None of the above

11. For the list L1= [1, 2, 3], What is the value of L2 after executing the following
code?
L2 = L1 * 2
(a) [2, 4, 6]
b) [1, 1, 2, 2, 3, 3]
c) [1, 2, 3, 1, 2, 3]
d) None of the above

12. Which of the following is the correct way to add an item at the end of a list,
L1?
(a) L1.append(item)
(b) L1.add(item)
(c) L1 + item
(d) All of the above

13. For L1 = [1,2,4,5], which of the following is the correct way to insert 3 between
2 and 4?
(a) L1.insert(2, 3)
(b) L1.insert(3, 2)
(c) L1.insert(3, 3)
(d) None of the above

14. For L1= ['Java', 'Pascal', 'Python'], What is the output of print (L1[-1][-1]) ?
(a) n
(b) Python
(c) Pascal
(d) None of the above

15. For L1= [2, 1, 5, 6, 5], what is L1.index(5)?


(a) 2
(b) 3
(c) 4
(d) 5

16. For L1= [2, 1, 5, 6, 5], what is L1.count(5)?

369
(a) 2
(b) 1
(c) 5
(d) None of the above

17. For L1= [2, 1, 5, 6, 5], what is the output of print(L1.reverse())?


(a) [5, 6, 5, 1, 2]
(b) [6, 5, 5, 2, 1]
(c) [6, 5, 5, 1, 2]
(d) None of the above

18. For L1= [2, 1, 5, 6, 5], what is L1 after executing L1.reverse()?


(a) [5, 6, 5, 1, 2]
(b) [6, 5, 5, 2, 1]
(c) [1, 2, 5, 5, 6]
(d) None of the above

19. For L1= [2, 1, 5, 6, 5], what is L1 after executing L1.pop(2)?


(a) [2, 1, 6, 5]
(b) [1, 5, 6, 5]
(c) [ 5, 6, 5]
(d) [2, 1, 5, 6, 5]

20. What is the output of the following program?

def myFun(item, values = []):


values.append(item)
return values

myFun(10)
myFun(20)
value = myFun(30)
print(value)

(a) [10, 20, 30]


(b) [30]
(c) [10], [10,20], [10,20,30]
(d) 30

370
21. What is the output of the following program?

L1 = [1, 2, 3, 4]
L1.append([5,6])
print(len(L1))

(a) 6
(b) 5
(c) 4
(d) None of the above

22. What is the output of the following program?

L1 = [1, 2, 3, 4]
L1.exend([5,6])
print(len(L1))

(a) 6
(b) 5
(c) 4
(d) None of the above

23. What is the output of the following program?

L1 = [1, 2, 3, 4]
L1 +=[5,6]
print(len(L1))

(a) 6
(b) 5
(c) 4
(d) None of the above

24. What is the output of the following program?


y = [[x, x + 1, x + 2] for x in range(0, 2)]
print(y)

(a) [0, 1, 2], [1, 2, 3]

371
(b) [0, 1, 2, 1, 2, 3]
(c) [[0, 1, 2], [1, 2, 3]]
(d) None of the above

25. What is the output of the following program?


m = [[x, y] for x in range(0, 2) for y in range(0, 3)]
print(len(m))

(a) 12
(b) 6
(c) 5
(d) None of the above

Review Questions

1. State whether the following statements are true or false:


a. A list can have heterogeneous data.
b. Lists are immutable.
c. L1[-1] is the second last element of L1.
d. We can convert any sequence of data into a list.
e. List comprehension cannot be nested.
f. We can traverse a list using a for loop.
g. A shallow copy of a list has a different ID.
h. A deep copy of a list has no link with the original list.
i. L1.append(L2) is equivalent to L1+=L2.
j. L1.extend(L2) is equivalent to L1+=L2.
k. The count () method of list returns the number of elements in the list.
l. The del operator can delete more than one element from a list.
m. The asterisk, *, operator is used to duplicate elements of a list.

372
n. We can join two lists using the + operator.
o. The expression L1.pop() removes the last element from L1.
p. The expression L1.push(10) adds 10 at the start of L1.
q. The expressions L1.append(L2) and L1.extend(L2) are the same.
2. What is a list in Python? Describe its advantages and disadvantages.
3. Describe different methods to create a list.
4. Describe list comprehension.
5. Describe list slicing.
6. Describe list indexing.
7. Describe methods to traverse a list.
8. Describe various methods of the list class.
9. Describe min and max built-in functions for lists.
10. Describe various methods to copy a list.
11. Differentiate among a reference copy, a shallow copy and a deep copy of a list.
12. Describe methods to randomly reshuffle elements of a list.
13. Describe methods to store matrices and arrays using lists.
14. Describe methods to read matrices from the console.
15. Describe nested list comprehension.
16. Describe various list operators.
17. Differentiate between the following:
a. pop() and remove() methods of list.
b. del statement and pop() method of list.
c. append() and insert() methods of list.
18. With L1 = [1,2,3,4], what is the output of the following:
a. max(L1)

373
b. min(L1)
c. sum(L1)
d. len(L1)
19. With L1 = [4, 6, 2, 7, 3, 5, 1], what is the output of the following:
a. L1[-1]
b. L1[: 3}
c. L1[:]
d. L1[: :-1]
e. L1[3:-1]
f. L1[-1:3]
g. L1[-1:3:-1]
h. L1[:-3:]
20. With L1 = [1,2,3], and L2 = [4,5], what is the output of the following:
a. L1+L2
b. L1*2+L2
c. L1*0
d. 3*L1
e. 2*L1+3*L2
f. L1*L2
g. L1-L2
h. L1/2

21. With L1 = [4, 6, 2, 7, 3, 5, 1], what is the value of L1 after executing the following:
a. L1.sort()
b. L1.append([8,9,10])

374
c. L1.extend([8,9,10])
d. L1.reverse()
e. L1.pop()
f. L1.clear()
g. L1.index(2)
h. L1.insert(3,4)
i. L1.remove(3)

Programming Assignments

1. Write a program to read a list of n numbers and create a list of valid numbers
from the list that fall within a given range.

2. Write a function that takes a list of integers and returns the list of even integers.

3. Write a function that takes a list of numbers and removes all the negative
numbers.

4. Write a program to read a list of n numbers and print the following statistics of
the list:

(a) the maximum, (b) the minimum, (c) average, (d) median and (e) standard
deviation.

5. Write a function that takes a list of numbers as its parameter and returns True if
the list is sorted, else returns False.

6. Write a function that takes a list and a positive integer as its parameters and
returns a list that consists of the n replication of each list item. For example, for
the list [1,2,3] and n=2, the desired list is [1,1,2,2,3,3].

7. Write a program to sort the elements of a list in ascending order using selection
sort.

375
8. Write a program to sort the elements of a list in ascending order using insertion
sort.

9. Write a program to read a list of n words and print the words that contains more
the two vowels.

10. Write a program to read two matrices and find their multiplication.

11. Write a program to read a 3x3 matrix and determine if it is the Lo Shu Magic
Square matrix.

Hint: The Lo Shu Magic Square matrix has the following properties:

• The grid contains the numbers 1 to 9.

• The sum of each row, each column, and each diagonal all add up to the same
number.

12. Write a program to create a random number square matrix of size n (use a 2D
list). The random numbers are between 1 and n.

13. Write a program to generate a square matrix of size n (use a 2D list) which
consists of rows of random permutations of 1 to n.

14. Read two lists of numbers and generate a list that contains the common numbers
of the lists.

15. Write a program to read an integer number and create a list of its digits and
generate the largest number using these digits.

376
Chapter 9
Strings
Learning Outcomes:

1. Understand strings in Python.


2. Create and manipulate strings.
3. Describe Indexing and slicing in string.
4. Describe string methods.
5. Discuss operations on strings.
6. Convert strings into other data types

In Python, by default, a string is a sequence of Unicode characters. The primary


advantage of using Unicode characters is that strings can contain any natural language
character using the same encoding system. This facilitates uniform treatment to all the
natural languages and their processing.

Strings are immutable, i.e. once a string is created, it cannot be edited. However, we
can access individual characters and can create substrings from a string. Strings are stored
as the str class. Hence, the expression, type("Python") will return <class 'str'>. The str class
has a large number of methods to perform common string processing operations.

In Python, there is no character data type. However, the character functionalities can
be achieved by storing a single character in a string object.

9.1 Creating String Objects


String objects can be creating in the following manners:

9.1.1 Assigning a String Literal to a Variable

String literals are created by enclosing characters inside a single quote, double-
quotes, triple single quotes or triple double quotes. The single quote or double quote are
identical and used to create single line string literals. Whereas, triple quotes are used to

377
create multiline strings. See ` for more details about string literals. Example 9.1(a) shows
how to create a string variable using string literals.

Example 9.1(a): Creating string objects from string literals

#Create string objects from string literals


#All of the following ways to create strings are the same
string1='Hello World'
string2="Hello World"
string3='''Hello World'''
string4="""Hello
World"""
print(string1,type(string1))
print(string2,type(string2))
print(string3,type(string3))
print(string4,type(string4))
Output
Hello World <class 'str'>
Hello World <class 'str'>
Hello World <class 'str'>
Hello
World <class 'str'>

9.1.2 Using the Construction of the String Class

The constructor of the str class can be used to create string literals from various data
types, which can be assigned to variables to create string objects. It simply returns the string
equivalent of the data. Example 9.1(b) shows how to convert various data types into strings.

Example 9.1(b): Convert various types of data into strings

>>> str(10) #Integer to string


'10'
>>> str(10.5) #Float to string
'10.5'
>>> str(True) #Boolean to string
'True'
>>> str(1.3e5) #Float to string
'130000.0'
>>> str(3+4j) #Complex to string
'(3+4j)'
>>> str([1,2,3]) #List to string
'[1, 2, 3]'
378
>>> str((1,2,3)) #Tuple to string
'(1, 2, 3)'
>>> str({1,2,3}) #Set to string
'{1, 2, 3}'
>>> str({1:"One",2:"Two"}) #Dictionary to string
"{1: 'One', 2: 'Two'}"
>>> str(range(5)) #Range to string
'range(0, 5)'
>>> str("Hello") #String to string
'Hello'
>>> s1=str(3.14)
>>> type(s1) #Type of a variable
<class 'str'>

9.2 Built-in Functions for Strings


Python has built-in functions to find the number of characters in a string (len), to
find the largest character (max) and the smallest character (min) in a string. The smallest
and the largest characters are decided based on the Unicode value of a character. Example
9.2 illustrates some usages of these functions.

Example 9.2: Built-in functions for strings

>>> s="Python"
>>> len(s) #Find the number of characters in a string
6
>>> max(s) #Find the largest character in a string
'y'
>>> min(s) #Find the smallest character in a string
'P'

9.3 Accessing Characters in a String


A string is an immutable data but we can access individual characters of a string
using the index operator, a pair of square brackets [ ]. For example, for the string
s="Python", s[1] will return 'y'. we can use a negative index value to access characters from
the end of a string. For example, s[-1] will return the last character of the string, i.e. 'n'.
Figure 9.1 shows the positive and negative indexing of a string. Example 9.3 shows how to
access a character from a string.

379
Positive index 0 1 2 3 4 5

String P y t h o n

Negative index -6 -5 -4 -3 -2 -1

Figure 9.1: Indexing of a string

Example 9.3: Accessing characters in a string

>>> s="Python"
>>> s[0] #The first character
'P'
>>> s[-1]#The last character
'n'
>>> s[3] #The fourth character
'h'
>>> s[-3] #the third character from the last
'h'
>>> s[8] #Error: out of range
Traceback (most recent call last):
File "<pyshell#100>", line 1, in <module>
s[8]
IndexError: string index out of range
>>> s[-8] #Error: out of range
Traceback (most recent call last):
File "<pyshell#101>", line 1, in <module>
s[-8]
IndexError: string index out of range
>>>

9.4 Traversing a String


We can use any looping technique, such as for loop or while loop, to traverse a
string. We can traverse in forward direction or backward direction. Example 9.4(a) traverses
a string and prints the ASCII value of each character of the string. Example 9.4(b) traverses
a string backward and creates a list of the characters in the reverse order.

380
Example 9.4(a): Traversing a string

#Print ASCII codes of the characters of a string


s="ABCXYZ"
for ch in s:
print(ch,":",ord(ch))
Output
A : 65
B : 66
C : 67
X : 88
Y : 89
Z : 90

Example 9.4(b): Traversing a string in backward direction

#Create a list of characters of a string in the reverse order


s="Python" #The given string
list1=[] #Initialize the list
n=len(s)-1 #Find length of the string
while(n>=0): #Traversing is backward direction
list1.append(s[n]) #Adding characters in the list
n=n-1
print(list1)
Output
['n', 'o', 'h', 't', 'y', 'P']

9.5 Slicing Operation with a String


Slicing is a mechanism to select a set of elements from a collection, including a string.
Through slicing, we can create a substring from a given string. The syntax of the slice
operator is start: stop: step, where the start is the starting index of the slice, the stop is the
stopping index (the element at the stop index in not included in the slice) and the step is the
increment between two consecutive indices.

All the slicing parameters are optional and the default value of step is 1. For a
positive value of step, the default value of start is 0, and the default value of stop is length
of the string. On the other hand, for a negative value of step, the default value of start is -1
and the value of stop is the minus value of the length of the string. The length of a string

381
can be calculated using len (string object). For example the slice 1:4 will generate the indices
1,2,3. Hence, for s="Python”, the expression s[1:4] will return 'yth'. Similarly, the slice 1:6:2
will generate indices 1,3,5 and the expression s[1:6:2] will return 'yhn'. Slicing can be done
with negative indices also. For example, the expression s[-1:-5:-1] will return 'noht' and the
expression s[-6:-1:1] will return 'Pytho'. If the step is positive, characters will be returned
in the forward direction, otherwise in the backward direction. The default value of start is
0 and the default value of end is the length of the string. For example, the expression s[::2]
will return 'Pto', i.e. alternate characters starting from the first character to the last character
of the string.

Slicing indices can also be generated by the construction of the slice object. The
syntax of the slice method is slice (start, stop, step), where the start, stop and step have the
same meaning as given above. For example, the s1 = slice(1,6,2) will return indices 1,3,5. A
slice object can be used as indices for getting substring from a string. For the string object
str1="Python" and the slice s1=slice(1,6,2), the expression str1[s1] will return 'yhn'.
Example 9.5 illustrates slicing operations on a string.

Example 9.5: Slicing of a string

>>> #Slicing operations


>>> s="I love Python"
>>> s[0:4] #The first four characters of the string
'I lo'
>>> s[:4] #The same as above
'I lo'
>>> s[-4:] #The last four characters of the string
'thon'
>>> s[-4:len(s)] #The same as above
'thon'
>>> s[::2] #Alternate characters of the string
'Ilv yhn'
>>> s[::-2]# Alternate characters in reverse order
'nhy vlI'
>>> s[::-1] #Reverse string
'nohtyP evol I'
>>> s1=slice(1,6) #A slice of 2nd to 6th characters
>>> s[s1]
' love'
>>> s2=slice(1,6,2) #A slice of 2nd to 6th alternate characters
>>> s[s2]
' oe'
>>> s3=slice(-1,-6,-2) #A slice in bachward direction
>>> s[s3]
382
'nhy'

9.6 String Operators


Python has the following built-in operators for strings: concatenation operator (+),
repetition operation (*) and membership checking (in). Example 9.6 illustrates usages of
these operators.

Example 9.6: String operations

>>> s1="Hello"
>>> s2="World"
>>> s3=s1+s2 #Concatenate two strings
>>> s4=s1*3 #Repeat a string
>>> print(s4)
HelloHelloHello
>>> print(s3)
HelloWorld
>>> s1 in s3 #Check whether a string exists in the other string or not
True
>>> s1 in s2
False
>>> s1 not in s2 #Check whether a string exists in other string or not
True
>>>

9.7 String Class Methods


The string class has a number of methods for the common string processing tasks, such as
capitalize all characters, remove extra spaces, etc. These methods return new strings
without affecting the original string. Table 9.1 lists commonly used methods with their brief
descriptions.

Table 9.1: String

Method Description
capitalize() Returns a new string with the first character converted to the upper
case.
>>> s1="python programming language"
>>> s2=s1.capitalize()
383
>>> print(s2) #Modified string
Python programming language
>>> print(s1) #Original string
python programming language
casefold() Returns a new string with all the characters converted to the lower
case.
>>> s1="Python Programming Language"
>>> s1.casefold()
'python programming language'
center(w,ch) Returns a new centered string in the specified width, w, by adding
the specified character, ch, in both sides. If the character is not
specified, space is used.
>>> s1="python programming language"
>>> s1.center(35,'$')
'$$$$python programming language$$$$'
>>> s1.center(35)
' python programming language '
count(value) Returns the number of times a specified substring value is found in
the string.
>>> s1="python programming language"
>>> s1.count('o')
2
>>> s1.count("python")
1
encode() Returns a binary encoded version of the string. The purpose of
encoding is to convert data into a form to properly use by other
system, for example, binary data for sending over email, or viewing
special characters on a web page. The following example converts s1
using ‘UTF-16’ encoding. Please note, the same encoding must be
used to get the string back properly. By default, Python uses ‘UTF-8’
encoding system.

>>> s1="python programming language"


>>> s1.encode('UTF-16')
b'\xff\xfep\x00y\x00t\x00h\x00o\x00n\x00
\x00p\x00r\x00o\x00g\x00r\x00a\x00m\x00m\x00i\x00n\x00g
\x00 \x00l\x00a\x00n\x00g\x00u\x00a\x00g\x00e\x00'
endswith(value) Returns true if the string ends with the specified value.
>>> s1="python programming language"
>>> s1.endswith('language')
True
>>> s1.endswith('python')
False
384
expandtabs(size) Replaces each tab character in the string by the specified number of
white spaces.
>>> s="Hello\tWorld"
>>> #Replace a tab with 4 white spaces
>>> s.expandtabs(4'Hello World')
find(value) Returns the index of the first occurrence of the value in the string. If
no match is found, it returns -1.
>>> s1="python programming language"
>>> s1.find('lang') #Find the index of the sub-string
19
>>> s1.find("hello") #No match found
-1
format() Formats the string with the specified value(s) and insert them inside
the string's placeholder. The placeholder is defined using curly
brackets: {}.
format_map() Formats specified values in a string
index() Returns the index of the first occurrence of the value in the string. If
no match is found, error is generated.
>>> s1="python programming language"
>>> s1.index('lang') #Index of the first match
19
>>> s1.index('hello') #Error: no match found
Traceback (most recent call last):
File "<pyshell#73>", line 1, in <module>
s1.index('hello')
ValueError: substring not found
isalnum() Returns True if all the characters in the string are alphanumeric, i.e.
there is no special character in the string.

>>> s2="Python3" #Contains only alphabets and numbers

>>> s2.isalnum()
True
>>> s3="Python3.8" #Contains a special character.
>>> s3.isalnum()
False
isalpha() Returns True if all the characters in the string are alphabets
>>> s2="Python"
>>> s2.isalpha()#Contains only alphabets
True
>>> s3="Python3"
>>> s3.isalpha() #Contains a digit

385
False
isdecimal() Returns True if all characters in the string are decimal digits only, i.e.
characters are from 0,1, 2…8,9.
>>> s2="1234"
>>> s2.isdecimal() #Contains only decimal digits
True
>>> s3="123.4"
>>> s3.isdecimal() #Contains a decimal point
False
isdigit() Returns True if all characters in the string are digits. It is the same as
isdecimal, above.
isidentifier() Returns True if the string is a valid identifier name.
>>> s2="abc"
>>> s2.isidentifier() #A valid identifier name
True
>>> s3="abc.32"
>>> s3.isidentifier() #An invalid identifier name
False
islower() Returns True if all the characters in the string are lower case.
>>> s1="Python"
>>> s1.islower() #All the alphabets are not in lower
case
False
>>> s2="python 3.8" #All the alphabets are in lower
case
>>> s2.islower()
True
isnumeric() Returns True if all characters in the string are digits only.
>>> s1="123.45"
>>> s1.isnumeric() #Contains a decimal point
False
>>> s2="123"
>>> s2.isnumeric() #Contains only digits
True
isprintable() Returns True if all the characters in the string are printable and does
not contain non-printable characters such as a newline, a tab, etc. A
space is a printable character.
>>> s1="Hello"
>>> s1.isprintable() #Contains only printable
True
>>> s2="Hello\n"
>>> s2.isprintable() #Contains non-printable, i.e. a
newline
False

386
>>> s3="Hello\tWorld" #Contains non-printable, i.e. a
tab
>>> s3.isprintable()
False
s4="Hello world"
>>> s4.isprintable() #A space character is printable
True
isspace() Returns True if all the characters in the string are spaces.
>>> s1=" "
>>> s1.isspace() #Contains only spaces
True
>>> s2="\t\t\\t" #Contains non-spaces
>>> s2.isspace()
False
istitle() Returns True if the string is in the title case. The title case means that
the first letter of each word is capitalized, except for short
prepositions and articles.
>>> s1="Python Programming Language"
>>> s1.istitle() #Each word of the string is
capitalised
True
>>> s2="Python programming language"
>>> #Each word of the string is not capitalised
>>> s2.istitle()
False
isupper() Returns True if all the alphabet characters in the string are in the
upper case.
>>> s1="Python 3.0"
>>> s1.isupper() #Contains small case letters
False
>>> s2="PYTHON 3.0"
>>> s2.isupper() #All the alphabets are in the upper
case
True
join(iterable) Joins the elements of an iterable consisting of stings, using the string
as the separator.
>>> list1=["One", "Two", "Three"]
>>> s1="-sep-"
>>> s1.join(list1) #Joint the list items
'One-sep-Two-sep-Three'
>>> tuple1=("Hello","World")
>>> s1=" "
>>> s1.join(tuple1) #Join tuple elements
'Hello World'

387
>>> dict1={"One":1,"Two":2}
>>> s1.join(dict1) #Keys will be used during join
'One Two'
ljust(w, ch) Returns the left aligned version of the string within a specified
width, w, using a specified character, ch, as the filler character. The
default filler character is a space.
>>> s1="Python"
>>> s1.ljust(20) #Left aligned string
'Python '
>>> #Left aligned string using # as filler
>>> s1.ljust(20,"#")
'Python##############'
lower() Returns the lowercase version of the string, by converting all the
upper case alphabets to the corresponding lower case alphabets.
>>> s1="PYTHON 3.0"
>>> s1.lower()
'python 3.0'
lstrip(ch) Returns a string after removing all the specified characters, ch, from
the lift side of the string. The default is the space character.
>>> s1=" 1234.34 "
>>> s1.lstrip() #Remove all leading spaces
'1234.34 '
>>> s1="000001234.4500"
>>> s1.lstrip('0') #Remove all leading 0s
'1234.4500'
>>>
partition(value) Returns a tuple of three strings. The first element consists of the part
of the string where the first match of the specified value is found.
The second element contains the specified string and, the third
element contains the remaining part of the string.
>> s1="PythonProgrammingLanguage"
>>> s1.partition("Programming")
('Python', 'Programming', 'Language')
replace(s1,s2,n) Returns a string after replacing the first n occurrences of s1 by s2 in
the string. By default, the value of n is all occurrences.
>>> s1="I ate one banana. The banana was very tasty"
>>> #Replace banana with apple
>>> s1.replace('banana','apple')
'I ate one apple. The apple was very tasty'
>>> #Replace the first occurrence of banana with apple
>>> s1.replace('banana','apple',1)
'I ate one apple. The banana was very tasty'
rfind(value) Returns the last index of the specified value found in the string.

388
>>> s1="I ate one banana. The banana was very tasty"
>>> s1.rfind('banana') #Find a string from the backward
22
>>> s1.rfind('apple') #In case no match found
-1
rindex(value) Searches the value in the string, and returns the index of the last
match where it was found. If no match is found, it generates an error.
>>> s1="I ate one banana. The banana was very tasty"
>>> s1.rindex('banana') #Index of the last match
22
>>> s1.rindex('apple') #Error: No match found
Traceback (most recent call last):
File "<pyshell#178>", line 1, in <module>
s1.rindex('apple')
ValueError: substring not found
rjust(w,ch) Returns the right aligned version of the string within a specified
width, w, using a specified character, ch, as the filler character. The
default filler character is space.
>>> s1="Python"
>>> s1.rjust(20) #Space padded right aligned string
' Python'
>>> s1.rjust(20,'#')#Hash padded right aligned string
'##############Python'
rpartition() Returns a tuple of three strings. The first element consists of the part
of the string where the last match of the specified value is found. The
second element contains the specified string, and the third element
contains the remaining part after the string.
>>> s1="I ate one banana. The banana was very tasty"
>>> s1.rpartition('banana') #Partition from end
('I ate one banana. The ', 'banana', ' was very tasty')
rsplit(sep) Splits the string at all the locations where the specified separator is
present (default is a space), and returns the substrings as a list.
Separators are not part of the returned substrings.
>>> s1="I ate one banana. The banana was very tasty"
>>> s1.rsplit() #Prepare a list of all words
['I', 'ate', 'one', 'banana.', 'The', 'banana', 'was',
'very', 'tasty']
>>> s1.rsplit('.') #Prepare a list of sentences
['I ate one banana', ' The banana was very tasty']
rstrip() Returns a string after removing all the specified character, ch, from
the right side of the string. The default is the space character.
>>> s1=" Python "
>>> s1.rstrip()#Remove all the trailing spaces

389
' Python'
>>> s2="---Python----"
>>> s2.rstrip('-')#Remove all the trailing hyphens
'---Python'
split(sep) Splits the string at all the locations where the specified separator is
present (default is a space), and returns the substrings as a list.
Separators are not part of the substrings.
>>> s1="I ate one banana. The banana was very tasty"
>>> s1.split()#Returns list of all words
['I', 'ate', 'one', 'banana.', 'The', 'banana', 'was',
'very', 'tasty']
>>> s1.split('.')#Returns all the sentences
['I ate one banana', ' The banana was very tasty']
splitlines(flag) Splits the string at new line characters and returns the substrings as
a list. If the flag is true, the new line characters are retained in the
returned sublists, otherwise they are ignored. The default is False.
>>> s1="I ate one banana. The banana was very tasty"
#Split at new line characters and ignore the new line
characters
>>> s1.splitlines()
['I ate one banana. ', 'The banana was very tasty']
#Split at new line characters and retain the new line
characters
>>> s1.splitlines(True)
['I ate one banana. \n', 'The banana was very tasty']
startswith(value) Returns True if the string starts with the specified value, otherwise
False.
>>> s1="Python is very simple"
>>> s1.startswith("Python")#The string starts with
Python
True
>>> s1.startswith("simple")#The string does not start
with simple
False
strip(ch) Returns the string after removing all the occurrences of the specified
character from both leading and trailing ends of the string. The
default character is a space.
>>> s1=" Python "
>>> #Removes all leading and trailing spaces
>>> s1.strip()
'Python'
>>> s2="---Python----"
>>> #Removes all leading and trailing hyphens
>>> s2.strip('-')
390
'Python'
>>>
swapcase() Swaps the cases of all the alphabets in the string from the lower case
to the upper case and the upper case to the lower case, i.e. the upper
case alphabets become the lower case alphabets and the lower case
alphabets become the upper case alphabets.
>>> s1="Hello World"
>>> #Change the upper case characters to the lower case
and vice a versa
>>> s1.swapcase()
'hELLO wORLD'
title() Returns the string after capitalizing the first character of each word
of the string.
>>> s1="hello world. i love python"
>>> #Make first letter capital of each word
>>> s1.title()
'Hello World. I Love Python'
upper() Returns the string after converting all the lower case alphabets to the
upper case.
>>> s1='hello world. i love python'
>>> #Converts all the alphabets to the upper case
>>> s1.upper()
'HELLO WORLD. I LOVE PYTHON'
zfill(width) Returns the string after adding some leading zeros to make the string
length equal to the specified width.
>>> s1="123"
>>> s1.zfill(4)#Add leading zeros
'0123'
>>> s1.zfill(8)#Add leading zeros
'00000123'

9.8 Solved Examples


Sample program 9.1: Write a program to toggle the upper and lower case letters in a
string.

Solution steps:
1. Read the string.
2. Initialize a blank string
2. Iterate over each character of the string
2.1 if the character is upper, convert to lower and then add to the blank string
391
2.2 else, convert to upper and then add to the blank string
str="Python Programming Language V3.11.4"
res = "" #Create a blank string
for ch in str: #Iterating each character of the string
if ch.isupper():
res += ch.lower() #Converting upper case character to lower
else:
res += ch.upper() #Converting lower case character to upper case
print(res)

Output
pYTHON pROGRAMMING lANGUAGE v3.11.4

Program 9.2: Write a program to remove all the punctuation symbols in a string.

Solution steps:
1. Create a string containing all the punctuation symbols to be removed
2. Read the string.
3. Iterate over each character of the punctuation string
3.1 Replace all occurrences of a punctuation symbol
#a string containing punctuation symbols
punctuation_str ='!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
str = "Hello World! I am a Python enthusiast, and love programming."
print("Original String :\n\t",str)
for c in punctuation_str: #Iterate over each punctuation
str = str.replace(c,"") #Replace occurrences of a punctuation mark
print("After removing Punctuations :\n\t",str)
Output
Original String :
Hello World! I am a Python enthusiast, and love programming.
After removing Punctuations :
Hello World I am a Python enthusiast and love programming

392
Program 9.3: Write a program to convert an integer into equivalent binary, octal and
hexadecimal strings.

Solution steps:
1. Read the integer
2. Convert the integer into binary, octal and hexadecimal strings
3. Remove the first two characters from the binary, octal and hexadecimal intro strings
i = int(input("Input an integer: ")) #Read an integer
#Convert to octal and remove the first two characters
o = str(oct(i))[2:]
#Convert to hexadecimal and remove the first two characters
h = str(hex(i))[2:]
h = h.upper()
#Convert to binary and remove the first two characters
b = str(bin(i))[2:] d = str(i)
print("Decimal : ",d)
print("Octal : ",o)
print("Hexadecimal (capitalized) :",h)
print("Binary :",b)

Output
Input an integer: 26
Decimal : 26
Octal : 32
Hexadecimal (capitalized) : 1A
Binary : 11010

Program 9.4: Write a program to print the smallest and the largest words in a string.

Solution steps:
1. Read the string
2. Replace all punctuation marks with a space character
3. Iterate over the characters of the string and separate words
4. Find the smallest and largest words based on the lengths of the words
punct_str ='!,.;:-'
str = "Popular Programming Laguages:Python, Java,C++ and C"
print("Original Strings : ",str)

393
for ch in punct_str:
str=str.replace(ch,' ')# Replace punctuation marks
word = ""
all_words = [] #Empty word list
str = str + " "
for i in range(0, len(str)):
if(str[i] != ' '):
word = word + str[i] #Detect a word
else:
if len(word)!=0 : #Ignore zero length word
all_words.append(word) #Append the word to the list
word = ""

small = large = all_words[0]

#Find smallest and largest word in the str


for k in range(0, len(all_words)):
if(len(small) > len(all_words[k])):
small = all_words[k]
if(len(large) < len(all_words[k])):
large = all_words[k]
print("Smallest word: " + small)
print("Largest word: " + large)

Output
Original Strings : Popular Programming Laguages:Python,Java,C++ and C
Smallest word: C
Largest word: Programming

Program 9.5: Write a program to remove duplicate characters in a string.

Solution steps:
1. Read the string
2. Initialize a blank string
3. Iterate over the characters of the string
3.1 if the character is in the blank string then
ignore it
3.2 else
add the character in the blank string

394
s="Python Programming Language"
s1=""
for ch in s: #Iterate over each character of the string
if ch not in s1: #If the character is included in the new string,
ignore it
s1=s1+ch #Add character to the new string
print(s1)
Output
Python rgamiLue

Sample program 9.6: Write a program to remove consecutive duplicate characters in a


string

Solution steps:
1. Read the string
2. Initialize a string with the first character of the original string as the target string
3. Take the first character of the string
4. Remove the first character of the original string
5. Iterate over the characters of the modified original string
3.1 if the character is equal to the previous character
ignore it
3.2 else
add the character in the target string
update the previous character
s='AAAABBBBCCCCAAAABBBBCCCC' #Original string
s1=s[0] # Create a string with the first character of the string
ch1=s[0]# Take the first character
s=s[1:] # Remove the first character from the original string
for ch in s: #Iterate over the modified original string
if ch != ch1:#Skip the character if it is equal to the previous
s1=s1+ch #Append the character in the new string
ch1=ch #Update the previous character
print(s1)
Output
ABCABC

395
Chapter Summary

1. A string is a sequence of Unicode characters, making it capable to contain any


natural language character.
2. Strings are immutable.
3. Strings are stored as the str class.
4. In Python, there is no character data type. However, the character functionalities
can be achieved by storing a single character in a string object.
5. A string object can be created by assigning a string literal to a variable or using
constructor of str class.
6. Built in functions len, max, min find the number of characters, character with
the maximum Unicode value and character with the minimum Unicode value in
the string, respectively.
7. Individual characters of a string can be accessed using the index operator, a pair
of square brackets [index]. S [0] returns the first character and S [-1] returns the
last character of the string S.
8. We can traverse characters of a string using any looping technique.
9. Slicing operator can be used to get a sub string of a string.
10. Python has built-in operators for concatenation operator (+), repetition operation
(*) and membership checking (in) for strings.

Multiple Choice Questions

1. Which of the following is False?


(a) String is immutable.
(b) max(s) returns the first largest Unicode character in the string s.
(c) len(s) returns the number of characters in the string s.
(d) None of these.

2. What will be the output of below Python code?


str1="Python"
print(str1[2:5])

(a) tho
(b) ytho
(c) th
(d) None of the above

396
3. What will be the output of below Python code?

str1="Python"
str2=str1.replace('y','Y')
print(str2)

(a) Python
(b) PYthon
(c) python
(d) None of the above

4. What will be the output of below Python code?

str1="Python"
str1.upper()
print(str1)

(a) Python
(b) PYTHON
(c) 'PYTHON'
(d) None of the above

5. Which of the following is not a correct way to create an str object?


(a) string1='Hello World'
(b) string2="Hello World"
(c) string3='''Hello World'''
(d) None of the above

6. Which of the following is incorrect?


(a) str(10)
(b) str(10.5)
(c) str(True)
(d) None of the above

7. Which of the following is not the correct way to access a character in a string?
(a) s[0]
(b) s[-1]
(c) s[1]

397
(d) None of the above

8. In Python, which of the following is true about string traversal?


(a) A string can only be traversed in forward direction
(b) A string cannot be traversed in backward direction
(c) A string can be traversed in both directions
(d) A string cannot be traversed

9. Which of the following is an incorrect Python statement, where s1 and s2 are


two string objects?
(a) s1+s2
(b) s1*s2
(c) s1 in s2
(d) s1 not in s2

10. Which of the following is an incorrect Python statement, where s1 and s2 are
two string objects?
(a) s1+s2
(b) s1*s2
(c) s1 in s2
(d) s1 *3+s2

11. What is the output of the following statement?


s1='A'
s2='B'
s1*3+s2

(a) 'AAAB'
(b) 'A3B'
(c) 'A^3B'
(d) None of the above

12. Which of the following is not a member function of the str class?
(a) capitalize
(b) len
(c) count
(d) center

398
13. What is the output of the following?
"abcd"[1:]
(a) a
(b) ab
(c) bcd
(d) dc

14. What is the output of the following?


str1 = 'hello'
str1[1:1]
(a) h
(b) e
(c) ''
(d) he

15. Which is not a valid string operator?


a) +
b) *
c) –
d) in

16. What is the output of the following?


print (r"\nhello")

a) hello
b) \nhello
c) r\n hello
d) It is an error

17. What is the output of the following?


print('x\97\x41')

(a) x\97A
(b) x\97\x41
(c) 97 41
(d) None of the above

399
18. What will be the output of the following Python code?
print (0xA + 0xB + 0xC)

(a) 0xA0xB0xC
(b) 0x22
(c) 33
(d) ABC

19. What will be the output of the following Python code?


example = "Python World"
print ("%s" % example[4:7])

(a) on
(b) Python World
(c) ho
(d) None of the above

20. What will be the output of the following?


s="Python"
s[0]="J"
print(s)

(a) Python
(b) Jython
(c) JPython
(d) It is an error

Review Questions

1. State whether the following statements are true or false:


a. A Python string object is mutable.
b. A Python string can contain only ASCII codes.

400
c. We cannot access individual character of a string using indexing.
d. We can use a triple single pair to create a string literal.
e. We cannot mix single and double quotes to create a string literal.
f. A str object can be created by assigning a string literal to a variable.
g. The max function returns the first character with the largest Unicode.
h. The statement s [-1] returns the second last character of the string s.
i. The statements s [-1] and s[len(s)] return the same character.
j. We cannot traverse a string in backward direction.
k. The slicing operator is used to extract a substring in a string.
l. We can use slicing with step of size 2 to get the alternate characters of s
string.
m. The + operator can be used concatenate two strings.
n. S1 in S2 return true if S1 is a sub string of S2.
o. S1 not in S2 return true if S1 is a sub string of S2.
p. S.capitalize() returns a corresponding string wilh all letters capitalized.
q. "ABC".center(7,"X") returns 'XXXABCXX'.
r. S.count('n') returns the number of characters in string S.
s. Is s.isdigit() and s.isdecimal() return the same output.
t. S.title() returns the string after making the first character of each word
capital of the string.

Programming Assignments

1. Write a program to print frequency of each character of a string.


2. Write a program to merge two strings character by character and stop when the
smaller string exhaust.
3. Write a program to exchange the first and the last characters of a string.

401
4. Write a program to print the frequency of each word in a given sentence.
5. Write a function to convert a given string to all uppercase if it contains at least 1
uppercase characters in the first 3 characters.
6. Write a program to sort characters of a string lexicographically, i.e. sorted in the
alphabetical order as used in dictionaries.
7. Write a program to check whether a string starts with a digit.
8. Write a function to return a leading zero padded string of specified width from a
given integer
9. Write a program to reverse each word in a string.
10 Write a program to convert a string into a list of words.
11. Write a program to print frequency of each vowel in a text.
12. Write a program to remove spaces and tabs from a given string.
13. Write a program to remove consecutive duplicate characters of a given string.
14 Write a program to count Uppercase, Lowercase, and digits in a given string
15 Write a function to get smallest and largest word in a given string.
16 Write a Python program to split a given paragraph into sentences.

402
Chapter 10

Tuples, Sets and Dictionaries


Learning Outcomes:

1. Understand tuples in Python.


2. Understand sets in Python.
3. Understand dictionaries in Python.
4. Create and manipulate items in tuples, sets and dictionaries.
5. Describe indexing and slicing in tuples.
6. Describe item retrieval in sets and dictionaries.
7. Discuss tuple comprehension.
8. Write program using tuples, sets and dictionaries.

In addition to the list data type, Python has three other collection data types: tuple,
set and dictionary. Similar to the list, they can store heterogeneous data, i.e. their elements
can be of different types. They provide some special features to create more efficient
programs. This chapter describes these data types in more details.

10.1 Tuple
A tuple is an immutable collection of heterogeneous data. Example 10.1 shows some
examples of tuples consisting of different types of data. A tuple once created does not
permit to change the values of its elements (elements are read only) and addition/deletion
of elements, i.e. size of a tuple is fixed. Except for the immutable nature of the tuple, it is
very similar to the list. Since elements of a tuple is immutable, accidental modification of a
tuple is not possible. Hence, it is recommended to use a tuple in place of a list whenever the
collection is read only. Further, since a tuple is stored in a single block of memory, it is faster
than a list.

Example 10.1: Tuples

>>> tuple1=(1,2,3,4) #Tuple of numbers


>>> print(tuple1)

403
(1, 2, 3, 4)
>>> #Tuple of numbers and strings
>>> tuple2=(1,"Two", "Three",4)
>>> print(tuple2)
(1, 'Two', 'Three', 4)
>>> #Tuple of a list, a tuple, a set and a dictionary
>>> tuple3=([1,2],(1,3),{6,3},{1:"One",2:"Two"})
>>> print(tuple3)
([1, 2], (1,3), {3, 6}, {1: 'One', 2: 'Two'})
>>>

10.2 Creating Tuples


Tuples can be created in the following manners:

10.2.1 From Data

Placing all the data inside parentheses (), separated by commas, creates a tuple
literal and assigning it to a variable creates a tuple variable. For example, the statement t =
(1,2,3) creates a tuple. A tuple can have any number of items of different types (integer,
float, list, string, etc.). The parentheses are optional. Hence, assigning a set of values
separated by commas to a variable also creates a tuple. This is called the packing of values
as a tuple. For example, the statement t = 1,2,3 creates a tuple.

If an empty parenthesis is assigned to a variable, it creates an empty tuple. Hence,


the statement t = () will create an empty tuple. However, if we assign a parenthesis to a
variable with a single item in it, Python does not create a tuple. it simply creates a variable
of the type of the data. To create a tuple with a single item, the item must be followed by a
comma. For example, in x = (2), x is not a tuple, but in x = (2,), x is a tuple. Example 10.2(a)
illustrates the above concepts.

10.2.2 From other Iterables

We can convert other data types into tuples by using the constructor of the tuple
class. Python permits conversion of other data into a tuple with the help of the tuple method
of the tuple class. For example, the statement t=tuple ([1,2,3]), converts a list into a tuple.
Example 10.2(b) illustrates the above concepts.

404
We can convert any collection data into a tuple. However, note the type of elements in
the returned tuple:

• When we convert a string into a tuple, all the characters of the string become
separate elements in the tuple.
• When we convert a list of strings into a tuple, the individual strings of the list
become the elements of the tuple.
• When we convert a dictionary into a tuple, the tuple consists of the keys of the
dictionary and values are ignored.
• In case of a range data, the tuple consists of series elements of the range as separate
elements in the tuple.
• Trying to convert atomic data, such as an int, a float, etc., will raise an error as the
tuple method can be used only with collections and sequences.

10.2.3 Using Comprehension

Similar to lists, tuples can also be created using the tuple comprehension from an
existing iterable data. Example 10.2(c) shows how to create a tuple of the even numbers
from a list using the tuple comprehension.

Example 10.2(a): Create tuples from data

>>> tuple1=(1,2,3)#Homogeneous tuple of numbers


>>> print(type(tuple1),tuple1)
<class 'tuple'> (1, 2, 3)
>>> tuple2=() #Empty tuple, denoted by ()
>>> print(type(tuple2),tuple2)
<class 'tuple'> ()
>>> tuple3=1,2,3 #Creating tuple without parentheses
>>> print(type(tuple3),tuple3)
<class 'tuple'> (1, 2, 3)
>>> tuple4=(3) #Single item in a parentheses is not a tuple
>>> print(type(tuple4),tuple4)
<class 'int'> 3
>>> tuple5=(3,) #Single item followed by a comma in a
parentheses is a tuple
>>> print(type(tuple5),tuple5)
<class 'tuple'> (3,)
>>> tuple5=2, #Single item followed by a comma is a tuple
>>> print(type(tuple5),tuple5)
<class 'tuple'> (2,)

405
>>> tuple6=(1,"Two",(1,2)) #Heterogeneous tuple
>>> print(tuple6)
(1, 'Two', (1, 2))
>>> #Tuple with different types of data
>>> tuple7=([1,2],{4,5},{1:"One",2:"Two"})
>>> print(tuple7)
([1, 2], {4, 5}, {1: 'One', 2: 'Two'})

Example 10.(b): Convert collections into tuples

>>> list1=[1,2,3]
>>> tuple1=tuple(list1) #Convert a list to a tuple
>>> print(list1,tuple1)
[1, 2, 3] (1, 2, 3)
>>> s1="Python"
>>> tuple2=tuple(s1) #Convert a string to a tuple
>>> print(tuple2)
('P', 'y', 't', 'h', 'o', 'n')
>>> set1={1,2,3,2,3,4}
>>> tuple3=tuple(set1) #Convert a set to a tuple
>>> print(tuple3)
(1, 2, 3, 4)
>>> dict1={1:"One",2:"Two"}
>>> tuple4=tuple(dict1)#Convert a dict to a tuple
>>> print(tuple4)
(1, 2)
>>> r=range(3,6) #Create a range
>>> r
range(3, 6)
>>> tuple5=tuple(r)#Convert a range to a tuple
>>> print(tuple5)
(3, 4, 5)
>>> list1=["One", "Two", "Three"]
>>> x=enumerate(list1) #Create an enumerate object
>>> tuple6=tuple(x) #Convert an enumerate object to a tuple
>>> tuple6
((0, 'One'), (1, 'Two'), (2, 'Three'))

Example 10.2(c): Tuple comprehension

list1=[1,2,3,4,5,6,7,8]
#Tuple comprehension
tuple1=tuple(x for x in list1 if x%2==0)

406
print(tuple1)
Output
(2, 4, 6, 8)

10.3 Built-in Functions for Tuples


Python built-in functions, such as sum, max, min, len, can be used for tuples, and
their behavior is similar to lists. Table 10.1 illustrates the usages of these functions with
tuples.

Table 10.1: Built-in functions for tuples

Built-in function Description and usages

sum The sum function sums all the elements if a tuple consists of
numeric values.

>>> tuple1=(1,2,3,4,5)
>>> sum(tuple1) #Sum all the elements
15
>>> tuple2=(2+3j,4-3j)#Can sum complex numbers
>>> sum(tuple2)
(6+0j)
>>> tuple3=(1,2.3,True)#Logical True=1 and False=0
>>> sum(tuple3)
4.3
>>> Tuple4=('a','b','c')
>>> sum(Tuple4)#Error: cannot sum non-numeric
Traceback (most recent call last):
File "<pyshell#54>", line 1, in <module>
sum(Tuple4)
TypeError: unsupported operand type(s) for +: 'int'
and 'str'
len The len method counts the number of elements in a tuple.

>>> tuple1=(1,2,3)
>>> len(tuple1) #Counts the number of elements
3
>>> tuple2=("Hello", "World")
>>> len(tuple2)
2

407
max The max function finds the maximum elements in a tuple.

>>> tuple1=(2,1,4,3,6,2)
>>> max(tuple1) #Find the maximum
6
>>> tuple2=('a','b','c','f','d')
>>> max(tuple2) #Find the character with maximum
Unicode value
'f'
>>> #Find the maximum string based on the dictionary
order
>>> tuple3=("Hello", "Hi", "Welcome")
>>> max(tuple3)
'Welcome'
>>> tuple4=(1,2,"Three",4)
>>> max(tuple4)#Error: mixing of strings and
integers are not allowed
Traceback (most recent call last):
File "<pyshell#67>", line 1, in <module>
max(tuple4)
TypeError: '>' not supported between instances of
'str' and 'int'
>>> tuple5=(1,2,True, False)#Integers and Booleans
are allowed together
>>> max(tuple5) #True=1 and False=0
2
min The min function finds the minimum of a tuple.

>>> tuple1=(2,4,2,6)
>>> min(tuple1) #Find minimum of a tuple
2
>>> tuple2=('a', 'b', 'c')
>>> min(tuple2)
'a'
>>> tuple3=("Hello", "World")
>>> min(tuple3)
'Hello'
>>> tuple4=(1,2,True, False)
>>> min(tuple4)
False

408
10.4 Indexing of Tuple Elements
Since a tuple is an ordered sequence of elements, an individual element of a tuple
can be accessed through an index. An index is given in a pair of square brackets and is
always an integer or a Boolean. Like lists, tuple elements can be accessed through positive
as well as negative indices. The positive indices start with 0, which refers to the first element
of the tuple. The negative indices start with -1, which refers to the last element of the tuple.
Figure 10.1 shows the positive and negative indexing schemes of a tuple. As can be seen
from figure 10.1, the same element can be accessed either using the positive indexing or the
negative indexing. For example, tuple1[0] and tuple1[-5] both will return the first element.
Similarly, tuple1[4] and tuple1[-1] will return the last element of tuple1. Example 10.4
illustrates the above concepts.

Forward index 0 1 2 3 4

tuple1 10 20 30 40 50

Backward index -5 -4 -3 -2 -1

Figure 8.1: Forward and backward indexing of a tuple

Example 10.4: Accessing tuple elements

>>> tuple1=(10,20,30,40,50)
>>> tuple1[0] #The first element of the tuple
10
>>> tuple1[-5] #The first element of the tuple
10
>>> tuple1[4] #The last element of the tuple
50
>>> tuple1[-1] #The last element of the tuple
50
>>> tuple1[0]+tuple1[-1] #Sum the first and the last element
60
>>> tuple1[True] #True is equal to 1
20
>>> tuple1[False] #True is equal to 0
10
>>> tuple

409
10.5 Slicing of Tuple
Similar to lists, multiple elements of a tuple can be obtained using a slicing
operation. A slicing operation on a tuple returns a tuple. Example 10.5 illustrates slicing
operations on a tuple.

Example 10.5: Slicing operations

>>> tuple1=(1,2,3,4,5,6,7,8,9,10)
>>> tuple1[:] #All elements of tuple1
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> tuple1[::2]#Alternative elements from start to end
(1, 3, 5, 7, 9)
>>> #Alternative elements from the second to ninth
>>> tuple1[1:9:2]
(2, 4, 6, 8)
>>> tuple1[::] #All the elements
(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
>>> tuple1[:4]#The first four elements
(1, 2, 3, 4)
>>> tuple1[-4:] #The last four elements
(7, 8, 9, 10)
>>> tuple1[::-1] #All the elements from end to start
(10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
>>> tuple1[::-2] #Alternative elements from end to start
(10, 8, 6, 4, 2)
>>> tuple1[3:7] #All the elements from the forth to the seventh
(4, 5, 6, 7)
>>> tuple1[3:8:6] #Single element is also returned as a tuple.
(4,)

10.6 Operations on Tuples


Similar to lists, tuples also support concatenation (+), repetition (*) and membership
(in and not in) operators. Example 10.6 illustrates their usages.

Example 10.6: Operations with tuples

>>> tuple1=("Hello", "World")


>>> tuple2=("I", "Love", "Python")
>>> tuple3=tuple1+tuple2 #Concatenate tuples
>>> tuple3

410
('Hello', 'World', 'I', 'Love', 'Python')
>>> tuple4=tuple1*2 #Repeat a tuple
>>> tuple4
('Hello', 'World', 'Hello', 'World')
>>> #Check presence of a value in a tuple
>>> 'Hello' in tuple1
True
>>> 'Hello' in tuple2
False
#Check absence of a value in a tuple
>>> 'Python' not in tuple1
True

10.7 Traversing Tuples


A tuple can be traversed from start to end using: (1) for loop, (2) while loop, and (3)
enumerate function. The enumerate () method adds a counter to an iterable and returns it
as an enumerate object, which can be used in a for loop for traversing. Example 10.7(a-e)
gives some illustrative examples. As can be seen from example 10.7(e), we can unpack
elements while traversing.

Example 10.7(a): Traverse using a for loop

tuple1=(1,2,3)
for t in tuple1: #Traversing a tuple
print(t, t*t)
Output
1 1
2 4
3 9

Example 10.7(b): Traverse using a for loop and an index

tuple1=(1,2,3)
for index in range(len(tuple1)): #Traverse using index
print(tuple1[index], tuple1[index]*tuple1[index])
Output
1 1
2 4
3 9

411
Example 10.7(c): Traverse using a while loop and an index

tuple1=(1,2,3)
n=len(tuple1)
index=0
while(index<n):#Traverse using a while loop
print(tuple1[index], tuple1[index]*tuple1[index])
index+=1
Output
1 1
2 4
3 9

Example 10.7(d): Traverse using a for loop and an enumerate function

tuple1=(1,2,3)
#Traverse using the enumerate function
for t in enumerate(tuple1):
print(t)
Output
(0, 1)
(1, 2)
(2, 3)

Example 10.7(e): Unpacking while traversing

tuple1=((1,"One"),(2,"Two"),(3,"Three"))
for x,y in tuple1:#Unpacking while traversing
print(x,y)
Output
1 One
2 Two
3 Three

412
10.8 Sorting a Tuple
As discussed earlier, a tuple is an immutable sequence of data, hence it cannot be
sorted in place. However, we can convert a tuple into a list, which can be sorted and
converted back as a tuple. Example 10.8 illustrates the above process to get a sorted tuple.

Example 10.8: Sorting a tuple

tuple1=(1,6,4,2,8,9)
list1=list(tuple1)#Convert to list
list1.sort() #Sort the list
tuple2=tuple(list1) #Convert back to tuple
print("Original tuple:",tuple1)
print("Sorted tuple:",tuple2)
Output
Original tuple: (1, 6, 4, 2, 8, 9)
Sorted tuple: (1, 2, 4, 6, 8, 9)

10.9 Zipping Tuples Together


The zip () function is used to generate a zipped object which is a series of tuples
containing elements from a number of iterables. Iterables can be of any type of sequence
data. Zipping is stopped at the shortest iterable and elements in the other larger iterables
are ignored. Example 10.9(a) illustrates the zipping of two tuples. A zipped object or a
combined tuple can be unzipped in separate tuples using the * operator with the zip
function, as illustrated in example 10.9(b).

Example 10.9(a): Zipping tuples together

tuple1=(1,2,3,4,5)
tuple2=('a', 'b', 'c', 'd', 'e', 'f', 'g')
zip1=zip(tuple1, tuple2)#Zipping tuples together
print(tuple(zip1))#Converting the zipped object into a tuple
Output
((1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'))

413
Example 10.9(b): Unzipping

>>> #Nested tuple


>>> tuple1=((1, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e'))
>>> a,b=zip(*tuple1) #Unzipping a nested tuple
>>> a
(1, 2, 3, 4, 5)
>>> b
('a', 'b', 'c', 'd', 'e')
>>> zip1=zip(a,b)
>>> c,d=zip(*zip1)#Unzipping a zip object
>>> c,d
((1, 2, 3, 4, 5), ('a', 'b', 'c', 'd', 'e'))

10.10 Tuple Methods


The tuple object has only two member methods: count and index. The count method
returns the number of times a specified value occurs in a tuple, and the index method
searches a specified value in the tuple and returns the index of the first match. Table 10.2
describes these two with examples

Table 10.2: Built-in methods of the tuple object

Built-in function Description and usages

count(value) Counts the number of occurrences of the value in the tuple.


>>> tuple1=(1,2,3,4,26,2,3,2)
>>> #Count the number of occurrences of 2
>>> tuple1.count(2)
3
>>> tuple2=tuple("Hello World")
>>> tuple2
('H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l',
'd')
>>> #Count the number of occurrences of 'o'
>>> tuple2.count('o')
2
index(value) Finds the index of the first match of the value in the tuple.
>>> tuple1=(1,2,3,4,5)
>>> #Find the index of the first match of 3
>>> tuple1.index(3)
2
414
>>> tuple2=('a', 'b', 'c', 'd', 'e', 'f')
>>> #Find the index of the first match of 'd'
>>> tuple2.index('d')
3

10.11 Lists and Other Mutable Sequences as Elements of Tuples


Though a tuple is an immutable sequence, but it can contain mutable sequences,
such as lists, sets and dictionaries as its elements. Once a tuple is created with mutable
sequences as its elements, we cannot remove them or replace these mutable sequences with
other data. But we can edit and add elements to these mutable sequences. Example 10.11
illustrates these concepts.

Example 10.11: Lists and other mutables as elements of a tuple

>>> list1=[1,2,3]
>>> set1={7,8,9}
>>> dict1={1:"One",2:"Two"}
>>> #A tuple with a list, a set and a dict as its elements
>>> tuple1=(list1,set1,dict1)
>>> tuple1
([1, 2, 3], {8, 9, 7}, {1: 'One', 2: 'Two'})

>>> list1.append(4) #Adding an element to the list


>>> set1.add(10) #Adding an element to the set
>>> dict1[3]="Three" #Adding an element to the dict
>>> tuple1 #Updated tuple
([1, 2, 3, 4], {8, 9, 10, 7}, {1: 'One', 2: 'Two', 3: 'Three'})

>>> list1.remove(2) #Removing an element


>>> set1.remove(8) #Removing an element
>>> del dict1[3] #Removing an element
>>> tuple1 #Updated tuple
([1, 3, 4], {9, 10, 7}, {1: 'One', 2: 'Two'})

>>> #Creating a new list with the same name does not change the tuple
>>> list1=['a','b']
>>> tuple1
([1, 3, 4], {9, 10, 7}, {1: 'One', 2: 'Two'})
>>> tuple1[0].append(5) #Mutable tuple element
>>> tuple1
([1, 3, 4, 5], {9, 10, 7}, {1: 'One', 2: 'Two'})
>>>

415
10.12 Tuple vs List
Both tuple and list can store heterogeneous data in an ordered sequence but there are
some differences in these two widely used data types, as given below:

a. A lists uses square brackets [] and a tuple uses parenthesis () to surround their
elements. For example, [1,2,3] is a list whereas (1,2,3) is a tuple.
b. A list is mutable in nature, i.e. we can edit, add/remove elements in a list, whereas
a tuple is immutable in nature, i.e., we cannot edit or modify a tuple once it is
created. If we try to edit a tuple, error will be generated as shown in example 10.12.
c. A list has variable length whereas a tuple has fixed length.
d. A tuple is stored in a single block of memory, whereas a list may be spread over
many blocks of memory. Due to this, tuples operations are faster as compared to
lists.
e. Lists has more built-in functions than that of tuple, therefore, there are many
additional functionalities associated with a list as compared to a tuple. For example,
we can perform sorting, reversal of elements in a list whereas these facilities are
unavailable in a tuple.

Example 10.12: List vs tuple

>>> var1=[1,2,3] #Create a list


>>> var2=(1,2,3) #Create a tuple
>>> print(type(var1), type(var2)) #Knowing types
<class 'list'> <class 'tuple'>
>>> print(var1[1],var2[1]) #Accessing elements
2 2
>>> var1[1]=5 #Editing a list element
>>> var2[1]=5 #Error: editing a tuple element
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
var2[1]=5
TypeError: 'tuple' object does not support item assignment
>>> print(len(var1),len(var2)) #Find sizes of list and tuple
3 3
>>> #Adding an element to a list. it is not permitted in a tuple
>>> var1.append(4)
>>> len(var1)
4
>>> #Reversing a list. it is not allowed in a tuple
>>> var1.reverse()
>>> var1
[4, 3, 5, 1]

416
10.13 Sets
A set is an unordered collection of distinct items of various types. Since it is
unordered, it is unindexed, i.e. we cannot access elements with an index. Further, the
elements of a set are distinct. Hence a duplicate entry is not added into the set. In contrast
to the list, which is an ordered collection that maintains the elements in insertion order, the
set, being unordered collection of elements, does are not maintained any order. Hence,
traversal of a set may return items in a different order than the order of elements given
during creation. Example 10.13 illustrates the above.

Example 10.13: Sets

>>> set1={1,2,4,6,2,4} #Duplicate elements are removed


>>> set1
{1, 2, 4, 6}
>>> set2={8,5,3,2} #Order of elements may change
>>> set2
{8, 2, 3, 5}

10.14 Creating Sets


Sets can be created in the following ways:

a. Sets from data: By enclosing data within curly brackets, {}, separated by commas.
Non-hashable iterables, such as lists, dictionaries and sets are not allowed.
b. Sets from other data types: We can convert other iterable data types into sets by
using the set () method. The syntax is set_var = set(iterable_data).
c. Sets from the set comprehension: Similar to lists and tuples, the compression can
be used to create sets from an existing iterables.

Example 10.14(a) shows how to create sets from data, and example 10.14(b) shows how
to convert other types of iterables into sets. If there are duplicate entries in data or other
iterables, they are removed automatically. Further, order of the elements may change
during creation or conversion. If there is no element is a set, it is called an empty set, which
is denoted by set (). Please note, empty curly bracket, {}, represents an empty dictionary not
a set. An empty set is created by assigning set () to a variable. Example 10.14(c) shows how
to create a set using the set comprehension.

417
Example 10.14(a): Creating sets from data

>>> set1={1,2,3,4} #Set of homogeneous data


>>> set1
{1, 2, 3, 4}
>>> #Set of heterogeneous data
>>> set2={1,"Two",True, None, 2.3,2+3j}
>>> set2
{1, 2.3, (2+3j), None, 'Two'}
>>> set3={(1,2,3),"Hello"}
>>> set3
{(1, 2, 3), 'Hello'}
>>> set4={[1,2,3],[6,7]} #Error: Lists are not allowed
Traceback (most recent call last):
File "<pyshell#53>", line 1, in <module>
set4={[1,2,3],[6,7]}
TypeError: unhashable type: 'list'
>>> set6=set() #Create an empty set
>>> print(set6)
set()

Example 10.14(b): Converting iterables into sets

>>> set7=set([1,2,3,4,5,6,2,3,4]) #convert a list into a set


>>> set7
{1, 2, 3, 4, 5, 6}
>>> set8=set((1,2,3,4,5,1,3,6)) #Convert a tuple into a set
>>> set8
{1, 2, 3, 4, 5, 6}
>>> set9=set({1,2,3,4}) #Convert a set into a set
>>> set9
{1, 2, 3, 4}
>>> #Convert a dictionary into a set
>>> set10=set({1:"One",2:"Two",3:"Three"})
>>> set10
{1, 2, 3}

Example 10.14(c): Set comprehension

list1=[1,2,3,4,5,6,7,8]

418
#Set comprehension
set1=set(x for x in list1 if x%2==0)
print(set1)
Output
{8, 2, 4, 6}

10.15 Built-in Functions for Sets


Similar to lists and tuples, the sum, max, min, len, any, all, sorted and enumerate
built-in functions can be used with sets. Example 10.15 illustrates some typical usages of
these functions with sets.

Example 10.15: Built-in functions with sets

>>> set1={1,2,3}
>>> sum(set1) #Sum all the elements
6
>>> max(set1) #Find the maximum value in the set
3
>>> min(set1) #Find the minimum value in the set
1
>>> len(set1) #Count the number of elements in the set
3
>>> set2={"One", "Two", "Three", "Four"}
>>> max(set2) #Maximum based on the dictionary order
'Two'
>>> min(set2) #Minimum based on the dictionary order
'Four'
>>> sorted(set2) #Create a sorted list of the set elements
['Four', 'One', 'Three', 'Two']
>>> #Create an enumerated list of the set elements
>>> list(enumerate(set2))
[(0, 'Three'), (1, 'One'), (2, 'Four'), (3, 'Two')]
>>> set3={1,2, False}
>>> #Returns true if all the elements of the set are True
>>> all(set3)
False
>>> #Returns true if any element of the set is True
>>> any(set3)
True

419
10.16 Membership Operators: in and not in
Similar to other collection data types, sets also support in and not in operators to
check the existence of a value in a set. Example 10.16 illustrates their typical usages.

Example 10.16: Membership operators

>>> set1={1,2,4,5,7}
>>> 2 in set1 #Check presence of a value in the set
True
>>> 2 not in set1 #Check absence of a value in the set
False
>>> set2={"Hello", "World"}
>>> "Hello" in set2 #Check presence of a value in the set
True
>>> "Hi" in set2 #Check presence of a value in the set
False

10.17 Set Methods


The set class has many methods to perform various operations on set data. Table
10.3 lists some of the methods with their brief descriptions and some typical usages.

Table 10.3: Built-in methods of the set class

Built-in function Description and usages

add(value) Adds value as an element to the set if it is not in the set.

>>> set1={1,2,3}
>>> set1.add(4) #Add an element to the set
>>> set1
{1, 2, 3, 4}
clear() Removes all the elements from a set to make it an empty
set.

>>> set1={1,2,3}
>>> set1
{1, 2, 3}
>>> set1.clear() #Remove all the elements of
the set
420
>>> set1
set()
copy() Creates and returns a copy of the set

>>> set1={1,2,3}
>>> set2=set1.copy() #Create a copy of the
set
>>> set2.add(4)
>>> print(set1,set2)
{1, 2, 3} {1, 2, 3, 4}
difference(set2) Performs the set difference operation, i.e. to create and
return a set that contains the items that only exist in the
first set but not in the second set.

>>> set1={1,2,3}
>>> set2={1,2,5}
>>> set1.difference(set2) #Performs set1-set2
{3}
>>> set2.difference(set1) #Performs set2-set1
{5}
difference_update(set2) Removes the items from the set which are also in the set2.
It modifies the original set.

>>> set1={1,2,3}
>>> set2={1,2,5}
>>> #Remove the common elements from set1
>>> set1.difference_update(set2)
>>> set1
{3}
discard(value) Removes value from the set.

>>> set1={1,2,3,4}
>>> set1.discard(3) #Remove 3 from the set
>>> set1
{1, 2, 4}
intersection(set2) Performs the intersection operation of the set with set2
and returns the intersection set. The original sets are
unaffected.

>>> set1={1,2,3,4}
>>> set2={1,4,2,7}
>>> #Find intersection of the set with set2
>>> set1.intersection(set2)
{1, 2, 4}
421
#Find intersection of the set with set1
>>> set2.intersection(set1)
{1, 2, 4}
intersection_update(set2) Removes the items in the set which are not present in
set2. It updates the original set.

>>> set1={1,2,3,4}
>>> set2={1,4,2,7}
>>> #Remove elements from set1 which are not
in set2
>>> set1.intersection_update(set2)
>>> set1
{1, 2, 4}
isdisjoint(set2) Returns true if the set and set2 have no common values,
i.e. their intersection is an empty set.

>>> set1={1,2,3,4}
>>> set2={1,3,6,8}
>>> set3={5,6,7,8}
>>> #Check whether set1 and set2 are disjoint
set
>>> set1.isdisjoint(set2)
False
>>> #Check whether set1 and set3 are disjoint
set
>>> set1.isdisjoint(set3)
True
issubset(set2) Tests whether the set is a subset of set2, returns True if
so, otherwise returns False.

>>> set1={1,2,3}
>>> set2={1,2,3,4,5}
>>> set3={1,2,4,6}
>>> #Check whether set1 is a subset of set2
>>> set1.issubset(set2)
True
>>> #Check whether set1 is a subset of set3
>>> set1.issubset(set3)
False
issuperset(set2) Tests whether the set is a superset of set2, returns True if
so, otherwise returns False.

>>> set1={1,2,3,4,5,6}
>>> set2={2,4,5}

422
>>> set3={1,2,7}
>>> #Check if set1 is a superset of set2
>>> set1.issuperset(set2)
True
>>> #Check if set1 is a superset of set3
>>> set1.issuperset(set3)
False
pop() Removes an item from the set based on its internal
iterator and returns the removed value. The internal
iterator may return random values as a set is an
unordered and unindexed collection of items.

>>> set1={1,7,6,2,3}
>>> #Remove an item from set1
>>> set1.pop()
1
>>> #Remove an item from set1
>>> set1.pop()
2
remove(value) Removes value from the set.

>>> set1={1,2,3,4,5}
>>> #Remove 3 from set1
>>> set1.remove(3)
>>> set1
{1, 2, 4, 5}
symmetric_difference(set2) Returns the symmetric difference of the set and set2. The
symmetric difference of two sets A and B is the set (A –
B) ∪ (B – A).

>>> set1={1,2,3,5}
>>> set2={1,2,6,7}
>>> #Find the symmetric difference of set1
and set2
>>> set1.symmetric_difference(set2)
{3, 5, 6, 7}
symmetric_difference Updates the set with the symmetric difference of the set
with set2.
_update(set2)
>>> set1={1,2,3,5}
>>> set2={1,2,6,7}
>>> #Update set1 with the symmetric
difference of set1 and set2
>>> set1.symmetric_difference_update(set2)
423
>>> set1
{3, 5, 6, 7}
union(set2) Return the union of the set and set2. The original sets are
unaffected.

>>> set1={1,2,3,4}
>>> set2={3,4,5,6}
>>> set3=set1.union(set2) #Union of set1 and
set2
>>> set3
{1, 2, 3, 4, 5, 6}
>>> set1 #The original set unaffected
{1, 2, 3, 4}
update(set2) Adds all the elements of set2 into the set, ignoring the
already existing elements in the set.

>>> set1={1,2,3,4}
>>> set2={3,4,5,6}
>>> #Add all the elements of set2 into set1,
ignoring duplicates
>>> set1.update(set2)
>>> set1
{1, 2, 3, 4, 5, 6}

10.18 Traversing Sets


Though a set is unordered and unindexed collection of items, we can traverse a set
using a for loop. Please note, the items returned during traversal of a set may not be in the
order in which the set is created, but we will get all the items one by one. We cannot access
items in a set using indices, as sets are unordered. Hence, we cannot use while loop to
traverse a set. However, we can create an enumerate object from a set and use it to traverse
using a while or a for loop. Example 10.18 shows traversal of a set.

Example 10.18: Traversing a set

>>> set1 ={'Three', 'One', 'Four', 'Two'}


>>> for x in set1: #Traversing a set using a for loop
print(x,end=' ')

Three One Four Two


>>> enm1=enumerate(set1)

424
>>> for i,x in enm1: #Traversing a set using enumeration
print(x, end=" ")

Three One Four Two


>>> enm1=list(enumerate(set1))
>>> i=0
>>> while i < len(enm1): #Traversing a set a while loop
print(enm1[i])
i=i+1

(0, 'Three')
(1, 'One')
(2, 'Four')
(3, 'Two')

10.19 Frozenset
Python has added frozenset class that has the characteristics of a set, but it is
immutable, i.e. its contents cannot be modified after its creation. It is similar to a tuple and
can be used a key in a dictionary. Frozen sets are created using the frozenset () function.
The frozenset supports all the methods of the set class methods except the methods which
modifies the set itself. Example 10.19 shows how to create a frozenset and use it in a
dictionary.

Example 10.19: Frozenset

>>> set1=frozenset([1,2,3,4]) #Create a frozenset


>>> type(set1)
<class 'frozenset'>
>>> set1
frozenset({1, 2, 3, 4})
#Frozenset as a key in a dictionary
>>> dict1={set1:"Frozenset",2:"Two"}
>>> dict1
{frozenset({1, 2, 3, 4}): 'Frozenset', 2: 'Two'}
>>> set1.add(8) #Error: cannot modify a frozenset
Traceback (most recent call last):
File "<pyshell#189>", line 1, in <module>
set1.add(8)
425
AttributeError: 'frozenset' object has no attribute 'add'

10.20 Dictionaries
A dictionary in Python is basically an associative array, also called map, that holds
data in the form of key and value pairs. In this each key is associated with a value. It is
similar to a phone directory where we can find the phone number of a person based on his
name. Each key is unique and immutable in a dictionary. From Python 3.7, a dictionary is
an ordered and mutable collection of items. In the earlier versions of Python, dictionaries
are un-ordered collection. Example 10.20 shows examples of dictionaries.

Example 10.20: Dictionaries

>>> Examples of dictionaries


>>> phone={"Amit":"12345678","Ram":"23412343","John":"32145643"}
>>> phone["Amit"]
'12345678'
>>> phone["John"]
'32145643'
>>> square={1:1,2:4,3:9,4:16}
>>> square[1]
1
>>> square[3]
9
>>>

10.21 Creating Dictionaries


Dictionaries can be created in the following ways:

a) From data: We can create a dictionary by placing key: value pairs within a pair of
curly brackets, {}, separated by commas. A key and the corresponding value is
separated by a colon, such as key1: value1. Keys must be immutable and hashable.
Hence, lists and sets cannot be used as keys. However, we can use tuples, strings,
integers, floats, complex numbers, Booleans as keys. In case of duplicate keys, the
value corresponding to the last duplicate key will be retained. In this way, we cannot
have duplicate keys in a dictionary. However, we can have duplicate values in a
dictionary. Example 10.21(a) illustrates the above.

426
b) From other collections: Other collections such as lists, tuples, sets can be converted
to dictionaries in a two-step process: First create a zip object of two iterables, the first
will work as keys and the other will work as values. In the second step, the function
dict() will be used to convert the zip object into a dictionary. Since, sets are
unordered collection, it is recommended not to use this method to convert sets into
dictionaries as keys and values are mapped randomly. Example 10.21(b) illustrates
the above process.
c) Dictionary comprehension: We can also create a dictionary using the dictionary
comprehension from existing collections. Example 10.21(c) illustrates the dictionary
comprehension.
d) From variables and values: The dict function can also be used with variables and
their values to create a dictionary. A dictionary can also be created using a list
consisting of tuples of key value pairs, using the dict function, see example 10.21(d).

e) By iteratively adding values to a dictionary: we can create an empty dictionary and


then add items in it, see example 10.21(e)

Example 10.21(a): Create a dictionary from data

>>> dict1={1:"One",2:"Two",3:"Three"} #Integers as keys


>>> type(dict1)
<class 'dict'>
>>> dict1
{1: 'One', 2: 'Two', 3: 'Three'}
>>> dict2={"One":1,"Two":2,"Three":3} #Strings as keys
>>> dict2
{'One': 1, 'Two': 2, 'Three': 3}
>>> dict3={(1,1):"One, One",(2,1):"Two one"} #Tuples as keys
>>> dict3
{(1,1):"One, One",(2,1):"Two one"}
>>> #Floats, complex numbers, Booleans as keys
>>> dict4={1.1:"Float",2+3j:"Complex",True:"Boolean"}
>>> dict4
{1.1: 'Float', (2+3j): 'Complex', True: 'Boolean'}
>>> #Lists and sets are mutable. They cannot be used as keys
>>> dict5={[1,2]:"List1",{2,3}:"Set1"}
Traceback (most recent call last):
File "<pyshell#249>", line 1, in <module>
dict5={[1,2]:"List1",{2,3}:"Set1"}
TypeError: unhashable type: 'list'

427
Example 10.21(b): Create a dictionary using iterables

>>> list1=[1,2,3,4]
>>> list2=["One", "Two", "Three", "Four"]
>>> zip1=zip(list1,list2) #Zipping lists
>>> dict1=dict(zip1) #Convert a zipped object into a dictionary
>>> dict1
{1: 'One', 2: 'Two', 3: 'Three', 4: 'Four'}
>>> tuple1=(1,2,3,4)
>>> tuple2=("One", "Two", "Three", "Four")
>>> zip2=zip(tuple1,tuple2) #Zipping tuples
>>> dict2=dict(zip2)#Convert a zipped object into a dictionary
>>> dict2
{1: 'One', 2: 'Two', 3: 'Three', 4: 'Four'}
>>> set1={1,2,3,4}
>>> set2={"One", "Two", "Three", "Four"}
>>> zip3=zip(set1,set2) #Zipping sets
>>> dict3=dict(zip3) #Convert a zipped object into a dictionary
>>> dict3 #Note the randomness occurred due to sets
{1: 'Four', 2: 'Three', 3: 'Two', 4: 'One'}
>>> zip4=zip(list1,tuple2) #Zipping a list and a tuple
>>> dict4=dict(zip4) #Convert a hybrid zipped object into a dictionary
>>> dict4
{1: 'One', 2: 'Two', 3: 'Three', 4: 'Four'}
>>>

428
Example 10.21(c): Dictionary comprehension

>>> list1= [0,1,2,3]


>>> list2= ["One", "Two", "Three", "Four"]
>>> #Create a dictionary of even numbers in list1 and the corresponding
element in list2
dict1={x:list2[x] for x in list1 if x%2==0}
>>> dict1
{0: 'One', 2: 'Three'}
>>> tuple1= (2,6,2,3,5)
>>> tuple2= (3,2,6,6,2)
>>> #Create a dictionary of pair of elements of tuple1 and tuple2 where
tuple1[i]<tuple2[i]
>>> dict1={tuple1[i]: tuple2[i] for i in range(min([len(tuple1),
len(tuple2)])) if tuple1[i]<tuple2[i]}
>>> dict1 #The previous value of key (here 2) is overwritten by the
current value of 2
{2: 6, 3: 6}

Example 10.21(d): Dictionaries from variables

>>> dict1=dict(Name="John", Age=20) #Dictionary from variables


>>> dict1
{'Name': 'John', 'Age': 20}
>>> #Creating a dictionary from a list consisting of tuples with key-
value pairs
>>> dict2=dict([(1,"One"),(2,"Two"),(3,"Three")])
>>> dict2
{1: 'One', 2: 'Two', 3: 'Three'}

Example 10.21(e): Create a dictionary by iteratively adding elements

>>> dict1={} #Create an empty dictionary


>>> for i in range(5): #Adding elements to the dictionary
dict1["key"+ str(i)]="Value"+ str(i)

>>> dict1

429
{'key0': 'Value0', 'key1': 'Value1', 'key2': 'Value2', 'key3':
'Value3', 'key4': 'Value4'}

10.22 Accessing a Dictionary Element


An element of a dictionary can be accessed by using the key of the element in a pair
of square brackets, []. It can also be accessed using the get method of the dictionary. Example
10.22 illustrates the above.

Example 10.22: Accessing dictionary elements

>>> phone={"Amit":"12345678","Ram":"23412343","John":"32145643"}
>>> phone["Amit"] #Accessing through square brackets
'12345678'
>>> phone.get("Amit") #Accessing through the get method
'12345678'

10.23 Nested Dictionary


A dictionary can be used as a value in other dictionary. In this way, we can create a
nested dictionary. Nesting can be done up to any depth. Example 10.23 creates a nested
dictionary and illustrates how to access elements in a nested dictionary

Example 10.23: Nested dictionary

>>> dict1 = {1: 'One', 2: 'Two', 3: 'Three'}


>>> dict2 = {'i': "One", "ii": "Two", "iii": "Three"}
>>> dict3={"Numeric": dict1,"Roman": dict2} #Nested dictionary
>>> dict3
{'Numeric': {1: 'One', 2: 'Two', 3: 'Three'}, 'Roman': {'i': 'One',
'ii': 'Two', 'iii': 'Three'}}
>>> dict3["Numeric"][1] #Accessing elements
'One'
>>> dict3["Roman"]['i'] #Accessing elements
'One'

430
10.24 Removing an Element from a Dictionary
An element of a dictionary can be removed by using del keyword. The syntax is del
dictionary[key]. Items in a Nested dictionary can also be deleted by using del keyword. If
we do not provide a key, the complete dictionary will be deleted. Example 10.24 illustrates
the above.

Example 10.24: Deleting an element from a dictionary

>>> dict1 = {1: 'One', 2: 'Two', 3: 'Three'}


>>> del dict1[2] #Deleting an element from the dictionary
>>> dict1
{1: 'One', 3: 'Three'}
>>> phone={"Amit":"12345678","Ram":"23412343","John":"32145643"}
>>> del phone["Amit"]
>>> phone
{'Ram': '23412343', 'John': '32145643'}

10.25 Traversing a Dictionary


A dictionary can be traversed to access all the keys and values one by one using a
for loop. Since, a dictionary element has two parts: key and value, we can traverse for all
keys, all values or both using keys(), values() and items() methods of the dictionary,
respectively. The default is traversing through keys. Example 10.25 illustrates the above.

Example 10.25: Traversing a dictionary

>>> dict1={'India': 'New Delhi', 'China': 'Beijing', 'Japan' : 'Tokyo'}


>>> for country in dict1.keys(): #Traversing for keys
print(country)

India
China
Japan
>>> for x in dict1: #The same as traversing through keys
print(x)

India
China
Japan

431
>>> for capital in dict1.values(): #Traversing for values
print(capital)

New Delhi
Beijing
Tokyo
>>> #Traversing for keys and values both
>>> for country, capital in dict1.items():
print(country,":", capital)

India : New Delhi


China : Beijing
Japan : Tokyo
>>>

10.26 Built-in Functions for Dictionaries


Built-in functions len(), all(), any() and sorted() can be used with dictionary. The
len() function returns the total number of elements in the dictionary. The all() function
returns true if all the keys are true, otherwise returns false. The any() function returns true
if any key is true, otherwise it returns false. The sorted() function returns all the keys in the
sorted order. Example 10.26 illustrates some usages of these functions.

Example 10.26: Built-in functions

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> len(dict1) #Returns the count of the elements in the dictionary
4
>>> all(dict1) #Returns true if all the keys are True else False
True
>>> any(dict1) #Returns true if any of the keys are True else False
True
>>> dict2={0:"False",1:"True"}
>>> all(dict2) #Contains a False key
False
>>> any(dict2) #Contains a True key
True
>>> dict3={} #Empty dictionary
>>> all(dict3) #all() returns True for an empty dictionary
True
>>> any(dict3) #any() returns False for an empty dictionary
False
>>> sorted(dict1) #Returns a sorted list of all keys
['Four', 'One', 'Three', 'Two']

432
10.27 Methods of the Dict Class
The dict class has many methods to manipulate the elements of a dictionary object.
Table 10.4 list them and explains their usages with simple examples.

Table 10.4: Methods of dict class

Method Description

clear() Removes all the elements from the dictionary and makes the dictionary
an empty dictionary.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> dict1.clear() #Remove all the elements of the
dictionary
>>> dict1 #An empty dictionary
{}
copy() Returns a shallow copy of the dictionary. For deep copy, use the
deepcopy method of the copy class.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> dict2=dict1.copy() #Shallow copy
>>> dict2
{'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}
>>> del dict2["Two"]
>>> dict1 #Original dictionary is not affected
{'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}
>>> dict2
{'One': 1, 'Three': 3, 'Four': 4}

>>> dict3={1:dict1,2:dict2} #Nested dictionary


>>> dict4=dict3.copy() #Shallow copy
>>> dict3
{1: {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}, 2:
{'One': 1, 'Three': 3, 'Four': 4}}
>>> dict4
{1: {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}, 2:
{'One': 1, 'Three': 3, 'Four': 4}}
>>> dict2["Five"]=5 #Changes will be visible in dict3 and
dict4
>>> dict3
{1: {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}, 2:
{'One': 1, 'Three': 3, 'Four': 4, 'Five': 5}}
>>> dict4
433
{1: {'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}, 2:
{'One': 1, 'Three': 3, 'Four': 4, 'Five': 5}}

fromkeys(keys, Returns a dictionary with the specified keys. Each key is assigned the
value) specified value. If the argument value is not given, the default value
None is assigned to all the keys.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> #Create a dictionary with the specified keys
>>> dict2=dict1.fromkeys(("One", "Three"))
>>> dict2 #Uses default value None
{'One': None, 'Three': None}
>>> dict2=dict1.fromkeys(("One", "Three"),2)
>>> dict2 #Uses the specified value
{'One': 2, 'Three': 2}
get(key) Returns the value of the specified key. If key does not exist in the
dictionary, the function returns None.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> dict1.get("Two") #Get the value of the specified key
2
>>> x=dict1.get("Five") #Returns None if key does not
exist
>>> print(x)
None
items() Returns a dict_items object containing a list of tuples of all key-value
pairs. The dict_items object is not subscriptable, hence we need to
convert it into a list or use a for loop to traverse it to access its elements.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> #Returns a dict_items consisting of tuples of key
value pairs
>>> x=dict1.items()
>>> x
dict_items([('One', 1), ('Two', 2), ('Three', 3),
('Four', 4)])
>>> list1=list(x) #Converting dict_items into a list
>>> list1
[('One', 1), ('Two', 2), ('Three', 3), ('Four', 4)]
>>> list1[0][0] #Accessing the first key
'One'
>>> list1[0][1] #Accessing the first value
1
>>> for a in x: #Traversing a dict_items

434
print(a)

('One', 1)
('Two', 2)
('Three', 3)
('Four', 4)
keys() Returns a dict_keys object consisting of a list containing all the keys of
the dictionary. The dict_keys object is not subscriptable, hence we need
to convert it into a list or use a for loop to traverse it to access its
elements.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}

>>> #Returns dict_keys consisting of a list of all the


keys
>>> keys=dict1.keys()
>>> print(keys)
dict_keys(['One', 'Two', 'Three', 'Four'])
>>> list_keys=list(keys) #Converting dict_keys into a
list
>>> list_keys[0] #Accessing a key
'One'
>>> for key in keys: #Traversing a dict_keys
print(key)

One
Two
Three
Four
>>>
pop(k, v) Removes the item from the dictionary with key=k and returns the
corresponding value. In case, k does not match with any key, the value,
v, is returned. If v is not specified and no matching key is found, an
error is generated.

>>> dict1={"One":1,"Two":2,"Three":3,"Four":4}
>>> dict1
{'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}
>>> #Remove an item from the dictionary and returns its
value
>>> dict1.pop("Two")
2
>>> dict1
{'One': 1, 'Three': 3, 'Four': 4}

435
#If no matching key is found, it returns the value of the
second parameter.
>>> dict1.pop("Five", "Not Found")
'Not Found'
#If no matching key is found and the second parameter is
not given, an error is generated.
>>> dict1.pop("Five")
Traceback (most recent call last):
File "<pyshell#144>", line 1, in <module>
dict1.pop("Five")
KeyError: 'Five'
popitem() Removes and returns the last inserted item from the dictionary. The
returned value is in the form of a tuple of key-value pair.

>>> dict1 ={'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}


>>> dict1.popitem() #Removes and returns the last item
('Four', 4)
>>> dict1
{'One': 1, 'Two': 2, 'Three': 3}
>>> dict1.popitem() #Removes and returns the last item
('Three', 3)
setdefault(k,v) Returns the value of an item in the dictionary with key = k. If the
specified key does not exist, inserts the key in the dictionary with value
= v.

>>> dict1 ={'One': 1, 'Two': 2, 'Three': 3, 'Four': 4}


#Return the value corresponding to the key
>>> dict1.setdefault("Two")
2
>>> #Insert the key and value into the dictionary if the
key is not found.
>>> dict1.setdefault("Five", 5)
5
>>> dict1
{'One': 1, 'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5}
update(dict2) Updates the dictionary with the items of dict2. If there are duplicate
keys in dict2, the values of those keys in the original dictionary will be
updated by those of dict2. The values of dict2 will replace the existing
values of the original dictionary.

>>> dict1 = {'One': 1, 'Two': 2, 'Three': 3}


>>> dict2={"Four":4,"Five":5}
>>> dict1.update(dict2) #Add all the items of dict2 to
dict1

436
>>> dict1
{'One': 1, 'Two': 2, 'Three': 3, 'Four': 4, 'Five': 5}
>>> dict3={"one": "i", "Three": "iii", "Six":6}
>>> dict1.update(dict3) #Replace the duplicate key values
>>> dict1
{'One': 1, 'Two': 2, 'Three': 'iii', 'Four': 4, 'Five':
5, 'one': 'i', 'Six': 6}
values() Returns a list of all the values in the dictionary

>>> dict1 = {'One': 1, 'Two': 2, 'Three': 3}


>>> x=dict1.values() #Get all the values of dict1
>>> list1=list(x) #Convert a dict_values object into a
list
>>> list1[0] #Accessing list values
1
>>> for v in x: #Traversing a dict_values object
print(v)

1
2
3
>>>

10.28 Solved Examples


Sample program 10.1: Write a program to reverse a tuple.

Solution steps:
1. Use reverse slicing to get the elements in reverse order
t=(1,2,3,4,5) #Original tuple
t=t[::-1] #Reverse slicing
print(t)
Output
(5, 4, 3, 2, 1)

Sample program 10.2: Write a Python program to calculate the sum and average value
of the numbers in a given tuple of tuples.

Solution steps:

437
1. Traverse the outer tuple to get inner tuple
2. Calculate the sum and average of the inner tuple elements

t=((1,2,3,4,5),(6,7,8),(9,10)) #Tuples in tuple


for t1 in t: #Traversing a tuple
s= sum(t1) #Sum of elements of a tuple with numeric elements
a=s/len(t1)#Element count
print(s,a)
Output
15 3.0
21 7.0
19 9.5

Sample program 10.3: Write a program to calculate distance of points from the origin.
Also find the point farthest from the origin. The x, y and z co-ordinates of points are
stored in a dictionary as given below:
d={'x': [1,2,4,4,2], 'y': [2,1,1,2,3], 'z': [1,5,2,3,4]}

Solution steps:
1. Traverse the dictionary to get coordinates of points
2. Calculate distance from the origin
3. Track the farthest point

import math #Import the math module for square root calculation
#Coordinates of points are stored in a dictionary
d={'x': [1,2,4,4,2],
'y': [2,1,1,2,3],
'z': [1,5,2,3,4]}
x=-1
index=0
print("p x y z : Distance")
for i in range(5): #Traverse the dictionary to get points
#Calculate distance of a point from the origin
a=math.sqrt(d['x'][i]*d['x'][i]+ d['y'][i]*d['y'][i]+
d['z'][i]*d['z'][i])
print(i+1, d['x'][i],d['y'][i],d['z'][i],":",round(a,2))
if a> x: #Track the farthest point
x=a
index=i

438
print("The farthest point is point no", index+1)

Output
p x y z : Distance
1 1 2 1 : 2.45
2 2 1 5 : 5.48
3 4 1 2 : 4.58
4 4 2 3 : 5.39
5 2 3 4 : 5.39
The farthest point is point no 2

Sample program 10.4: Write a program to create a new dictionary extracting few keys
from a master dictionary

Solution steps:
1. Create the master dictionary
2. Create the list of keys to be included in the new dictionary
3. Use comprehension to extract the desired key: values pairs

#Master dictionary
masterDict = {
"name": "Ravi",
"age":25,
"salary": 8000,
"city": "New Delhi" }
#Keys for the new dictionary
keys = ["name", "salary"]
#Creating sub dictionary
newDict = {k: masterDict[k] for k in keys}
print(newDict)
Output
{'name': 'Ravi', 'salary': 8000}

439
Sample program 10.5: Write a program that finds all pairs of elements in a list whose
sum is equal to a given value.

Solution steps:
1. Traverse the list of numbers
2. Find the complementary number
3. Check the presence of the complement in the list
4. Add the pair in the list of pairs
list1=[1,2,3,4,5,6,7,8,9] #List of numbers
target=10
pairs=[]
for n in list1: #Traverse the list
complement = target - n #Find the complementary number
if complement in list1: #Check the complementary number in the
list
pairs.append((n, complement))
print(pairs)
Output
[(1, 9), (2, 8), (3, 7), (4, 6), (5, 5), (6, 4), (7, 3), (8, 2), (9, 1)]

Sample program 10.6: Write a program to count frequency of each character in a string
and store the results in a dictionary.

Solution steps:
1. Convert the string to lower case
2. Create the list of characters of the string
3. Create a set of characters
4. Create an empty dictionary
5. Iterate the set to get each character
6. Count the character in the list and add to the dictionary
#Original string
string="Welcome to Python Programming Language"
string1=string.lower() #Covert upper case letters to lower case
list1=list(string1)#Create list of characters of the string
set1=set(list1) #Convert the list to a set to remove the duplicate
characters
dict1={} #Initialize an empty dictionary
for x in set1: #Iterate over the set elements
dict1[x]=list1.count(x) #Get the count of a character
print(dict1)
440
Output
Character: Frequency
m :3
w :1
g :4
a :3
u :1
c :1
h :1
l :2
o :4
:4
n :3
t :2
r :2
y :1
e :3
p :2
i :1

Sample program 10.7: Write a program to convert a dictionary into a list of tuples
containing key-value pairs.

Solution steps:
1. Convert the dictionary into a dict_obj object list
2. Convert dict_obj object into a list of tuple
#Original dictionary
d = {'Red': 1, 'Green': 3, 'White': 5, 'Black': 2, 'Pink': 4}
d1=d.items() #Create dict_obj object from the dictionary
print(list(d1)) # Convert dict_obj into a list of tuple
Output
[('Red', 1), ('Green', 3), ('White', 5), ('Black', 2), ('Pink', 4)]

441
Sample program 10.8: Write a program to extract elements in a tuple having k digits.

Solution steps:
1. Traverse the tuple
2. Convert the element into string
3. Calculate the length of the string
4. if the length of the string is equal to the desired number of digits, add to the list
val = (12,123,453,2,6,34) #Original tuple
print("Original List : " ,val)
k = 2 #Number of digits in retracted elements
#Extract the elements with k digits
res = [ele for ele in val if len(str(ele))==k]
print("Extracted Tuples : " ,res)
Output
Original List: (12, 123, 453, 2, 6, 34)
Extracted Tuples : [12, 34]

Sample program 10.9: Write a program to extract symmetrical tuples form a list of
tuples of two elements.

Solution steps:
1. Convert the list into a set to remove duplicate tuples
2. Create a set by swapping the elements of the tuples of the list
3. Take the intersection of the above two set to get the symmetrical tuples

#List of tuples
myList = [(3, 4), (5, 1), (1, 5), (7, 4),(4,3),(5,6)]
print("The tuple list : " + str(myList))
# Extracting all Symmetric tuples from list
set1 = set(myList) # Convert the list into a set
set2 = {(b, a) for a, b in myList} # Exchange the tuple elements
symTupleSet = set1 & set2
# Printing Symmetric tuples
print("Symmetric tuples : " + str(symTupleSet))
Output
The tuple list : [(3, 4), (5, 1), (1, 5), (7, 4), (4, 3), (5, 6)]
Symmetric tuples : {(4, 3), (5, 1), (3, 4), (1, 5)}

442
Chapter Summary

1 A tuple is an immutable collection of heterogeneous data.


2 A tuple is stored in a single block of memory. Hence, it is faster than a list.
3 Placing all the data inside a pair of parentheses (), separated by commas, creates
a tuple literal and assigning it to a variable creates a tuple variable.
4 Iterable objects and comprehension objects can be converted into a tuple
using the tuple method.
5 Zero based indexing is used to access individual elements of a tuple.
6 Slicing is used to get multiple elements of a tuple.
7 Tuples support concatenation (+), repetition (*) and membership (in and not in)
operators.
8 A tuple can be traversed from start to end using: (1) for loop, (2) while loop and
(3) enumerate function.
9 As a tuple is an immutable sequence of data, it cannot be sorted in place.
10 The zip () function is used to generate a zipped object which is a series of tuples
containing elements from a number of iterables.
11 The tuple object has only two member methods: count and index.
12 Though a tuple is an immutable sequence, but it can contain mutable sequences,
such as lists, sets and dictionaries as its elements.
13 A set is an unordered collection of distinct items of various types.
14 we cannot access elements with an index.
15 A set does are not maintained any order for its elements.
16 A set can be created using data enclosing within curly brackets, converting other
iterable, collection objects and set comprehension using set method.
17 Sets support in and not in operators to check the existence of a value in a set.
18 Though a set is unordered and unindexed collection of items, however, we can
traverse a set using a for loop but order of elements returned is random.

443
19 A dictionary in Python is basically an associative array, also called map, that
holds data in the form of key and value pairs.
20 We can create a dictionary by placing key: value pairs within a pair of curly
brackets, {}, separated by commas.
21 An element of a dictionary can be accessed by using the key of the element in a
pair of square brackets, [].
22 A dictionary can be used as a value in other dictionary. In this way, we can create
a nested dictionary. Nesting can be done at any depth.
23 An element of a dictionary can be removed by using del keyword. The syntax is
del dictionary[key].
24 A dictionary can be traversed to access all the keys and values one by one using
a for loop.

Multiple Choice Questions

1. Which of the following is a Python tuple?


(a) [1, 2, 3]
(b) (1, 2, 3)
(c) {1, 2, 3}
(d) {}

2. Which of the following is not true for a tuple object in Python?


(a) it is mutable
(b) It can store heterogeneous data
(c) It can be nested with other tuple
(d) All of the above

3. Which of the following is an incorrect way to create a tuple?


(a) T1 = tuple ((1, 2, 3, 4))
(b) T2 = tuple ()
(c) T3 = "1,2,3,4".split(',')
(d) T4 = tuple([1, 2, 3, 4])

4. Which of the following is incorrect?


(a) tuple1 = ((1,2,3))

444
(b) tuple1 = (1, (2,3), [1,2])
(c) tuple1 = (3,)
(d) None of the above

5. Which of the following is incorrect?


(a) t=tuple (4)
(b) t=tuple ([4])
(c) t= tuple ((4,))
(d) all of the above

6. Which of the following cannot be converted to a tuple?


(a) an integer
(b) a string
(c) a list
(d) a set

7. Which of the following cannot be used to create a tuple?


(a) a data
(b) an iterable
(c) comprehension
(d) None of the above

8. Which of the following built-in function cannot be used with tuple?


(a) len
(b) max
(c) sum
(d) None of the above

9. Which of the following cannot be used to get the first element in tuple t =
(1,2,3,4,5)?
(a) t[0]
(b) t(0)
(c) t[-5]
(d) None of the above

10. For a tuple, which of the following will be used to get all the elements of the
tuple?
(a) t[:]

445
(b) t[::]
(c) t[0:10:1]
(d) All of the above

11. Which of the following is true about a tuple?


(a) tuple cannot be traversed in the backward direction.
(b) tuple cannot have negative index.
(c) tuple uses zero based indexing.
(d) All of the above.

12. Which of the following is true about a tuple?


(a) t[True]
(b) t[-1]
(c) t[0]
(d) all of the above

13. Which of the following is an operator for tuples?


(a) +
(b) –
(c) *
(d) All of the above

14. Which of the following cannot be used to traverse a tuple?


(a) for loop
(b) while loop
(c) enumerate
(d) none of the above

15. Which of the following is not true about a tuple?


(a) Elements of a tuple cannot be edited
(b) Elements cannot be sorted in-place
(c) a tuple can have a list as its element
(d) All of the above

16. Which of the following is true about a set?


(a) a set cannot have duplicate elements
(b) a set cannot access elements using index
(c) a set does not maintain the order of its elements

446
(d) All of the above

17. Which of the following is not a method to create a set object?


(a) sets from data
(b) sets from other iterables
(c) sets from the set comprehension
(d) None of the above

18. A tuple cannot be traversed by using one of the following method?


(a) for loop
(b) while loop
(c) enumerate
(d) None of the above

19. Which of the following is true about a frozenset?


(a) It cannot contain duplicate elements
(b) It is immutable
(c) It can be used as a key in a dictionary
(d) All of the above

20. Which of the following built-in method cannot be used with a dict object?
(a) len
(b) all
(c) any
(d) None of the above

21. Which of the following is not true for an empty dict object, d?
(a) all(d) returns true
(b) any(d) returns false
(c) all(d) returns false
(d) None of the above

22. What will be the output of the following code?


d = {"abc":40, "xyz":45}
print ("abc" in d)

(a) True
(b) False

447
(c) Error
(d) None of the above

23. What will be the output of the following Python code snippet?

d1 = {"abc":40, "xyz":45}
d2 = {"abc":"40", "xyz":45}
print(d1 == d2)

(a) True
(b) False
(c) Error
d) None of the above

24. For code, d = {"abc":40, "xyz":45}, the number of entries in the dictionary can
be obtained by?
(a) d.size()
(b) len(d)
(c) size(d)
(d) All of the above

25. What will be the output of the following code?


D1 = {"abc":40, "xyz":45},
print(list(d.keys()))

(a) ['abc', 'ayz']


(b) 'abc', 'ayz'
(c) [40,45]
(d) Error

Review Questions

1. State whether the following statements are true or false:


a. A tuple is mutable.

448
b. A tuple can store heterogeneous data.
c. An integer and a string cannot be stored in a single tuple.
d. A tuple is more efficient to store a read only collection than a list.
e. A tuple is stored in a single block of memory.
f. The code t = (2) will create a tuple object.
g. The code t= (2,) will create a tuple object.
h. Any collection can be converted in a tuple.
i. Comprehension can be used to create a collection.
j. The code sum ((1,2,3.0)) returns 6.
k. The code sum sum ((1,2,"3")) returns 6.
l. The code t [-1] returns the last element of the tuple t.
m. The code t [1] returns the first element of the tuple t.
n. The code t[::-1] returns the elements of tuple t in reverse order.
o. The code, 3 in (1,2,3) returns 3.
p. A tuple cannot sort its elements in place.
q. The zip () function is used to generate a zipped object from tuples.
r. The code t.count(n) returns the number of elements in the tuple.
s. A tuple cannot contain mutable sequences.
t. A set is an unordered collection of distinct items of various types.
u. During the traversal of a set, elements of the set may be in different order
than the order of elements given during creation.
v. An empty {} represents a set.
w. An empty set is created as s=set ().
x. The code sorted(set1) returns a sorted set.
y. The code sorted(set1) returns a sorted list of the set elements.

449
z. We cannot use an index to access an element of a set.
aa. A frozenset is mutable.
bb. A dictionary in Python is basically an associative array.
cc. A dictionary is also called a map.
dd. Keys must be immutable and hashable.
ee. Lists and sets cannot be used as keys.
ff. We can have duplicate keys in a dictionary.
gg. We cannot have duplicate values in a dictionary.
hh. The zip object of two lists can be used to create a dict object.
ii. We cannot append key: value pairs to an existing dict object.
jj. We cannot create a dict object using comprehension.
kk. We can access an element of a dict object using indexing.
ll. We cannot nest dictionaries.
mm. We cannot delete items from a dictionary.
nn. A dictionary can be traversed using a for loop.
oo. The len(d) returns the count of elements in dictionary d.

Programming Assignments

1. Write a program to find the index of an item of a tuple.

2. Write a program to compute sum of elements of a given tuple.

3. Write a program to sort a list of tuples based on the number of elements in the
tuples.

4. Write a program to unpack a tuple storing coordinates of a 3D point into x, y,


and z variables and then find the distance of the point from the origin.

450
5. Write a program to sort a list of tuples based on the second item in the tuple. All
the tuples have n numbers.

6. Write a program to test that two sets have at least one common item.

7. Write a program to find union of n sets.

8. Write a program to combine two dictionaries.

9. Write a program to create a dictionary to store n: n*n*n as key: value pairs for 1
to 10.

10. Write a program to sort a dictionary by its keys.

11. Write a program to store coordinates of Cartesian points in a dictionary.

12. Write a program to find the length of a dictionary of values.

13. Write a program to filter even numbers from a dictionary of values.

14. Write a program to accept the strings which contains all vowels.

451
452
Chapter 11

File Handling
Learning Outcomes

1. Understand various types of files in Python.


2. Understand modes of files
3. Read and write text files
4. Read and write binary files
5. Write programs for file handling

Until now, we have used input and print functions to read and write data in a
program/script. This console-oriented (using keyboard and monitor) input and output
operations are fine for small programs where a small amount of data are involved. Further,
data stored in RAM are temporary and when we close the program or computer, data is
lost. However, programs for real-life situations invariably involve a huge amount of data to
be read and written by the programs. In such situations, files are used to store data and
perform input and output operations.

A file is a collection of data in the form of records. It is used to store data in a storage
device, such as a hard disk, pen drive, etc., permanently. A file can be created manually
using an editor or a file can be generated by a program. Later, when data is required, data
stored in a file can be retrieved using file reading operations. File handling is a set of
processes used to store and retrieve data as and when required by a program. Typical
processes involved in file handling are: creating a file, opening a file, reading data from a
file, writing data to a file, and closing a file. Data in a file can be stored in human-readable
text format (called text file) or in binary code (called a binary file). Python has rich and easy-
to-use facilities for handling both text and binary files.

11.1 Types of Files


Every file is stored in the computer memory in the form of a sequence of 0s and 1s
(i.e., in the binary form). The file can be classified as a text file or a binary file. A text file
consists human-readable symbols and characters. A text file uses either ASCII or Unicode
to form binary patterns of various symbols and characters. In this way, a text file can be
considered as a sequence of characters consisting of alphabets, numbers, and other special
453
symbols. Each line of a text file is terminated by an End of Line (EOL) character such as the
newline (\n). Further, the content in a text file is usually separated by some delimiters, such
as a whitespace, a comma (,) a tab (\t), etc., for consistent reading and writing. Hence, a text
file can be opened by any text editor.

On the other hand, a binary file uses raw data and does not apply any encoding
before writing it on the disk. Hence, they can only be read by the program (or compatible
programs) that has generated it. Binary files are typically used to store actual content such
as an image, audio, video, executable files, etc. A binary data file is not human-readable.

11.2 Steps in File Handling


File handling in general involves the following three steps: (1) opening a file, (2)
reading/writing data from/to the file, and (3) Closing the file. For performing
reading/writing operations in a file, the file must be opened first and after the operations
are performed , it must be closed. Figure 11.1 shows the process of file operations. As can
be seen from the figure, when we open a file, a file stream object is created which links the
actual file and the program. Typically, a stream represents a sequence of bytes, which can
be accessed by the program. A strem can be read-only, write-only, or read/write both. A
stream may permit only sequential access or random access to data. We read data from a
stream and we write data to a stream. When we close a file, the data written in the stream
are stored on the disk. Hence, it is advised to close all the opened files to write all the data
properly on the disk. We can also flush the data before closing a stream using the flush()
method.

454
Input file
stream

Input file

Output file
stream

Output file

Figure 11.1: File operations

11.3 Opening a File


We can open a file to perform many operations such as to read, to write or to
read/write both from/to a file. Further, a file can be opened in text mode or binary mode.
Python has a built-in open () function to open a file. The access parameter decides the type
of operations permitted with the opened file. Following is the syntax of the open function:

455
file_object = open(file_name, mode='r', buffering=-1, encoding=None,
errors=None, newline=None)

Table 11.1 briefly describes the various parameters of the open function. Except for
the file_name parameter, all other parameters are optional. The function opens the file
specified by the file_name parameter according to the other parameters and returns a file
object if successful, else generates an error message. The opened file should be closed by the
programer after the file operations in no longer required.

We can also use the open () function to open a file with a with statement as given
below. The primary advantage of this format is that the file will be closed automatically
as soon as we exit the block. Sometimes, we forget to close a file which leads to tied up
resources that we no longer required. Other than the above, there is no other difference.

with open (file_name, [optional parameters]) as fp:

statement2

Table 11.1: Various parameters of the open function

Parameter Description

file_name It is a string that contains the name of the file to open. If it contains only the
name of the file, the file will be looked at in the current folder. However, we
can also include the relative or absolute path of the file in the file_name
variable. The absolute path of a file contains the root element and the
complete directory list required to locate the file, for example,
"C:\Users\MBM\Documents\Python". Whereas, the relative path of a file
refers to a location that is relative to the current directory, for example,
"Documents\Python".

Please note, as a file path may contain a backslash, \, which is a control


character in Python which changes the meaning of the preceding character,
we should take care in creating a string for file name. It is recommended to
precede file path string with r to make it a raw string and to avoid the effect
of slash characters. For example, r"C:\Users\MBM\Documents\Python"
and r"Documents\Python". These strings can also be written as
"C:\\Users\\MBM\\Documents\\Python" and "Documents\\Python".

456
mode It is a string that specifies the mode in which the file is opened. A file can be
opened in different modes, such as read, write, append, text, binary, etc. In
the read mode, we can only read data from the file. Whereas, in the write
mode, we can only write data in the file. In the append mode, we can write
data at the end of the existing content of the file. In the read and write mode,
reading and writing from/to the same file are permitted.

By default, a file is opened in read-only text file mode. Python uses


'r' for reading, 'w' for writing, 'a' for appending, 'b' for the binary file mode,
't' for the text file mode, and '+' to indicate an additional operation. A mode
string can be formed by combining these characters in any order. For
example, 'rb+', or '+rb' means to open an existing file in binary mode for both
reading and writing. By default, a file is opened in the text mode, hence the
character 't' is optional, i.e. 'rt' and 'r' are the same. Table 11.2 describes
various mode values which set various modes of the opened file and table
11.3 summurizes operations in different file modes.

buffering It is an integer that is used to set the buffering policy. Buffering is the process
of transferring a chunk of data from the disk to the main memory (or from
the main memory to the disk) from where it will be used by a program. This
reduces the number of disk access and improves performance. The following
are the buffering policy supported in Python:

No buffering: In this mode, there is no buffering of the data and all the
operations are directly performed on the disk file. For this mode, we set the
value of the buffering parameter = 0. This mode is allowed only in binary
file mode.

Line buffering: In this mode, one disk operation is performed till a newline
character is encountered and is only used in the text mode. For this mode,
we set the value of the buffering parameter = 1.

Fixed-size chunk buffer. In this mode, a fixed size of data is moved from
the disk to the main memory or vice versa in one disk operation. When the
buffering parameter is >1, this mode is used.

457
By default, the buffering policy (buffering=-1) works as follows: for binary
files, the fixed size buffering of typically 4096 or 8192 bytes is used and for
text files, the line buffering is used.

encoding It is a string that specifies the encoding/decoding scheme, such as ASCII,


Unicode, used to create the binary patterns of characters and symbols.
Python supports many encoding schemes but the default is UTF-8. The
encoding parameter is only used with text files.

errors It is a string that specifies how encoding and decoding errors in text files are
to be handled. It is important to note that the same encoding and decoding
scheme should be used for a consistent result. Following are the commonly
used values that the error parameter can take:

'strict’: it raises a ValueError exception if there is an encoding error and is


the default setting.

'ignore': it ignores encoding and decoding errors. Please note, this setting
may lead to data loss.

'replace': It replaces the character in question with a marker such as '?' to


indicate the error.

newline It is a string. It can take anyone of the following values: None, '', '\n', '\r',
and '\r\n'. These are the legal values of the newline parameter. The default
value of the newline parameter is None. This parameter is used only with
text files.

While in the reading mode, if the newline parameter is set to None, the
newline characters ('\n', '\r', or '\r\n') are translated into '\n' before being
returned to the caller. If it is set to empty string, i.e. '', no translation takes
plance and the given newline characters are returned to the caller. If it is set
to other legal values, input lines are only terminated by that string, and the
original line ending is returned to the caller.

While in the writing mode, if the newline parameter is set to None, the new
line characters are translated to the system's default line separator. If the
parameter is set to ' ' or '\n', no translation takes place. If the parameter is set

458
to the other legal values, newline characters are translated to the given string
before writing.

file_object It is an object of the class '_io.TextIOWrapper'. On success, the open function


returns a file_object. A file_object is not the actual file but is a link between
the actual data in the file and the program. It provides many methods to
perform various file operations, such as reading and writing. Internally, it
also maintains the current location in the file from where the next data will
be read or written using a file pointer. The file pointer will automatically
move forward after performing an operation. However, we can relocate the
pointer in the file as per the requirement using the seek () method. The
current location of the pointer can be obtained using the tell () method. Table
11.4 briefly discusses the commonly used methods of this object.

Table 11.2: Various access modes

Mode Description

'r ' Opens a text file for reading only. This is the default mode. The file pointer is
placed at the start of the file.

'rb' Opens a binary file in the read-only mode. The file pointer is placed at the
beginning of the file.

'r+' Opens an existing text file for both reading and writing. If the file does not exist,
it will raise an error. The file pointer is placed at the beginning of the file. Write
operations will overwrite the existing content from the current file pointer.

'rb+' Opens an existing file for both reading and writing in binary format. If the file
does not exist, it will raise an error. The file pointer is placed at the beginning of
the file.

'w' Opens a file for writing only. If the file already exists, its contents will be deleted
and if the file does not exist, it creates a new file for writing. The file pointer is
placed at the beginning of the file.

459
'wb' Opens a file for writing only in the binary format. If the file already exists, its
contents is deleted and if the file does not exist, it creates a new file for writing.
The file pointer is placed at the beginning of the file.

'w+' Opens a file for both writing and reading in the text mode. If the file already
exists, its contents will be deleted and if the file does not exist, it creates a new
file for both reading and writing. The pointer is placed at the beginning of the
file.

'wb+' Opens a file for both writing and reading in the binary mode. If the file already
exists, its contents are deleted and if the file does not exist, it creates a new file
for both reading and writing. The pointer is placed at the beginning of the file.

'a' Opens a text file in the append mode for writing at the end of the existing content
of the file. If the file does not exist, it will create a new file for writing. For an
existing file, the file pointer is placed at the end of the existing content. No
writing is allowed in the existing content. We cannot send the file pointer in the
existing content with the help of the seek () method, i.e. writing will always be
at the end of the existing content.

'ab' Opens a binary file in the append mode for writing at the end of the existing
content of the file. If the file does not exist, it will create a new file for writing.
For an existing file, the file pointer is placed at the end of the existing content.
No writing is allowed in the existing content.

'a+' Opens a text file in the append mode for both reading and writing at the end of
the existing content of the file. If the file does not exist, it will create a new file
for writing. For an existing file, the file pointer is placed at the end of the existing
content. No writing is allowed in the existing content. However, the read pointer
can be moved to the beginning of the file for reading the existing contents also.

'ab+' Opens a binary file in the append mode for both reading and writing at the end
of the existing content of the file. If the file does not exist, it will create a new file
for writing. For an existing file, the read and write file pointers are placed at the
end of the existing content. No writing is allowed in the existing content.
However, the read pointer can be moved to the beginning of the file for reading
the existing contents also.

460
x Exclusively creates a new file for writing. If the file already exists, it will raise an
error. The file pointer is placed at the start.

Table 11.3: Summary of operations in different file modes

Modes
Operations r r+ w w+ a a+ x
Read Yes Yes No Yes No Yes No
Write No Yes Yes Yes Yes Yes Yes
Write after seek No Yes Yes Yes No No Yes
Read after seek Yes Yes No Yes No Yes No
Create a new file No No Yes Yes Yes Yes Yes
Erase the existing content No No Yes Yes No No No
Default initial file pointer location Start Start Start Start End End Start

Table 11.4: Commonly used methods of the file object

Method Description
close() Closes the opened file. We should close all the opened files if no further
file operations are required. This frees the resources.
flush() Clears the internal buffer of the opened file stream.
read() Reads the complete content of the file and returns it.
readable() Returns true if the file stream permits reading operations, otherwise
returns false.
readline() Reads and returns one line from the file and moves the file pointer to the
next line.
readlines() Reads all the lines of the file and returns them as a list of strings.
seek() Reposition the file pointers to perform the next operation.
seekable() Returns true if the file allows us to change the file pointer position, else
returns false.
tell() Returns the current file pointer position.
truncate() Truncates the data beyond the specified size.
writable() Returns true if the file permits writing operations, else it returns false.

461
write() Writes the specified string to the file.
writelines() Writes a list of strings to the file.
11.4 Reading from a Text File
A file object has many methods to read data from a file: readline (), readlines () and
read (). These methods can be used if the file permits reading operation, i.e. file is opened
in the read mode or the read and write mode. The content of the input file to illustrate these
methods is given in figure 11.2

Figure 11.2: The sample input file

File name file1.txt


Content Line1: Hello World.
Line2: I love Python Programming.
Line3: It is one of the most widely used programming languages.

The readline (n=-1) method reads the maximum n characters or up to the end of the
line of the current line (starting from the current file pointer) from the file. If n is not given
or n = -1, it reads up to the end of the current line. If n is more than the number of remaining
characters in the current line, the reading will stop at the end of the line. The read data are
returned as a string. After reading, it moves the file pointer to the next reading location. At
the end of the file, it returns an empty string. Example 11.4(a) uses the readline method to
read a file line by line and convert each line to the upper case and print it on the console.
Example 11.4(b) reads 10 bytes of data and convert them to the upper case and print on the
console. As can be seen from the example, at the most specified number of characters (here
n=10) are read from the current line. If the available number of characters in the line is less
than 10, only the available characters are returned.

Example 11.4(a): Read a line from a text file

#Open a file with with statement in read mode


with open("file1.txt","r") as fp:
while (1):
line=fp.readline() #Read a line
if line=="":
break
#Convert the line to the upper case and print
print(line.upper())
Output

462
LINE1: HELLO WORLD.

LINE2: I LOVE PYTHON PROGRAMMING.

LINE3: IT IS ONE OF THE MOST WIDELY USED PROGRAMMING LANGUAGES.

Example 11.4(b): Read the specified number of characters from a line from a text file

fp=open("file1.txt","r") #Open the file in text and read only mode


while(1):
#Read maximum 10 characters or till end of the line
line=fp.readline(10)
if line=="":
break
print(line.upper())

fp.close()
Output
LINE1: HEL
LO WORLD.

LINE2: I L
OVE PYTHON
PROGRAMMI
NG.

LINE3: IT
IS ONE OF
THE MOST W
IDELY USED
PROGRAMMI
NG LANGUAG
ES.

The readlines (n=-1) method reads the lines till the total returned bytes exceeds n or
up to the end of the file (starting from the current file pointer). Once the reading of a new
line starts, the reading will continue till the end of the line even if it exceeds the returned
bytes than n. For example, suppose if a file contains four lines and each line contains 10
bytes and n is set to 23, the readlines () will read the first three lines and a total of 30 bytes.
This is because once the readlines () start reading a new line, it reads till the end of the line.
If n is not given or n = -1, it reads up to the end of the file. If n is more than the number of

463
remaining characters in the file, it will read all the reaming lines of the file. The read data
are split into sub-strings at each newline character and return as a list of strings. The newline
character is retained in each string. After reading, it moves the file pointer to the next
reading location. At the end of the file, it returns an empty string. Example 11.4(c) uses the
readlines () method to read all the lines of a file and print them on the console as raw byte
strings. Example 11.4(d) reads lines till the total returned bytes exceeds 30 and print each
read line on the console as a raw byte string along with the length of the line.

Example 11.4(c): Read all the lines of a text file

fp=open("file1.txt","r") #Open the file in the text and read only mode
list1=fp.readlines()
for line in list1:
print(bytes(line, encoding="UTF-8"))#Print as a raw byte string
fp.close()
Output
b'Line1: Hello World.\n'
b'Line2: I love Python Programming.\n'
b'Line3: It is one of the most widely used programming languages.\n'

Example 11.4(a): Read lines till the total returned bytes is less than the specified
value

fp=open("file1.txt","r") #Open the file in text and read only mode


list1=fp.readlines(30) #Read lines till total returned bytes exceeds 30
for line in list1:
#Print as a raw byte string and its length
print(bytes(line, encoding="UTF-8"), len(line))
fp.close()
Output
b'Line1: Hello World.\n' 20
b'Line2: I love Python Programming.\n' 34

The read(n) method reads the specified number of bytes from the file starting from
the current pointer and returns it as a string. If n=-1 (default) or n is more than the total
remaining bytes in the file, it reads all the remaining bytes. Example 11.4(e) reads all the
characters of a file and returns it as a string. Example 11.4(f) reads the first 25 characters of
a file and prints it as a raw byte string. The escape character sequences, such as '\n', are
counted as one character.

464
Example 11.4(e): Read all the lines of a file as a string

fp=open("file1.txt","r") #Open the file in the text and read only mode
string1=fp.read() #Read all the remaining bytes from the file
print(string1) #Print as a string
fp.close()
Output
Line1: Hello World.
Line2: I love Python Programming.
Line3: It is one of the most widely used programming language.

Example 11.4(f): Read the specified number of bytes from a file

fp=open("file1.txt","r") #Open the file in text and read only mode


string1=fp.read(25) #Read 25 bytes from the current file pointer
print(bytes(string1, encoding="UTF-8")) #Print as a byte string
fp.close()
Output
b'Line1: Hello World.\nLine2'

11.5 Writing into a Text File


The file object class has many methods to write data into a file: writelines () and
write (). These methods can be used if the file permits writing operations, i.e. file is opened
in the write mode, the append mode or the read and write mode.

The writelines (List) method writes the content of the List parameter, which is a list
of strings, into the file. Please note, all the elements of the list should be a string. If we want
to write each list item into a separate line, we have to add a new line character at the end of
each string item. Further, to write numerical values, we have to first convert them into
strings. Example 11.5(a) reads four lines of text from the console and writes them to a file.
Example 11.5(b) creates the multiplication table of 1 to 10 and writes it into a file.

Example 11.5(a): Writing a list of strings into a text file

fp=open("file2.txt","w") #Open the file in the text and write only mode
for i in range(4):
line=input("Enter your string:") #Read a line from the console
#Write the line along with a newline character
fp.writelines([line,"\n"])

465
fp.close() #Close the file
Input
Enter your string: Hello, everyone
Enter your string: I am enjoying Python
Enter your string: It is an easy to learn language
Enter your string: Thanks
Output(file2.txt)
Hello, everyone
I am enjoying Python
It is an easy to learn language
Thanks

Example 11.5(b): Writing a multiplication table in a file

fp=open("file3.txt","w") #Open the file in text and read only mode


table=[] #Create an empty list
for i in range(1,11):
row="" #An empty string
for j in range(1,11):
m="{:4d}".format(i*j) #Formatting
row=row+m # Add to the string
row=row+"\n" #Add a new line character to the row
table.append(row) #Add row string to the list
fp.writelines(table) #Write the list to the file
fp.close() #Close the file
fp=open("file3.txt","r") #Open the file for reading
print(fp.read()) #Read the file and print on the console
fp.close()
Output( file3.txt)
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100

The write(text) method writes the specified text into the file, starting from the
current pointer. To use this function, the file must be open in the write mode, the append

466
mode, or read and write mode. The overlapping existing content will be overwritten. After
writing, the file pointer will move to the end of the currently written text. Example 11.5(c)
add a line of text at the end of a file using the write method. The file already has one line,
say, You are new to Python.

Example 11.5(c): Write the specified text to a file

fp=open("file4.txt","a") #Open the file in text and append mode


#Write at the end of the file
fp.write("\nWelcome in the world of Python.")
fp.close() #Close the file
fp=open("file4.txt","r") #Open the file in the read mode
print(fp.read()) #Read the file and print
fp.close()
Output
You are new to Python.
Welcome in the world of Python.

11.6 Writing Numbers and Booleans in a File


All the writing methods can only write strings. If we attempt to write other data
types directly, they will raise errors. However, we can convert any other data type into the
equivalent string type and write them in a file. Example 11.6 illustrates how to write
different types of data into a file.

Example 11.6: Write different data types in a file

fp=open("file4.txt","w") #Open the file in text and write mode


num1=10
num2=0.5
num3= 1.33e4
com1=3.4+3j
bool1=True
bool2=False
fp.write(str(num1)+"\n") #Write an integer
fp.write(str(num2)+"\n") #Write a float
fp.write(str(num3)+"\n") #Write a float
fp.write(str(com1)+"\n") #Write a complex number
fp.write(str(bool1)+"\n") #Write a Boolean
fp.write(str(bool2)+"\n") #Write a Boolean
fp.close() #Close the file
fp=open("file4.txt","r") #Open the file in the read mode

467
print(fp.read()) #Read the file and print
fp.close()
Output
10
10.5
13000.0
(3.4+3j)
True
False
11.7 Reading Numbers from a file
All the reading methods read data from the file and return it in the form of strings.
However, we can convert the returned values into other data types. If a line in the file
contains more than one number, we can split the returned strings into substrings and then
convert each sub-string to an equivalent number. Example 11.7(a) illustrates how to read
numbers from the file. The file contains 1 to 10 and each number is written in a separate line
and there is no blank line. The program reads all the numbers given in the file and finds
their sum. Example 11.7(b) reads numbers from a file, in which a line may contain more
than one number, separated by commas, in a line. The program reads a line as a string and
splits it along the commas and find the sum of numbers in each row and print on the
console.

Example 11.7(a): Read numbers from a file

fp=open("file5.txt","r") #Open the file in the text and read only mode
total=0
while(1):
s=fp.readline() #Reads a line and returns it as a string
if s=="": #Break the loop if the returned string is empty
break
n=float(s) #Convert the string to an equivalent number
total=total+n #Find sum
print(total)
fp.close()
Output
55.0

468
11.8 Seek and Tell Methods
Till now, we have read and have written data into a file sequentially. However, it is
possible to read and write data from any position in the file. For this, we have to reposition
the file pointer in the file using the seek method. The current position of the file pointer can
be obtained by the tell () method. The syntax of the seek () method is as given below

fp.seek(offset, reference)

where fp is the handle of the opened file, offset is an integer that specifies the number of
positions that the file pointer will move with respect to the specified reference. The reference
is specified by the second parameter reference. The reference parameter can take any of the
following three values: 0,1 and 2. The meaning of these values are:

0: sets the reference point at the beginning of the file, i.e. offset will be from the start.
This is the default setting. This is supported by both the text file mode and binary file
mode.
1: sets the reference point at the current file position, i.e. offset will be from the current
position. The positive value will move the pointer in the forward direction, whereas
the negative value will move the file pointer in the backward direction. This option is
only supported in binary file mode.
2: sets the reference point at the end of the file, i.e. offset will be from the end of the file.
The positive value will move the pointer in the forward direction, whereas the
negative value will move the file pointer in the backward direction. This option is
only supported in binary file mode.

The syntax of the tell () method is fp.tell() which returns the current location of the file
pointer with reference to the beginning of the file. The returned value is an integer.

Example 11.8(a) illustrates some usages of the seek () and the tell () methods. In this,
reading is performed from different locations of file file8.txt containing ABCDEFGHIJ.
Please note, the value of the file pointer of the first character of a file is 0. In example 11.8(b),
the seek () method is used to write a character at random locations in a text file. The original
file contains 0 to 9 out of which some digits are replaced by ‘#’.

469
Example 11.8(a): Reading randomly from a text file

fp=open("file8.txt","r") #Open the file in the text and read mode


print("Current location:",fp.tell())
print(fp.read(1)) #Read the first character
fp.seek(4,0) #Move to the fifth character from the start
print("Current location:",fp.tell())
print(fp.read(1)) #Read a character from the current location
fp.seek(8,0) #Move to the ninth character from the start
print("Current location:",fp.tell())
print(fp.read(1))
fp.seek(1,0) #Move to the second character from the start
print("Current location:",fp.tell())
print(fp.read(1))
fp.close()
Output
Current location: 0
A
Current location: 4
E
Current location: 8
H
Current location: 1
B

Example 11.8(b): Write randomly in a text file

fp=open("file8.txt","r+") #Open the file in the read/write mode


print("Original content:", fp.read()) #Print the original file
fp.seek(3,0) #Locate the file pointer at the fourth character
fp.write("#")#Overwrite the character
fp.seek(6,0) #Locate the file pointer at the seventh character
fp.write("#")
fp.seek(1,0) #Locate the file pointer at the second character
fp.write("#")
fp.close() #Save the modified file
fp=open("file8.txt","r")
print("Modified content:", fp.read()) #Print the modified file
fp.close()
Output
Original content: ABCDEFGHIJ
Modified content: A#C#EF#HIJ

470
11.9 Iterating over Lines in a File
We can iterate over the lines of a file using a for loop. The for loop returns the content
of the file line by line. This method can be used for both text files and binary files. Following
is the syntax:

for line in fp:

Statement1
Statement 2
:
Statement n

Where fp is the file handle and line is a variable that holds each line. Once a line is
available, we can process it as any other string. Example 11.9 iterates over each line of a file
and print it on the console.

Example 11.9: Iterate over lines of a file

fp=open("file1.txt","r")
for line in fp: #Iterate over each line
print(line)
fp.close()
Output
Line1: Hello World.

Line2: I love Python Programming.

Line3: It is one of the most widely used programming language.

11.10 Accessing Binary Files


Till now we have used text files to store and retrieve data. As discussed earlier, data
in a text file is consisting of sets of characters. Though text files are human-readable, the text
format is very inefficient in terms of the number of bytes required to store non-string data.
For example, to store the largest standard python floating-point value
(1.7976931348623157e+308), which uses 64 bits (i.e. 8 bytes) in memory, a text-mode file
requires 23 bytes to store the individual characters of it as a string. Thus, storing a float as

471
an ASCII string requires around 2.75 times more disk memory than the data in the memory.
It also requires additional time to convert a float to a string during writing and convert it
back to a float during reading. This is a waste of disk space and time. Due to this, data sets
of any substantial size are invariably stored as binary rather than as text data.

Python supports the reading and writing of binary files. For this, we have to open a
file using binary file mode codes as given the table 11.2. In the binary file mode, data are
read and written in the form of byte strings. In this, the bit patterns of data in the memory
are directly written byte-by-byte in the file and they are not converted to any sort of string
representation before it is written. However, we require to pack the memory bit patterns
into a byte string so that it can be written in a binary file. Similarly, when we read data from
a binary file, it is returned as a byte string, which needs to be unpacked to convert then back
into the desired format. Unfortunately, there is no built-in function for these operations.
However, we can import and use the struct module that provides the pack () function which
converts the bit patterns of data into an equivalent byte string, and the unpack () function
which converts a byte string into desired data. Table 11.5 briefly describes the commonly
used functions of the struct module.

Table 11.5: Commonly used functions of the struct module

str=pack(fmt, *v) The pack () method converts the variable-length arguments into
a byte string as per the given format. The fmt parameter is a
string consisting of format characters according to which the
data will be converted into byte strings. The commonly used
format characters are: 'c' for a character, 's' for a byte array, 'i' for
integer, and 'f' for a float. We can precede these characters with a
number to indicate the number of repetitions. For example, '4s' is
equal to 'ssss'. These characters are mapped to the native size of
the computer. For other format specifiers, please see online help.
The second parameter of the function is a variable-length
argument. The argument can be of integer, float, and byte string
types. The function returns the bit patterns of the arguments as a
byte string according to the specified format. See the following
example:

>>> import struct #Import the module

472
>>> struct.pack('ii',340,5021) #Convert integers in
a byte string
b'T\x01\x00\x00\x9d\x13\x00\x00'
>>> #Convert floats in a byte string
>>> struct.pack('ff',3.124,1/3)
b'\x9e\xefG@\xab\xaa\xaa>'
>>> #Convert a string and a float in a byte string
>>> struct.pack('6sf',b"Python", 3.7)
b'Python\x00\x00\xcd\xccl@'
>>> #Convert the largest float in a byte string
>>> struct.pack('f',1.7976931348623157e+308)
b'\x00\x00\x80\x7f'
tple=unpack(fmt, str) The unpack () method is the opposite of the pack method and
converts a byte string into the original data as per the given
format. The meaning of the fmt parameter is identical to the
above. The second parameter, str, is a byte string. The function
returns the converted data in the form of a tuple. See the
following example which performs the reverse operations of the
above operations:

>>> #Converting a byte string into numbers


>>>
struct.unpack('ii',b'T\x01\x00\x00\x9d\x13\x00\x00')
(340, 5021)
>>> #Converting a byte string into floats
>>> struct.unpack('ff',b'\x9e\xefG@\xab\xaa\xaa>')
(3.124000072479248, 0.3333333432674408)
>>> #Converting a byte string into a string and a
float
>>> struct.unpack('6sf',b'Python\x00\x00\xcd\xccl@')
(b'Python', 3.700000047683716)
>>> #Converting a byte string into a float
>>> struct.unpack('f',b'\x00\x00\x80\x7f')
(inf,)
>>>
Size =calcsize(fmt) Calculates the size of the byte string generated by the pack
method, according to the specified format, fmt. The fmt
parameter has identical meaning that of the above. The size is
returned is in bytes. For example,

>>> struct.calcsize('i') #Size of an integer


4
>>> struct.calcsize('c') #Size of a character
1
473
>>> struct.calcsize('4s')#Size of a string
4
>>> struct.calcsize('f') #Size of a float
4

Example 11.10(a) writes the content of a list consisting of numeric values into a
binary file and reads it back into another list. The program also writes the same list into a
text file and compares the size of the binary and the text files. It also shows how the content
of a binary file will look if we read it as a text file. Example 11.10(b) writes the square roots
of 0 to 100 in a binary file and then returns the square root of a given integer number from
the file. The program uses the file as a look-up table.

Example 11.10(a): Reading and writing binary files

import struct #Importing the struct module


fp=open("list.dat","wb") #Creating a binary file for writing
list1=[10.1234,20.0323,30.12312,12345.564] #List of floats
print("Original list",list1)
for x in list1: #Iterating over the list items
st=struct.pack('f',x) #Packing a float to create a byte string
fp.write(st) #Write the byte string to the file
fp.close()
list2=[]
fp=open("list.dat","rb") #Open the binary file for reading
for i in range(len(list1)):
st=fp.read(struct.calcsize('f')) #Reading a fixed size data
x=struct.unpack('f',st) #Unpacking a byte string into a float
list2.append(x[0]) # x is a tuple
fp.close()
print("Read list:", list2)

fp=open("list.dat","rb") #Open the binary file for reading


st=fp.read() #Read the complete file as a byte string
print("Size of the binary file:",len(st))
x=struct.unpack('f'*len(list1),st) #Unpack the byte string
print("Read list", list(x)) #Convert to a list
fp.close()

fp=open("list.txt","w") #Creating a text for writing


for x in list1: #Iterating over the items of list1
st=str(x)+"\n"
fp.write(st) #Writing the number as a string to the file
fp.close()

474
fp=open("list.txt","r") #Open the text file for reading
st=fp.read() #Read the complete file as a string
print("Size of the text file:", len(st)) #Size of the text file
st=st.split("\n") #Split the string along the new line characters
st.remove("") #Remove the last blank entry
list3=[]
for x in st:
x=float(x) #Convert a string into a float
list3.append(x) #Add to list3
fp.close()
print("Read list:", list3)

fp=open("list.dat","r") #Open the binary file as a text file


st=fp.read() #Read all the content
#Print the binary file. Note it is not human readable
print("Binary file printed as a text file:",st)
fp.close()

Output
Original list [10.1234, 20.0323, 30.12312, 12345.564]
Read list: [10.12339973449707, 20.03230094909668, 30.123119354248047,
12345.564453125]
Size of the binary file: 16
Read list [10.12339973449707, 20.03230094909668, 30.123119354248047,
12345.564453125]
Size of the text file: 35
Read list: [10.1234, 20.0323, 30.12312, 12345.564]
Binary file printed as a text file: rù!A'B A&üðABæ@F

Example 11.10(b): Random access of binary files

import struct #Import struct module


import math #Import math module
fp=open("list.dat","wb") #Create a binary file
for i in range(101): #
x=math.sqrt(i)
st=struct.pack('f',x) # Pack x as a byte string
fp.write(st) #Write to the file
fp.close()

fp=open("list.dat","rb")

for i in range(4):

475
x=int(input("Enter a number:"))
fp.seek(x*struct.calcsize('f'),0) #Locate the file pointer
st=fp.read(struct.calcsize('f')) #Read a fixed size
x=struct.unpack('f',st) #Convert the byte to a float
print("Root is:", x[0])
fp.close()

Output
Enter a number:2
Root is: 1.4142135381698608
Enter a number:4
Root is: 2.0
Enter a number:9
Root is: 3.0
Enter a number:81
Root is: 9.0

11.11 Serialization in Python


In Python, we have many complex data structures, such as the list, the tuple, the set,
and the dictionary. We cannot directly save these data into a file or transfer them over a
network. Hence, we need to convert them into a linear form, such as a byte string, to write
them into a file or transfer them over a network. The process of converting a data structure
into a linear form is called serialization or pickling. The reverse process of the serialization
process, i.e. converting a linear form back into a data structure, is called deserialization, or
unpicking.

Other than saving or transferring data, serialization can be used to save intermediate
states of a long computation, such as neural network training.

The commonly used standard Python modules to serialize and reserialize objects
are the pickle module and the json module. The pickle module saves data in binary format,
whereas the json module saves in a human-readable and language-independent format.
Currently, the JSON format is a very convenient and widely used format for data exchange.
It is recommended to use the json module for exchanging information among applications,
but use the pickle module for other use cases. The pickle is faster and more compact than
the json, but not human readable.

476
11.11.1 The pickle Module

We will briefly describe the two commonly used functions of the pickle module: dump ()
and load (). The dump () function writes the object into a file and uses the following syntax:

pickle.dump(obj, fp, [optional parameters])

where obj is the object that we want to serialize and fp is the file handle where the serialized
data will be written. The file should be opened in binary and write mode.

The load () function reads the serialized file and reconstruct the object in memory and uses
the following syntax:

pickle.load(fp, [optional parameters])

where the first parameter, fp, is the file handle of the serialized file, opened in the binary
and read mode.

Example 11.11(a) shows how to pickle and unpickle different types of Python objects.

Example 11.11(a): Pickling and unpickling objects

import pickle #import the pickle module


list1=[1,2,3,4,5] #Create a list
fp=open("list.dat","wb") #Open file in binary and write mode
pickle.dump(list1,fp) #Write a list in a file
fp.close()
fp=open("list.dat","rb")
list2=pickle.load(fp) #Unpickle a file containing a list
print(list2)

tuple1=(1,2,3,4,5) #Create a tuple


fp=open("tuple.dat","wb")
pickle.dump(tuple1,fp) #Write a tuple in a file
fp.close()
fp=open("tuple.dat","rb")
tuple2=pickle.load(fp) #Unpickle a file containing a tuple
print(tuple2)

set1={3,5,6,8} #Create a set


fp=open("set.dat","wb")
pickle.dump(set1,fp) #Write a set in a file
fp.close()

477
fp=open("set.dat","rb")
set2=pickle.load(fp) #Unpickle a file containing a set
print(set2)

dict1={1:"One",2:"Two"} #Create a dictionary


fp=open("dict.dat","wb")
pickle.dump(dict1,fp) #Write a dictionary in a file
fp.close()
fp=open("dict.dat","rb")
dict2=pickle.load(fp) #Unpickle a file containing a dictionary
print(dict2)

list3=[list1,tuple1,set1,dict1] #Create a nested complex object


fp=open("list2.dat","wb")
pickle.dump(list3,fp) #Write a nested list in a file
fp.close()
fp=open("list2.dat","rb")
list4=pickle.load(fp) #Unpickle a file containing a nested list
print(list4)

Output
[1, 2, 3, 4, 5]
(1, 2, 3, 4, 5)
{8, 3, 5, 6}
{1: 'One', 2: 'Two'}
[[1, 2, 3, 4, 5], (1, 2, 3, 4, 5), {8, 3, 5, 6}, {1: 'One', 2: 'Two'}]

11.11.2 The json Module

JSON is an industry-standard, text-based data\object serialization and exchange


format. It is derived from JavaScript and is used in web services and other connected
applications to exchange data. JSON stands for JavaScript Object Notation. A JSON file
consists of objects and arrays. An object is a comma-separated collection of name: value
pairs, which are enclosed within a pair of curly brackets, {}. For example, {"Name": "David",
"Age": 40, "Married": true}. On the other hand, an array is an ordered collection of values,
which are enclosed with a pair of square brackets, []. For example, [1,2,3]. A name in an
object is always a string. Values used in objects and arrays could be any one of the seven
data types supported in JSON: string, number, object, array, true, false, and null.

Objects and arrays can be nested and used inside each other. Typically, a JSON file
contains an object or an array. If it contains an object, it will begin with an opening curly
bracket, {, and ends with a closing curly bracket,}. On the other hand, it contains an array,
478
it will start with an opening square bracket, [, and ends with a closing square bracket,]. The
following is a typical JSON data file to store the details of a person:

{
"FirstName": "Arvind",
"LastName": "Verma",
"Age": 51,
"Address": "XYZ, Jodhpur, India",
"City": "Jodhpur",
"State": "Rajasthan",
"PINCode": "123456",
"PhoneNumbers": [
{ "Mobile": "111-111-1111" },
{ "Home": "222-222-2222" }
]
}

Similarly, for storing details of more than one person, we can create an array of the
above objects, which is given as below:
[
{
"FirstName": "Rachna",
"LastName": "Verma",
"Age": 44,
"Address": "XYZ, Jodhpur, India",
"City": "Jodhpur",
"State": "Rajasthan",
"PINCode": "123456",
"PhoneNumbers": [
{ "Mobile": "111-111-1111" },
{ "Home": "222-222-2222" }
]
},
{
"FirstName": "Arvind",
"LastName": "Verma",
"Age": 51,
"Address": "XYZ, Jodhpur, India",

479
"City": "Jodhpur",
"State": "Rajasthan",
"PINCode": "123456",
"PhoneNumbers": [
{ "Mobile": "111-111-1111" },
{ "Home": "222-222-2222" }
]
}
]

In Python, a JSON object is mapped to a dictionary and a JSON array is mapped to


a list. Table 11.6 lists the mapping of various Python objects with the seven value types
of JSON. Please note, we cannot directly map a set of Python with any data type of JSON.
So to serialize a Python set object, we have to convert it to either a list or a tuple. Otherwise,
we will get an error. Similarly, for all other Python data types not listed in table 11.6, we
have to convert them into a serializable data type so that they can be serialized.

Table 11.6: Equivalence of Python objects and JSON values

Python JSON
dict Object
list Array
tuple Array
str String
int Number
float Number
True true
False false
None Null

The commonly used functions to serialize and deserialize various Python objects as
JSON files or strings are briefly described in Table 11.7. Example 11.11(b) converts a Python
object into a JSON string using a dumps () method and recreates the python objects from
the same JSON string using a loads () function. Example 11.11(c) serializes (saves) a Python
object into a JSON file using the dump () function and reserializes the same file in another
Python object. Example 11.11(d) shows how to convert non-serializable data into a JSON
string by first converting them into a serializable object.

480
Table 11.7: Functions of serialization and deserialization of Python objects as JSON
files and strings
dumps(obj, The dumps () function creates a JSON string of the obj parameter, where
[optional obj is any JSON serializable Python object (See table 11.6). See online
parameters]) helps for optional parameters, which are primarily used for formatting,
error detection, etc.
For example,
>>> import json
>>> x=["One","Two","Three"]
>>> json.dumps(x) #Convert a list into s JSON string
'["One", "Two", "Three"]'
>>> x={1:"One",2:"Two",3:"Three"}
>>> json.dumps(x) #Convert a dictionary into s JSON string
'{"1": "One", "2": "Two", "3": "Three"}'
>>> x=(1,2,3)
>>> json.dumps(x) #Convert a tuple into s JSON string
'[1, 2, 3]'
>>> x=10.0
>>> json.dumps(x) #Convert a number into s JSON string
'10.0'
>>> x=True
>>> json.dumps(x) #Convert a Boolean value into s JSON
string
'true'
>>> x=None #Convert None into s JSON string
>>> json.dumps(x)
'null'

See example 11.11(b) for complex Python objects.


loads(js) The loads () function converts a JSON string into the corresponding
Python object. The js parameter is a JSON string.
>>> x=json.loads('["One", "Two", "Three"]') #A JSON array
to a list
>>> print(x, type(x))
['One', 'Two', 'Three'] <class 'list'>
>>> #A JSON object to a dictionary
>>> x=json.loads('{"1": "One", "2": "Two", "3": "Three"}')
>>> print(x, type(x))
{'1': 'One', '2': 'Two', '3': 'Three'} <class 'dict'>
>>> x=json.loads('10.0') #A JSON number to a float
>>> print(x, type(x))
10.0 <class 'float'>
>>> x=json.loads('true') #The JSON true to the Python True
>>> print(x, type(x))

481
True <class 'bool'>
>>> x=json.loads('null') #The JSON null to the Python None
>>> print(x, type(x))
None <class 'NoneType'>

See example 11.11(b) for complex Python objects.


dump(obj, fp, The dump () function serializes the obj parameter as a JSON file linked
,[optional with the file handle fp. The obj parameter is any JSON serializable
parameters]) Python object (See table 11.6). The parameter fp is the file handle of a
JSON file opened in the write mode. See online helps for optional
parameters, which are primarily used for formatting, error detection, etc.
See example 11.11(c).
load(fp) The load () function reads a JSON file and recreates the corresponding
Python object. The parameter fp is the file handle of a JSON file opened
in the read mode. See example 11.11(c).

Example 11.11(b): Convert a Python object into a JSON string

import json #Import the json module


#A complex Python object consisting of most of the Python data types
x = {
"name": "Dave", #String
"age": 55, #Number
"married": True, #Boolean
"divorced": False,
"children": ("John","Boby"), #Tuple
"pets": None, #None
"vehicles": [ #List
{"car": "Ford", "mileage": 16}, #Dict
{"scooter": "Bajaj", "mileage": 50}]
}

s=json.dumps(x) #Converting a Python object to a JSON string


print("Convert a Python object to a JSON string:")
print(s)

print("\nConvert a JSON string to a Python object:")


y=json.loads(s) #Converting a JSON string to a Python object
print(y)
Output
Convert a Python object to a JSON string:

482
{"name": "Dave", "age": 55, "married": true, "divorced": false,
"children": ["John", "Boby"], "pets": null, "vehicles": [{"car":
"Ford", "mileage": 16}, {"scooter": "Bajaj", "mileage": 50}]}

Convert a JSON string to a Python object:


{'name': 'Dave', 'age': 55, 'married': True, 'divorced': False,
'children': ['John', 'Boby'], 'pets': None, 'vehicles': [{'car':
'Ford', 'mileage': 16}, {'scooter': 'Bajaj', 'mileage': 50}]}

Example 11.11(c): Serialize and reserialize a Python object as a JSON file

import json #Import the json module


#Complex Python object consisting of most of the Python data types
x = {
"name": "Dave", #String
"age": 55, #Number
"married": True, #Boolean
"divorced": False,
"children": ("John","Boby"), #Tuple
"pets": None, #None
"vehicles": [ #List
{"car": "Ford", "mileage": 16}, #Dict
{"scooter": "Bajaj", "mileage": 50}]
}

fp=open("myObject.json","w") #Open a writable test file


s=json.dump(x,fp, indent=6)
fp.close()

fp=open("myObject.json","r") #Open a readable text file

print("\nRead a JSON file and convert it to a Python object:")


y=json.load(fp) #Read a JSON file
fp.close()
print(y)

Output
Read a JSON file and convert it to a Python object:
{'name': 'Dave', 'age': 55, 'married': True, 'divorced': False,
'children': ['John', 'Boby'], 'pets': None, 'vehicles': [{'car':
'Ford', 'mileage': 16}, {'scooter': 'Bajaj', 'mileage': 50}]}

483
Example 11.11(d): Converting various types of objects into JSON strings

import json
#Serialise/Deserialize a complex number
print("Serialize/Deserialize a complex number")
c=4+5j
s=str(c) #Convert a complex number to a string
js=json.dumps(s) #Serialize as a string
print("JSON string:", js)
s1=json.loads(js) #Deserialize as a string
c1=complex(s1) #Convert a string to a complex number
print("Original:", c,", Recreated:",c1)

#Serialise/Deserialize a set
print("\nSerialize/Deserialize a set")
s={1,2,5,4,3}
list1=list(s) #Convert a set to a list
js=json.dumps(list1) #Serialize as a string
print("JSON string:", js)
list2=json.loads(js) #Deserialize as a list
s1=set(list2) #Convert a list to a set
print("Original:", s,", Recreated:",s1)

#Serialize/Deserialize a zipped object


print("\nSerialize/Deserialize a zipped object")

z=zip([1,2],('a','b'))
z2=zip([1,2],('a','b'))
list1=list(z) #Convert a zipped object to a list
js=json.dumps(list1) #Serialize as a string
print("JSON string:", js)
list2=json.loads(js) #Deserialize as a list
z1=zip(list2) #Convert a list to a zipped object
print("Original zipped object:")
for x in z2:
print(x)
print("Recreated zipped object:")
for x in z1:
print(x)

#Serialize/Deserialize a byte string


print("\nSerialize/Deserialize a byte string")
bs=bytes("Python", encoding="UTF-8") #Create a byte string
s=bs.decode() #Convert a byte string to a string
js=json.dumps(s) #Serialize as a string
print("JSON string:", js)

484
s=json.loads(js) #Deserialize as a string
bs1=bytes(s, encoding="UTF-8") #Convert a string to a byte string
print("Original:",bs,", Recreated:",bs1)

Output
Serialize/Deserialize a complex number
JSON string: "(4+5j)"
Original: (4+5j) , Recreated: (4+5j)

Serialize/Deserialize a set
JSON string: [1, 2, 3, 4, 5]
Original: {1, 2, 3, 4, 5} , Recreated: {1, 2, 3, 4, 5}

Serialize/Deserialize a zipped object


JSON string: [[1, "a"], [2, "b"]]
Original zipped object:
(1, 'a')
(2, 'b')
Recreated zipped object:
([1, 'a'],)
([2, 'b'],)

Serialize/Deserialize a byte string


JSON string: "Python"
Original: b'Python' , Recreated: b'Python'

11.12 CSV Files

We frequently use the CSV (Comma Separated Values) format to store tabular data
in a text file. In the CSV format, each line of the file is a data record and each record consists
of one or more fields, separated by commas. Table 11.8 shows an example of a CSV file.
Commonly, .csv is used as the extension of a CSV file, but we can also use .txt extension.
The most commonly used character to separate fields, called delimiters, in a record, is a
comma. However, we can also use some other characters, such as tab, as a delimiter. In a
CSV file, normally the first line contains the names of the fields. If the value of a field
contains a comma i.e. a delimiter, the must be enclosed within double/single quotes.

Table 11.8: An example of a CSV file (test.csv)

ID, Name, Age, City


1, Jill, 45, New Delhi
2, Jack, 35, Mumbai

485
Python has the csv built-in module to read and write CSV files. Table 11.9 briefly
describes the commonly used functions of the csv module. The functions discussed in the
table have many optional parameters, for those readers can refer to online documentation.
Further, there are other powerful modules, such as pandas, etc. for processing CSV files.
However, we will limit ourselves to only the csv module in this book.

Table 11.9: The commonly used functions of the csv module

csv.reader(csvfile, The csv.reader () function reads a CSV file and returns a


[optional parameters] csv.reader object which will iterate over lines in the given
csvfile. Each line read from the CSV file is returned as a list of
strings, by default. For reading a tab-delimited file, use
csv.reader(csvfile, delimiter = '\t'). For the optional
parameters, see the online help. Example 11.12(a) illustrates
the reading of a CSV file using this function.
csv.DictReader(csvfile, The csv.DictReader () function reads a CSV file and returns an
[optional parameters) csv.DictReader object which is an iterator consisting of each
row as a dictionary. By default, the first row of the CSV file is
used as the name of the fields of the dictionary. Example
11.12(b) illustrates the csv.DictReader () function.
csv.writer(file,[Optional The csv.writer () function returns a csv writer object, which can
parameters]) be used to write data into a CSV file. The writer object provides
many functions, such as writerow () and writerows (), to write
writerow(1D_list) the data to a CSV file. The writerow () writes a single row into
the file, whereas the writerows () writes a list of rows in the
writerows(2D_list) file. Example 11.12(c) illustrates these functions.

Example 11.12(a): Reading a CSV file

import csv #Import the csv module


fp=open("D:\\test\\test.csv","r")
reader=csv.reader(fp)#Create a CSV reader
print(type(reader))#Print the type of an object
rows=[] #Create an empty list
for row in reader: #Iterate over the reader
rows.append(row)#Add the row to the list
print(row)#Print the current row
486
print(rows) #Print the list
Output
<class '_csv.reader'>
['ID', ' Name', ' Age', ' City']
['1', ' Jill', ' 45', ' New Delhi']
['2', ' Jack', ' 35', ' Mumbai']
[['ID', ' Name', ' Age', ' City'], ['1', ' Jill', ' 45', ' New Delhi'],
['2', ' Jack', ' 35', ' Mumbai']]

Example 11.12(b): Read a CSV file as a list of dictionaries

import csv #Import the csv module


with open("D:\\test\\test.csv","r") as fp:
reader=csv.DictReader(fp)#Create a CSV DictReader
print(type(reader))#Print the type of an object
rows=[] #Create an empty list
for row in reader: #Iterate over the reader
rows.append(row)#Add the row to the list
print(row)#Print the current row

print(rows) #Print the list


Output
<class 'csv.DictReader'>
{'ID': '1', ' Name': ' Jill', ' Age': ' 45', ' City': ' New Delhi'}
{'ID': '2', ' Name': ' Jack', ' Age': ' 35', ' City': ' Mumbai'}
[{'ID': '1', ' Name': ' Jill', ' Age': ' 45', ' City': ' New Delhi'},
{'ID': '2', ' Name': ' Jack', ' Age': ' 35', ' City': ' Mumbai'}]

Example 11.12(c): Write a CSV file

import csv #Import the csv module


#Open a file in write mode
with open('d:\\test\\test1.csv', 'w', newline='') as file:
writer = csv.writer(file) #Create a csv writer object
writer.writerow(["ID", "Name", "Age", "City"]) #Write the head row
#Create a list of all the data row
list1=[[1, "Jill", 45, "New Delhi"],[2, "Jack", 35, "Mumbai"]]
writer.writerows(list1) #Write the data rows
fp=open('d:\\test\\test1.csv', 'r') #Open a file
print(fp.read()) #Read and print the content of the file
Output
ID,Name,Age,City
1,Jill,45,New Delhi
2,Jack,35,Mumbai

487
11.13 File and Directory Management
As the number of files increases, we use folders/directories to group similar files
together for easy management. A folder or directory is a storage space, or container, where
files are stored in the computer. A folder can also contain other folders, called sub-folders.
In a computer, a tree structure is used to organize files and folders, where nodes represent
folders and leaves represent files. Sometimes, we require to create/delete/rename folders
or change directories in a program. For these tasks, Python has many modules but we will
discuss some commonly used functions of the os and shutil modules. Table 11.10 briefly
describes commonly used file and directory management functions of the os and shutil
modules. For more details about these modules and other functions, readers can refer to
online help.

Table 11.10: Files and directories Management functions of the os module

os.getcwd() The os.getcwd () function returns the present working directory as


a string. The current working directory is the directory where we
save our files by default files are saved or
>>> import os
>>> os.getcwd() #Returns the current working
directory
'C:\\Users\\MBM\\AppData\\Local\\Programs\\Python\\Py
thon39'
The extra backslashes are escape sequences.
>>> print(os.getcwd())
C:\Users\MBM\AppData\Local\Programs\Python\Python39
os.chdir(path) The os.chdir () function is used to change the current working
directory. The path parameter is a string which is the path of the
new current directory.
>>> import os
>>> os.chdir("c:\\Users") #Change the current working
directory
>>> os.getcwd() #Get the current working directory
'c:\\Users'
os.listdir(path) The os.listdir () function returns a list of all files and sub-folders
inside a folder specified by the path parameter. The path
parameter is a string and it is optional. Its default value is the
current working directory.

488
>>> os.listdir() #Lists files and folders of the
current working directory
['All Users', 'Default', 'Default User',
'desktop.ini', 'MBM', 'Public']
>>> os.listdir("d:\\") #Lists files and folders of
the specified path
['$RECYCLE.BIN', 'abc.txt', 'akv', 'file1.txt',
'System Volume Information']
os.mkdir(dir) The os.mkdir () is used to create a new directory at the specified
path. The dir parameter is a string. If dir contains the absolute path
of a new directory, the new directory will be created there. If only
the name of a new directory is provided, the new directory will be
created in the current working directory. Please note, the program
requires the creation permission to create a directory in the
specified folder, otherwise, an access error will be generated.
>>> import os #Import the os module
>>> os.chdir("c:\\Users") #Change the current working
directory
>>> os.getcwd()
'c:\\Users'
>>> os.mkdir("text") #Create a new directory
>>> os.listdir() #List directory
['All Users', 'Default', 'Default User',
'desktop.ini', 'MBM', 'Public', 'text']
>>> #Creating a new directory at an absolute path
>>> os.mkdir("D:\\akv\\Book Python\\test")
>>> #List directory
>>> os.listdir("D:\\akv\\Book Python")
['Introduction to Python.docx', 'test']

os.rename(old_dir, The os.rename () function is used to rename an existing directory


new_dir) or a file with a new name. The first parameter is the name of the
old directory/ file and the second parameter is the new name.

Both the parameters are strings.

>>> os.getcwd() #Get the current working directory


'd:\\'
>>> os.listdir()
['abc.txt', 'akv', 'file1.txt', 'Hello']
>>> os.rename("Hello","Hi") #Rename a directory
>>> os.listdir() #List directory
['abc.txt', 'akv', 'file1.txt', 'Hi']

489
os.remove(file) The os.remove () function deletes a file specified by the file
parameter.
>>> os.listdir() #List directory
['abc.txt', 'akv', 'file1.txt', 'Hi']
>>> os.remove("file1.txt") #Delete a file
>>> os.listdir()
['abc.txt', 'akv', 'Hi']
>>>
os.rmdir(dir) The os.rmdir () function deletes an empty directory. We cannot
use this function of remove non-empty directory. To remove a
non-empty directory, we can use the rmtree () function of shutil
module.
>>> os.listdir()
['abc.txt', 'akv', 'Hi']
>>> os.rmdir('Hi') #Remove an empty directory
>>> os.listdir()
['abc.txt', 'akv']
os.walk(root) The os.walk(root) function can be used to traverse all the
subfolders and files of a directory. The root parameter is the root
directory whose files and folders will be traversed. The function
returns a list of tuples. Each tuple consists of three items: the
current root folder name, a list of all the sub-folders in the current
folder, and a list of all the files in the current folder. Example
11.13(a) illustrates a use of the os.walk () function.
shutil.rmtree(dir) The shutil.rmtree () function removes the dir directory and all its
files and sub-directories. The dir parameter is a string that contains
the complete path of the directory to be deleted. If on directory
name is given, the directory in the current working directory will
be deleted.

>>> import os #Import the os module


>>> import shutil #Import the shutil module
>>> os.chdir("d:\\test") #Change directory
>>> os.listdir() #List the current directory
['file1.txt', 'file2.txt', 'Folder1']
>>> shutil.rmtree("Folder1") #Remove a folder along
with its content
>>> os.listdir()#List the current directory
['file1.txt', 'file2.txt']
shutil.copy(src, dst) The shutil.copy () function copy a file from one location to another
location. The first parameter, src, is the source file and the second

490
parameter, dst, is the destination file. If the designation is a folder
name, then the file will be copied with the same name in the
designation location. However, if the destination is a file name, the
source file will be copied with the destination file name in the
destination file location. Example 11.13(b) illustrates an example
of the shutil.copy () function.
shutil.copytree(src, The shutil.copytree() function copies the src folder including all
dst) its subfolders and files to the dst folder. Example 11.13(c)
illustrates this.
shutil.move(src, dst) The shutil.move () function moves the src file to the dst folder.
Example 11.13(d) illustrates a use of the shutil.move () function.

Example 11.13(a): Traversal of all the files and sub-folders of a folder

import os #Import the os module


def traverse_dir(root): #Function to traverse a directory
i=0
#The os.walk () function generates directory and file tree
for root, dirs, files in os.walk(root): #Iterate a directory tree
print("\directory level:", i)
i=i+1
print("Current root folder:", root)
print("List of directories:")
for d in dirs: #Iterate directories in the current folder
print (root+"\\" +d)
print("List of files:")#Iterate files in the current folder
for f in files:
print(root+"\\" +f)
traverse_dir("D:\\test")

Output
Directory level: 0
Current root folder: D:\test
List of directories:
D:\test\Folder1
List of files:
D:\test\file1.txt
D:\test\file2.txt

Directory level: 1
Current root folder: D:\test\Folder1
List of directories:

491
D:\test\Folder1\Folder2
List of files:
D:\test\Folder1\abc.txt
D:\test\Folder1\abc1.txt

Directory level: 2
Current root folder: D:\test\Folder1\Folder2
List of directories:
List of files:
D:\test\Folder1\Folder2\xyz.txt
D:\test\Folder1\Folder2\xyz2.txt

Example 11.13(b): Copy a file from one folder to another folder

import os #Import the os module


import shutil #Import the shutil module
os.chdir("D:\\test") #Change the current directory
os.mkdir("dir1") #Make a new directory
print("List of ", os.getcwd(), ":")
print(os.listdir()) #List files and folders of the current directory
#Copy a file from one location to another
shutil.copy('file1.txt', 'd:\\test\\dir1')
os.chdir("D:\\test\\dir1")
print("List of ", os.getcwd(), ":")
print(os.listdir())
Output
List of D:\test :
['dir1', 'file1.txt', 'file2.txt']
List of D:\test\dir1 :
['file1.txt']

Example 11.13(c): Copy the complete directory structure to another location

import os #Import the os module


import shutil #Import shutil module
def traverse_dir(root): #Function to traverse a directory
i=0
#The os.walk () function generates directory and file tree
for root, dirs, files in os.walk(root): #Iterate a directory tree
print("\ndirectory level:", i)
i=i+1
print("Current root folder:", root)
print("List of directories:")
for d in dirs: #Iterate directories in the current folder
492
print (root+"\\" +d)
print("List of files:")#Iterate files in the current folder
for f in files:
print(root+"\\" +f)
#Copy the complete directory structure
shutil.copytree("D:\\test","D:\\test1")
print("Original Directory")
traverse_dir("D:\\test")

print("\nCopied Directory")
traverse_dir("D:\\test1")

Output
Original Directory

directory level: 0
Current root folder: D:\test
List of directories:
D:\test\dir1
List of files:
D:\test\file1.txt
D:\test\file2.txt

directory level: 1
Current root folder: D:\test\dir1
List of directories:
List of files:
D:\test\dir1\file1.txt

Copied Directory

directory level: 0
Current root folder: D:\test1
List of directories:
D:\test1\dir1
List of files:
D:\test1\file1.txt
D:\test1\file2.txt

directory level: 1
Current root folder: D:\test1\dir1
List of directories:
List of files:
D:\test1\dir1\file1.txt

493
Example 11.13(d): Move a file from one folder to another

import os #Import the os module


import shutil #Import the shutil module
print(os.listdir("D:\\test")) #List the contents of a directory
print(os.listdir("D:\\test1"))#List the contents of a directory
#Move a file from one folder to another folder
shutil.move("D:\\test\\file1.txt","D:\\test1")
print("Contents of the directories after moving a file")
print(os.listdir("D:\\test")) #List the contents of a directory
print(os.listdir("D:\\test1"))#List the contents of a directory
Output
Source directory: ['dir1', 'file1.txt']
Destination directory: []
Contents of directories after moving a file
Source directory: ['dir1']
Destination directory: ['file1.txt']

11.14 Solved Examples

Sample Program 8.1: Write a program to write the multiplication table of numbers
between n1 and n2 in a text file.

Solution steps:
1. Read n1 and n2.
2. Open the file in the write mode
3. Iterate between n1 and n2 to generate each number in the range.
3.1. Iterate between 1 and 10:
3.1.1 Calculate a multiplication term
3.1.2 Convert the term into a formatted string
3.1.3 Write the formatted value into the file
3.2. Write a newline character
4. Close the file.

n1=int(input("Enter the lower number:")) #Read n1


n2=int(input("Enter the upper number:")) #Read n2
fp=open("myTable.txt","w") #Open the file in the write mode
for n in range(n1,n2+1): #Loop to generate numbers between n1 and n2
for i in range(1,11): #Loop to generate a row in the table
t=n*i #Calculate a multiplication term
s= f"{t:5}" #Convert the term into a formated string
fp.write(s) #Write the formated term in the file

494
fp.write("\n")#Write a newline character at the end of each line
fp.close() #Close the file
Output (The content of myTable.txt)
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100

Sample Program 8.2: Write a program to read myfile.txt containg numbers in each row
separated by commas and find the sum of numbers in each row.

Solution steps:
1. Open the file and read all the lines.
2. Iterate over each line:
2.1 Split the line into substrings
2.2 Initialise sum
2.3 For each substring in the list:
2.3.1 Convert the substring into a float
2.3.2 Add the number to the sum
2.4 Print the sum of the line
with open("myfile.txt","r") as fp:#Open the file in the read mode
lines=fp.readlines() #Read all the lines
i=1
for line in lines: #Iterate over each line
numbers= line.split(",") #Split the line into substrings
s=0
print(f"Line {i}:", end="")

495
for n in numbers: #Iterate over each substring in a line
x=float(n) #Convert a subtring into a number
s=s+x #Calculate sum
print(x, end=" ") #Print numbers
print(", Sum = ", f"{s:<8.2f}") #Print sum
Output
Line 1:1.0 3.2 5.5 6.1 , Sum = 15.80
Line 1:2.0 3.0 , Sum = 5.00
Line 1:5.0 8.0 2.3 , Sum = 15.30
Line 1:5.0 2.0 1.5 6.0 7.0 , Sum = 21.50

Sample Program 8.3: Write a program that reads the entire contents of a file and count
the frequency of each character. Also print the total number of characters and total
number of unque characters in the file. Here, Sample program 1 given above is used as
input file for the illustration.

Solution steps:
1. Read the file name.
2. Check the existence of the file. If it does not exist exit.
3. Open the file in the read mode.
4. Read the entire content of the file in a str object.
5. Create an empty dictionary.
6. Iterate over each character of the string:
6.1 If the character exist in the dictionary, increment its count.
6.2 Else create a new key in the dictionary.
7. Iterate over each item in the dictionary and print the frequency.
8. Get the total number of characters and total number of unique characters in the file
using the len method.
from os import path #Import the path module
filename=input("Enter file name:") #Read the filename
check= path.exists(filename) #Check whether the given file exists or
not
if check == False: #Show mesaage:file does not exist
print("File does not exist")
exit(0)
file =open(filename,'r') #Open the file for reading

496
s=file.read() #Read the entire content of the file
d=dict() #Create an empty dictinary
for c in s: #Iterate over each character of the string
if c in d: #If the character exist as a key in the dict,increment
its count
d[c]=d[c]+1
else: #Create a new key in the dictionary and set count to 1
d[c]=1
print("Total number of characters:",len(s)) #Count total characters
print("Total number of unique characters:",len(d)) #Count total unique
characters
print("Frequencies of characters:")
for k in sorted(d): #Print frequencies of characters
print(k,"=", d[k], end=', ')
Output
Enter file name:sample1.py
Total number of characters: 910
Total number of unique characters: 49
Frequencies of characters:

= 19, = 146, " = 12, # = 13, ' = 4, ( = 14, ) = 14, + = 1, , = 8, . = 2, 0 = 1, 1 = 3, : = 10, = = 11,
C = 5, E = 1, F = 3, I = 3, O = 1, P = 1, R = 2, S = 1, T = 2, [ = 4, ] = 4, a = 44, b = 2, c = 37, d
= 22, e = 94, f = 25, g = 4, h = 28, i = 49, k = 8, l = 22, m = 14, n = 49, o = 35, p = 14, q = 4, r
= 47, s = 28, t = 69, u = 14, v = 2, w = 3, x = 6, y = 5,

Sample Program 8.4: Write a program that reads the entire content of a file and count the
frequency of each word. Here, Sample program 2 given above is used as input file for the
illustration. Here, Sample program 3 given above is used as input file for the illustration.

Solution steps:
1. Read the file name.
2. Check the existence of the file. If it does not exist exit.
3. Open the file in the read mode.
4. Read the entire content of the file in a str object.
497
5. Replace all non-alphabets with spaces.
6. Split the string into words.
7. Create an empty dictionary.
8. Iterate over each word in the list:
8.1 If the word exist in the dictionary, increment its count.
8.2 Else create a new key in the dictionary.
9. Iterate over each item in the dictionary and print the frequency.
10. Get the total number of words and total number of unique word in the file using the
len method.
from os import path #Import the path module
filename=input("Enter file name:") #Read the filename
check= path.exists(filename) #Check whether the given file exist or not
if check == False: #Show the message: file does not exist
print("File does not exist")
exit(0)
file =open(filename,'r') #Open the file for reading
s=file.read() #Read the entire content of the file
s1=""
for c in s: #Replace all non-alphabets with spaces
if c.isalpha()or c==" ": s1=s1+c
else: s1=s1 +" "

words= s1.split() #Split the string into a list of words


d=dict() #Create an empty dictinary
for word in words: #Iterate over each word in the list
if word in d: #If the word exist as a key in the dict,increment
its count
d[word]=d[word]+1
else: #Create a new key in the dictionary and set its count to 1
d[word]=1
print("Total number of words:",len(words)) #Count total number of words
print("Total number of unique words:",len(d)) #Count unique words
print("Frequencies of words:")
for k in sorted(d): #Print frequencies of words
print(k,"=", d[k], end=', ')
Output
Enter file name:sample2.py
Total number of words: 190
Total number of unique words: 89
Frequencies of words:

498
Check = 1, Count = 2, Create = 2, Enter = 1, False = 1, File = 1, Frequencies = 1, If = 1,
Import = 1, Iterate = 1, Open = 1, Print = 1, Read = 2, Replace = 1, Show = 1, Split = 1,
Total = 2, a = 3, all = 1, alphabets = 1, an = 1, and = 1, as = 1, c = 4, check = 2, content = 1,
count = 2, d = 8, dict = 2, dictinary = 1, dictionaly = 1, does = 2, each = 1, else = 2, empty
= 1, end = 1, entire = 1, exist = 4, exists = 1, exit = 1, file = 7, filename = 4, for = 4,
frequencies = 1, from = 1, given = 1, if = 3, import = 1, in = 7, increment = 1, input = 1,
into = 1, isalpha = 1, its = 2, k = 3, key = 2, len = 2, list = 2, message = 1, module = 1,
name = 1, new = 1, non = 1, not = 3, number = 3, of = 7, open = 1, or = 2, os = 1, over = 1,
path = 3, print = 5, r = 1, read = 1, reading = 1, s = 8, set = 1, sorted = 1, spaces = 1, split
= 1, string = 1, the = 12, to = 1, total = 1, unique = 2, whether = 1, with = 1, word = 7,
words = 10,

Sample Program 8.5: Write a program that prints the first and the n lines of a file. Here,
Sample program 3 given above is used as input file for the illustration.

Solution steps:
1. Read the file name
2. Read the number of lines to read
3. Check the existence of the file. If it does not exist exit.
4. Open the file in the read mode
4. Read all the lines using readlines() method
5. Print the first n lines.
6. Print the last n lines
from os import path #Import the path module
filename=input("Enter file name:") #Read the filename
n=int(input("Enter the number of lines to read from the start and the
end:"))
check= path.exists(filename) #Check whether the given file exist or not
if check == False: #Show the message: file does not exist
print("File does not exist")
exit(0)
file =open(filename,'r') #Open the file for reading
lines=file.readlines() #Read all the lines of the file

499
print(f"The first {n} lines are:")
for line in lines[:n]:
print(line, end="")

print(f"\nThe last {n} lines are:")


for line in lines[-n:]:
print(line, end="")
Output
Enter file name:sample3.py
Enter the number of lines to read from the start and the end:3
The first 3 lines are:
from os import path #Import the path module
filename=input("Enter file name:") #Read the filename
n=int(input("Enter the number of lines to read from the start and the end:"))

The last 3 lines are:


print(f"\nThe last {n} lines are:")
for line in lines[-n:]:
print(line, end="")

Sample Program 8.6: Write a program to create a book database using a binary file. Write
functions to add a new book, list all books and list books of an author. The book record
contains book ID, title, author and price.

Solution steps:
1. Import pickle module to handle binary files
2. Add book function:
2.1 Open file in append and binary mode
2.2 Input book ID, title, author and price
2.3 Create a book record using a list containing book details
2.4 add pickle.dump() method to write the record in the book database
2.5 Close the file

500
3. Get books by author function:
3.1 Open the book database in binary read mode
3.2 Input the author name
3.3 Iterate over each record in the file and print the record that matches with the
author
3.4 Close the file
4. List all the books functions:
4.1 Open the book database in binary read mode
4.2 Iterate over each record in the file and print them
4.3 Close the file
5. Create the main menu to get the choice
import pickle #Import the pickle module

def addBook(): #Add a new book in the database


file = open("book.dat","ab")
BookNo = int(input("Enter book ID: "))
Book_Name = input("Enter book name: ")
Author =input("Enter author name: ")
Price = int(input("Enter price: "))
record = [BookNo, Book_Name, Author, Price]
pickle.dump(record, file)
file.close()

def getBook(): #List books of an author


Author = input('Enter author name to search: ')
file = open("book.dat","rb")
count = 0
try:
while True:
record = pickle.load(file)
if record[2]==Author:
count+=1
print(record)
except EOFError:
pass
return count
file.close()

def listBooks(): #List all the books


file = open("book.dat","rb")
count = 0
try:
while True:
record = pickle.load(file)

501
print(record)
except EOFError:
pass
return count
file.close()

#Main menu
while(True): #Show menu
print("\nMain Menu")
print("1. Add a book")
print("2. Find author's books")
print("3. List all the books")
print("4. Exit")

choice = int(input("Choose you option:")) #Get a choice


if choice ==1: addBook()
elif choice == 2:
getBook()
elif choice == 3:
listBooks()
else:
print("Exiting...")
break
Output
Main Menu
1. Add a book
2. Find author's books
3. List all the books
4. Exit
Choose you option:3
[1, 'Python', 'Ravi', 300]
[2, 'C++', 'Shyam', 200]
[3, 'Java', 'Ravi', 400]
[4, 'Javascript', 'Ravi', 120]

Main Menu

502
1. Add a book
2. Find author's books
3. List all the books
4. Exit
Choose you option:1
Enter book ID: 5
Enter book name: Pearl
Enter author name: Shyam
Enter price: 230

Main Menu
1. Add a book
2. Find author's books
3. List all the books
4. Exit
Choose you option:2
Enter author name to search: Shyam
[2, 'C++', 'Shyam', 200]
[5, 'Pearl', 'Shyam', 230]

Main Menu
1. Add a book
2. Find author's books
3. List all the books
4. Exit

503
Choose you option:

Chapter Summary

1 A text file consists of binary forms of human-readable symbols and characters and
uses either ASCII or Unicode to form binary patterns of various symbols and
characters. On the other hand, a binary file uses raw data and does not apply any
encoding before writing it on the disk. Hence, they can only be read by the
program (or compatible programs) that has generated it.
2 File handling, in general, involves the following three steps: (1) opening a file, (2)
reading/writing data from/to the file, and (3) Closing the file.
3 The open() method is used to open a file, and the close() method is used to close
it. A file opened using the open () method with a with statement is automatically
closed after the file operation.
4 A file can be opened in different modes, such as read, write, append, text, binary,
etc. The valid mode values are 'r ', 'rb', 'r+', 'rb+', 'w', 'wb', 'w+', 'wb+', 'a', 'ab', 'a+',
'ab+' and 'x'.
5 Commonly used file handling functions are close(), flush(), read(), readable(),
readline(), readlines(), seek(), seekable(), tell(), truncate(), writable(), write(), and
writelines().
6 The commonly used standard Python modules to serialize and reserialize objects
are the pickle and the json modules.
7 The CSV (Comma Separated Values) format is used to store tabular data in a text
file. In the CSV format, each file line is a data record, and each record consists of
one or more fields, separated by commas. Python has the csv built-in module to
read and write CSV files.
8 The os and shutil modules are commonly used to manage files and directory
operations, such as copy files, rename files, move files, create directories.

504
Multiple Choice questions

1. A file that consists of human-readable characters is called


(a) Binary file
(b) Text file
(c) Human file
(d) None of the above
2. A file that directly stores the bit patterns of data in RAM is called.
(a) Unicode file
(b) Text file
(c) Binary file
(d) None of the above
3. What will you see if you open a binary file using a text editor?
(a) Garbage values
(b) ASCII values of characters
(c) The binary code of each byte
(d) The Unicode of each byte
4. If we open a file with the statement fp = open('myfile.dat'), what will be the value
of fp.mode?
(a) 'r'
(b) 'x'
(c) 'w'
(d) 'a'
5. Which of the following is used as the default EOL character in Python?
(a) '\r'
(b) '\n'
(c) '\t'
(d) '\b'
6. Which of the following is an invalid file mode in Python?
(a) 'r '
(b) 'rb'
(c) 'r+'
(d) 'rw'
7. Which of the following is a valid file mode in Python?

505
(a) 'r'
(b) 'w'
(c) 'a'
(d) All of the above
8. Which of the following file mode will raise an error if we attempt to open an
existing file?
(a) 'r+'
(b) 'a'
(c) 'w'
(d) 'x'
9. To open a file c:\mydata.txt for reading, which of the following is the correct
statement?
(a) fp = open(“c:\ mydata.txt”, “r”)
(b) fp = open(“c:\\ mydata.txt”, “r”)
(c) fp = open(file = “c:\ mydata.txt”, “r”)
(d) i fp = open(file = “c:\\ mydata.txt”, “r”)
10. Which of the following method can be used to read the entire content of a file
and return it as a string
(a) read()
(b) readline()
(c) readlines()
(d) readall()
11. Which of the following methods can be used to read the entire file content and
return each line as an item in a list of strings?
(a) read()
(b) readline()
(c) readlines()
(d) readall()
12. To read five characters from a file object fp, which of the following statement can
be used?
(a) fp.read(5)
(b) fp.readline(5)
(c) fp.readlines(5)
(d) None of the above

506
13. Which of the following statement can be used to read all the remaining characters
of the current line of a file object fp?
(a) fp.read()
(b) fp.readline()
(c) fp.readlines()
(d) All of the above
14. The number of characters read by the statement fp.readline(20) from the file
handle fp is
(a) 20
(b) 19
(c) 21
(d) It depends on the current position of the file location pointer.
15. The statement fp.readlines(20) reads
(a) minimum 20 bytes
(b) maximum 20 bytes
(c) exactly 20 bytes
(d) none of the above
16. Which of the following method can be used to write a list of strings in a file?
(a) writelines()
(b) write()
(c) writelist()
(d) None of the above
17. Which of the following method can be used to write a list of numbers in a file?
(a) writelines()
(b) write()
(c) writelist()
(d) None of the above
18. Which of the following method can be used to get the current location of the file
pointer?
(a) tell()
(b) get()
(c) find()
(d) None of the above
19. Which of the following method can be used to change the current location of the
file pointer?

507
(a) set()
(b) seek()
(c) change()
(d) None of the above
20. The statement fp.seek() with a read and write file object fp will position the file
pointer to
(a) the start of the file
(b) the end of the file
(c) at its current location
(d) it is an error
21. The binary file mode is typically used for large datasets due to
(a) it requires less disk space than a corresponding text file
(b) it is more efficient than a corresponding text file
(c) Both a and b
(d) None of the above.
22. Which of the following modes permits both read and write in the binary format
in a file?
a) 'wb+'
b) 'w'
c) 'wb'
d) 'w+'
23. Which of the following modes does not permit writing in a file?
a) 'r+'
b) 'w'
c) 'x'
d) None of the above
24. What is the type of the returned object of the readlines() method?
(a) string
(b) a list of strings
(c) a tuple of strings
(d) None of the above
25. Which of the following is true for ‘r+’ file mode?
(a) It will return an error if the file does not exist
(b) It will permit both reading and writing
(c) It will permit relocation of the file pointer

508
(d) All of the above

Review Questions

1. State whether the following statements are true or false


a. When we open a file for reading, an error will be generated if the file does
not exist.
b. When we open a file for writing, if the file does not exist, a new file is
created.
c. When you open a file for writing, if the file exists, the existing file is
overwritten with the new file.
d. A binary file is human readable.
e. When we open a file with the with construct, the file is automatically closed
after file operations are over.
f. The readline() method returns a string.
g. The readlines() method returns a list of strings.
h. The read() method returns an integer object.
i. The write() method automatically adds a new line character at the end of
the string.
j. The writelines() method can directly write a list of numbers into a file.
k. The seek() method is used to get the current location of the file pointer.
l. Binary files are smaller than the corresponding text files.
m. The pickle module is used to save data in binary format.
n. The json module is use to save data in text format.
2. Describe different types of files supported by Python.
3. Describe steps involved in a typical file handling operation.
4. Describe open methods along with different file modes.
5. Describe methods and attributes of the file object.
6. Describe various methods to read data from a text file.
7. Describe various methods to write data in a text file.
8. Describe methods to read and write numerical data in a file.
9. Describe random accessing of a file.
10. Describe reading and writing in a binary file.
11. Describe seek and tell methods of the file object.
12. Describe object serialization using the pickle module.
13. Describe object serialization using the json module.
14. Describe the CSV file and methods to read and write in it.
15. Describe the commonly used methods of os and shutil modules.
509
Programming Assignments

1. Write a program to read and print each line of a text file.


2. Write a program of print the size of a text file.
3. Write a program to read a file and print the number of lines that start with the
word The.
4. Write a program to read a file and count the number of vowels in the file.
5. Write a program to convert all the letters of a file to upper case.
6. Write a program to reverse each word in a text file.
7. Write a program to find sum of all the integer numbers scattered in a text file.
8. Write a program to write numbers between n1 and n2 and their squares, cubes,
and square roots in a file
9. Write a program to read all the numbers in a file and find their sum.
10. Write a program to print the longest word in a file. If there is more than one word,
print them all.
11. Write a program to merge the contents of two text files line by line. The remaining
lines of the larger file are ignored.
12. Write a program to manage a book database in binary file "Book.dat" with the
structure [BookNo, Book_Name, Author, Price]. The program should have the
following features:
i. Add a bood to the database.
ii. Count number of books by an author
iii. List all the books
13. Write a program to create and manage a student database using a binary file. The
database consists of student records containing Admission Number, Name, and
Percentage. Create functions to add a new student, list all the students, list
students with more than a given percentage, and search a student by his
admission number.
14. Create an employee database employee.dat to store employee records given as a
list of dictionary objects with keys: empcode, name, and salary. Your program
should perform: (1) add a record at the end of the file and (2) display all employee
records whose salary is more than a given value.
15. Write a program to save a list of dict objects in a json file and read them back in
another list.
16. Write a program to create and manage a student database using a CSV file. The
database consists of student records containing Admission Number, Name, and
Percentage. Create functions to add a new student, list all the students, list

510
students with more that a given percentage, and search a student by admission
number.
17. Create an employee database using a json file to store employee records given as
a list of dictionary objects with keys: empcode, name, and salary. Your program
should be able to perform: (1) add a new record at the end of the file and (2)
display all employee records whose salary is more than a given value.

511
512
Chapter 12

Object Oriented Programming in


Python

Learning Outcomes

1. Understand the concept of OOPs


2. Define class in Python.
3. Understand encapsulation.
4. Understand various types of inheritances.
5. Understand polymorphism.
6. Write programs using OOP concepts.

Software development is a dynamic and complex process as it has to meet the dynamic
needs of users to solve real-life complex problems. Further, as the size of a program
increases, it becomes difficult to debug, maintain and reuse it economically and effectively
using the traditional procedural programming strategies. These are the basic motivation
behind the development of the object-oriented programming (OOP) strategy, which aims
to implement real-world complex problem-solving strategies like inheritance, hiding,
polymorphism, etc. in computer programming. The main aim of OOP is to use
encapsulation, inheritance, and polymorphism to bind together the data and the functions
to avoid inadvertent modification of data and to promote the scalability and reusability of
the existing code. It was rightly said by Alan Kay, one of the promoters of OOP, that as the
complexity and size of a program increase, the architecture dominates the logic of the
program. OOP is a code management system that reduces the inadvertent modification of
variables and promotes the reusability of codes.

Python supports object oriented programming concepts from its inception in an easy-
to-implement manner. For easy comprehension, we will briefly introduce the basic concepts
of OOP before using it in Python.

513
12.1 Basic Concepts of Object Oriented Programming
The object oriented programming concepts revolves around the following concepts:
objects, classes, encapsulation, inheritance, polymorphism, dynamic binding, and message
passing.

12.1.1 Objects and Classes

If we look around, we will find that any ecosystem consists of a variety of objects.
These self-contained objects maintain their internal states and interact with each other
through well-defined interfaces for the proper functioning of the ecosystem as a whole.
Consider a banking system, it consists of customers, managers, cashiers, clerks, databases,
etc. Every entity in this ecosystem has well-defined roles and limited access to the resources
of the ecosystem. For example, a customer can view his records but cannot modify them,
whereas a manager can view records and can modify them also. In OOPs, we divide
complex software task into small self-contained subcomponents called classes and develop
well-defined interfaces through which these classes interact with each other to perform the
intended tasks.

A class is a blueprint or prototype of a subcomponent that defines the variables


(features and characteristics) and the methods to perform their role in the overall system.
For example, the customer, the employee, etc. When we create an instance of a class by
providing specific data to its variables, it is called an object. For example, John is a customer
of the bank. Here, John is an object of the class customer.

A class is a data structure to map a real-life object along with methods to manipulate
its data and interact with other objects. A class is called abstract data as it only uses the
essential features of a real-life object which is necessary for the proper function of the
software. Figure 12.1 shows a schematic representation of a class. It is important to note that
a class is just a blueprint but objects are actual data in the memory. For each instance, a
separate memory for the data is used, whereas the same copy of the methods is used for all
the instances.

514
Class: Customer Object: Customer

Variables: Data:
Name Name: John
Account_Number Account_Number: 123456
Account_Type Account_Type: Saving
Balance Balance: 10000
Methods: Methods:
Show_details () Show_details ()
Deposit () Deposit ()
Withdraw() Withdraw ()

Class Structure An instance

Figure 12.1: Schematic diagrams of a class and an object

12.1.2 Data Encapsulation

Data encapsulation, also called data hiding, is one of the most striking features of
OOP, which wraps the data and methods of a class as a single unit. It means, private data
of a class can only be directly accessed by the methods of its class. Any method outside the
class cannot modify the private data directly. This removes the chance of inadvertent
modification of the data of a class as this will be easily caught by the compiler/interpreter.
However, for the convenience of programming, sometimes, we make some variables public,
which can be directly accessed by codes outside the class, but it is not recommended.

12.1.3 Inheritance

Inheritance is the process of creating another class by using other existing classes.
The existing classes are called base classes (or parent class or super class) and the new class
is called a child class (or derived class or subclass). By inheritance, a child class acquires the
data and methods of the base classes. Additional variables and methods can be added to a
child class to increase its functionality. Inheritance is the primary mechanism of OOP to
promote the reusability of existing codes. Through inheritance, we create more specific
objects from generic objects. For example, let us consider a generic class employee which
defines the basic features such as name, age, address, phone number, etc. We can use this
class to create two derived classes: programmer and manager. When we extend the

515
employee class to define the programmer class, we only need to add variables and methods
that are specific to the programmer class, such as programming languages. Similarly, when
we create the manager class from the employee class, we need to add specific variables and
methods to the new class such a team size, etc. The generic features such as name, age, etc.
will be inherited from the base class. This way, we can reuse the codes of the base class to
manipulate the generic features of the derived classes. Figure 12.2 shows the above
concepts.

Based on the number of base classes, child classes, and level of derivation, the types
of inheritance can be: single, multiple, hierarchical, multilevel, and hybrid. The types are
shown in figure 12.3.

Single Inheritance: In single inheritance, there is one parent class and one child class
(Figure 12.3(a)).

Multiple Inheritance: In multiple inheritance, there is more than one parent class for a
derived class. In this, the features of all the parent classes are inherited into the child class
(Figure 12.3(b)).

Hierarchical Inheritance: In hierarchical inheritance, we use one parent to inherit more


than one child, i.e. we can have more than one child of a parent class (Figure 12.3(c)).

Multilevel Inheritance: In multilevel inheritance, we inherit a child from a parent class (call
grandparent) and the child class is further used as a parent for another child class. The
features of the grandparent class are inherited to the parent class and then all the features
of the parent class are inherited to the child class (Figure 12.3(d)).

Hybrid Inheritance: In hybrid inheritance, more than one inheritance type of the above is
used to create a new class (Figure 12.3(e)).

516
Class: Employee

Variables:
Name
Address
Methods:
Set_name ()
Set_address()

Base Class

Class: Programmer Class: Customer

Variables: Variables:
Languages Team_size
Methods: Methods:
Set_languages () Set_team_size ()

Child class Child class

Figure 12.2: Inheritance

517
A A
A A B A
B
B C
B C B C D C
D

(a) Single (b) Multiple (c)Hierarchical (d)Multi-level (e)Hybrid


Inheritance Inheritance Inheritance Inheritance Inheritance

Figure 12.3: Different types of inheritance

12.1.4 Polymorphism

Polymorphism in OOP means using a function name or an operator to perform


different tasks depending on the context. For example, using the + operator to perform the
addition of two numbers and to perform the concatenation of two strings. This is called
operator overloading. The selection of operations is based on the types of operands.
Similarly, we can use the same function name to perform different tasks based on the types
and number of arguments. This is called function overloading. Further, a base class and its
derived class can have methods with the same name. This is called method overriding. The
polymorphism makes our code more natural and elegant. Polymorphism is widely used in
inheritance to achieve more specific behavior in derived classes. Figure 12.4 illustrates the
concepts of polymorphism.

518
Shape

Draw ()

Circle Box Triangle

Draw () Draw () Draw ()

Figure 12.4: Polymorphism - Function overloading

12.1.5 Dynamic Binding

Dynamic binding, also known as late binding, refers to the linking of a procedure at
the run time. In this, it is not known which functions with the same name will be called
before run-time. Method Overriding is an example of dynamic binding as in this case which
method to call is decided only after determining the underline object. In figure 12.4, the
Draw () method is defined in the base class as well as in all the derived classes. The derived
class Draw () method overrides the base class and implements different algorithms to draw
different shapes.

12.1.6 Message Passing

As we already stated, in OOP, the variables of a class are not directly accessible to
other classes or methods outside the class. To manipulate the variables of objects, objects
communicate with one another by sending and receiving messages to each other. A message
passed to an object is a request to execute one of its procedures to generate the desired
results. Message passing involves specifying the name of the object, the name of the
function, and the information to be sent.

519
12.2 Define a Class in Python
Python is an object oriented programming language and provides easy to use
mechanism to implements OOP concepts. In Python, every built-in data type, such as int,
str, bool, float, list, set, tuple, dict, etc. are built-in classes.

We can create a new class by using the keyword class. A class definition requires
the following three elements:

1. Class_name: Every class has a unique name, which is used to identify it and create
its instances (objects).
2. Attributes: It is a set of variables (data) used to maintain the states and properties of
its objects. Attributes can be defined at the class level or the object level.
• In the class level attribute, only one copy of a class attribute is created which
is shared among all the instances of the class. Any instance can access and
modify a class attribute.
• In the object level attribute, a separate memory is allocated to an object
attribute for each object. Changes made in an object attribute of an object do
not affect the same attribute of the other objects.
3. Methods: It is a set of functions used to control the behavior and response
(manipulation of its data) of its objects.

Following is the syntax of class definition:

class Class_name:
attributes=values
Methods (self, [Parameters])

Except for the Class_name, all other components of a class are optional. For example,
the class definition is shown in example 12.2(a) is syntactically valid and we can create
objects from it, but the objects have no functionality.

Example 12.2(a): Creating an empty class

class empty_class: #Class header


pass #Class body

object1= empty_class() #Creating and instance

520
An empty class is of no use. We can add some functionality to a class by adding
attributes and methods to it. Attributes are variables to hold the data of objects created from
the class. Methods are functions to manipulate attributes and interact with other objects. In
a method definition, the first parameter of the method is always a reference to the class
itself. Generally, the variable name self is used for this, however, any other variable name
can be used. During calls, this first parameter is omitted. It will be automatically given by
the Python interpreter. Example 12.2(b) creates a class with some attributes and methods.

Example 12.2(b): Creating a class

#Class definition
class Rect: #Creating a class
length=0 #Creating an attribute
width=0

def set_dimension(self, length, width): #Defining a method


Rect.length=length #Assigning a value to an attribute
Rect.width=width

def area(self):
return self.length*self.width #Accessing attributes

#Main program
r1=Rect() #Creating an instance object of a class

#Please note, we have to omit the first parameter of the method.


r1.set_dimension(10,20) #Calling a method of a class
print("Area r1:",r1.area())

r2=Rect() #Creating another instance


r2.set_dimension(10,10)
print("Area r2:",r2.area())
#Note the ID of attributes
print("ID of Rect.length:",id(Rect.length))
print("ID of r1.length:",id(r1.length))
print("ID of r2.length:",id(r2.length))

Output
Area r1: 200
Area r2: 100
ID of Rect.length: 1621718231632
ID of r1.length: 1621718231632
ID of r2.length: 1621718231632
521
In the previous example above, the attributes are created at the class level, called
class attributes. Kindly note the IDs of the attributes. They are the same. Each object created
from this class will share the same memory for these attributes. Hence, we can have data of
the last object created from it and the previous data will be overwritten by the new object
data. However, we can create object attributes (also called instance attributes) by creating
attributes inside a method. Each object has separate memory for its object attributes. In a
class, we can have class-level attributes as well as object-level attributes.

Example 12.2(c) creates a class with both types of attributes. Note the IDs of various
attributes in the output. For the same object attribute, the IDs for different objects will be
different. However, for the same class attribute, the IDs will be the same for all the objects.

Example 12.2(c): Creating a class with class attributes and object attributes

class Rect:
count=0 #Creating a class attribute
def set_length(self, length):
self.length=length #Creating an object attribute
def set_width(self,width):
self.width=width #Creating an object attribute
def area(self):
Rect.count+=1 #Accessing a class attribute
return self.length*self.width

r1=Rect()
r1.set_length(10)
r1.set_width(20)
print("Area r1:",r1.area())

r2=Rect()
r2.set_length(100)
r2.set_width(200)
print("Area r2:",r2.area())

print("Object attribute IDs: r1.length:", id(r1.length),"not equal to


r2.length", id(r2.length))
print("Object attribute IDs:r1.width", id(r1.width),"not equal to
r2.width", id(r2.width))
print("Class attribute IDs: r1.count",id(r1.count),"equal to r2.count",
id(r2.count))

print("r1.length:", r1.length,", r2.length", r2.length)

522
print("r1.width:", r1.width,", r2.width:", r2.width)
print("r1.count:",r1.count,", r1.count", r2.count, ", Rect.count:",
Rect.count)
Output
Area r1: 200
Area r2: 20000
Object attribute IDs: r1.length: 1853819087440 not equal to r2.length
1853819278800
Object attribute IDs:r1.width 1853819087760 not equal to r2.width
1853819282064
Class attribute IDs: r1.count 1853819087184 equal to r2.count
1853819087184
r1.length: 10 , r2.length 100
r1.width: 20 , r2.width: 200
r1.count: 2 , r1.count 2 , Rect.count: 2

Python allows using the same name to create a class attribute and an object attribute
in a class. In this situation, class attributes will be accessed by the syntax:
Class_name.class_attribute, whereas object attributes are accessed using the syntaxes:
self.object_attribute inside the class, where self is a reference of the class.

For access a public object attribute outside a class, we use object.object_attribute.


Here, object is an instance of the class. If there is no object attribute with the same name that
of a class attribute, the class attribute can also be accessed for reading only by using the
syntax self.class_attribute. Please note, if we assign a value to a class attribute in the form
of self.class_attribute= value, inside a method, it will create a new object attribute with the
same name.

To reduce the confusion, it is recommended to avoid the use of the same name for a
class attribute and an instance attribute. Example 12.2(d) illustrates the above concepts.

Example 12.2(d): Creating a class with a class attribute and an object attributes with
the same name

class myClass:
class_attribute=0 #Creating a class attribute
def myMethod(self,p):
self.object_attribute=p #Creating an object attribute
myClass.class_attribute=p*2 #Updating a class attribute

523
#Creating an object attrinute with the same name as a class
attribute
self.class_attribute=p*3 #Be careful
object1=myClass()
object1.myMethod(10)
#Printing an object attribute
print("Object attribute:",object1.object_attribute)
#Printing an object attribute
print("Object attribute:",object1.class_attribute)
#Printing a class attribute
print("The original class attribute", myClass.class_attribute)

Output
Object attribute: 10
Object attribute: 30
The original class attribute 20

12.3 Constructors and Destructor


A constructor is a special method of a class that is automatically called when we
create an instance. The task of a constructor is to initialize the attributes of the class
whenever an instance is created. In Python, the special name __init__ () is reserved and
used to create a constructor. The name consists of two leading underscores (__) and two
trailing underscores (__) attached to the word init. The word init is a short form of the word
initializer. In Python, a method that precedes and succeeds with two underscores, such as
__init__ (), is called a dunder method. Dunder methods are typically used for operator
overloading. Example 12.3(a) creates a class with a constructor.

Example a12.3(a): Class constructors

class Rect:
def __init__(self, a, b): #Defining the constructor
self.length=a #Creating object attributes
self.width=b #Creating object attributes

def area(self): #Normal method


return self.length*self.width

r1=Rect(10,20) #Calling the constructor automatically


print("Area of r1:",r1.area())

r2=Rect(10,10)

524
print("Area of r2:",r2.area())

Output
Area of r1: 200
Area of r2: 100

Constructors are of two types: default and parameterized constructors. The default
constructor is a constructor which has only one argument. This argument is a reference to
the instance being constructed. The parameterized constructor has more than one
argument. The first argument is again a reference to the instance being constructed and
other arguments are the values for the various attributes of the class. Python does not
support multiple constructors. If we write more than one __init__ () method in a class, the
last method will overwrite all the previous ones. However, we can achieve multiple
constructors by using the variable-length argument facility of Python. Example 12.3(b)
illustrates how to achieve multiple constructors based on the number of arguments. Note
the use of a variable-length argument to process different forms of constructors. Example
12.3(c) shows how to implement multiple constructors based on the type of arguments.

Example a12.3(b): Constructor overloading

class Shape:
def __init__(self,*args): #Defining the constructor
if len(args)==1: #Processing constructor with one argument
self.type=1
self.length=args[0]
elif len(args)==2: #Processing constructor with two arguments
self.type=2
self.length=args[0]
self.width=args[1]
else: #Processing constructor with no argument
self.type=3

def area(self):
if self.type==1:
return " square:" + str(self.length*self.length)
elif self.type==2:
return " rectangle:"+ str(self.length * self.width)
else:
return "Invalid shape"

s1=Shape(10,20) #Calling the constructor with two arguments


print("Area of the",s1.area())

525
s2=Shape(10) #Calling the constructor with one argument
print("Area of the",s2.area())
s3=Shape() #Calling the constructor with no argument
print(s3.area())

Output
Area of the rectangle:200
Area of the square:100
Invalid shape

Example 12.3(c): Constructor overloading

class myAdd:
# constructor overloading based on argument types
def __init__(self, arg1,arg2):

if isinstance(arg1, int) and isinstance(arg2, int):


self.ans = arg1+arg2
elif isinstance(arg1, str) and isinstance(arg2, int):
self.ans=arg1+str(arg2)
elif isinstance(arg1, int) and isinstance(arg2, str):
self.ans=str(arg1)+arg2
else:
self.ans=None
def show(self):
return self.ans
x=myAdd(10,20) #Both the arguments are integers
print(x.show())
#The first argument is an integer and the second a string
y=myAdd(10,"ABC")
print(y.show())
#The first argument is a string and the second an integer
z=myAdd("ABC", 30)
print(z.show())

Output
30
10ABC
ABC30

Destructor: When a variable (object) goes out of scope in a program or we explicitly


delete an object with the del command (syntax: del object_name), Python automatically

526
destroys the object and releases the memory. This is called automatic garbage collection.
However, before destroying an object, Python calls a special function of the object, known
as the destructor. The __del__ () is reserved to name the destructor method of a class. Similar
to the constructor, the destructor is inherited to all the created classes from the object class.
Normally, no action is required from us to destroy an object, but if we want to perform some
operations before Python kills an object, we should write that code inside the destructor
method. Following is the syntax of the destructor of a class:

class class_name:
Attributes
Methods (…)

def __del__(self):
Statements

Example 12.3(d) uses the destructor of a class to print a message. Python does not
call the destructor till the last alias of an object is deleted or goes out of scope. Example
12.3(e) illustrates this, where three aliases of an object are created. The destructor is called
when we delete the last alias.

Example 12.3(d): Destructor

class myClass:
count=0
def __init__(self): #Defining the constructor
myClass.count+=1
self.instance_number=myClass.count
print('Creating the instance number:',self.instance_number )

def __del__(self): #Defining the destructor


print('Destroying the instance number:', self.instance_number )

def myFun():
#This instance will be deleted once we return from the function
obj1 = myClass()
obj2=myClass()
myFun()
del obj2 #Explicitly deleting an instance
Output
Creating the instance number: 1
Creating the instance number: 2
Destroying the instance number: 2

527
Destroying the instance number: 1

Example 12.3(e): Destructor in aliases

class myClass:
def __init__(self): #Defining the constructor
print('An instance created')

def __del__(self): #Defining the destructor


print('Destroying the instance')

obj=myClass() #Creating an instance


obj1=obj #Creating an alias
obj2=obj #Creating an alias

del obj #Deleting an alias


del obj1 #Deleting an alias
del obj2 #Deleting the last alias. Now the destructor is called

Output
An instance created
Destroying the instance

12.4 Encapsulation in Python


One of the basic pillars of OOP is the encapsulation of members of a class to avoid
unauthorized access to its members. Members of a class can be classified into three
categories, based on the restriction of their access: public, protected, and private members.

Public member: A public member of a class is like a global variable and is accessible in any
part of the program, i.e. there is no restriction on its the access either inside or outside the
class. In Python, by default, all data members and member functions are public. The public
members can be accessed by using the dot notation, such as class_object.public_member, in
any part of the program.

Protected member: A protected member of a class is accessible to the other members of the
class as well as members of derived classes from the class. Protected members are primarily
used to enable specific resources of the parent class to be inherited by the child class. Be
528
careful about a protected member, as the dot notation can be used to access the member
even outside the class.

Private member: A private member of a class is accessible within the class only. No other
part of the program can access a private member, including the members of derived classes.
A private member is the most secure member of a class and is completely encapsulated
inside the class. We cannot use the dot notation to access a private member outside the class.
Any attempt to do so will raise an error.

In Python, public, protected, and private members are declared by following a


specific naming convention of members. A private member’s name is preceded by two
underscores, such as __abc. A protected member’s name is preceded by a single underscore,
such as _abc and a public member’s name does not precede any underscore, such as abc.

Underscores in Python: Python uses underscores in variable and function names in a


variety of ways and it changes the accessibility of members of a class. Table 12.1 briefly
describes various usages of underscores. So be careful about the names of the members of
a class. Typically, in OOP, data members are private and methods are public. It is
completely valid to make a method private and a data member public. The data members
of a class which we want to pass on to its derived classes are made protected. It is important
to note that once declared private, it cannot be used outside the class, except by using the
name mangling.

Table 12.1: Usages of underscore patterns in identifier names

Underscore pattern Description

Single leading underscore A single leading underscore before a member of a class


makes the member (both attributes and methods)
Example: _var protected and controls its behavior during inheritance.

If we import a module using the wildcard syntax: from


module_name import *, the functions with a leading
underscore will not be imported. However, for the normal
import syntax: import module_name, the single leading
underscore does not affect the importing behavior. All the
functions will be available.

529
Single trailing underscore A single trailing underscore is primarily used to use
keywords as variable names, when it seems this variable
Example: var_ name is the most suitable. For example, class_, int_ list_,
etc. This is just a convention and Python enterpriser does
not give any special meaning to the training single
underscore.

Double leading underscore A double underscore before a member of a class makes the
member private. This means the member cannot be
Example: __var accessed outside the class, using the simple dot notation.
Further, a double underscore forces the Python interpreter
to rewrite the member name using the name mangling.

Double leading and trailing A double leading and trailing underscores in an attribute
underscore or method name indicate that it is a special method or
attribute defined by the Python language. These naming
Example: __var__ patterns should be avoided by programmers. Attributes
and methods with these naming patterns are accessible
outside the class, i.e. they are not private to the class.

Single underscore In Python, frequently we use a single underscore to create


a temporary or insignificant variable. It is typically used to
Example: _ unpack the return values from a function, where only a
few returned values are significant and the rest are
insignificant in the current context. The insignificant
returned values are collected in single underscore
variables to avoid unpacking errors. In the following
example, the myFun function returns four values, but only
the first two values are useful in the current context and
the other two are collected in underscore variables.

>>> def myFun(a,b):


return a+b, a*b, a-b, a/b

>>> x,y,_,_=myFun(10,20)
>>> print(x,y)
30 200

530
Example 12.4 illustrates private, protected, and public members of a class. We will
further illustrate protected members after discussing derived classes later in the chapter.

Example 12.4: Private, protected, and public members

class Student:

def __init__(self, name,age,grade): #Constructor

self.name=name #Creating a public member


self._age=age #Creating a protected member
self.__grade=grade #Creating a private member

def show(self):
print("Student name:", self.name) #Accessing a public member
print("Student age:",self._age) #Accessing a protected member
print("Student grade:" ,self.__grade) #Accessing a private
member
return None

s1=Student("John",18,8.5)
s1.show()
print("Student name:",s1.name) #Accessing a public member
print("Student age:",s1._age) #Accessing a protected member
print("Student grade:", s1.__grade) #Error: Accessing a private member

Output
Student name: John
Student age: 18
Student grade: 8.5
Student name: John
Student age: 18
Traceback (most recent call last):
File "D:\akv\akv\Python_book\Chapter 12\test1.py", line 19, in <module>
print("Student grade:", s1.__grade) #Error: Accessing a private member
AttributeError: 'Student' object has no attribute '__grade'

12.5 Instance Methods


Instance methods are functions that are defined inside a class. They can only be
called from an instance (public and protected methods) of that class or the self-reference
inside the class. The first parameter of an instance method is always a reference of the class
531
itself, frequently self is used as its name. However, any other variable name is equally valid.
An instance method can have additional parameters or can have variable length
parameters. We can define a local method inside an instance method, but it is visible in the
instance method where it is defined.

During calls, we do not require to provide the first parameter. It is automatically


provided by the interpreter. Example 12.5 illustrates instance methods.

Example 12.5: Instance methods

class myClass:
def instance_method1(self): #Defining a public instance method
print("Hello, I am a public instance method with no parameter")

def instance_method2(me,par1): #Defining a public instance method


print("Hello, I am a public instance method with a parameter")
print("Value of the parameter:",par1)
me.instance_method1()
me.__Private_instance_method(par1*2)

def __Private_instance_method(self, par1):


print("Hello, I am a private instance method")
print("Value of the parameter:", par1)
#A local method, not visible outside this instance method
def local_method():
print("Hello, I am a local method")
local_method()

A=myClass() #Creating an instance


A.instance_method1() #Calling a public instance method
#Calling a public instance method with a parameter
A.instance_method2(10)

Output
Hello, I am a public instance method with no parameter
Hello, I am a public instance method with a parameter
Value of the parameter: 10
Hello, I am a public instance method with no parameter
Hello, I am a private instance method
Value of the parameter: 20
Hello, I am a local method

532
12.6 Name Mangling
The name mangling is a mechanism used by Python to rename a member of a class
with a double underscore prefix to avoid naming conflicts in inherited classes. In this, an
identifier name with two leading underscores is renamed as _classname__identifier, where
classname is the name of the class where the identifier is defined. For example, an attribute
name __abc in a class xyz will be renamed as _xyz__abc.

As we discussed earlier, private members of a class are not accessible outside the
class. However, since Python renames all the private members using the name mangling,
we can use the new name of a private member to access it outside the class. In this, we use
the syntax object._classname__private_member to access a private member. Here, an
object is an instance of the class, classname is the name of the class and __private_member
is a private member of the class. We use an underscore before the name of the class and
then attach the private member with it to create its name mangling. Example 12.6 illustrates
the name mangling to access a private member. However, this is against the basic tenets of
OOP and is strongly discouraged.

Example 12.6: Calling private members outside the class

class myClass:
__Private_data=10 #Creating a private data
Public_data=20 #Creating a public data

def __Private_method(self): #Defining a private method


print("Hello, I am a private method")
def Public_method(self): #Defining a public method
print("Hello, I am a public method")
A=myClass() #Creating an instance
print("Public data", A.Public_data) #Using a public data
A.Public_method() #Calling a public method

#Using name mangling to access private members outside the class


print("Private data", A._myClass__Private_data)#Using a private data
A._myClass__Private_method() #Calling a private method
Output
Public data 20
Hello, I am a public method
Private data 10
Hello, I am a private method

533
12.7 Display Class Attributes and Instance Methods
We can list all the attributes and methods of a class by using the dir () built-in
function. The dir () method accepts either the name of the class or an instance of the class.
Example 12.7(a) uses the dir () method to list all the attributes and methods of a class. Notice
the first entry in the output, which is the new name of the private attribute __count,
generated by the name mangling. As can also be seen from the output, the dir () method
does not list instance attributes. It only lists class attributes and instance methods.

We can also list symbol tables of a class and its instances by using a special attribute
__dict__ of the class or an instance, respectively. It uses the syntaxes: class_name.__dict__
(to list the class attributes and instance methods) or object.__dict__ (to list the object
attributes). Example 12.7(b) illustrates the above.

Example 12.7(a): Listing attributes and methods of a class

class Rect:
__count=0 #Creating a private class attribute
def set_length(self, length):
self.length=length #Creating an object attribute
def set_width(self,width):
self.width=width #Creating an object attribute
def area(self):
Rect.count+=1 #Accesssing a class attribute
return self.length*self.width
print(dir(Rect)) #List class attributes and methods using class
r1=Rect()
print("\n")
print(dir(r1)) #List class attributes and methods using instance

Output
['_Rect__count', '__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__', 'area', 'set_length', 'set_width']

534
['_Rect__count', '__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__', 'area', 'set_length', 'set_width']

Example 12.7(b): Symbol tables of a class and its instance

class Rect:
count=0 #Creating a class attribute
def set_length(self, length):
self.length=length #Creating an object attribute
def set_width(self,width):
self.width=width #Creating an object attribute
def area(self):
Rect.count+=1 #Accesssing a class attribute
return self.length*self.width

print("Class symbol table:")


print(Rect.__dict__) #List the class symbol table
r1=Rect()

print("\nInstance symbol table:")


r1.set_length(10)
r1.set_width(20)
print(r1.__dict__)

Output
Class symbol table:
{'__module__': '__main__', 'count': 0, 'set_length': <function Rect.set_length at
0x0000021477F58550>, 'set_width': <function Rect.set_width at 0x0000021477F585E0>,
'area': <function Rect.area at 0x0000021477F58670>, '__dict__': <attribute '__dict__' of
'Rect' objects>, '__weakref__': <attribute '__weakref__' of 'Rect' objects>, '__doc__':
None}

Instance symbol table:


{'length': 10, 'width': 20}

535
12.8 Inheritance in Python
As discussed earlier in this chapter, inheritance is the primary mechanism to reuse
a class and extend or override its functionalities. Following is the syntax of inheritance in
Python:
class child_class(parent_class1, parent_class2,…, parent_classN):
child_attributes
child_methods
As can be seen from the syntax, many parent classes can be used to create a child class.
Parent classes are given in parenthesis.

Example 12.8(a) shows a simple example of inheritance, where a child class is


derived from a parent class. In the child class, one more method is added. It can be seen
from the example that the child class has two functions, one from the parent class and one
defined in itself.

Example 12.8(a): Inheritance

class Parent():#Parent Class


def parentMethod(self): #Parent method
print('Hello, I am in the parent class')

class Child(Parent): #Creating a child class inherited from a parent


class
def childMethod(self): #Child method
print('Hello, I am in the child class')

ob = Child() #Creating a child object


ob.parentMethod() #Calling an inherited method
ob.childMethod() #Calling a method

Output
Hello, I am in the parent class
Hello, I am in the child class

Example 12.8(b) shows the behavior of public, protected and private attributes in a
derived class. It can be seen from the output that public and protected attributes of the
parent class are inherited in the derived class but private attributes of the parent class are
not inherited.

536
Example 12.8(b): Behavior of various types of attributes in inheritance

class Parent():#Parent Class


publicClassVar=10 #Public class attribute
_protectedClassVar=20 #Protected class attribute
__privateClassVar=30 #Private lass attributes
def parentMethod(self): #Parent method
self.objectVar=40 #Public object attribute
self._objectVar=50 #Protected object attribute
self.__objectVar=60 #Private object attribute
print('Hello, I am in the parent class')

class Child(Parent): #Creating a child class inherited from a parent


class
def childMethod(self): #Child method
print('Hello, I am in the child class')

ob = Child() #Creating a child object


ob.parentMethod() #Calling an inherited method
ob.childMethod() #Calling a method
print(ob.publicClassVar)
print(ob._protectedClassVar)
print(ob.objectVar)
print(ob._objectVar)
print(ob.__privateClassVar) #Error: private class attributes are not
inherited
print(ob.__objectVar) #Error: private object attributes are not
inherited

Output
Hello, I am in the parent class
Hello, I am in the child class
10
20
40
50
Traceback (most recent call last):
File "D:/akv/akv/Python_book/Chapter 12/test3.py", line 22, in <module>
print(ob.__privateClassVar)
AttributeError: 'Child' object has no attribute '__privateClassVar'

The method/attribute overriding: If we redefine a method in a derived class that has the
same name as that of a base class method, the derived class method will override the

537
inherited base class method. The same is true for an attribute. Example 12.8(c) illustrates
the above.

Example 12.8(c): Overriding in inheritance

class Parent():#Parent Class


var1=10
def parentMethod(self): #Parent method
print('Hello, I am in the parent class')
def fun(self):
print("I am defined in the parent class")

class Child(Parent): #Creating a child class inherited from a parent


class
var1=20 #Overrides the base class attribute
def childMethod(self): #Child method
print('Hello, I am in the child class')
def fun(self): #Overrides the base class method
print("I am defined in the child class")

ob = Child() #Creating a child object


ob.parentMethod() #Calling an inherited method
ob.childMethod() #Calling a method
ob.fun()
print(ob.var1)
Output
Hello, I am in the parent class
Hello, I am in the child class
I am defined in the child class
20

The super () method: The overridden methods and attributes of the parent class can be
accessed in the derived class by using the super () built-in method. For this we use the
syntaxes super().method_name() and super().attribute_name. The non-overridden
inherited members of the parent class can be used using the simple dot notation, such as
self.parent_member, where self is a reference to the current class. See example 12.8(d).

Example 12.8(d): Using parent class methods and attributes in a derived class

538
class Parent():#Parent Class
var1=10
var2=20
def parentMethod(self): #Parent method
print('Hello, I am in the parent class')
def fun(self):
print("I am defined in the parent class")

class Child(Parent): #Creating a child class inherited from a parent


class
var1=30
def childMethod(self): #Child method
print('Hello, I am in the child class')
def fun(self): #Overriding an inherited method
print("I am defined in the child class")
super().fun() #Calling a base class method
self.parentMethod() #Calling a base class method
#Accessing a base class attribute
print("Using the base class attributes:" ,super().var1)
print("Using a local attribute:",self.var2)

ob = Child() #Creating a child object


ob.parentMethod() #Calling an inherited method
ob.childMethod() #Calling a method
ob.fun() #Calling an overridden method
print(ob.var1) #Using an overridden attribute
print(ob.var2) #Using a derived attribute

Output
Hello, I am in the parent class
Hello, I am in the child class
I am defined in the child class
I am defined in the parent class
Hello, I am in the parent class
Using the base class attributes: 10
Using a local attribute: 20
30
20

539
12.9 Types of Inheritance in Python
Python supports all the five types of inheritance which are discussed in section
12.1.3. In this section, we will illustrate each type of inheritance with examples.

In the single inheritance, there is only one parent class and one derived child class.
Example 12.9(a) illustrates the single inheritance.

Example 12.9(a): Single inheritance

class Parent: #Defining a parent class


var1=10
def func1(self):
self.var2=20
print("This function is defined in the parent class")
class Child(Parent): #Defining a child class
def func2(self):
print("This function is defined in the child class")
ob = Child()#Creating a child object
ob.func1() #Calling a function inherited from the parent class
ob.func2() #Calling a function defined in the chid class
print(ob.var1) #An attribute defined in the parent class
print(ob.var2) #An attribute defined in the child class

Output
This function is defined in the parent class
This function is defined in the child class
10
20

In the multiple inheritance, there is more than one parent class and one derived child
class. Example 12.9(b) illustrates the multiple inheritance. If the two or more parents have
the member with the same name, the member in the first parent will be inherited to the
child class, others will be ignored.

Example 12.9(b): Multiple inheritance

class Parent1: #Defining a parent class


var1=10
def func1(self):
print("This function is defined in Parent1")

540
class Parent2: #Defining another parent class
var2=20
def func2(self):
print("This function is defined in Parent2")

class Child(Parent2,Parent1): #Defining a child class


def func3(self):
print("This function is defined in Child")
ob = Child()#Creating a child object
ob.func1() #Calling a function inherited from Parent1
ob.func2() #Calling a function inherited from Parent2
ob.func3() #Calling a function defined in the chid class
print(ob.var1) #An attribute defined in Parent1
print(ob.var2) #An attribute defined in Parent2
Output
This function is defined in Parent1
This function is defined in Parent2
This function is defined in Child
10
20

In multi-level inheritance, a child class is derived from another derived class. This is
similar to a grandparent–parent-child relationship. Example 12.9(c) illustrates the multi-
level inheritance.

Example 12.9(c): Multi-level inheritance

class Grandparent: #Defining a class


var1=10
def func1(self):
print("Level 0: This function is defined in Grandparent")
class Parent(Grandparent): #Defining an inherited class
var2=20
def func2(self):
print("Level 1: This function is defined in Parent")

class Child(Parent): #Defining a multi-level inherited class


def func3(self):
print("Level 2: This function is defined in Child")
ob = Child()#Creating a Child object
ob.func1() #Calling a function inherited from Grandparent
ob.func2() #Calling a function inherited from Parent
ob.func3() #Calling a function defined in Child
print(ob.var1) #An attribute defined in Grandparent
541
print(ob.var2) #An attribute defined in Parent

Output
Level 0: This function is defined in Grandparent
Level 1: This function is defined in Parent
Level 2: This function is defined in Child
10
20

In the hierarchical inheritance, more than one child class is derived from a parent
class. Example 12.9(d) illustrates the hierarchical inheritance.

Example 12.9(d): Hierarchical inheritance

class Parent():#Defining a base class


def func1(self):
print("This function is defined in Parent")

class Child1(Parent): #Defining a child class


def func2(self):
print("This function is defined in Child1")

class Child2(Parent): #Defining a child class


def func2(self):
print("This function is defined in Child2")
ob1 = Child1()#Creating an object
ob2 = Child2()#Creating an object
ob1.func1() #Calling a function inherited from the parent class
ob2.func1() #Calling a function inherited from the parent class
ob1.func2() #Calling a function defined in a child class
ob2.func2() #Calling a function defined in a child class
Output
This function is defined in Parent
This function is defined in Parent
This function is defined in Child1
This function is defined in Child2

In hybrid inheritance, different types of inheritance are used in a single derived


class. Example 12.9(e) illustrates the hybrid inheritance.

542
Example 12.9(e): Hybrid inheritance

class Parent: #Defining a class


def func1(self):
print("This function is defined in Parent")

class Child(Parent): #Defining a single inheritance class


def func2(self):
print("This function is defined in Child")

class Child1(Parent): #Defining an inheritance class


def func3(self):
print("This function is defined in Child1")

class Hybrid(Child , Child1): #Defining a hybrid class


def func4(self):
print("This function is defined in Hybrid")

ob = Hybrid() #Creating an object of a hybrid class


ob.func1() #Calling an inherited method
ob.func2() #Calling an inherited method
ob.func3() #Calling an inherited method
ob.func4() #Calling a method

Output
This function is defined in Parent
This function is defined in Child
This function is defined in Child1
This function is defined in Hybrid

12.10 The object Class


In Python, every data is an object derived from a class and every class in Python,
both built-in and user-defined, is derived from the object class. In other words, we can say
that every object in Python is an instance of the object class. Hence, a statement isinstance
(data, object) will always return True, where data is an instance of any class. Example
12.10(a) illustrates this. The object class defines the most common methods, such as
constructor, destructor, comparison methods, etc., which are inherited to all the class
automatically. Mostly, these methods are overridden in the derived classes. Example
12.10(b) lists all the methods and attributes defined in the object class. Technically, the
following two definitions (Table 12.2) of a class are the same. By default, the Python
interpreter adds object class as a base to all the created classes.

543
Table 12.2: Class definitions

Class definition 1 Class definition 2


class A: class A(object):
pass pass

Example 12.10(a): object class

>>> isinstance(10,object) #Integer is an instance of object class


True
>>> isinstance("ABC",object) #String is an instance of object class
True
>>> isinstance(list,object) #list is an instance of object class
True
>>> isinstance(float,object) #float is an instance of object class
True
>>> class A: #A user defined class
pass

>>> isinstance(A,object) #A user defined class is an instance of object


class
True

Example 12.10(b): Methods and attributes of the object class

>>> dir(obj)
['__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__', 'process']

12.11 Method Resolution Order in Python


In multiple inheritance, frequently, there may be many methods/attributes with the
same name in itself and various super classes of a derived class. The method resolution
order (MRO) is the sequence of classes in which Python looks for a method/attribute in a

544
hierarchy of classes. Following are the rules, to be used in the given sequence, to create
MRO:
a. A method/attribute is first searched in the current class. This means a
method/attribute in the current class overrides all the inherited methods/attributes
with the same name. The mro () method or __mro__ attribute can be used to obtain
the MRO of a derived class. Example 12.11(a) illustrates the above.
b. In the case of multiple inheritance, if a method/attribute is not found in the current
class, it is searched in the tuple of parent classes in depth-first, left-right fashion,
without searching the same class twice. It means the left-most parent and all its
super classes are searched first. If still not found, the second parent and all its super
classes are searched next, and so on. Example 12.11(b) illustrates this. Here, class C
has two base classes (A, B) and both have defined a function with the same name.
But class C inherits the function from class A, as it is the first class in the tuple of
base classes. However, since attribute var is defined only in class B, it is inherited
from class B.
During this process, the good head rule and the inheritance rule must be
followed strictly. The good head rule says that a class must appear before its parents
in MRO, whereas the inheritance rule says that a more specific class should come
before a generic class. If there is a violation of the good head rule, Python removes
the violating class from MRO. After removal, if the MRO follows the above two
rules, Python uses that to inherit methods and attributes (see example 12.11(c)), else
it raises the inconsistent MRO error (see Example 12.11(d)).
Example 12.11(c) shows a valid MRO after applying the good head rule and
the inheritance rule. The MRO of D without the good head and inheritance rules is
D->B->A->C->A->object. But after applying the good head rule, the MRO is
D->B->C->A->object. The first A is removed as it violates the good head rule. The
new MRO also fulfills the inheritance rule; hence it is consistent.
Example 12.11(d) shows an example of inheritance that violates the
inheritance rule. In this example, the MRO derived after applying the good head
rule is C->B->A->object, but A is also a direct super class of C. So if a method is in
both A and B classes then which version should class C call? According to the new
MRO, the version in B is called first ahead of A and that is not according to
inheritance rules (specific to generic) resulting in Python to throw the inconsistent
MRO error.
The most generic class in Python is the object class, from which every Python
class is derived. Hence, it will always be the last class in MRO. If a method/attribute
is not found in the complete search path, the undefined method/attribute error will
be raised.

545
Example 12.11(a): The MRO of a class

class A: #Defining a class


var=10 #Defining an attribute
def myFun(self): #Defining a method
print('myFun is defined in class A')

class B(A): #Defining an inherited class


def myFun(self): #Overriding the inherited method
print('myFun is defined in class B')

obj = B() #Create an instance


obj.myFun() #Calling a method
print(obj.var) #Printing an attribute
print(B.mro()) #printing MRO for class B
Output
myFun is defined in class B
10
[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

Example 12.11(b): The MRO of a class

class A: #Defining a class


def myFun(self): #Defining a method
print('myFun defined in A')

class B:
var=20 #Defining an attribute
def myFun(self): Defining a method
print('myFun defined in B')

class C(A, B): #Creating a multiple inherited class


pass

obj = C() #Creating an instance


obj.myFun() #Calling a method
print(obj.var) #Printing an attribute
print(C.mro()) #Printing the MRO of C

Output
myFun defined in A
20

546
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,
<class 'object'>]

Example 12.11(c): The MRO of a class after applying the good head rule

#MRO of D without the good head and inheritance rules


#D->B->A->C->A->object
#MRO after the good head and inheritance rules, the first A is removed
# as it violates the good head rule
#D->B->C->A->object
class A: #Defining a class
def myFun(self):
print('myFun defined in A')

class B(A): #Defining a simple inherited class


pass

class C(A): #Defining a simple inherited class


def myFun(self):
print('myFun defined in C')

class D(B, C):#Defining a multiple inherited class


pass

obj = D()
obj.myFun()
print(D.mro())
Output
myFun defined in C
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>,
<class '__main__.A'>, <class 'object'>]

Example 12.11(d): The MRO of a class

#The MRO of C without the good head and the inheritance rules.
#C->A->B->A->object
#The MRO after the good head rule. The first A is removed as it
violates the good head rule.
#C->B->A->object
#The above MRO is inconsistent as it violates the inheritance rule as A
#and B are the direct parents of C and A is also a direct parent of B.
#This type of ambiguous inheritance is not supported in Python.
class A:
547
def myFun(self):
print('myFun defined in A')

class B(A):
def myFun(self):
print('myFun defined in B')

class C(A, B):


pass

obj = C()
obj.myFun()

print(C.mro()) #Error: the computed MRO violates the inheritance rule

Output
Traceback (most recent call last):
File "D:/akv/akv/Python_book/Chapter 12/test3.py", line 16, in
<module>
class C(A, B):
TypeError: Cannot create a consistent method resolution
order (MRO) for bases A, B

12.12 Type and Class Membership Tests


In Python, every variable (object) is strongly typed based on the type of value
assigned to it but the type of a variable is dynamic, i.e. if we assign a different type of values
to a variable, its type will change. The type of object is the class from which the object is
instantiated. We can use the built-in function type (object_name) to know the current type
of an object. The function returns the type of object. The type of an object matters as it
decides the set of operations that can be performed on it.

Python supports multiple and multilevel inheritances. Due to this, an object inherits
behaviors (methods and attributes) from many super classes (parents and grandparents).
We can use the built-in function isinstance (object_name, (class1, class2..., classN)) to test
the class membership of an object to a set of classes. The method returns true if the object is
an instance of any one of the specified tuple of classes or their supper classes. Similarly, we
can test whether a given class is a subclass of any of the specified tuple of classes or their
super classes) by using the built-in method, issubclass (class_name, (class1, class2...,
classN)). Here, the first parameter must be the name of a class. Example 12.12 illustrates
some usages of the above-discussed methods.

548
Example 12.12: Type and Class Membership Tests

class Vehicles:
# Constructor
def __init__(vehicleType):
print('Vehicle is a ', vehicleType)

# Defining a Child class


class Car(Vehicles):
# Constructor
def __init__(self):
Vehicles.__init__('Car')

obj=Car()
print("Type of obj is", type(obj))
print("Is obj an instance of Car:", isinstance(obj, Car))
print("Is obj an instance of Vehicles:", isinstance(obj, Vehicles))
print("Is obj an instance of the object class:", isinstance(obj,
object))
print("Is obj an instance of the list class:", isinstance(obj, list))
print("Is obj an instance of Car or list:", isinstance(obj,(Car,
list)))

print("Is Car a subclass of Vehicles:", issubclass(Car, Vehicles))


print("Is Car a subclass of Car:", issubclass(Car, Car))
print("Is Car a subclass of list:", issubclass(Car, list))
print("Is Car a subclass of Vehicles or list:", issubclass(Car,
(Vehicles, list)))

Output
Vehicle is a Car
Type of obj is <class '__main__.Car'>
Is obj an instance of Car: True
Is obj an instance of Vehicles: True
Is obj an instance of the object class: True
Is obj an instance of the list class: False
Is obj an instance of Car or list: True
Is Car a subclass of Vehicles: True
Is Car a subclass of Car: True
Is Car a subclass of list: False
Is Car a subclass of Vehicles or list: True

549
12.13 Polymorphism in Python
Polymorphism is one of the core concepts of OOP. In this, the same name or the
same symbol is used to execute a different set of codes based on the types of arguments
and/or the number of arguments. The word polymorphism means poly (many) and
morphism (forms), i.e. the same thing that has different functions in different situations.
In Python, polymorphism can be achieved by the following ways:
• method overloading
• method overriding, and
• operator overloading

12.14 Method Overloading


Method overloading means creating more than one method with the same name in
a code block but having different functionalities based on either the number of arguments
or argument types. In a true sense, there is no method overloading in Python, as Python
overwrites the previous method when we create a new method with the same name.
However, we can use the variable-length argument facility of a method to create the method
overloading by writing conditional statements based on the number of arguments (Example
12.14(a)) and the type of arguments (Example 12.14(b)) to execute a different set of codes. It
is possible to use both, the number of arguments and the type of arguments, to overload a
method.

Example 12.14(a): Function overloading based on the number of arguments

class Shape:
#Overloaded method based on the number of arguments
def area(self,*arg):
n=len(arg)
if n <1 and n > 2:
print("Undefined shape")
return
if n==1:
print("Area of the circle is:", 3.14*arg[0]*arg[0])
return
if n==2:
print("Area of the Rectangle is:", arg[0]*arg[1])
return
S1=Shape()
S1.area(1) #Call of an overloaded method
S1.area(1,2) #Call of an overloaded method
Output

550
Area of the circle is: 3.14
Area of the Rectangle is: 2

Example 12.14(b): Function overloading based on argument types

class myClass:
#Overloaded method based on the number of arguments
def add(self,arg1,arg2):
if isinstance(arg1,str) and isinstance(arg2,str):
print("Concatenated string:",arg1+arg2)
elif isinstance(arg1,float) and isinstance(arg2,float):
print("Sum of numbers is:",arg1+arg2)
elif isinstance(arg1,str) and (isinstance(arg2,float) \
or isinstance(arg2, int)):
print("Concatenation of str and float is:",arg1+str(arg2))
elif (isinstance(arg1,int) or isinstance(arg1,float)) \
and isinstance(arg2,str):
print("Concatenation of float and str is:", str(arg1)+arg2)
else:
print("Unrecognised data types")
return

S1=myClass()
S1.add(1.5,3.2) #Call of an overloaded method
S1.add("Abc",2) #Call of an overloaded method
S1.add("Abc","Xyz") #Call of an overloaded method
S1.add(2, "Abc") #Call of an overloaded method

Output
Sum of numbers is: 4.7
Concatenation of str and float is: Abc2
Concatenated string: AbcXyz
Concatenation of float and str is: 2Abc

Methods in a class can also be overloaded by using the multipledispatch module .


Example 12.14(c) illustrates the method overloading of an instance method of a class using
the multipledispatch module.

Example 12.14(c): Function overloading using multiple dispatch

#Importing dispatch from the multipledispatch module


from multipledispatch import dispatch
551
class myClass:
#Overloaded method using multipledispatch
@dispatch(str,str)
def add(self,arg1,arg2):
print("Concatenated string:",arg1+arg2)
@dispatch(float,float)
def add(self,arg1,arg2):
print("Sum of numbers is:",arg1+arg2)
@dispatch(str,float)
def add(self,arg1,arg2):
print("Concatenation of str and float is:",arg1+str(arg2))
@dispatch(str,int)
def add(self,arg1,arg2):
print("Concatenation of str and int is:",arg1+str(arg2))
@dispatch(float,str)
def add(self,arg1,arg2):
print("Concatenation of float and str is:", str(arg1)+arg2)
@dispatch(int,str)
def add(self,arg1,arg2):
print("Concatenation of int and str is:", str(arg1)+arg2)
@dispatch(str)
def add(self,arg1):
print("Reverse of the string is:",arg1[::-1 ])

#Main program
S1=myClass()
S1.add(1.5,3.2) #Call of an overloaded method
S1.add("Abc",2.2) #Call of an overloaded method
S1.add("Abc","Xyz") #Call of an overloaded method
S1.add(2, "Abc") #Call of an overloaded method
S1.add("Python")
Output
Sum of numbers is: 4.7
Concatenation of str and float is: Abc2.2
Concatenated string: AbcXyz
Concatenation of float and str is: 2Abc
Reverse the string: nohtyP

12.15 Operator Overloading


As discussed earlier, an operator is a special symbol that performs one operation on
its operands. When an operator performs different types of operations depending on the
type of its operands, it is called operator overloading. For example, the + operator performs
arithmetic addition when its operands are numbers, but it performs a concatenation

552
operation when its operands are strings. It is a polymorphism in which an operator achieves
customized behavior depending on the type of operands. The feature in Python that allows
the same operator to have a different meaning according to the context is called operator
overloading.

When we try to use an operator with a user-defined class without defining the
operator overloading, we will get an error. Example 12.15(a) illustrates this point, where a
user-defined class vector tries to use the + operator. The error is raised as the + operator
does not know what to do with the Vector operands. However, we can define an overloaded
method to perform the desired operation for vector operands. In Python, operator
overloading is achieved by writing a special function corresponding to the operator in the
user-defined class. For example, to overload the + operator for the Vector class, we include
the special function __add__ () in the Vector class. Python internally maps this method to
the + operator. Similarly, we can overload the – operator for the Vector class by including
the special function __sub__ () in the class. Example 12.15(b) illustrates the overloading of
the addition and subtraction operators for the Vector class. Similarly, we can overload any
Python operator by including the corresponding special function in the class definition.
Table 12.2 lists commonly used operators and their corresponding special functions.

Example 12.15(a): Using an operator without overloading it

#A user defined class


class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y

#Main program
p1 = Vector(1, 2)
p2 = Vector(2, 3)
print(p1+p2) #Trying to perform addition of two vectors
Output
Traceback (most recent call last):
File "D:\akv\akv\Python_book\Chapter 12\test3.py", line 9, in
<module>
print(p1+p2)
TypeError: unsupported operand type(s) for +: 'Vector' and 'Vector'

553
Example 12.15(b): Operator overloading

#Operator overloading for a class


class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __add__(self, v1): #Overloading the + operator
v2=Vector(0,0)
v2.x=self.x+v1.x
v2.y=self.y+v1.y
return v2
def __sub__(self, v1): #Overloading the - operator
v2=Vector(0,0)
v2.x=self.x-v1.x
v2.y=self.y-v1.y
return v2
#Main program
v1 = Vector(1, 2)
v2 = Vector(2, 3)
v3=v1+v2 #Using the overloaded + operator
print((v3.x,v3.y))
v3=v1-v2 #Using the overloaded - operator
print((v3.x,v3.y))
Output
(3, 5)
(-1, -1)

Table 12.2 : Python Operators and their corresponding special methods

Operator Expression Corresponding special function


for the operator overloading
Addition ( + ) p1 + p2 p1.__add__( self, p2)
Subtraction ( - ) p1 - p2 p1.__sub__( self, p2)
Multiplication ( * ) p1 * p2 p1.__mul__( self, p2)
Power ( ** ) p1 ** p2 p1.__pow__( self, p2)
Division ( / ) p1 / p2 p1.__truediv__( self, p2)
Floor Division ( // ) p1 // p2 p1.__floordiv__( self, p2)
Remainder (modulo) ( % ) p1 % p2 p1.__mod__( self, p2)
Bitwise Left Shift ( << ) p1 << p2 p1.__lshift__( self, p2)
Bitwise Right Shift ( >>) p1 >> p2 p1.__rshift__( self, p2)
Bitwise AND ( & ) p1 & p2 p1.__and__( self, p2)

554
Bitwise OR ( | ) p1 | p2 p1.__or__( self, p2)
Bitwise XOR ( ^ ) p1 ^ p2 p1.__xor__( self, p2)
Bitwise NOT ( ~ ) ~p1 p1.__invert__( self)
Less than ( < ) p1 < p2 p1.__lt__( self, p2)
Less than or equal to ( <= ) p1 <= p2 p1.__le__( self, p2)
Equal to ( == ) p1 == p2 p1.__eq__( self, p2)
Not equal to ( != ) p1 != p2 p1.__ne__( self, p2)
Greater than ( > ) p1 > p2 p1.__gt__( self, p2)
Greater than or equal to ( >= ) p1 >= p2 p1.__ge__( self, p2)
Unary negation ( – ) -p1 p1.__neg__(self)
Unary plus ( + ) +p1 p1.__pos__(self)
Subtract and assign ( -= ) p1-=p2 p1.__isub__(self, p2)
Add and assign (+= ) p1+=p2 p1.__iadd__(self, p2)
Multiply and assign ( *= ) p1*=p2 p1.__imul__(self, p2)
Divide and assign (/= ) p1/=p2 p1.__idiv__(self, p2)
Floor divide and assign ( //=) p1//=p2 p1.__ifloordiv__(self, p2)
Modulo and assign ( %= ) p1%=p2 p1.__imod__(self, p2)
Power and assign ( **= ) p1**=p2 p1.__ipow__(self, p2)
Right shift and assign ( >>= ) p1>>=p2 p1.__irshift__(self, p2)
Left shift and assign ( <<= ) p1<<=p2 p1.__ilshift__(self, p2)
Bitwise AND and assign ( &= ) p1&=p2 p1.__iand__(self, p2)
Bitwise OR and assign ( |= ) p1|=p2 p1.__ior__(self, p2)
Bitwise XOR and assign (^= ) p1^=p2 p1.__ixor__(self, p2)

When we print an object of a user-defined class, the print () function displays the
memory reference location of the object, such as the statement print(v3) will print
<__main__.Vector object at 0x000002039734E730> on the console. However, to print the
content of the object, we can overload the special function __str__ () method, which is
internally used by the print method to print the content of an object. The __str__ () method
overloads the str () as well as the format () built-in function for the class. Example 12.15(c)
illustrates this.

Example 12.15(c): Printing the content of an object of a user-defined class

#Converting and printing the content of an object of a user defined


#class
class Vector:

555
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __add__(self, v1): #Overloading the + operator
v2=Vector(0,0)
v2.x=self.x+v1.x
v2.y=self.y+v1.y
return v2
def __sub__(self, v1): #Overloading the - operator
v2=Vector(0,0)
v2.x=self.x-v1.x
v2.y=self.y-v1.y
return v2
#The __str__ method converts the content of the object into a string
def __str__(self): #The method to be called by the print function
return "Vector({0},{1})".format(self.x, self.y)
#Main program
v1 = Vector(1, 2)
v2 = Vector(2, 3)
v3=v1+v2 #Using the overloaded + operator
print("v1+v2 =",v3)
v3=v1-v2 #Using the overloaded - operator
print("v1-v2 =",v3)
s1=str(v1) #The overloaded str method
s2=format(v2) #The overloaded format method
print(s1)
print(s2)

Output
v1+v2 = Vector(3,5)
v1-v2 = Vector(-1,-1)
Vector(1,2)
Vector(2,3)

We can not only overload arithmetic operators but we can overload every type of
operator, such as comparator operators, bitwise operators, etc. Example 12.15(d) illustrates
the overloading of the less than (<) operator.

Example 12.15(d): Overloading of the less than (<) operator

#Operator overloading for a class


class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
556
#Comparison of two vectors based on their magnitude
def __lt__(self, v1): #Overloading the < operator
if self.x**2+self.y**2 <v1.x**2+v1.y**2:
return True
else:
return False

#Main program
v1 = Vector(1, 2)
v2 = Vector(2, 3)
print(v1<v2)

v1 = Vector(5, 2)
v2 = Vector(2, 3)
print(v1<v2)

Output
True
False

12.16 Overloading Built-in Python Functions


Similar to operator overloading, Python provides special functions to overload
built-in functions. For example, we can overload the abs () method to handle custom class
objects by overloading the special function __abs__(self). Example 12.16 illustrates the
overloading of the abs () method for the Vector class. Table 12.3 lists commonly used built-
in functions and their corresponding special functions. For other special functions, readers
can refer online documentation.

Table 12.3: Built-in functions and their corresponding special functions

Function Special function Description


abs(x) __abs__(self) Absolute value of x
float(x) __float__(self) Float representation of x
str(x) __str__(self) String representation of x
len(x) __len__(self) Length of x

557
Example 12.16: Overloading built-in methods

#Built-in method overloading for a class


import math
class Vector:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __abs__(self): #Overloading the built-in abs () method
return math.sqrt(self.x**2+self.y**2)

#Main program
v1 = Vector(3, 4)
#Using the abs () method for the Vector class
print("The absolute value of the vector is:", abs(v1))
Output
The absolute value of the vector is: 5.0

12.17 Decorator Classes


A decorator class extends the behavior of a class, without permanently modifying
it. We can define a decorator class that can decorate a function by calling it inside the
__call__ method of a class. Example 12.17(a) illustrates a simple decorator class. A function
that accepts arguments and returns values can also be decorated. The arguments are passed
to the underlying __call__ method and a return statement is added to return values.
Example 12.17(b) illustrates a decorator that accepts arguments and returns a value.

Example 12.17(a): A decorator class

class MyDecorator:
def __init__(self, function):
self.function = function

def __call__(self):
# Additional code before the function call
print("Decorated: Welcome")
self.function()
# Additional code after the function call
print("Decorated: Good bye")

# Decorating the function


@MyDecorator #Using the decorator class
def function(): #Decorating the function
print("Original: Hello world")

558
function() #Calling the decorated function

Output
Decorated: Welcome
Original: Hello world
Decorated: Good bye

Example 12.17(b): A decorator class for a function with arguments and return values

import math
class myDecorator:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
if args[0]<0:
return "Error: No square root of a negative number"
result = self.function(*args, **kwargs)
return result

#Decorating a function with arguments and return values


@myDecorator #Decorator
def get_square(n):
return math.sqrt(n)
x=25
print("Square of ",x, " is ", get_square(x))
x=-25
print("Square of ",x, " is ", get_square(x))

Output
Square of 25 is 5.0
Square of -25 is Error: No square root of a negative number

Solved Examples

Sample Program 12.1: Define a bank account class that holds the following information :
Customer Name, Account Number, Account Type and current balance and performs the
following functions: make a deposit, make a withdrawal and the details of the account.
Solution Steps:
class Account: #Create a Account class
#Define constructor
def __init__(self, name, acc_num, acc_type, balance=0):

559
self.name = name
self.acc_num=acc_num
self.acc_type=acc_type
self.balance = balance

def show(self): #Show the current status of the account


print(self.name,self.acc_num, self.acc_type, self.balance)

def deposit(self): #Make a deposit


amt =float(input("Enter amount to deposit:"))
self.balance +=amt
def withdrawal(self): #Make a withdrawal
amt =float(input("Enter amount to withdraw:"))
if self.balance > amt:
self.balance -= amt
else:
print("Insufficient balance")

# Main program
name = input("Enter name of the account holder:")
acc_num=input("Enter account number:")
acc_type=input("Enter account type(SB/Current)")
amt =float(input("Enter initial amount:"))
A = Account(name, acc_num, acc_type, amt)

while(True): #Create the main menu


print("\nMain menu")
print("1. Show details")
print("2. Deposit ")
print("3. Withdrawl")
print("4. exit")
choice = input("Enter your choice")
if choice == "1":
A.show()
elif choice == "2":
A.deposit()
elif choice == "3":
A.withdrawal()
else:
break

Output
Enter name of the account holder:Arvind
Enter account number:SBI001
Enter account type(SB/Current)SB

560
Enter initial amount:2000

Main menu
1. Show details
2. Deposit
3. Withdrawl
4. exit
Enter your choice2
Enter amount to deposit:1500

Main menu
1. Show details
2. Deposit
3. Withdrawl
4. exit
Enter your choice3
Enter amount to withdraw:1000

Main menu
1. Show details
2. Deposit
3. Withdrawl
4. exit
Enter your choice1
Arvind SBI001 SB 2500.0

Main menu
1. Show details
2. Deposit
3. Withdrawl
4. exit
Enter your choice4
>>>

Sample Program 12.2: Create a Polar class that stores a polar coordinate (radius and
angle) and overloads the + operator.
Solution Steps:

561
import math
class Polar: #Create a class to hold and process polar points
#Define constructor
def __init__(self, radius, angle):
self.radius = radius
self.angle=math.radians(angle)#Store angle in radians

def show(self): #Show the current value of the polar coordinate

print(f"Radius:{self.radius:8.3f},\tAngle={math.degrees(self.angle):8.3
f}")
def __add__(self, p): #Overload the + operator
#Convert polar coordinates to cartesian coordinates
x1=self.radius * math.cos(self.angle)
y1=self.radius * math.sin(self.angle)
x2=p.radius * math.cos(p.angle)
y2=p.radius * math.sin(p.angle)
#Add cartesian coordinates
x=x1+x2
y=y1+y2
#Convert a cartesian coordinate to a polar coordinate
angle= math.atan(y/x) if x != 0 else 0
radius= math.sqrt(x*x+y*y)
p1=Polar(radius,math.degrees(angle))
return p1

# Main program
p1=Polar(4,0) #The first polar point
p2=Polar(3,90) #The second polar point
p3=p1+p2 #Add two polar points
print("P1=", end=" ")
p1.show()
print("P2=", end=" ")
p2.show()
print("P3=", end=" ")
p3.show()

Output
P1= Radius: 4.000, Angle= 0.000
P2= Radius: 3.000, Angle= 90.000
P3= Radius: 5.000, Angle= 36.870

562
Sample Program 12.3: Write a program to implement the following classes.

Staff

Code
Name
Show()

Teacher Officer

Subject Grade
Publications
Show()
Show()

Solution Steps:
1. Create the Staff class
2. Derive the Teacher class from the Staff class
3. Derive the Officer class from the Staff class
class Staff: #Define a class
def __init__(self, code, name):
self.code=code
self.name=name

def show(self):
print("Code:",self.code, "\nName:", self.name)

class Teacher(Staff): #Define a class derived from the Staff class


def __init__(self, code, name, subject, publication):
super().__init__(code,name)
self.subject=subject
self.publication=publication
def show(self):
super().show()
print("Subject:",self.subject, "\nPublication",
self.publication)

class Officer(Staff): #Define a class derived from the Staff class


def __init__(self, code, name, grade):
super().__init__(code, name)

563
self.grade=grade
def show(self):
super().show()
print("Grade:", self.grade)

#Main program
teacher= Teacher(100, "John", "English",10)
teacher.show()
officer=Officer(200, "Joe",4)
officer.show()
Output
Code: 100
Name: John
Subject: English
Publication 10
Code: 200
Name: Joe
Grade: 4

Sample Program 12.4: Create two classes CM and INCH which stores distances in cm
and inch, respectively. Overload the + operator to add the objects of these classes.
Solution Steps:
class CM: #Create CM class
def __init__(self,dist): #Constructor
self.dist=dist
self.unit="cm"

def __add__(self, obj): #Overload the + operator


if self.unit == obj.unit: #No conversion required
C=CM(self.dist+obj.dist)
return C
else:
if self.unit=="cm": #Convert the second object into cm
C = CM(self.dist+ obj.dist* 2.54)
else: #Convert the second object into inch
C = INCH(self.dist + obj.dist*0.3937)
return C
def __str__(self):
return f"{self.dist:8.3f} cm"

class INCH:
def __init__(self,dist): #Constructor

564
self.dist=dist
self.unit="inch"

def __add__(self, obj): #Overload the + operator


if self.unit == obj.unit: #No conversion required
C=INCH(self.dist+obj.dist)
return C
else:
if self.unit=="inch": #Convert the second object into inch
C = INCH(self.dist+ obj.dist * 0.3937)
else: #Convert the second object into cm
C = MC(self.dist + obj.dist*2.54)
return C
def __str__(self):
return f"{self.dist:8.3f} inch"

print(CM(10)+CM(20)) #No conversion required


print(INCH(10)+INCH(20)) #No conversion required
print(CM(10)+INCH(20)) #Convert the second object into cm
print(INCH(10)+CM(20)) #Convert the second object into inch
Output
30.000 cm
30.000 inch
60.800 cm
17.874 inch

Sample Program 12.5: Create a class to hold data of a matrix and overload the matrix
addition operation.
Solution Steps:
class MAT:
def __init__(self, matrix):
self.matrix=matrix

def __add__(self, mat):


n1= len(mat.matrix)
n2= len(self.matrix)

if n1==n2: # check equality of rows in both matrices


result=[]
m=len(mat.matrix[0])

for i in range(n1):
m1=len(mat.matrix[i])

565
m2=len(self.matrix[i])
if m1 == m2 and m1 == m : # Check equality of columns
row=[]
for j in range(m):
row.append(mat.matrix[i][j]+ self.matrix[i][j])
result.append(row)
else:
result ="Invalid dimensions for addition"
break
else:
result ="Invalid dimensions for addition"
return result

#Main program
M1=MAT([[1,2,3],[4,5,6],[7,8,9]])
M2=MAT([[1,2,3],[4,5,6],[7,8,9]])
M3= M1+M2
print(M3, type(M3))

M1=MAT([[1,2,3],[4,5],[7,8,9]])
M2=MAT([[1,2,3],[4,5],[7,8,9]])
M3= M1+M2
print(M3, type(M3))

M1=MAT([[1,2,3],[4,5],[7,8,9]])
M2=MAT([[1,2,3],[4,5,6],[7,8,9]])
M3= M1+M2
print(M3, type(M3))
Output
[[2, 4, 6], [8, 10, 12], [14, 16, 18]] <class 'list'>
Invalid dimensions for addition <class 'str'>
Invalid dimensions for addition <class 'str'>

Chapter Summary

1. OOP is a code management system that reduces the inadvertent modification of


variables and promotes the reusability of codes. It aims to implement real-world
complex problem-solving strategies like inheritance, hiding, polymorphism in
computer programming.
2. In OOPs, we divide complex software into small self-contained subcomponents
called classes and develop well-defined interfaces through which these classes
interact with each other to perform the intended tasks.

566
3. A class is a data structure to map a real-life object and methods to manipulate its
data and interact with other objects. A class is a blueprint, but an object is an
instance of a class that actually holds data in the memory.
4. Data encapsulation, also called data hiding, wraps a class's data and methods as
a single unit and. It means only its class methods can directly access the private
data of a class. Any method outside the class cannot modify the private data
directly. The encapsulation removes the chances of inadvertent modification of
the data of a class as this will be easily caught by the compiler/interpreter.
5. Inheritance is the process of creating a class by using other existing classes. The
existing classes are called base classes (or parent class or superclass), and the new
class is called a child class (or derived class or subclass).
6. Polymorphism in OOP means using a function name or an operator to perform
different tasks depending on the context.
7. Dynamic binding, also known as late binding, refers to linking a procedure at
the run time.
8. Python is an object-oriented programming language and provides easy to use
mechanism to implements OOP concepts. In Python, built-in data types, such as
int, str, bool, float, list, set, tuple, dict, are built-in classes.
9. A constructor is a special method of a class that is automatically called when we
create an instance. The task of a constructor is to initialize the attributes of the
class whenever an instance is created.
10. When a variable (object) goes out of scope in a program, or we delete an object
with the del command, Python automatically destroys the object and releases
the memory. This process is called automatic garbage collection. However,
before killing an object, Python calls a special function known as the destructor.
11. The name mangling is a mechanism used by Python to rename a member of a
class with a double underscore prefix to avoid naming conflicts in inherited
classes.
12. If we redefine a method in a derived class that has the same name as that of a
base class method, the derived class method will override the inherited base
class method.
13. The overridden methods and attributes of the parent class can be accessed in the
derived class by using the super () built-in method.

567
14. In Python, every data is an object derived from a class, and every class in Python,
both built-in and user-defined, is derived from the object class.
15. In multiple inheritances, there may be many methods/attributes with the same
name in itself and various superclasses of a derived class. The method resolution
order (MRO) is the sequence of classes in which Python looks for a
method/attribute in a hierarchy of classes.

Multiple Choice Questions

1. Which of the following is not a feature of object-oriented programming?


(a) Encapsulation
(b) Inheritance
(c) Polymorphism
(d) None of the above
2. Which of the following is true for the object-oriented programming concept?
(a) Objects are real-world entities, while classes are just templates.
(b) Classes are real-world entities, while objects are just templates.
(c) Both objects and classes are real-world entities.
(d) Both objects and classes are just templates.
3. Which of the following is used to create an object?
(a) class constructor
(b) User-defined functions
(c) In-built functions
(d) None of the above
4. The assignment of more than one function to a particular operator is _______
(a) Operator multiple assignments
(b) Operator overriding
(c) Operator overloading
(d) All of the above
5. Data encapsulation helps in
(a) polymorphism
(b) inadvertent modification of variables
(c) extending a class
(d) None of the above

568
6. In inheritance
(a) the child class gets only the data members of the parent class
(b) the child class gets only the methods of the parent class
(c) the child class gets both the methods and data members of the parent class
(d) None of the above
7. Which of the following types of inheritance is not supported in Python?
(a) single inheritance
(b) multi-level inheritance
(c) hybrid inheritance
(d) None of the above
8. Which of the following is not an example of polymorphism?
(a) operator overloading
(b) method overloading
(c) inheritance
(d) none of the above
9. Which of the following is not a built-in class in Python?
(a) Boolean
(b) int
(c) NoneType
(d) complex
10. Which of the following keyword is used to define a class in Python?
(a) def
(b) class
(c) define
(d) None of the above
11. Which of the following is an essential component of a class definition?
(a) class name
(b) attributes
(c) methods
(d) all of the above
12. In a class method definition, the first parameter refers to
(a) The first argument passed during the call
(b) The object of the class itself
(c) It can be any object
(d) None of the above

569
13. Which of the following is true about a class attribute?
(a) The ID of the class attribute is the same in all the instances of the class
(b) Only one copy of the class attribute is created
(c) Any instance of the class can modify it
(d) All of the above
14. Which of the following is true about an instance attribute?
(a) The IDs of the instance attribute are different for the different objects
(b) Separate memory is allocated to the instance attribute for each object
(c) It is also called object attribute
(d) All of the above
15. Which of the following is not true in Python?
(a) We can use the same name to create a class attribute and an object attribute in
a class
(b) The ID of the class attribute is the same in all the instances of the class
(c) Separate memory is allocated to the instance attribute for each object
(d) None of the above
16. Which of the following is true about the constructor of a class?
(a) It is called automatically when we create an instance
(b) The name of the construction is the name of the class
(c) We can have more than one valid construction in a class
(d) All of the above
17. Which of the following is true about the constructor of a class?
(a) It is automatically called when we create an instance
(b) The name of the construction is always __init__().
(c) we can achieve multiple constructors by using the variable-length argument
facility of Python
(d) All of the above
18. Which of the following is true about the destructor of a class?
(a) It is automatically called when the object goes out of scope
(b) When we delete an object with the del command
(c) The name of the destructor of a class is __del__()
(d) All of the above.
19. Which of the following access modifier is not supported in Python?
(a) public
(b) private

570
(c) protected
(d) None of the above
20. How is a member of a class made private?
(a) using the keyword private
(b) using two leading underscores before the name of the member
(c) using one leading underscore before the name of the member
(d) using two leading and two trailing underscores before the name of the
member
21. Which of the following is valid for an instance method of a class?
(a) It is defined inside the class
(b) It can only be called with the help of an instance
(c) The first parameter of the method is always the reference of the class
(d) All of the above.
22. Which of the following is not true?
(a) We can overload a function
(b) We can overload built-in Python methods
(c) We can overload user-defined functions
(d) None of the above
23. How many objects are there in the memory for the given Python code?
class A:
print("Inside class")
A()
A()
A()

(a) 1
(b) 0
(c) 3
(d) None of the above is true
24. What is the type of inheritance implemented in the following Python code?

class A():
pass
class B(A):
pass
class C(B):

571
pass

(a) Multi-level inheritance


(b) Multiple inheritances
(c) Hierarchical inheritance
(d) None of the above
25. What is the output of the following?
class A:
def __init__(self):
self.__a = 10
self.b = 50

def display(self):
print(self.__a, self.b)
class B(A):
def __init__(self):
super().__init__()
self.__a = 20
self.b = 100
C = B()
C.display()

(a) 10 100
(b) 20 200
(c) 10 50
(d) 20 50

Review Questions

1. State whether the following statements are true or false


a. As the complexity and size of a program increase, the architecture
dominates the logic of the program.
b. Python supports object-oriented programming concepts from its inception.
c. A class is called an abstract data type.
d. Python supports single, multiple, hierarchical, multi-level, and hybrid
inheritances.
e. In a Python class, we cannot have two base classes.

572
f. We cannot overload a built-in operator in Python.
g. In dynamic binding, the method linking is done at the run time.
h. Except for the class name, all other components of a class definition are
optional.
i. Each object created from a class will share the same copy of a class attribute.
j. A class attribute cannot be accessed in an instance method.
k. The constructor of a class is used to initialize the attributes of the class
whenever an instance is created.
l. In Python, a dunder method precedes and succeeds with two underscores.
m. When we delete an object with the del command, the destructor of the class
is not called.
n. A private member's name is preceded by two underscores.
o. A protected member name is preceded by a single underscore.
p. The name mangling is a mechanism used by Python to rename a member of
a class with a double underscore prefix to avoid naming conflicts in
inherited classes.
q. The super () method is used to access the parent class members.

2. Describe the merit and demerits of object-oriented programming.


3. Describe different types of inheritances supported by Python.
4. Describe operator overloading.
5. Describe method overloading.
6. Describe components of a class.
7. Describe constructors and destructors.
8. Describe various access modifies of class members.
9. Describe usages of underscores in modifying the access of class members.
10. Describe the name mangling.
11. Describe method resolution order in Python
12. Describe overloading of built-in methods in Python.

Programming Assignments

1. Create a class to store an integer number (<=3999) and implement member


functions to print it as a roman numeral, binary, octal and hexadecimal.
2. Create a class Shape to represent a closed shape with attributes border color,
area, and perimeter. From Shape, derive classes Circle, Triangle, and Rectangle
and implement methods to calculate the area and perimeter and print details of
the Shape.

573
3. Create a class to store a 2D point and implement a member method to determine
the quadrant of the point.
4. Create a class Stats to store a list of floating-point numbers and implement the
methods to calculate the mean, the standard deviation of the list.
5. Create a Rectangle Class to store the length and width of a rectangle and
implement the > operator to check whether the area of the first rectangle is
greater than the second rectangle.
6. Create a class Temp to store a temperature value in a given unit (Celsius,
Fahrenheit, and Kelvin) and implement a method to print the temperature in the
desired unit.
7. Create a Vehicle class to represent general features of a vehicle such as color,
weight, price, registration number. Define two classes Electric and Petrol vehicles
derived from the Vehicle class.
8. Create a Student class to store student details such as the student's name, class,
subject names and marks in five subjects, maximum marks in each subject.
Implement a method to print the mark sheet.
9. Define a class to hold the following data for a bank account: Name, Account
Number, Balance. The class should have the following functions: Open a new
account with an initial balance, deposit an amount, withdraw an amount, and
show the names and their balances. The program should be able to handle 100
customers.
10. Create a class to represent a three-dimensional vector of the for ai+bj+ck, where
a, b, and c are floats and I, k and k are unit vectors in the x-axis, y-axis, and z-
axis, respectively. The class should be able to perform the following functions:
create a new vector, modify components a vector, multiply a vector with a
constant, add two vectors, find the magnitude of a vector, and find the dot
product and cross product of two vectors.
11. Create a class to hold data of a matrix and overload the matrix addition,
subtraction, and multiplication operations.
12. Create a class Rand that generates a random number and stores all the random
numbers generated so far.
13. Create two classes, Metric and British, to hold a distance in the metric system
(meter and centimeter) and the imperial system (feet and inch), respectively.
Also, overload the addition and subtraction of two distances given in any
combination of units.
14. Create a class to store details of a book in a book shop. The details include title,
authors, price, publisher, and quantity in the stock. Define member functions to
show the book's details, sell the book, and purchase the book. The program

574
should store any number of books, update the book's price, and provide a facility
to find a book using title and author names. Design a suitable menu also.
15. Create two classes, Polar and Cartesian, to store the coordinate of a 2D vector in
the Polar and the Cartesian system, respectively. Overload + and – operators and
write a member function to convert from one system to another.

575
576
Chapter 13

Exception Handling in Python


Learning outcomes:

1. Understand various types of exceptions in Python.


2. Understand built-in exception handling in Python.
3. Understand general exception handling in Python.
4. Understand user generated exceptions.
5. Write program for exception handling.

When we execute a Python program, the Python interpreter may encounter two
types of errors that will stop the execution of the program: syntax errors and runtime errors
( exceptions). Syntax errors are caused by wrong syntaxes, i.e. incorrect punctuations, in the
code, for example, missing a comma, a bracket, a colon, or misspelling a word, etc. Example
13 (a) shows some syntax errors and the error messages generated by the Python interpreter.
An exception is an operation performed by a statement that is not allowed or
undefined in the given situation or the requested resources are not available. It is a runtime
error, for example, division by zero, unable to open a file, dividing a string with a number,
etc. Example 13(b) shows some examples of exceptions. Whenever a runtime error occurs,
Python creates an exception object and raises an error. If the error is not handled properly,
it prints a generic traceback to that error along with some details about the cause of the
error.
By default, the interpreter will stop the execution of the program when an exception
occurs. However, Python provides some mechanisms, called exception handling, to manage
exceptions and continue the execution of the program.

Example 13 (a) Examples of some syntax errors

>>> #Example of some syntax errors


>>> #Missing of a colon at the end of if statement is a syntax error
>>> if x > 20
SyntaxError: invalid syntax
>>> #Missing an operator is a syntax error
>>> a= 10 20
SyntaxError: invalid syntax

577
>>> #Missing commas is a syntax error
>>> a=[1 2 3 4]
SyntaxError: invalid syntax
>>>

Example 13 (b) Example of some exceptions

>>> print(1/0) #Error: division by zero


Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
print(1/0)
ZeroDivisionError: division by zero
>>> open("abc.dat","r") #Error: trying to open a non-existing file
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
open("abc.dat","r")
FileNotFoundError: [Errno 2] No such file or directory: 'abc.dat'
>>> "abc"/2 #Error: performing unsupprted division operation
Traceback (most recent call last):
File "<pyshell#9>", line 1, in <module>
"abc"/2
TypeError: unsupported operand type(s) for /: 'str' and 'int'

13.1 Python Built-in Exceptions


Most of the runtime errors are common to all the programs. Hence, Python has
already created objects corresponding to them to systematically handle them. We can print
all the built-in exceptions, along with functions and attributes, using the statement
print(dir(locals()['__builtins__']))(See Example 13.1). Table 13.1 lists common built-in
exception objects with a brief description of each.

Example 13.1: Built-in exceptions

>>> print(dir(locals()['__builtins__']))
['ArithmeticError', 'AssertionError', 'AttributeError',
'BaseException', 'BlockingIOError', 'BrokenPipeError', 'BufferError',
'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError',
'ConnectionError', 'ConnectionRefusedError', 'ConnectionResetError',
'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError',
'Exception', 'False', 'FileExistsError', 'FileNotFoundError',
'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError',
'ImportError', 'ImportWarning', 'IndentationError', 'IndexError',

578
'InterruptedError', 'IsADirectoryError', 'KeyError',
'KeyboardInterrupt', 'LookupError', 'MemoryError',
'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError',
'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError',
'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError',
'RuntimeWarning', 'StopAsyncIteration', 'StopIteration', 'SyntaxError',
'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError',
'TimeoutError', 'True', 'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError',
'Warning', 'WindowsError', 'ZeroDivisionError', '__build_class__',
'__debug__', '__doc__', '__import__', '__loader__', '__name__',
'__package__', '__spec__', 'abs', 'all', 'any', 'ascii', 'bin', 'bool',
'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod',
'compile', 'complex', 'copyright', 'credits', 'delattr', 'dict', 'dir',
'divmod', 'enumerate', 'eval', 'exec', 'exit', filter', 'float',
'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help',
'hex', 'id', 'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
'license', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
'object', 'oct', 'open', 'ord', 'pow', 'print', 'property', 'quit',
'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type',
'vars', 'zip']

Table 13.1: Built-in Python Exceptions

Exception Cause of exception error


AssertionError Raised when an assert statement fails.
AttributeError Raised when attribute assignment or reference fails.
EOFError Raised when the input() function hits the end-of-file
condition.
FloatingPointError Raised when a floating-point operation fails.
GeneratorExit Raise when a generator's close() method is called.
ImportError Raised when the imported module is not found.
IndexError Raised when the index of a sequence is out of range.
KeyError Raised when a key is not found in a dictionary.
KeyboardInterrupt Raised when the user hits the interrupt key (such as Ctrl+C).
MemoryError Raised when an operation runs out of memory.

579
NameError Raised when a variable is not found in the local or global
scope.
NotImplementedError Raised by abstract methods.
OSError Raised when system operation causes a system-related error.
OverflowError Raised when the result of an arithmetic operation is too large
to be represented.
ReferenceError A ReferenceError exception occurs when we try to use a
variable or object that has not been defined or declared.
RuntimeError Raised when an error does not fall under any other category.
StopIteration Raised by the next() function to indicate that there is no
further item to be returned by the iterator.
SyntaxError Raised by the parser when a syntax error is encountered.
IndentationError Raised when there is incorrect indentation.
TabError Raised when indentation consists of inconsistent tabs and
spaces.
SystemError Raised when the interpreter detects an internal error.
SystemExit Raised by sys.exit() function.
TypeError Raised when a function or operation is applied to an object of
the incorrect type.
UnboundLocalError Raised when a reference is made to a local variable in a
function or method, but no value has been bound to that
variable.
UnicodeError Raised when a Unicode-related encoding or decoding error
occurs.
UnicodeEncodeError Raised when a Unicode-related error occurs during
encoding.
UnicodeDecodeError Raised when a Unicode-related error occurs during
decoding.
UnicodeTranslateError Raised when a Unicode-related error occurs during
translating.
ValueError Raised when a function gets an argument of correct type but
the passed is invalid value and canot be processed. Such as
passing negative value to find squire root of real numbers.
ZeroDivisionError Raised when the second operand of division or modulo
operation is zero.

580
13.2 Handling a General Exception
We can use the try-except construct to handle any exception with the following
syntax:
try:
#Put your suspicious code here
Statements
except:
#Handles exception
Statements
We put a suspicious code in the try block. If no exception occur in the try block code,
the except block will be skipped. However, if the Python interpreter raises an exception in
the try block, the execution of the remaining part of the try block code will be skipped and
the except block code is executed. This construction does not differentiate different types of
exceptions and handles all the exceptions in the same manner. Example 13.2 illustrates its
use in finding inverse of elements of a list, which consists of elements of different types. As
can be seen from the output of example 13.2(a), we do not know what are the types of
exceptions. However, we can use the exc_info () method of the sys module to know the
types of exceptions. The exc_info() method returns a list containing the class of the current
exception, its type and the reference of the object that caused the error. These can be helpful
to debug the program to avoid such exceptions in future. Example 13.2(b) illustrates this.

Example 13.2(a): The try-except block

List = [3,'a', 0, True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspicious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
except: #The exception handler
print("Error: An exception occurred")

Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
The value of the element: a
Error: An exception occurred
The value of the element: 0
Error: An exception occurred

581
The value of the element: True
The reciprocal of the element: 1.0
The value of the element: (2+3j)
Error: An exception occurred

Example 13.2(b): The try-except block

import sys
List = [3,'a', 0, True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspicious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
except: #The exception handler
print("Error: An exception occurred")
print("The class of exception: ", sys.exc_info()[0])
print("The type of exception: ", sys.exc_info()[1])

Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
The value of the element: a
Error: An exception occurred
The class of exception: <class 'ValueError'>
The type of exception: invalid literal for int() with base 10: 'a'
The value of the element: 0
Error: An exception occurred
The class of exception: <class 'ZeroDivisionError'>
The type of exception: division by zero
The value of the element: True
The reciprocal of the element: 1.0
The value of the element: (2+3j)
Error: An exception occurred
The class of exception: <class 'TypeError'>
The type of exception: can't convert complex to int

13.3 Catching Specific Exceptions


Python has a more elegant mechanism to handle exceptions in a program than the
above using the try-except-else-finally construct. In this case, we can handle different types
582
of exceptions differently. For this, the construct has many except blocks. One except for a
particular exception or for a tuple of exceptions. We can also include a default except block
that will handle all other exceptions not handled through the specific except block. The
default except block is the last except block. We cannot write it before any specific except
block. We can also include an else block that will be executed if there is no exception in the
try block code. Further, we can also include a finally block that will always be executed
either there is an exception or not in the try block. The general except, the else, and the
finally blocks are all optional. Following is the general syntax of this construct:

try:
#Put your suspicious code here
Statements
except exception1:
#Handles exception1
Statements
except (exception2, exception3,…, exceptionM):
#Handles multiple exceptions
Statements

except exceptionN:
#Handles exceptionN
Statements
except:
#General exception handler. Handles all other unhandled exceptions
Statements
else :
#Executes this block when there is no exception raised by the try block
Statements
finally:
#This block is always executed either there is an exception or not
Statements

Similar to the try-except, we put a suspicious code block in the try block that may
raise different types of exceptions during execution. If an exception is raised by the try block
code, the further execution of the remaining part of the try block code is stopped and the
Python interpreter starts executing the corresponding except block code if it is defined else
it executes the general except block, if defined. If there is no error in the try block code, the

583
interpreter executes it completely and then also executes the else block. And the finally
block code is always executed either there is an exception or not. Example 13.3(a) illustrates
the working of the above construction. We can handle a tuple of exceptions in a single
except block, see example 13.3(b).

Example 13.3(a): Example of some exceptions

List = [3,'a', 0, True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspicious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
except ValueError: #The ValueError exception handler
print("ValueError exception occurred")
except ZeroDivisionError: #The ZeroDivisionError exception handler
print("ZeroDivisionError exception occurred")
except TypeError: #The TypeError exception handler
print("TypeError exception occurred")
else:
print("No exception occurred")
finally:
print("Executing the finally block\n")

Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
No exception occurred
Executing the finally block

The value of the element: a


ValueError exception occurred
Executing the finally block

The value of the element: 0


ZeroDivisionError exception occurred
Executing the finally block

The value of the element: True


The reciprocal of the element: 1.0
No exception occurred
Executing the finally block

584
The value of the element: (2+3j)
TypeError exception occurred
Executing the finally block

Example 13.3(b): Handling multiple exceptions in a single except block

List = [3,'a', 0, True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspecious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
#Multiple exceptions handler except block
except (ValueError,ZeroDivisionError):
print("ValueError or ZeroDivisionError exception occurred")
except TypeError:
print("TypeError occurred")
else:
print("No exception occurred")
Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
No exception occurred
The value of the element: a
ValueError or ZeroDivisionError exception occurred
The value of the element: 0
ValueError or ZeroDivisionError exception occurred
The value of the element: True
The reciprocal of the element: 1.0
No exception occurred
The value of the element: (2+3j)
TypeError occurred

More about the finally block: If there is an exception raised by the try block and there is no
corresponding except block or generic except block, then it will be treated as an unhandled
exception and the execution of the remaining part of the try code is skipped and the
program execution will stop after executing the finally block code. Since the finally block
always executes whether or not the try statement raises an exception, keep the following
point in mind:
a) If an exception occurs during the execution of the try clause and the exception is not
handled by an except clause, the exception is re-raised after the finally block has
585
been executed. Hence, it is important to handle the generated exceptions to avoid
crashing the program. Example 13.3(c) illustrates this point.
b) If an exception occurs during the execution of an except block or else block, the
exception is re-raised after the finally block has been executed. Example 13.3(d)
illustrates this point.
c) If the try block or except block or else block has a break, continue or return
statement, the finally block will execute just before executing the break, continue or
return statement. In simple words, if the finally block has a return statement, other
return statements in try, except or else blocks will never execute. Example 13.3(e)
illustrates this point.
d) If the try block and the finally block both include a return statement, the return
statement of the finally block will only be executed and the return statement of the
try block will never be executed. Example 13.3(f) illustrates this point.

Example 13.3(c): Example of unhandled exceptions

List = [3,0,'a',True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspecious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
except ZeroDivisionError: #The ZeroDivisionError exception handler
print("ZeroDivisionError exception occurred")
else:
print("No exception occurred")
finally:
print("Executing the finally block\n")
Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
No exception occurred
Executing the finally block

The value of the element: 0


ZeroDivisionError exception occurred
Executing the finally block

The value of the element: a


Executing the finally block

586
Traceback (most recent call last):
File "D:\akv\akv\Python_book\chapter 7\test1.py", line 8, in <module>
r = 1/int(x) #Calculating the inverse of the element
ValueError: invalid literal for int() with base 10: 'a'

Example 13.3(d): An exception generated in the else block

List = [3,0,'a',True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
#Suspecious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)

except ZeroDivisionError: #The ZeroDivisionError exception handler


print("ZeroDivisionError exception occurred")

else:
print("No exception occurred in the try block")
#The following statement will generate an exception
a=x+"abc" #Error: Cannot add an integer with a string
finally:
print("Executing finally\n")
Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
No exception occurred in the try block
Executing finally

Traceback (most recent call last):


File "D:\akv\akv\Python_book\chapter 7\test1.py", line 17, in
<module>
a=x+"abc" #Error: Cannot add an integer with a string
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Example 13.3(e): break, continue and return in the try, except or else block

List = [3,0,'a',True, 2+3j] #A list with different types of data

for x in List: #Iterating the list


try:
587
#Suspecious code where an exception can occur
print("The value of the element: ", x)
r = 1/int(x) #Calculating the inverse of the element
print("The reciprocal of the element: ",r)
continue #The finally block will get executed before this

except ZeroDivisionError: #The ZeroDivisionError exception handler


print("ZeroDivisionError exception. Breaking the loop.")
break #The finally block will get executed before this
else:
print("No exception occurred in the try block")
finally:
print("Executing finally\n")
Output
The value of the element: 3
The reciprocal of the element: 0.3333333333333333
Executing finally

The value of the element: 0


ZeroDivisionError exception. Breaking the loop.
Executing finally

Example 13.3(f): return statements in the try, except, else and finally block

def myInverse(x):
try:
#Suspecious code where an exception can occur
r = 1/int(x) #Calculating the inverse of the element
print("Try block")
return r #This return will never execute
except ZeroDivisionError: #The ZeroDivisionError exception handler
print("Except block")
#The following return will never execute
return "ZeroDivisionError exception occurred."
else:
print("Else block")
return "No exception" #This return will never execute
finally:
print("Finally block")
return "Finally" #Only this return will execute

List = [3,0,'a'] #A list with different types of data


for x in List:
print("Returned value: ", myInverse(x), "\n")

588
Output
Try block
Finally block
Returned value: Finally

Except block
Finally block
Returned value: Finally

Finally block
Returned value: Finally

13.4 Raising Exceptions


Python has a robust mechanism to handle exceptions. However, there are situations
where programmer wants to write generate exceptions to handle custom invalid situations.
This is called raising exceptions and we can use the raise keyword to raise an exception.
The raise statement creates an exception object, and immediately stops execution of the
remaining part of the current code block and sends control to the corresponding except
block if defined else stops the execution of the program with a generic exception error
message. The raise statement can raise a built-in exception (see Table 13.1), a generic
exception, or an user-defined exception. See section 13.5 for user-defined exceptions.
Example 13.4 raises an exception using the raise keyword.

Example 13.4: Raising an exception

#A function that raises an exception


def myFun(x):
if x > 5:
#Raising a generic exception
raise Exception(f"{x} exceeds the upper limit(5)")
elif x<0:
#Raising a built-in exception
raise ValueError(f"A negative value {x} is illegal ")

return 1/x #Automatically raise built-in exception

#Main program
a=[3,6,0,-2]
for x in a:
#Handling user defined exceptions and buitin-exception
try:
print(myFun(x))
589
except Exception as ex:
print(ex)
Output
0.3333333333333333
6 exceeds the upper limit(5)
division by zero
A negative value -2 is illegal

13.5 User-defined Exception


Generally, built-in exceptions are automatically raised by the interpreter. However,
there may be an exceptional situation in a program that is not mapped to any built-in
exception. For such a unique situation, we need to define a user-defined exception. We can
create a new exception class by extending the built-in generic Exception class. The
Exception class is the base class of all the built-in exception classes. Following is the syntax
to define a user-defined exception class:

class MyException( Exception ):


Statements

Where MyException is the name of the new exception class created. We can then
raise a MyException error in a program using a raise statement and catch it through the try-
except construct. Example 13.5(a) illustrates the creation of a user-defined exception and its
handling.

Example 13.5(a): Defining a custom exception error

import math
#defining a user-defined exception
class QuadError( Exception ):
pass

def root_quad(a,b,c):
if a == 0:
#Creating an exception object
ex= QuadError( "Not a quadratic equation." ) #Error message
ex.coef= ( a, b, c ) #Adding additional information
raise ex #Raising an exception
if b*b-4*a*c < 0:
ex= QuadError( "No Real Roots exist for this equation." )
ex.coef= ( a, b, c )
raise ex
x1= (-b+math.sqrt(b*b-4*a*c))/(2*a)

590
x2= (-b-math.sqrt(b*b-4*a*c))/(2*a)
return (x1,x2)

#main program
equations=[(0,2,3),(1,2,3),(1,-4,4)]
for c in equations:
try:
print("Roots are:",root_quad(*c))
except QuadError as ex:
print(ex,": With coefficients", ex.coef)

Output
Not a quadratic equation. : With coefficients (0, 2, 3)
No Real Roots exist for this equation. : With coefficients (1, 2, 3)
Roots are: (2.0, 2.0)

We can further customize a user-defined exception class to accept additional


arguments as per our needs by overriding the base __init__ method. We can also override
the base __str__ method and other methods in the created exception class. Example 13.5(b)
illustrates the above.

Example 13.5(b): Defining a custom exception

#Creating a custom exception with parameters


class MonthError(Exception):
#Overriding the base __init__ method
def __init__(self, month, message="Month number should be within
(1,12)"):
self.month = month #Adding an additional parameter
self.message = message
super().__init__(self.message)
#Overriding the base __str__ method
def __str__(self):
return f'{self.month} -> {self.message}'

#Main program
for i in range(3):
try:
month = int(input("Enter the month number: "))
if not 1 <= month <= 12:
raise MonthError(month)
print(f"{month} is a valid month number")
except MonthError as ex:
print(ex)

591
print("Entered value:",ex.month) #Additional parameter access
Output
Enter the month number: 3
3 is a valid month number
Enter the month number: -4
-4 -> Month number should be within (1,12)
Entered value: -4
Enter the month number: 15
15 -> Month number should be within (1,12)
Entered value: 15

13.6 Assertions
The assertion is used to verify a condition in a programming language as a
debugging tool. If the condition specified in the assert statement is true, no action is taken
and the execution of the program continues as normal, otherwise, an assertion error is raised
and the execution of the program stops. Following is the syntax of the assert statement:

assert condition [, Error_Message]

where condition is a Boolean expression and Error_Message is the error message to


be generated when the condition evaluates to False. Error_Message is optional. Example
13.6(a) illustrates an illustrative use of the assert keyword. We can catch the error generated
by an assert statement, see example 13.6(b). It is strongly recommended that don’t use
asserts for data validation as asserts can be turned off globally in the Python interpreter.
Use it only to debug your program.

Example 13.6(a): An assert statement

a=[10,-20]
for x in a:
#The execution stops if the assert condition is false
assert x > 0, f"{x} is a negative number"
print(f'{x} is a positive number.')

Output
10 is a positive number.
Traceback (most recent call last):
File "D:/akv/akv/Python_book/Chapter 13/t.py", line 3, in <module>
assert x > 0, f"{x} is negative"
AssertionError: -20 is negative

592
Example 13.6 (b): Handling an assertion error

while(1):
try:
x=int(input("Enter a positive number:"))
assert x > 0, f"{x} is a negative number"
print(f'{x} is a positive number.')
break
except AssertionError as ex: #Handling assertion error
print(ex)
print("Please retry...")
continue
except: #Handling other exceptions
print("Invalid entry. Retry")
continue
print("Value read successfully")
Output
Enter a positive number:-5
-5 is a negative number
Please retry...
Enter a positive number:five
Invalid entry. Retry
Enter a positive number:5
5 is a positive number.
Value read successfully

Sample programs

Sample Program 13.1: Write a program to read an integer from the keyboard. The
program should stop only when a valid integer is entered.

Program
while True: #The loop keeps repeating till a valid integer is entered
try:
n = input("Enter an integer: ")
n = int(n) #Raises the ValueError exception if n is not an
integer
break #Break the loop if n is a valid integer
except ValueError:
print("Invalid input. Please try again ...")
print("Valid integer:", n)

593
Output
Enter an integer: a
Invalid input. Please try again ...
Enter an integer: 12.3
Invalid input. Please try again ...
Enter an integer: 12
Valid integer: 12

Sample Program 13.2: Write a program to add all the digits present in a string.
Program
s=input("Enter the string:")
x=0
for c in s: #Iterate over each character of the string
try:
x=x+int(c) #Raises an exception if c is not a digit
except:
continue #Ignore non-digits and continue to the next character
print(x)

Output
Enter the string:A23rfd21df6as3
The sum of digits in A23rfd21df6as3 is 17

Sample Program 13.3: Write a program to calculate the square root of all the valid
numbers in a list. Use exception handling to ignore the invalid entries.
Program
import math #import math module
data= [1, 2, 3.5, 'a', -5, 20]
result=[]
for x in data: #Iterate over each item in the list
try:
result.append(math.sqrt(x)) #Raises an exception if x is
invalid
except:
result.append("Invalid")

print("List:",data,"\nResult:", result)
Output
List: [1, 2, 3.5, 'a', -5, 20]

594
Result: [1.0, 1.4142135623730951, 1.8708286933869707, 'Invalid', 'Invalid',
4.47213595499958]

Sample Program 13.4: Write a program to read lines in a file and sum all the numbers
found in the file and ignore lines which are not valid numbers.
Program
try:
file_name = input("Enter the file name:")
s=0
file =open(file_name,'r') #May generate exception
flag=True
while(flag):
try:
a=file.readline()
n=float(a) #May generate exception
s=s+n
except: #Handles invalid number situations
if len(a)== 0: #Handling end of file situation
break
else: #Skips lines not containg valid numbers
continue
except Exception as e: #Handles file errors
print("Error:", e)
else:
print("Sum:",s) #Print the sum of all valid numbers

Input file (a.txt)


1
2
text1
3
ds
4

5
Output
Enter the file name:a.txt
Sum: 15.0
Enter the file name:b.txt
Error: [Errno 2] No such file or directory: 'b.txt'

595
Sample Program 13.5: Write a program to read a string from the keyboard and count the
frequencies of letters. Ignore other characters using exceptions.
Solution steps:
letters=dict() #Create an empty dictionary
for i in range(65,91): #Initialise the dictionary with letters
c=chr(i)
letters[c]=0
s=input("Enter the string:")
s=s.upper() #Convert the string to upper case letters

for c in s:
try:
letters[c]=letters[c]+1 #Can generate IndexError Exception for
non-letters
except:
continue #Ignore non-letters
print("Frequencies of letters")
for k in letters:
if letters[k] >0: print( k, ":",letters[k])
print("All other letters: 0")
Output
Enter the string:Arvind Kumar Varma 1970.
Frequencies of letters
A:4
D:1
I:1
K:1
M:2
N:1
R:3
U:1
V:2
All other letters: 0

596
Chapter Summary

1. Incorrect punctuations in the code cause syntax errors. Whereas an exception is


an operation performed by a statement that is not allowed or undefined in the
given situation or the requested resources are not available. It is a runtime error,
such as division by zero, unable to open a file, dividing a string with a number.
2. By default, the interpreter will stop the execution of the program when an
exception occurs. However, Python provides a mechanism, called exception
handling, to manage exceptions and continue the program's execution.
3. For common exception errors, such as division by zero, Python has built-in
objects, such as ZeroDivisionError, corresponding to them to handle them
systematically.
4. The try-except construct can be used to handle any exception.
5. An else block is used in a try-except construct to execute a block of code if there
is no exception in the try block code.
6. A finally block is used in a try-except construct to execute a block of code that
will always execute either there is an exception or not in the try block.
7. The raise keyword can be used to raise a user-defined exception.
8. A new exception class can be defined by extending the built-in generic Exception
class.
9. The assert keyword can be used to verify a condition in a programming language
as a debugging tool.

Multiple Choice questions

1. When an exception occurs in a Python program, the Python interpreter by


default _____.
(a) Stops executing the program
(b) Ignores the statement causing the exception and continues the next statement
(c) Generate an error message and then stops
(d) None of the above.
2. A code that is expected to generate exceptions is placed in _____.

597
(a) try block
(b) except block
(c) finally block
(d) else block
3. How many except blocks can a try-except construct have?
(a) 0
(b) 1
(c) >=1
d) None of the above
4. The try-except construct can handle which of the following error
(a) syntax error
(b) runtime error
(c) logical error
(d) all of the above
5. Which of the following exception is raised when the result of an arithmetic
calculation exceeds the maximum limit for a numeric type?
(a) StandardError
(b) ArithmeticError
(c) OverflowError
(d) FloatingPointError
6. The else block of the try-except-else construct is executed ______.
(a) always
(b) when an exception occurs
(c) when no exception occurs
(d) when an exception occurs in the except block
7. The finally block of the try-except-else _finally construct is executed ______.
(a) always
(b) when an exception occurs
(c) when no exception occurs
(d) when an exception occurs in the else block
8. How many exceptions can one block of except statements handle?
(a) 1
(b) 2
(c) 3
(d) None of the above

598
9. What is the output of the following code?
def myFun():
try:
return 1
finally:
return 2
k = myFun()
print(k)

(a) 1
(b) 2
(c) It is an error
(d) None of the above
10. What is the output of the following code?

def myFun():
try:
print("The try block", end=", ")
except:
print("An except block", end=", ")
else:
print("The else block", end=", ")
finally:
print("The finally block")
myFun()

(a) The try block, The else block, The finally block
(b) The try block, The finally block
(c) The try block, The else block
(d) The try block
11. What is the output of the following code?
def myFun():
try:
raise "Custom Error"
print("The try block", end=", ")
except:
print("An except block", end=", ")

599
else:
print("The else block", end=", ")
finally:
print("The finally block")
myFun()

(a) An except block, The finally block


(b) The try block, The else block, The finally block
(c) The except block, The else block, The finally block
(d) The except block, The else block, The finally block
12. What is the output of the following code?
def myFun():
try:
pass
except:
pass
else:
pass
finally:
pass
print(myFun())

(a) None
(b) It has syntax errors
(c) It has runtime errors
(d) Nothing will be printed
13. What is the output of the following program?
x=-10
assert x<0, print(f"{x} is negative")

(a) -10 is negative


(b) {x} is negative
(c) Nothing will be printed
(d) None of the above is correct
14. Which of the following exception is generated when we try to execute the
following code?
math.sqrt(-1.2)

600
(a) ValueError
(b) ArithmeticError
(c) NegativeValueError
(d) None of the above
15. When we attempt to read after the end of the file, which of the following
exception is raised?
(a) EOFError
(b) EndofFileError
(c) UnabletoReadError
(d) None of the above

Review Questions

1. State whether the following statements are true or false:


a. Incorrect punctuations can cause an exception.
b. Division by zero is a syntax error.
c. By default, the Python interpreter will stop the execution of the program
when an exception occurs.
d. The ImportError exception is raised when the requested module is not
found.
e. The KeyError exception is raised when the keyboard is not working.
f. OverflowError is raised when the result of an arithmetic operation is too
large to be represented.
g. The try-except construct is used to handle exceptions.
h. The try-except construct can have a finally block that always gets executed.
i. The try-except construct can have an else block that gets executed when
there is no exception.
j. The raise keyword generates an exception.
k. We cannot create custom exception errors in Python.
2. Describe different types of errors that can occur in a program.
3. Describe a few built-in exception objects.
4. Describe try-except construct to handle exceptions.
5. Describe uses of the else block in the try-except construct.
6. Describe uses of the finally block in the try-except construct.
7. Describe the raise keyword.
8. Describe steps to create a user defined exception class.

601
9. Describe the assert keyword.

Programming Exercises

1. Define a function fraction (a, b) which returns a/b, but when b is zero, it should
raise an exception.
2. Define a function find_even_number(L) which returns the first even number
found in the list L. If no even number is found in the list, raise an exception.
3. Write a function to read an integer between 1 and 10. If the entered number is
outside this range, raise the ValueError exception.
4. Write a program that converts a time given in 24-hour time format to 12-hour
time format. Handle the exceptions caused by invalid hours and minutes.
5. Write a program that converts date from numerical month/day format to
Month_name day format; for example, 1/31 will result in January 31. Your
program should raise two exceptions MonthError and DayError, for invalid
month and day, respectively.
6. Write a function factorial(n) to calculate the factorial of n. If the value of n is
negative or a number with a fraction value, the function should raise the
ValueError exception.
7. Write a function quadratic_eq_roots(a, b, c) that returns the real roots otherwise
raises the ValueError exception.
8. Create a Car class that stores details of a car. Generate a list of cars. Some of the
cars have troubles with their Motors. Write a function quality_check that iterates
over the list of cars and raises exceptions whenever it finds a car with a motor
problem.
9. Write a program to read a file and print the content. Use a try_except block to
read a valid file name.
10. Write a program to evaluate the expression (a(i)+b(i))/(a(i)-b(i)), where a and b
are vectors of integers. Use exceptions to handle the indeterminate situations.

602
Chapter 14

Introduction to NumPy
Learning outcomes:

1. Create NumPy arrays.


2. Understand data structure of NumPy arrays
3. Convert Python data types into NumPy arrays
4. Understand indexing in NumPy Array
5. Perform operations with NumPy arrays

14.1 Introduction
NumPy (Numerical Python) is an open-source Python package for efficiently
processing multidimensional arrays. It is developed by Travis Oliphant in 2005. It is
primarily used for mathematical and logical operations on arrays, shape manipulation of
arrays, linear algebra, random number generations, Fourier transforms, etc. NumPy, along
with SciPy (Scientific Python) and Matplotlib (plotting library), is widely used as a free
substitute for MATLAB, for engineering and scientific computations and visualization.
Most of the popular Python distributions have NumPy pre-installed. However, if required,
we can install them using the pip install numpy command.

14.2 NumPy Arrays


An array is an ordered collection of homogeneous data elements, i.e. all the data
elements are of the same type, arranged in a multi-dimensional grid. An array is stored in
contiguous memory, using a single identifier. An individual data element is referenced
using indexing.

Python has no built-in array data type. However, we can use a list as an array but it
is very slow and does not provide functions to manipulate array data. To use arrays in
Python, programmers typically use NumPy arrays. Since NumPy is written in C, it provides
a very fast array implementation. Further, it has a large number of array processing
functions.

NumPy supports multi-dimensional arrays. Each dimension in an array is called an


axis. The index of each axis starts with zero. Figure 14.1 shows some examples of arrays of

603
different dimensions along with their axis systems. The shape of an array is specified as an
ordered tuple of integers with the following syntax: shape (axis-0, axis-1, axis-2, …, axisN),
where axis-0, axis-1, …, axis-N are sizes of the corresponding axis. For example, an array of
the shape (4,3) is a 2D array and has four rows and each row has three columns, Figure
14.1(b). Similarly, an array of the shape (2, 4,3) is a 3D array and has two planes; each plane
has four rows and each row has three columns, Figure 14.1(c). Similarly, an array of the
shape (2,2,4,3) is a four-dimensional array. It consists of two cubes. Each cube consists of 2
planes and each plane consists of 4 rows and 3 columns. See Figure 14.1(d).

Figure 14.1: Arrays of different dimensions and their axis systems

604
An element of a multi-dimensional array is accessed by an ordered tuple of integers
with the following syntax, arr[i1, i2,…, iN], where arr is the array identifier and i1,i2,… iN
are indices of the element in axis-0, axsis-1, …, axisN, respectively. Indices are enclosed
within a pair of squire bracket and are separated by commas. Consider various arrays
shown in figure 14.1, the value 2 is accessed as a [1], b [0, 1] and c [0, 0, 1], d [0,0,0,1] in
arrays a, b, and c, respectively. Please note, NumPy arrays uses 0-based indexing system.
Similarly, 9 in array c will be accessed as c [0,2,2] and 18 in array d will be accessed as d
[1,0,1,2].

14.3 Data structure of NumPy Arrays


Internally, data in a NumPy array (NumPy array is also called ndarray) are stored
in a contiguous linear memory block along with some metadata (attributes) to store other
information such as shape, the data type of elements, etc., using the data structure as shown
in figure 14.2. The structure consists of metadata such as dtype, itemsize, size, ndim, shape
and strides along with the actual data.

Traditionally, there are two approaches to store a multi-dimensional array in a


contiguous memory block (for simplicity, consider a 2D array, shown in Figure 14.3(a)):
row-wise (also called C-contiguous as it was initially used in C programming language)
and column-wise (also called F-contiguous as it was initially used in FORTRAN
programming language).

In the C-contiguous, the first row is written in the memory, then the second row,
and so on, as shown in Figure 14.3(a). Whereas, in the F-contiguous system, the first column
is written than the second column and so on, as shown in Figure 14.3(c).

605
dtype Float32
itemsize 4
size 12
ndim 2
shape 4 3
strides 12 4
data 1 2 3 4 5 6 7 8 9 10 11 12
(a) The array shape (4,3)

dtype Float32
itemsize 4
size 12
ndim 2
shape 6 2
strides 4 24
data 1 2 3 4 5 6 7 8 9 10 11 12
(b) The array shown in (a) reshaped as (6,2) using the F-contiguous system

dtype Float32
itemsize 4
size 12
ndim 3
shape 3 2 2
strides 16 8 4
data 1 2 3 4 5 6 7 8 9 10 11 12

(c) The array shown in (a) reshaped as (3,2,2)

Figure 14.2: The data structure of NumPy arrays

By default, NumPy arrays are stored in the C-contiguous system. Numpy uses the
concept of strides for various dimensions of the array to efficiently access the given data
either in the C-continuous system or in the F-continuous system, without changing the
order of the actual data. Stride in a dimension refers to the number of bytes required to skip
to reach the next element in that particular dimension.

606
1 2 3 4
5 6 7 8
9 10 11 12
(a) Matrix

1 2 3 4 5 6 7 8 9 10 11 12
(b) C-contiguous system

1 5 9 2 6 10 3 7 11 4 8 12
(c) F-contiguous system

Figure 14.3: Systems of storing an array in a memory block

In figure 14.2, the same data is viewed in different shapes. The data consists of 12
integer values. Figure 14.2(a) shows how to store the data as a matrix of shape 4x3, i.e. four
rows and three columns using C- continuous system. It can be noted that when we change
the shape of an array, data remains the same, only the metadata changes. In Figure 14.2(b),
the same data is accessed as six rows and two columns using F-continuous system by
changing shape attribute to 6x2 and stride to 4x24. Similarly, in Figure 14.2(c), the same data
is accessed as three-dimensional array of shape 3x2x2, using the C-continuous system by
setting the stride to 16x8x4.

14.4 Creating Arrays in NumPy


The ndarray is the backbone of the NumPy module and is the most widely used
construct in scientific and engineering computations. A NumPy array can be created in the
following three ways:

(1) Using Numpy built-in functions

(2) Converting other Python data types, such as lists, tuples, etc., into arrays

(3) Using special library functions.

Using Numpy built-in functions: Numpy has many built-in functions for creating arrays
of different dimensions. Some methods create only one-dimensional arrays, but those can
be converted to other compatible multiple-dimensional arrays. However, some methods
can directly create multi-dimensional arrays. Table 14.1 lists commonly used built-in
methods to create arrays along with some illustrative examples. Before using NumPy in our

607
programs, we have to import it into our program. Typically, we import it using the
statement import numpy as np. Once imported, we can use a NumPy method with the
syntax np.method_name(parameters).

Table 14.1: NumPy built-in methods to create arrays

Method description

arange The arange() method creates a one-dimensional array from a range. The range
is specified by start, end, and step. It uses the following syntax:

arr = np.arange([start, ]stop, [step, ], dtype=None)

where start is a number (integer or decimal) that defines the first value in the
array, stop is the number that defines the end of the array but isn’t included
in the array and step is the difference between two consecutive values in the
array. The default value of start is 0 and of step is 1. Note, step cannot be
zero. The last parameter, dtype is the data type of the elements. The default
value of dtype is None, which means arange () will use the most precise data
type from the types of start, stop, and step for the array elements. For
example, an array created using arr=np.arange(1, 10, 1) will have integer data
type. Whereas, an array created using arr=np.arange(1,10,0.5) will have float
data type.

A one-dimensional array generated by the arange() method can be reshaped


to any other shape with the built-in method reshape(). Example 14.4 (a)
illustrates the arange () method.

zeros The zeros() method creates an array filled with zeros of a specified shape. Its
syntax is np.zeros(shape, dtype = None, order = 'C') where shape is a tuple
or list of integers representing the shape of the returned array. See the
following examples:

>>> z=np.zeros(10) #Create a 1D array of zeros


>>> print(z)
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
>>> print(z.shape)
(10,)
>>> z=np.zeros((2,3)) #Create a 2D array of zeros
>>> print(z)
608
[[0. 0. 0.]
[0. 0. 0.]]
>>> print(z.shape)
(2, 3)
>>> z=np.zeros([2,2,3], dtype="int16") #Create a 3D
array of zeros
>>> print(z)
[[[0 0 0]
[0 0 0]]

[[0 0 0]
[0 0 0]]]

ones The ones () method creates an array filled with ones of a specified shape. Its
syntax is np.ones(shape, dtype = None, order = 'C'). See the following
examples:

>>> arr=np.ones((2,3)) #Create a 2D array of ones


>>> print(arr)
[[1. 1. 1.]
[1. 1. 1.]]
empty The empty () method creates an array of a specified shape with random values
of its elements based on the state of the memory. Its syntax is
np.empty(shape, dtype = float, order = 'C') . See the following examples:

>>> em=np.empty((3,3)) #Create an empty array


>>> print(em)
[[2.12199579e-314 6.36598737e-314 1.06099790e-313]
[1.90979621e-313 2.33419537e-313 2.75859453e-313]
[3.60739285e-313 4.03179200e-313 4.45619116e-313]]

full The full () method creates an array of a specified shape with a specified value
for all its elements. Its syntax is np.full(shape, fill_value, dtype = None,
order = 'C'). See the following examples:

>>> f=np.full((2,3),4,dtype="float32")
>>> print(f)
[[4. 4. 4.]
[4. 4. 4.]]

609
eye The eye () method creates a diagonal array of a specified shape. Its syntax is
np.eye(shape, dtype = None, order = 'C'). See the following examples:

>>> e=np.eye(3,4) #Create a diagonal matrix


>>> print(e)
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]]
linspace The linspace () method creates a 1D array of evenly spaced numbers for a
given interval. Its syntax is np.linspace(start, stop, num = 50, endpoint =
True, retstep = False, dtype = None), where start is the start of the interval
range, stop is the end of the interval range, num is the number of elements to
be generated (default value is 50). retstep is a flag (default value is False). If
its value is True, the function will return array and step, both. Whereas, if its
value is False, the function will not return the value of step. endpoint is a flag
(default value is True). If it is true, the stop value will be included in the array,
else it will not be included. See the following examples.

>>> np.linspace(0,100, dtype="int16") #Divide the range


in 50 steps as the default vale of num is 50.
array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18,
20, 22, 24,
26, 28, 30, 32, 34, 36, 38, 40, 42, 44,
46, 48, 51,
53, 55, 57, 59, 61, 63, 65, 67, 69, 71,
73, 75, 77,
79, 81, 83, 85, 87, 89, 91, 93, 95, 97,
100], dtype=int16)

>>> np.linspace(1,5,5) #Divide the range in 5 equal


steps
array([1., 2., 3., 4., 5.])
>>> np.linspace(1,5,5, endpoint=False) #Does not include
the step value
array([1. , 1.8, 2.6, 3.4, 4.2])
>>> np.linspace(1,5,5, endpoint=False, retstep=True)
#Return the step size also
(array([1. , 1.8, 2.6, 3.4, 4.2]), 0.8)

610
Example 14.4(a): Creating arrays with the arange () method

import numpy as np #Import the NumPy module


#Default start=0, step=1
arr=np.arange(12) #Create an array from a range data
print("Array:",arr) #Print an array
print("Array shape:",arr.shape) #Print the shape of an array
print("Array element type:", arr.dtype) #Print the element data type

arr=np.arange(12).reshape(3,4) #Create and reshape the array


print("Array:",arr)
print("Array shape:",arr.shape)

arr=np.arange(12).reshape(2,2,3)#Create and reshape the array


print("Array:",arr)
print("Array shape:",arr.shape)

arr=np.arange(10,22,1,"float32") #Create an array with float type


elements
print("Array:",arr)
print("Array element type:", arr.dtype)

arr=np.arange(1,24,2) #Create an array from a range data with a step


size of 2
print("Array:",arr)
print("Array element type:", arr.dtype)

arr=np.arange(1,4,0.5) #Create an array from a range data with a float


step
print("Array:",arr)
print("Array element type:", arr.dtype)

arr=np.arange(24,1,-2) #Create an array from a range data with a


negative step
print("Array:",arr)
print("Array element type:", arr.dtype)

Output
Array: [ 0 1 2 3 4 5 6 7 8 9 10 11]
Array shape: (12,)
Array element type: int32
Array: [[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]

611
Array shape: (3, 4)
Array: [[[ 0 1 2]
[ 3 4 5]]

[[ 6 7 8]
[ 9 10 11]]]
Array shape: (2, 2, 3)
Array: [10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.]
Array element type: float32
Array: [ 1 3 5 7 9 11 13 15 17 19 21 23]
Array element type: int32
Array: [1. 1.5 2. 2.5 3. 3.5]
Array element type: float64
Array: [24 22 20 18 16 14 12 10 8 6 4 2]
Array element type: int32

Converting Python data in Arrays: We can convert Python lists and tuples into
NumPy arrays using the numpy.array(data) and numpy.asarray(data) methods of the
NumPy module. Here, data can be a list or a tuple of homogeneous data elements or another
NumPy array. If the data is a multi-dimensional list or tuple, it must contain an equal
number of elements in an axis. For example, each row of a list must contain the same
number of elements. The list [[1,2,3], [4,5,6]] can be converted to a NumPy array as it
contains an equal number of elements in both rows, whereas, the list [[1,2,3], [4,5]] will
generate an error as the numbers of elements in two rows are not the same. Example 14.4(b)
illustrates the numpy.array() and numpy.asarray() methods to create 1D and multi-
dimensional arrays.

For list and tuple data, both the functions create independent NumPy arrays, but for
a NumPy array data, the numpy.array() creates another independent NumPy array but
numpy.asarray() method creates an alias of the data array, i.e. any changes made in either
the original array or the created array will change both. Example 14.4(c) illustrates this.

Example 14.4(b): Converting Python lists and tuples into NumPy arrays

import numpy as np
lst1=[1,2,3]
arr=np.array(lst1) #Converting a 1D list into a NumPy array
print(arr, "\n")

612
arr1=np.asarray(lst1) #Converting a 1D list into a NumPy array
print(arr1, "\n")

lst2=[[1,2,3],[4,5,6]] #Converting a 2D list into a NumPy array


arr=np.array(lst2)
print(arr, "\n")
arr1=np.asarray(lst2) #Converting a 2D list into a NumPy array
print(arr1, "\n")

lst2=[(1,2,3),(4,5,6)] #Converting a list of tuples into a NumPy array


arr=np.array(lst2)
print(arr, "\n")
arr1=np.asarray(lst2) #Converting a list of tuples into a NumPy array
print(arr1, "\n")

#Converting a list which contains lists and tuples into a NumPy array
lst2=[(1,2,3),[4,5,6]]
arr=np.array(lst2)
print(arr, "\n")
arr1=np.asarray(lst2)
print(arr1, "\n")

tpl=((1,2,3),(4,5,6))#Converting a tuple into a NumPy array


arr=np.array(tpl)
print(arr, "\n")
arr1=np.asarray(tpl)
print(arr1, "\n")

#Converting a tuple which contains lists and tuples into a NumPy array
tpl=([1,2,3],(4,5,6))
arr=np.array(tpl)
print(arr, "\n")
arr1=np.asarray(tpl)
print(arr1, "\n")
Output
[1 2 3]

[1 2 3]

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

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

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

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

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

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

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

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

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

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

Example 14.4(c): Difference between the numpy.array () and numpy.asarray()


methods

import numpy as np
lst1=[1,2,3]
arr=np.asarray(lst1) #Creating an independent copy
arr1=np.asarray(arr) #Creating a linked copy
print(lst1,arr, arr1)
arr[0]=10 #This change will also be in arr1 but not in lst1
arr1[1]=20 #This change will also be in arr
print(lst1,arr,arr1, "\n")

arr=np.array(lst1) #Creating an independent copy


arr1=np.array(arr) #Creating an independent copy

614
print(lst1, arr, arr1)
arr[0]=10 #This change will not affect arr1
arr1[1]=20 #This change will not affect arr1
print(lst1, arr,arr1, "\n")

arr=np.array(lst1) #Creating an independent copy


arr1=np.asarray(arr) #Creating an independent copy
print(lst1, arr, arr1)
arr1[0]=10 #This change will affect arr1
print(lst1, arr,arr1)

Output
[1, 2, 3] [1 2 3] [1 2 3]
[1, 2, 3] [10 20 3] [10 20 3]

[1, 2, 3] [1 2 3] [1 2 3]
[1, 2, 3] [10 2 3] [ 1 20 3]

[1, 2, 3] [1 2 3] [1 2 3]
[1, 2, 3] [10 2 3] [10 2 3]

Using Special Library Functions to create arrays: NumPy has many special library
functions to create arrays, such as arrays of random numbers. Arrays of random numbers
are widely used in scientific and engineering computations. NumPy offers the random
module to work with random numbers. We can import the random module of NumPy by
using the following syntax: from numpy import random. Table 14.2 lists commonly used
special functions to create random number arrays.

Table 14.2: NumPy special functions to create arrays

Method Description

randint The random.randint(a,b,sh=1) method returns an array of random


integers between a (included) and b (excluded) of the shape sh, where a
and b are integers and sh can be an integer or a tuple or a list of positive
integers. Some illustrative examples are given below:

>>> random.randint(0,10)#A random integer between 0 and 10


8
>>> random.randint(10) #By default start point is 0

615
2
>>> random.randint(-5,5) #A random number between -5 and 5
3
>>> random.randint(0,10,5) # 1D array of random integers
array([3, 1, 3, 6, 3])
>>>#Use a tuple to specify the shape of the array
>>>random.randint(0,10,(2,3))
array([[6, 1, 3],
[5, 2, 8]])
>>>#Use a list to specify the shape of the array
>>> random.randint(-5,5,[2,3])
array([[ 4, 1, 1],
[-5, -1, 1]])
rand The random.rand(s1,s2,…,sN) method returns an array of random float
between 0 and 1. The shape of the returned array is specified through the
integers parameters s1,s2,…, sN. All the parameters are optional and by
default, it returns a single random float number. Contrary to the
random.randint () method, we cannot use a tuple or a list to specify the
shape of the returned array. Some illustrative examples of this method are
given below:

>>> random.rand() #Single float random number


0.6476449639230797
>>> random.rand(3) #1D array of random floats
array([0.79008844, 0.82748269, 0.99430981])
>>> random.rand(2,3) #2D array of random floats
array([[0.68910637, 0.6205986 , 0.75173923],
[0.62197815, 0.24170407, 0.2026154 ]])
>>>
choice The choice(arr, size) method generates an array of randomly chosen
numbers from a given 1D array, 1D list, or 1D tuple. The shape of the
returned array is given by the size parameter. If the size parameter is not
given, it returns a randomly selected number for the given array. Some
illustrative examples of this method are given below:

>>> #Randomly choose a number from a list


>>> random.choice([1,2,3,4,5])
5
>>> #Randomly choose a number from a list
>>> random.choice([1,2,3,4,5])
3
>>> #Randomly choose n numbers from a list
>>> random.choice([1,2,3,4,5],3)

616
array([3, 1, 4])
>>> #Randomly choose numbers from a list and return them as
a multi-dimensional array
>>> random.choice([1,2,3,4,5],(2,2))
array([[5, 4],
[3, 4]])
>>> #Randomly choose numbers from a tuple and return them
as an array
>>> random.choice((1,2,3,4,5),5)
array([2, 3, 5, 2, 4])
>>> #Randomly choose numbers from an array and return them
as an array
>>> arr=np.array([1,2,3,4,5])
>>> random.choice(arr)
5

The choice () method can also specify the probabilities of selection of


individual numbers through the p parameter.
>>> #Selecting numbers with the given probabilities
>>> random.choice([1, 2, 3, 4], p=[0.1, 0.3, 0.4, 0.2],
size=(15))
array([4, 1, 1, 1, 3, 2, 3, 3, 2, 3, 2, 4, 2, 3, 3])

shuffle The random.shuffle(arr) method shuffles the elements of the given array
For a multidimensional array, the shuffling is done along the axis=0. See
the following examples.

>>> a=[1,2,3,4,5]
>>> random.shuffle(a) #Shuffles elements of a list
>>> a
[4, 2, 3, 5, 1]
>>> b=np.array((1,2,3,4,5))
>>> random.shuffle(b) #Shuffles elements of an array
>>> b
array([5, 4, 3, 1, 2])
>>> a=np.arange(12).reshape(3,2,2) #Create a multi-
dimensional array
>>> print(a)
[[[ 0 1]
[ 2 3]]

[[ 4 5]
[ 6 7]]

[[ 8 9]

617
[10 11]]]
>>> random.shuffle(a) #Shuffle a multi-dimensional array
>>> print(a)
[[[ 0 1]
[ 2 3]]

[[ 8 9]
[10 11]]

[[ 4 5]
[ 6 7]]]
permutation The random.permutation (seq) method returns a random permutation of
the given sequence.

>>> a=np.array([1,2,3,4,5])
>>> #Create a random permutation of the given sequence
>>> b=random.permutation(a)
>>> b
array([2, 4, 1, 3, 5])

14.5 Attributes of the ndarray Class


The ndarray class has a large number of attributes and methods for processing data
efficiently. Table 14.3 describes commonly used attributes of the ndarray class.

Table 14.3: Commonly use attributes of ndarray objects

Method Description

ndim The attribute ndarray.ndim represents the number of dimensions (axes) of the
ndarray.

>>> arr=np.arange(12).reshape(2,2,3) #Create an array


>>> arr
array([[[ 0, 1, 2],
[ 3, 4, 5]],

[[ 6, 7, 8],
[ 9, 10, 11]]])
>>> arr.ndim #Get the number of dimensions

618
3
shape The attribute ndarray.shape is a tuple of integers representing the size of the
ndarray in each dimension.

>>> arr.shape #Get the shape of an array


(2, 2, 3)
size The attribute ndarray.size is the total number of elements in the ndarray.

>>> arr.size #Get the total number of elements in an array


12
dtype The attribute ndarray.dtype tells the data type of the elements of a NumPy
array. Table 14.4 lists different data types supported by NumPy arrays.

>>> arr.dtype #Get the data type of elements of an array


dtype('int32')
itemsize The attribute ndarray.itemsize tells the size (in bytes) of each element of a
NumPy array.

>>> arr.itemsize #Get the memory size in bytes of each element


of an array
4
strides The attribute ndarrays.strides returns a tuple consisting of strides of various
axes.

>>> arr.strides #Get the strides of each axis in bytes


(24, 12, 4)

Table 14.4: Datatypes supported by NumPy

Datatype Description
bool_ Boolean type (True or False)
int_ Default integer type (either int64 or int32)
intc Equivalent to C int (either int32 or int64)
intp Integer used for indexing (either int32 or int64)
int8 Byte (-128 to 127)
int16 Integer (-32768 to 32767)
int32 Integer (-2147483648 to 2147483647)
int64 Integer (-9223372036854775808 to 9223372036854775807)
uint8 Unsigned integer (0 to 255)

619
uint16 Unsigned integer (0 to 65535)
uint32 Unsigned integer (0 to 4294967295)
uint64 Unsigned integer (0 to 18446744073709551615)
float_ float64
float16 Half precision float: sign bit, 5 bits exponent, 10 bits mantissa
float32 Single precision float: sign bit, 8 bits exponent, 23 bits mantissa
float64 Double precision float: sign bit, 11 bits exponent, 52 bits mantissa
complex_ complex128
complex64 Complex number, represented by two 32-bit floats (real and imaginary
components)
complex128 Complex number, represented by two 64-bit floats (real and imaginary
components)

14.6 Indexing and Slicing NumPy Arrays


Indexing: Elements of an array can be accessed by using indices in each axis of the array.
The index of each axis starts with zero. NumPy arrays also support backward indexing by
using negative indices, for example, the index value -1 represents the last element in that
axis. Technically, a multi-dimensional array is arrays within an array. Hence, we can access
these arrays by giving their indices. If the number of indices given is less than the number
of dimensions of an array, it returns a sub-array. The indices can be given in either within a
square bracket separated by commas or in separate square brackets. Example 14.6(a)
illustrates the above concepts.

Example 14.6(a): Indexing in NumPy arrays

>>> a=np.arange(12).reshape(3,4)
>>> print(a)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> a[0,0] #Accessing the first element of the first row
0
>>> a[0][0] #Using two separate square brackets to access an element
0
>>> a[2,3] #Using a single square bracket to access an element
11
>>> a[-1,-1] #Accessing elements with negative indexing
11

620
>>> a[1] #Accessing a sub-array
array([4, 5, 6, 7])
>>> b=a.reshape(2,2,3)
>>> b
array([[[ 0, 1, 2],
[ 3, 4, 5]],

[[ 6, 7, 8],
[ 9, 10, 11]]])
>>> b[0] #Accessing a sub-array
array([[0, 1, 2],
[3, 4, 5]])
>>> b[1][1] #Accessing a sub-array
array([ 9, 10, 11])

Slicing: Similar to Python collection objects, such as lists, tuples, NumPy arrays also
support slicing. Through slicing, we can get a sub-array of an array. Numpy uses the Python
slicing notations, which has the following syntax: [start: end: step], where start is the
starting index, end is the last index of the original array and step is the increment used to
create the sub array. All the parameters are optional. The default value of start is 0, default
value of end is size of the concerned axis and the default value of step is 1. Example 14.6(b)
illustrates slicing operations.

Example 14.6(b): Slicing in NumPy arrays

>>> import numpy as np


>>> a=np.arange(12)
>>> print(a)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
>>> a[2:5] #Get 2,3,and 4 elements of the array
array([2, 3, 4])
>>> a[:5] #Get the first 5 elements
array([0, 1, 2, 3, 4])
>>> a[5:] #Get all the remaining elements after the fifth element
array([ 5, 6, 7, 8, 9, 10, 11])
>>> a[2:8:3] #Get non-contiguous elements
array([2, 5])
>>> a[::-1] #Get all the elements in the reverse order
array([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
>>> a[::2] #Get all the alternative elements
array([ 0, 2, 4, 6, 8, 10])

621
>>> a[-12:-1:2] #Get alternate elements starting from the 12th from the
end
array([ 0, 2, 4, 6, 8, 10])
>>> a[11:0:-2] #Get alternative elements starting from the 11th in the
reverse order
array([11, 9, 7, 5, 3, 1])
>>> b=np.arange(12).reshape(3,4)
>>> print(b)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> b[1:3,1:3]#Get a slice of 2nd and 3rd rows and 2nd and 3rd columns
array([[ 5, 6],
[ 9, 10]])
>>> #Select alternate elements from each row and each column
>>> c=b[::2,::2]
>>> print(c)
[[ 0 2]
[ 8 10]]
>>> b[1:3,:] #Get 2 and 3 rows
array([[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b[::-1] #Transpose the array in axis-0
array([[ 8, 9, 10, 11],
[ 4, 5, 6, 7],
[ 0, 1, 2, 3]])
>>> b[:,::-1] #Transpose the array in axis-1
array([[ 3, 2, 1, 0],
[ 7, 6, 5, 4],
[11, 10, 9, 8]])

List indexing: For accessing more than one element in an array, we can use lists of indices
for each axis. All the lists used should be of the same size. The elements are accessed by
pairing the first element of each list, then the second and so on. We can also use list for some
axes and slicing for the others. The selected elements are returned as 1D array. Example
14.6(c) illustrates this.

Example 14.6(c): List indexing in NumPy arrays

>>> a=np.arange(10)
>>> ind=[1,4,2,6,5,2]
>>> a[ind] #List indexing
array([1, 4, 2, 6, 5, 2])

622
>>> a=np.arange(9).reshape(3,3)
>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> a[[0,1,2],[0,1,2]] #Select diagonal elements
array([0, 4, 8])
>>> a[[0,0,2,2],[0,2,0,2]] #Select all corner elements
array([0, 2, 6, 8])
>>> a[[0,1,2,2,2],[0,0,0,1,2]] #Select the first column and the last
row
array([0, 3, 6, 7, 8])
>>> a[:,[1,2]] #Combining slicing and list indexing
array([[1, 2],
[4, 5],
[7, 8]])
>>> a[[0,2],:] #Mixing list indexing and slicing
array([[0, 1, 2],
[6, 7, 8]])
>>> a[[0,2,1],:] #Rearranging rows
array([[0, 1, 2],
[6, 7, 8],
[3, 4, 5]])
>>> a[[0,0,1,1,2,2],:] #Repeating rows
array([[0, 1, 2],
[0, 1, 2],
[3, 4, 5],
[3, 4, 5],
[6, 7, 8],
[6, 7, 8]])

Array indexing: Similar to the list indexing, we can use a NumPy array to access multiple
elements from an array. The selected elements are returned in the shape of the index array.
We can use array indexing in a multidimensional array as well, where corresponding
elements are paired to access the elements. Example 14.6(d) illustrates the array indexing.

Example 14.6(d): Array indexing in NumPy arrays

>>> a=np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> ind=np.array([2,3,6,8])
>>> a[ind] #Array indexing
array([2, 3, 6, 8])
623
>>> a[ind[::-1]] #Indexing array can be manipulated
array([8, 6, 3, 2])
>>> ind=np.array([[1,5],[6,8]]) #Multi-dimensional indexing array
>>> a[ind]
array([[1, 5],
[6, 8]])
>>> a=np.arange(12).reshape(3,4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> rows=np.array([0,2])
>>> columns=np.array([1,3])
>>> a[rows,columns] #Array indexing in multi-dimension
array([ 1, 11])
>>> #Multi-dimensional indexing in a multi-dimensional array
>>> ind1=np.array([[0,2],[1,2]])
>>> ind2=np.array([[1,2],[0,2]])
>>> a[ind1,ind2]
array([[ 1, 10],
[ 4, 10]])

Ellipsis indexing: NumPy arrays use ellipsis (…), three dots, to automatically add the
required number of full slice (:) to make the number of the indexing dimensions equal to
the number of axes of the array. We can use only one ellipsis in ellipsis indexing. Example
14.6(e) illustrates the ellipsis indexing. In this example, a [0 ,0, …] is equal to a [0, 0, :, :] and
a[0, …] is equal to a[0, :, :, :].

Example 14.6(e): Ellipsis in NumPy arrays

>>> a=np.arange(24).reshape(2,2,2,3)
>>> a
array([[[[ 0, 1, 2],
[ 3, 4, 5]],

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

[[[12, 13, 14],


[15, 16, 17]],

[[18, 19, 20],

624
[21, 22, 23]]]])
>>> a[0,0,...] #The ellipsis covers the remaining 2 dimensions
array([[0, 1, 2],
[3, 4, 5]])
>>> a[0,...] #The ellipsis covers the remaining 3 dimensions
array([[[ 0, 1, 2],
[ 3, 4, 5]],

[[ 6, 7, 8],
[ 9, 10, 11]]])
>>> a[0,...,0] #The ellipsis covers the middle 2 dimensions
array([[0, 3],
[6, 9]])
>>> a[0:1,...] #Ellipsis with slicing
array([[[[ 0, 1, 2],
[ 3, 4, 5]],

[[ 6, 7, 8],
[ 9, 10, 11]]]])
>>> a[...,1:2] #Ellipsis with slicing
array([[[[ 1],
[ 4]],

[[ 7],
[10]]],

[[[13],
[16]],

[[19],
[22]]]])

Boolean Array Indexing: In the Boolean Array indexing, we use an array of Boolean values
as an indexing array. The values of the array corresponding to the True values in the
indexing array are selected and returned as a 1D array. A Boolean indexing array can be
created using a Boolean expression. Example 14.6(f) illustrates the Boolean array indexing.

Example 14.6(f): Boolean array indexing in NumPy arrays

>>> a=np.random.randint(100,size=10) #Generate 10 random numbers


>>> a
array([57, 25, 67, 79, 40, 47, 88, 42, 43, 59])
>>> b=a<50 #Create a Boolean array
625
>>> b
array([False, True, False, False, True, True, False, True, True,
False])
>>> c=a[b] #Boolean array indexing
>>> c
array([25, 40, 47, 42, 43])
>>> d=a[a<50] #Using Boolean expressions directly for indexing
>>> d
array([25, 40, 47, 42, 43])
>>> a=np.arange(12).reshape(3,4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> b=a%2==0 #Create a 2D Boolean indexing array to select even numbers
>>> b
array([[ True, False, True, False],
[ True, False, True, False],
[ True, False, True, False]])

>>> c=a[b] #Selecting even numbers


>>> c
array([ 0, 2, 4, 6, 8, 10])
>>> #Selecting even numbers but not multiple of 3
>>> #Use np.logical_and() and np.logical_or() methods to combine
Boolean expressions
>>> a[np.logical_and(a%2==0,a%3!=0)]
array([ 2, 4, 8, 10])

14.7 Operations on NumPy Arrays


NumPy has a large number of efficient built-in methods to process NumPy arrays.
We will briefly cover commonly used functionalities. However, interested users can explore
the NumPy manual for other functionalities. NumPy operations can be grouped as
elementwise operations, matrix and linear algebra operations, basic reductions,
broadcasting, array shape manipulation, and sorting data.

14.7.1 Element-wise Operations

In this, operations are performed on each element of the arrays. If an operation


involves more than one array, the shape of the arrays must be the same. However, if an

626
operation involves a scalar and an array, the same scalar is used with all the elements of the
array to perform the operations. Commonly used element-wise operations are arithmetic
operations, logical operations, transcendental operations, etc. Some of these operations can
be performed either through operators or the corresponding methods.

Arithmetic operations: All the Python arithmetic operators can be used with arrays to
perform element-wise arithmetic operations. All the numeric data types including complex
numbers can be processed by NumPy. Example 14.7(a) illustrates some arithmetic
operations.

Example 14.7(a): Arithmetic operations with NumPy arrays

>>> a=np.random.randint(10,size=4)
>>> b=np.random.randint(10,size=4)
>>> print(a,b)
[7 4 6 2] [7 8 8 5]
>>> a+b #Addition of arrays
array([14, 12, 14, 7])
>>> a-b #Subtraction
array([ 0, -4, -2, -3])
>>> a*b #Multilication
array([49, 32, 48, 10])
>>> a/b #Float division
array([1. , 0.5 , 0.75, 0.4 ])
>>> a**b #Power
array([ 823543, 65536, 1679616, 32], dtype=int32)
>>> a+2 #Scalar addition
array([16, 14, 16, 9])
>>> a/2 #Scalar division
array([7. , 6. , 7. , 3.5])
>>> c=a.reshape(2,2)
>>> d=b.reshape(2,2)
>>> print(c)
[[7 4]
[6 2]]
>>> print(d)
[[7 8]
[8 5]]
>>> c+d #Addition
array([[14, 12],
[14, 7]])
>>> c%d #Modulus
array([[0, 4],
[6, 2]], dtype=int32)

627
>>> c+=d #Compound operations
>>> print(c)
[[14 12]
[14 7]]
#Generate NumPy arrays of random complex numbers
>>> Z = np.random.random(3) + np.random.random(3) * 1j
>>> Y = np.random.random(3) + np.random.random(3) * 1j
>>> print(Z)
[0.63094606+0.343771j 0.04810698+0.89952661j 0.11646971+0.11310903j]
>>> print(Y)
[0.42228583+0.09089449j 0.59921329+0.56704785j 0.33460894+0.00751817j]
>>> Z+Y #Addition of complex arrays
array([1.05323189+0.43466549j, 0.64732027+1.46657446j,
0.45107865+0.12062719j])
>>>

Relational and Logical operations: Relational operations such as greater than, less than,
etc, and logical operations such as and, or, etc. can be efficiently performed on arrays. For
logical operations, use np.logical_and() and np.logical_or() methods to perform logical
AND and OR operations element-wise, instead of and and or operators. Example 14.7(b)
illustrates some logical and relational operations on arrays.

Example 14.7(b): Relational and logical operations with NumPy arrays

>>> a = np.array([1, 2, 3, 4])


>>> b = np.array([4, 2, 2, 4])
>>> a==b #Element-wise comparison
array([False, True, False, True])
>>> a>b #Element-wise comparison
array([False, False, True, False])
>>> a<=b #Element-wise comparison
array([ True, True, False, True])
>>> c = np.array([1, 2, 3, 4])
>>> np.array_equal(a,b) #Checking equality of two arrays
False
>>> np.array_equal(a,c) #Checking equality of two arrays
True
>>> np.logical_and(a,b) #Element-wise AND operations
array([ True, True, True, True])
>>> np.logical_or(a<b,a<c) #Element-wise OR operations
array([ True, False, False, False])
>>> np.logical_and(a<=b,a<=c) #Element-wise AND operations

628
array([ True, True, False, True])
>>> np.logical_and(a<=b,True) #Using a scalar logical value
array([ True, True, False, True])

Transcendental and mathematical functions: Numpy has many built-in transcendental


functions, such as sin, cos, log, etc. These functions can handle complex numbers also. The
complete list of transcendental and mathematical functions can be found in NumPy online
documentations. Example 14.7(c) illustrates a few transcendental and mathematical
functions.

Example 14.7(c): Mathematical and transcendental functions for NumPy arrays

>>> a=np.arange(1,5)
>>> a
array([1, 2, 3, 4])
>>> np.sin(a) #Calculate element-wise sine
array([ 0.84147098, 0.90929743, 0.14112001, -0.7568025 ])
>>> np.log(a) #Calculate element-wise natural log
array([0. , 0.69314718, 1.09861229, 1.38629436])
>>> np.log10(a) #Calculate element-wise log base 10
array([0. , 0.30103 , 0.47712125, 0.60205999])
>>> np.exp(a) #Calculate element-wise exponential
array([ 2.71828183, 7.3890561 , 20.08553692, 54.59815003])
>>> #Random integers between -5 and 5
>>> a=np.random.randint(-5,5, size=4)
>>> b=np.random.randint(-5,5, size=4)
>>> c=a+1j*b #Creating an array of complex numbers
>>> print(c)
[-4.-3.j 0.+4.j -5.-4.j -4.+1.j]
>>> np.sin(c) #Calculate sine of complex numbers
array([ 7.61923172 +6.54812004j, 0. +27.2899172j ,
26.18652736 -7.74111755j, 1.16780727 -0.76816276j])
>>> np.log(c) #Calculate natural log of complex numbers
array([1.60943791-2.49809154j, 1.38629436+1.57079633j,
1.85678603-2.46685171j, 1.41660667+2.89661399j])

14.7.2 Matrix and Linear Algebra Functions

The numpy.linalg sub-module of the NumPy module provides all the functionalities
required for linear algebra. Some of the commonly used functions of this module are
described in table 14.3.

629
Table 14.3: Linear algebra functions in NumPy

Function Description

dot The numpy.dot(a, b, out = None) method returns the dot product of a
and b if a and b are vectors. If a and b are matrices, it returns their matrix
multiplication. For higher order arrays, it returns the sum-product over
the last axis of a and the second-to-last axis of b. It can also handle vectors
of complex numbers.

>>> a=np.random.randint(5,size=3)
>>> b=np.random.randint(5,size=3)
>>> print(a,b)
[1 3 3] [4 2 3]
>>> np.dot(a,b) #Calculate the dot product of two vectors
19
>>> a=np.random.randint(5,size=6).reshape(2,3)
>>> b=np.random.randint(5,size=6).reshape(3,2)
>>> print(a)
[[0 3 2]
[0 4 1]]
>>> print(b)
[[2 4]
[1 3]
[2 4]]
>>> np.dot(a,b) #Calculate the matrix multiplication of
two 2D arrays
array([[ 7, 17],
[ 6, 16]])
>>> a=np.random.randint(5,size=8).reshape(2,2,2)
>>> b=np.random.randint(5,size=8).reshape(2,2,2)
>>> print(a)
[[[0 4]
[3 2]]

[[4 4]
[0 4]]]
>>> print(b)
[[[3 4]
[4 4]]

[[2 1]
[4 4]]]

630
>>> np.dot(a,b) #Calculate the dot product of higher
dimension arrays
array([[[[16, 16],
[16, 16]],

[[17, 20],
[14, 11]]],

[[[28, 32],
[24, 20]],

[[16, 16],
[16, 16]]]])
>>> a=2+3j
>>> b=4+5j
>>> np.dot(a,b) #Dot product of vectors
(-7+22j)
vdot The numpy.vdot(a, b) returns the dot product of vectors a and b. If a and
b are arrays of higher dimensions, they are flattened before calculating
the dot product. For vectors of complex numbers, the dot product of the
conjugate of the first vector with the second vector is returned.

>>> a=2+3j
>>> b=4+5j
>>> np.vdot(a,b) #Dot product of the conjugate of a and b
(23-2j)
>>> np.dot(a,b) #Dot product of a and b
(-7+22j)
>>> a=np.array([2,3,6])
>>> b=np.array([4,2,8])
>>> np.vdot(a,b) #Dot product of vectors
62
>>> a=np.arange(4).reshape(2,2)
>>> b=np.arange(4,8).reshape(2,2)
>>> np.vdot(a,b) #Dot product after flattening both a and
b
38
matmul The numpy.matmul(a,b) method returns the matrix multiplication of
two matrices a and b. For higher dimension arrays, it broadcasts the array
like a stack of matrices as elements residing in the last two indexes,
respectively. On the other hand, the numpy.dot(a,b,) method returns the
multiplication as the sum of products over the last axis of the first array
and the second-to-last of the second.(why to discuss this?). Whereas
631
numpy.multiply(a,b,) method returns the element-wise multiplication of
two arrays.

>>> a=np.arange(4).reshape(2,2)
>>> b=np.arange(4,8).reshape(2,2)
>>> a
array([[0, 1],
[2, 3]])
>>> b
array([[4, 5],
[6, 7]])
>>> np.matmul(a,b) #Matrix multiplication of two 2D arrays
array([[ 6, 7],
[26, 31]])
>>> np.dot(a,b) #Matrix multiplication of two 2D arrays
array([[ 6, 7],
[26, 31]])
>>> np.multiply(a,b) #Element-wise multiplication of two
2D arrays
array([[ 0, 5],
[12, 21]])
>>> a=np.arange(8).reshape(2,2,2)
>>> b=np.arange(8,16).reshape(2,2,2)
>>> print(a)
[[[0 1]
[2 3]]

[[4 5]
[6 7]]]
>>> print(b)
[[[ 8 9]
[10 11]]

[[12 13]
[14 15]]]
>>> np.matmul(a,b) #Plane-wise matrix multiplication of
two arrays
array([[[ 10, 11],
[ 46, 51]],

[[118, 127],
[170, 183]]])
>>> np.matmul(a[0],b[0]) #Plane 0
array([[10, 11],
[46, 51
>>> np.matmul(a[1],b[1]) #Plane 1
632
array([[118, 127],
[170, 183]])
>>> np.dot(a,b) #Dot product of two arrays
array([[[[ 10, 11],
[ 14, 15]],

[[ 46, 51],
[ 66, 71]]],

[[[ 82, 91],


[118, 127]],

[[118, 131],
[170, 183]]]])
>>> np.multiply(a,b) #Element-wise multiplication of two
arrays
array([[[ 0, 9],
[ 20, 33]],

[[ 48, 65],
[ 84, 105]]])
>>>
det >>> a=np.random.randint(5,size=9).reshape(3,3)
>>> a
array([[1, 2, 2],
[3, 2, 1],
[2, 0, 4]])
>>> np.linalg.det(a) #Calculate the determinant of a
matrix
-20.000000000000007
>>> a=np.random.randint(5,size=12).reshape(3,2,2)
>>> a
array([[[0, 4],
[1, 3]],

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

[[2, 0],
[2, 3]]])
>>> np.linalg.det(a) #Calculate the determinant of each
sub-matrix
array([-4., -7., 6.])

633
solve The numpy.linalg.solve(A, B) method solves a system of linear equations
of the form AX=B, where A is the coefficient square matrix and B is the
constant vector. For the following system of linear equations:

𝑥+𝑦+𝑧 = 3
2𝑥 + 3𝑦 + 𝑧 = 6
𝑥 + 𝑦 + 5𝑧 = 7

>>> A=np.array([[1,1,1],[2,3,1],[1,1,5]])
>>> B=np.array([3,6,7])
>>> print(A)
[[1 1 1]
[2 3 1]
[1 1 5]]
>>> print(B)
[3 6 7]
>>> X=np.linalg.solve(A,B) #Solve a system of linear
equations
>>> print(X)
[1. 1. 1.]
inv The numpy.linalg.inv(a) method finds the multiplicative inverse of an
array. If the array is of more than two dimensions, the inverses of the
matrices formed by the last two axes are calculated. The last two axes
must for a square matrix.

>>> A=np.array([[1,1,1],[2,3,1],[1,1,5]])
>>> print(A)
[[1 1 1]
[2 3 1]
[1 1 5]]
>>> np.linalg.inv(A) #Inverse of a matrix
array([[ 3.5 , -1. , -0.5 ],
[-2.25, 1. , 0.25],
[-0.25, 0. , 0.25]])
>>> A=np.random.randint(5,size=8).reshape(2,2,2)
>>> A
array([[[3, 3],
[4, 3]],

[[4, 4],
[1, 2]]])
>>> np.linalg.inv(A) #Plane-wise inverse of an array
array([[[-1. , 1. ],
[ 1.33333333, -1. ]],

634
[[ 0.5 , -1. ],
[-0.25 , 1. ]]])

14.7.3 Reduction Operations on Arrays

Any operation that reduces the number of dimensions of an array is known as


reduction operations, for example, mean, standard deviation, minimum, maximum, sum,
etc. These operations are typically performed along an axis of the array, such as along the
row, along the column, along the third dimension, along the nth dimension, etc. The NumPy
module has many methods to perform a variety of reduction operations. During a reduction
operation, the operation is performed in the specified axis. If we do not specify an axis, the
global reduction is performed and the result is a scalar. Table 14.4 discusses some
commonly used reduction operations.

Table 14.4: Commonly used reduction operations in NumPy

Function Description

sum The numpy.sum(a, axis=None) method sums the elements of the array
in the specified axis. The method can also be called with the array
object, such as a.sum(axis=0). In no axis is specified, all the elements
will be summed.

>>> a=np.arange(12).reshape(3,4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> a.sum(axis=0) #Sum elements along an axis
array([12, 15, 18, 21])
>>> np.sum(a, axis=1) #Sum elements along an axis
array([ 6, 22, 38])
>>> a.sum() #Sum all the elements. Global reduction
66
mean The numpy.mean(a, axis=None) method finds the mean of the
elements in the specified axis.

>>> a.mean(axis=0) #Find means along an axis


array([4., 5., 6., 7.])

635
>>> a.mean(axis=1)
array([1.5, 5.5, 9.5])
>>> np.mean(a) #Find global mean
5.5
std The numpy.std(a, axis=None) method finds the standard deviation of
the elements in the specified axis.

>>> a.std(axis=0) #Calculate standard deviation along an


axis
array([3.26598632, 3.26598632, 3.26598632, 3.26598632])
max The numpy.max(a, axis=None) method finds the maximum of the
elements in the specified axis.

>>> a=np.random.randint(100, size=12).reshape(3,4)


>>> a #Array of random integers
array([[94, 40, 97, 10],
[40, 37, 60, 75],
[94, 51, 74, 72]])
>>> a.max(axis=0) #Find maximum along an axis
array([94, 51, 97, 75])
min The numpy.min(a, axis=None) method finds the minimum of the
elements in the specified axis.

>>> a.min(axis=0) #Find minimum along an axis


array([40, 37, 60, 10])
argmax The numpy.argmax(a, axis=None) method finds the index of the
maximum of the elements in the specified axis.

>>> a.argmax(axis=0) #Find the index of the maximum along


an axis
array([0, 2, 0, 1], dtype=int64)
>>> a.argmax(axis=1)
array([2, 3, 0], dtype=int64)
>>> a.ravel() #Flatten the array
array([94, 40, 97, 10, 40, 37, 60, 75, 94, 51, 74, 72])
>>> a.argmax() #Index of the maximum in flattened view
>>> a.max() #Global maximum
97
argmin The numpy.argmin(a, axis=None) method finds the index of the
minimum of the elements in the specified axis.

>>> a.argmin(axis=1)
array([3, 1, 1], dtype=int64)
636
>>> a.ravel() #Flatten the array
array([94, 40, 97, 10, 40, 37, 60, 75, 94, 51, 74, 72])
>>> a.argmin() #The index of the minimum in the flattened
view
3
reduce The numpy.add.reduce(a, axis=0) sums the elements in a specified
axis.

>>> np.add.reduce(a) #Sum along axis=0 by default


array([228, 128, 231, 157])
>>> np.add.reduce(a, axis=1) #Sum along the specified axis
array([241, 212, 291])

accumulate The numpy.add.accumulate(a, axis=0) returns progressive cumulative


sum of the elements in a specified axis.

>>> #Progessive cumulative sum along axis=0 by default


>>> np.add.accumulate(a)
array([[ 94, 40, 97, 10],
[134, 77, 157, 85],
[228, 128, 231, 157]], dtype=int32)
>>> #Progessive cumulative sum along the specified axis
>>> np.add.accumulate(a, axis=1)
array([[ 94, 134, 231, 241],
[ 40, 77, 137, 212],
[ 94, 145, 219, 291]], dtype=int32)

14.7.4 Broadcasting NumPy Arrays

Typically, NumPy elementwise operations on arrays can be performed on arrays of


equal shape. However, if certain conditions meet, NumPy can stretch some dimensions, by
repeating a dimension of the lower-dimension array, to make two arrays of the same shape
to perform arithmetic operations. Following are the rules for the broadcasting:

1. An array with the size of dimension in an axis equal to 1 can be stretched to match the
other array in the same axis.
2. An array can be stretched in more than one axis if it meets the above criterion.

Figure 14.4 graphically illustrates the concept of the broadcasting. The elements written
in the solid boxes are the original array and the elements in the dotted boxes are the
broadcasted elements. Example 14.7(d) illustrates the broadcasting concept.

637
1 2 3 + 5 5 5 = 6 7 8
(a) Broad casting with a scalar

1 2 3 1 2 3 2 4 6
4 5 6 + 1 2 3 = 5 7 9
7 8 9 1 2 3 8 10 12
(b) Broadcasting with a vector

1 1 1 1 2 3 2 3 4
2 2 2 + 1 2 3 = 3 4 5
3 3 3 1 2 3 4 5 6
(c) Broadcasting with two vectors

Figure 14.4: Broadcasting

Example 14.7(d): Broadcasting with NumPy arrays

>>> a=np.arange(1,4).reshape(1,3)
>>> a
array([[1, 2, 3]])
>>> a+5 #Broadcasting with a scalar
array([[6, 7, 8]])
>>> a.shape
(1, 3)
>>> print(a, a.shape)
[[1 2 3]] (1, 3)
>>> b=np.arange(1,10).reshape(3,3)
>>> print(b,b.shape)
[[1 2 3]
[4 5 6]
[7 8 9]] (3, 3)
>>> b+a #Broadcasting with a matrix and a vector
array([[ 2, 4, 6],
[ 5, 7, 9],
[ 8, 10, 12]])
>>> c=a.T
>>> print(c, c.shape)
[[1]
[2]

638
[3]] (3, 1)
>>> a+c #Broadcasting with a row vector and a column vector
array([[2, 3, 4],
[3, 4, 5],
[4, 5, 6]])
>>> a=np.arange(8).reshape(2,2,2)
>>> print(a)
[[[0 1]
[2 3]]

[[4 5]
[6 7]]]
>>> b=np.array([[1,2],[3,4]])
>>> print(b)
[[1 2]
[3 4]]
>>> a+b #Broadcasting in multi-dimensional arrays
array([[[ 1, 3],
[ 5, 7]],

[[ 5, 7],
[ 9, 11]]])

14.7.5 Array Shape Manipulation

A NumPy array can be reshaped, resized and axes can be flipped depending on the
requirement in a situation. Table 14.5 list commonly used array shape manipulation
methods.

Table 14.5: Commonly used array shape manipulation methods

Function Description

reshape The numpy.reshape(arr, new_shape) method returns an array with a


new compatible shape. The shape of the original array does not change.
Two shapes are compatible if both shapes contain the same number of
elements. The method is frequently used with the syntax
arr.reshape(new_shape).

>>> a=np.arange(8)
>>> print(a) #Original array
[0 1 2 3 4 5 6 7]

639
>>> b=a.reshape(2,4) #Reshaped array
>>> print(b)
[[0 1 2 3]
[4 5 6 7]]
>>> c=np.reshape(a,(2,2,2)) #Reshaped array
>>> print(c)
[[[0 1]
[2 3]]

[[4 5]
[6 7]]]
>>> print(a.shape, b.shape,c.shape) #Shapes of arrays
(8,) (2, 4) (2, 2, 2)
ravel The numpy.ravel(arr, order="C") method returns a flattened 1D array.
The shape of the original array does not change.

>>> a=np.arange(12).reshape(3,4) #Original array


>>> print(a)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
>>> b=a.ravel() #Flattened array
>>> print(b)
[ 0 1 2 3 4 5 6 7 8 9 10 11]
>>> print(a.shape, b.shape)
(3, 4) (12,)
transpose The numpy.transpose(arr, axes_order=None) method returned a
transposed array based on the order of axes given by axes_order. The
length of the axes_order tuple must be equal to arr.ndim. Instead of a
tuple, we can also specify the new axes order by arr.dim integers. If we
do not provide axes_order, the order of all the axes is revered, i.e., the
current axes order (0, 1, …, n) will be made (n, n-1, …, 0), which is
equivalent to arr.T flag. It has no effect on 1-D arrays.

>>> a=np.arange(12).reshape(3,4) #Original array


>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> a.transpose() #Transposed array
array([[ 0, 4, 8],
[ 1, 5, 9],
[ 2, 6, 10],
[ 3, 7, 11]])

640
>>> b=a.reshape(2,2,3) #Reshaped array
>>> b
array([[[ 0, 1, 2],
[ 3, 4, 5]],

[[ 6, 7, 8],
[ 9, 10, 11]]])
>>> #Transposing an array in given axes order. Only axes 1
and 2 are swaped
>>> c=b.transpose((0,2,1))
>>> c
array([[[ 0, 3],
[ 1, 4],
[ 2, 5]],

[[ 6, 9],
[ 7, 10],
[ 8, 11]]])
>>> b.transpose(2,1,0) #All the axes are swapped
array([[[ 0, 6],
[ 3, 9]],

[[ 1, 7],
[ 4, 10]],

[[ 2, 8],
[ 5, 11]]])
>>>
>>> b.T # Using T flag to transpose all axes
array([[[ 0, 6],
[ 3, 9]],

[[ 1, 7],
[ 4, 10]],

[[ 2, 8],
[ 5, 11]]])
resize The numpy.resize(a, new_shape) returns a new array with the specified
shape. If the new array is larger than the original array, then the new
array is filled with repeated copies of a. However, the
a.resize(new_shape) syntax resizes the original array itself and fills the
extra new elements created due to resize with zeros. It is recommended
to use numpy.reshape() if the number of elements in the original and the
new arrays are the same.

641
>>> a=np.arange(6).reshape(2,3)
>>> a #Original array
array([[0, 1, 2],
[3, 4, 5]])
>>> b=np.resize(a,(3,4)) #Use the repeated copies of the
original array
>>> b #Resized array
array([[0, 1, 2, 3],
[4, 5, 0, 1],
[2, 3, 4, 5]])
>>> a.resize((3,4), refcheck=False) #Fill the extra
elements with zero
>>> a #Original but resized array
array([[0, 1, 2, 3],
[4, 5, 0, 0],
[0, 0, 0, 0]])
>>> #For the reduced size, extra tail elements are
discarded
>>> c=np.resize(a,(2,2))
>>> print(c)
[[0 1]
[2 3]]
pad The numpy.pad(arr, pad_width, mode='constant', **kwargs) enlarges an
array by padding values at the end of each axis. By default, it uses zero
as the padding value. However, there are other values, such as a constant
value, edge values, maximum of the axis, etc. can be used. See online help
for greater details.

>>> a=np.arange(9).reshape(3,3) #Original array


>>> print(a)
[[0 1 2]
[3 4 5]
[6 7 8]]
>>> np.pad(a,2) #Pad each axis with two zeros at both ends
of the axis
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 2, 0, 0],
[0, 0, 3, 4, 5, 0, 0],
[0, 0, 6, 7, 8, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
>>> #Pad each axis with one zero at the start and 2 zeros
at the end the axis
642
>>> np.pad(a,(1,2))
array([[0, 0, 0, 0, 0, 0],
[0, 0, 1, 2, 0, 0],
[0, 3, 4, 5, 0, 0],
[0, 6, 7, 8, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
>>> #Pad each axis with one edge element at both ends of
the axis
>>> np.pad(a,1,'edge')
array([[0, 0, 1, 2, 2],
[0, 0, 1, 2, 2],
[3, 3, 4, 5, 5],
[6, 6, 7, 8, 8],
[6, 6, 7, 8, 8]])
>>> #Pad with a constant value instead of zero
>>> np.pad(a,1,constant_values=9)
array([[9, 9, 9, 9, 9],
[9, 0, 1, 2, 9],
[9, 3, 4, 5, 9],
[9, 6, 7, 8, 9],
[9, 9, 9, 9, 9]])
>>> np.pad(a,2, 'maximum') #Pad with the maximum values of
each axis
array([[8, 8, 6, 7, 8, 8, 8],
[8, 8, 6, 7, 8, 8, 8],
[2, 2, 0, 1, 2, 2, 2],
[5, 5, 3, 4, 5, 5, 5],
[8, 8, 6, 7, 8, 8, 8],
[8, 8, 6, 7, 8, 8, 8],
[8, 8, 6, 7, 8, 8, 8]])

14.7.6 Sorting Data

The numpy.sort(a, axis=-1, kind=None, order=None) return a sorted copy of an array. By


default, an array is sorted along the last axis. However, we can specify the axis along which
we want to sort an array through the parameter axis. If the parameter axis is None (cannot
be used with a.sort() syntax) , then the array is flattened and then sorted. The parameter
kind specifies the sorting algorithm to be used. The supported algorithms are quicksort,
mergesort, heapsort, and stable. The order parameter is used with the structured array. The
sorting of an array is done in place. Example 14.7(e) illustrates the sorting of NumPy arrays.

643
Example 14.7(e): Sorting NumPy arrays

>>> a=np.random.randint(100,size=12).reshape(3,4)
>>> a #Original array
array([[50, 50, 31, 37],
[48, 78, 68, 96],
[11, 14, 41, 81]])
>>> a.sort() #Sort in place along the last axis, i.e. along the row
>>> a
array([[31, 37, 50, 50],
[48, 68, 78, 96],
[11, 14, 41, 81]])
>>> a.sort(axis=0) #Sort in place along axis=0
>>> a
array([[11, 14, 41, 50],
[31, 37, 50, 81],
[48, 68, 78, 96]])
>>> b=np.sort(a,axis=None) #Return sorted flattened array
>>> b
array([11, 14, 31, 37, 41, 48, 50, 50, 68, 78, 81, 96])
>>> a
array([[11, 14, 41, 50],
[31, 37, 50, 81],
[48, 68, 78, 96]])

14.8 Structured NumPy Arrays


Though NumPy is designed to efficiently store and process a homogeneous array of
values, it provides features to store and process compound, heterogeneous data. Consider
a situation where we want to store several categories of data of many people (say, name,
age, and weight), which we can store in three separate arrays:

name = ['Alice', 'John', 'Boby', 'Den']


age = [20, 40, 35, 15]
weight = [65.0, 85.0, 70.0, 40.5]

However, the above way to store data shows that there is no relationship among
data. A NumPy structured array can be used to store such data in a more meaningful
manner. Structured arrays are ndarrays whose compound datatype consists of a tuple of
named fields and their datatypes. A compound data type can be created using the following

644
methods: (a) using a list of tuples of field names and the corresponding data types, (b) using
a dictionary with two keys 'names' and 'formats' for field names and data types,
respectively, and (c) using a string, when the fild names are not important.

The syntax of the first method is as given below:

dtype=np.dtype([(field1, format1), field2, format2),… , fieldN, formatN)])

the syntax of the second method is as given below:

dtype= np.dtype({'names':(field1, filed2, …, fieldN), 'formats':(format1, format2,


…, formatN)})

and the syntax of the third method is as given below:

dytpe= np.dtype('format1, format2, …, formatN')

where field1,field2, …, fieldN and format1, format2,…, formatN are strings. A format string
consists of an alphabet and a number, for example, 'i4', 'S10', 'f8', etc. The alphabet indicates
the type of data. Various valid alphabets are given in table 14.6 along with their data types.
The number in a format string is the size of the data in bytes, for example, 'S10' means string
data type of 10 characters long 'i4' meand 4 byte integer. Optionally, a format string can be
prefixed with < or >, which means "little-endian" or "big-endian," respectively, and specifies
the ordering convention for significant bits.

For the example data given above, the compound datatype is defined using the three
methods are as given below:

(a) dtype = np.dtype([('name', 'S10'), ('age', 'i4'), ('weight', 'f8')])


(b) dtype = np.dtype('S10,i4,f8')
(c) dtype = np.dtype({'names':('name', 'age', 'weight'), 'formats':('U10', 'i4', 'f8')})

Once a compound data type is defined, it can be used to create a structured array.
In a structured array, data can be accessed using either a field name or the corresponding
integer index, similar to normal arrays. Example 14.8(a) illustrates the creation and

645
manipulation of a structured array. The creation of a compound data type and array
creation can be combined in one step. Example 14.8(b) illustrates this.

Table 14.6: Formatting string characters and their corresponding data types

Character Description Example


'b' Byte np.dtype('b')
'i' Signed integer np.dtype('i4') == np.int32
'u' Unsigned integer np.dtype('u1') == np.uint8
'f' Floating point np.dtype('f8') == np.int64
'c' Complex floating point np.dtype('c16') == np.complex128
'S', 'a' String np.dtype('S5')
'U' Unicode string np.dtype('U') == np.str_

Example 14.8(a): Structured NumPy arrays

>>> name = ['Alice', 'John', 'Boby', 'Den'] #Creating a normal array


>>> age = [20, 40, 35, 15]
>>> weight = [65.0, 85.0, 70.0, 40.5]
>>> #Creating a compound data type using tuples
>>> dtype = np.dtype([('name', 'S10'), ('age', 'i4'), ('weight',
'f8')])
>>> data=np.zeros(4,dtype=dtype) #Creating a skeleton structured array
>>> print(data) #Skeleton structured array
[(b'', 0, 0.) (b'', 0, 0.) (b'', 0, 0.) (b'', 0, 0.)]
>>> data['name']=name #Populating fields
>>> data['age']=age
>>> data['weight']=weight
>>> print(data) #Populated structured array
[(b'Alice', 20, 65. ) (b'John', 40, 85. ) (b'Boby', 35, 70. )
(b'Den', 15, 40.5)]
>>> #Creating a compound data type using a string
>>> dtype1 = np.dtype('S10,i4,f8')
>>> data1=np.zeros(4,dtype=dtype1) #Creating a skeleton structured
array
>>> dtype1
dtype([('f0', 'S10'), ('f1', '<i4'), ('f2', '<f8')])
>>> data1['f0']=name #Populating fields
>>> data1['f1']=age
>>> data1['f2']=weight
>>> data1

646
array([(b'Alice', 20, 65. ), (b'John', 40, 85. ), (b'Boby', 35, 70. ),
(b'Den', 15, 40.5)],
dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<f8')])
>>> #Creating a compound data type using a dictionary
>>> dtype2 = np.dtype({'names':('name', 'age', 'weight'),
'formats':('U10', 'i4', 'f8')})
>>> data2=np.zeros(4,dtype=dtype2)
>>> data2['name']=name #Populating fields
>>> data2['age']=age
>>> data2['weight']=weight
>>> data2
array([('Alice', 20, 65. ), ('John', 40, 85. ), ('Boby', 35, 70. ),
('Den', 15, 40.5)],
dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f8')])
>>> data[0] #Accessing using an index
(b'Alice', 20, 65.)
>>> data[0][0] #Accessing using indices
b'Alice'
>>> print(data[0][0],data[0][1],data[0][2])
b'Alice' 20 65.0
>>> data['name'] #Accessing using a field name
array([b'Alice', b'John', b'Boby', b'Den'], dtype='|S10')
>>> data['age']
array([20, 40, 35, 15])
>>> data['weight']
array([65. , 85. , 70. , 40.5])
>>> print(data['name'][0]) #Hybrid accessing
b'Alice'

Example 14.8 (b): Directly creating a structured NumPy arrays

>>> #Creating a structured array directly


>>> data=np.array([('John',20,60),('Jack',30,50),('Jill',25,45)],
dtype=("S10,i4,i4"))
>>> data
array([(b'John', 20, 60), (b'Jack', 30, 50), (b'Jill', 25, 45)],
dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<i4')])
>>> np.sort(data) #Sorting a structured array
array([(b'Jack', 30, 50), (b'Jill', 25, 45), (b'John', 20, 60)],
dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<i4')])
>>> np.sort(data,order=['f1','f0']) #Sorting a the specified field
order
array([(b'John', 20, 60), (b'Jill', 25, 45), (b'Jack', 30, 50)],
dtype=[('f0', 'S10'), ('f1', '<i4'), ('f2', '<i4')])

647
Sample Program 14.1: Write a program to add a border of zeros to a square matrix

Solution Steps:
1. Use pad method of NumPy module to add a border
import numpy as np # Import the NumPy package
m=3
n=1
array = np.ones((m, m)) # Creating a mXm Numpy matrix
print("Original array")
print(array)
print("\nMatrix with 0 border")
# using np.pad()
array = np.pad(array, pad_width=n, mode='constant',constant_values=0)
print(array)
Output
Original array
[[1. 1. 1.]
[1. 1. 1.]
[1. 1. 1.]]

Matrix with 0 border


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

Sample Program 14.2: Write a program to count zero and non-zero values in an array

Solution Steps:
1. Use count_nonzero method to get non zero elements
2. Use the size attribute to get the total elements in the array
import numpy as np #Import NumPy module
arr = np.array([[0, 1, 4, 3, 0], [0, 3, 8, 0, 7]]) #Original array
n = np.count_nonzero(arr) #Count non-zero elements
print ("Number of non zero elements:", n)
print("Number of zeros:", arr.size-n) #Number of zeros
Output
Number of non zero elements: 6
Number of zeros: 4
648
Sample Program 14.3: Write a program to remove leading and trailing zeros of a 1D
array.
Solution Steps:
1. Use trim_zero method to remove leading and trailing zeros
import numpy as np #Import NumPy module
arr = np.array([0,0,1,2,3,0]) #Original array
arr1 = np.trim_zeros (arr) #Remove leading and training zeros
print("Original array:", arr)
print("Trimmed array:",arr1)
Output
Original array: [0 0 1 2 3 0]
Trimmed array: [1 2 3]

Sample Program 14.4: Write a program to replace all the negative values in an array with
zero.
Solution Steps:
1. Use less than conditional operator, <, to generate a Boolean index matrix and use that
matrix to replace the negative values with zeros
import numpy as np #Import NumPy module
array1 = np.array([[1, 2, -3],[4, -5, -6]])
print("Original array:\n", array1)
# Code to replace all negative value with 0
array1[array1<0] = 0
print("Resulting array: \n", array1)
Output
Original array:
[[ 1 2 -3]
[ 4 -5 -6]]
Resulting array:
[[1 2 0]
[4 0 0]]

Sample Program 14.5: Write a program to remove all the columns containing non-
numeric values.
Solution Steps:

649
1. Use np.isnan method along with any method to locate the columns with non numeric
values. The n.nan method generates a Boolean index array.
import numpy as np # Import Numpy module
# Create 3X3 2-D Numpy array with non-numeric data
n_arr = np.array([[10, 22, 10, 23],
[41, 52, 25, np.nan],
[20, np.nan, 41, 31]])

print("Given array:")
print(n_arr)

print("\nRemove all columns containing non-numeric elements ")


print(n_arr[:, ~np.isnan(n_arr).any(axis=0)])

Output
Given array:
[[10. 22. 10. 23.]
[41. 52. 25. nan]
[20. nan 41. 31.]]

Remove all columns containing non-numeric elements


[[10. 10.]
[41. 25.]
[20. 41.]]

Sample Program 14.6: Write a program to get row indices of all the rows of a matrix
where rows contain a value greater than a given value.
Solution Steps:
1. Use numpy.where method and numpy.any method to identify the rows with values
grater than the specified value.
import numpy #Import NumPy Module
# Original array
arr = numpy.array([[1, 2, 3, 4, 5],
[7, -3, 20, 4, 5],
[3, 2, 4, -4, 1],
[9, 7, 34, 6, 0]
])
X = 6 # Specified value
print("Original Array:\n", arr)
# finding out the row numbers
output = numpy.where(numpy.any(arr > X, axis = 1))

650
print("Result:\n", output)
Output
Original Array:
[[ 1 2 3 4 5]
[ 7 -3 20 4 5]
[ 3 2 4 -4 1]
[ 9 7 34 6 0]]
Result:
(array([1, 3], dtype=int64),)

Sample Program 14.7: Write a program to create an array of normally distributed random
numbers
Solution Steps:
1. Import numpy.matlib to access randn method which generates the Normally
distributed random numbers.
import numpy as np #Import NumPy module
import numpy.matlib #Import numpy.matlib module

#Generate normally distributed random numbers of size 3 x 4


out_mat = np.matlib.randn((3, 4))
print ("Output matrix : ", out_mat)
Output
Output matrix : [[-1.04731334 0.21140059 0.0130174 0.92720196]
[-0.72350616 -0.83381002 0.76856087 0.75590594]
[-0.55050013 0.10951671 -1.26743009 -0.59185711]]

Sample Program 14.8: Write a program to get the first k smallest values from a 2D array.

Solution Steps:
1. Flatten the 2D array using ravel method
2. Use sort method to sort the flattened array
3. Print the first k values.
import numpy as np #Import NumPy module
mat1=np.array([[1,5,2,3],[7,2,0,3]]) #2D array
arr1=np.ravel(mat1)#Flatten the matrix
arr1=np.sort(arr1) #Sort the flattened array
k=3
print("Original matrix:\n",mat1)
print("The first k smallest values:",arr1[:k])#Print the first k values
651
Output
Original matrix:
[[1 5 2 3]
[7 2 0 3]]
The first k smallest values: [0 1 2]

Chapter Summary

1. NumPy (Numerical Python) is an open-source Python package for efficiently


processing multidimensional arrays.
2. It is primarily used for mathematical and logical operations on arrays, shape
manipulation of arrays, linear algebra, random number generations, Fourier
transforms, etc.
3. we can install NumPy using the pip install numpy command.
4. An NumPy array, formally called ndarray, is an ordered collection of
homogeneous data elements.
5. An array is stored in contiguous memory, using a single identifier. An individual
data element is referenced using indexing.
6. NumPy is written in C. Hence, very fast in processing arrays as compared to
Python lists.
7. NumPy arrays can be stored as C-contiguous or F-contiguous style similar to C
or FORTRAN, respectively.
8. Elements of an array can be accessed by using indices in each axis of the array.
The index of each axis starts with zero.
9. NumPy arrays also support backward indexing by using negative indices, for
example, the index value -1 represents the last element in that axis.
10. Technically, a multi-dimensional array is array within an array.
11. The indices can be given in either within a square bracket separated by commas
or in separate square brackets.
12. Similar to Python collection objects, such as lists, tuples, NumPy arrays also
supports slicing.
13. Through slicing, we can get a sub-array of an array.

652
14. The syntax of the slicing is [start: end: step], where start, end and step are
optional and have default values, 0, size of the concerned axis and 1, respectively.
15. We can use lists of indices for accessing multiple non-contiguous elements from
a NumPy array.
16. Similar to the list indexing, we can use a NumPy array to access multiple
elements from an array.
17. The Boolean Array indexing is used to return elements corresponding to true
entry in Boolean indexing array.
18. NumPy operations can be grouped as elementwise operations, matrix and linear
algebra operations, basic reductions, broadcasting, array shape manipulation,
and sorting data.

Multiple Choice Questions

1. What does NumPy stand for?


(a) Numerical Python
(b) Natural Python
(c) Numeric Program
(d) Nonlinear Python

2. What is the default data type of NumPy arrays?


(a) int32
(b) float64
(c) int132
(d) float32

3. Which of the following is widely used for scientific computations?


(a) SciPy
(b) NumPy
(c) Matlab
(d) All of the above

4. Which of the following is not true about a NumPy array?


(a) It stores homogeneous data only

653
(b) It can have only three dimensions
(c) It is stored in a contiguous memory
(d) Indexing can be used to access individual elements

5. Which of the following is not true about NumPy arrays?


(a) NumPy is written in C
(b) NumPy supports multidimensional array
(c) Slicing cannot be used to access elements in the array
(d) Elements of an array can not be used by an ordered tuple

6. Which of the following is not true about a NumPy array?


(a) Data of the array can be stored in C style array
(b) Data of the array can be stored in FORTRAN style array
(c) The data is stored in contiguous memory
(d) All of the above

7. Which of the following is an attribute of the data structure of the NumPy


array?
(a) dtype
(b) itemsize
(c) size
(d) all of the above

8. Which of the following is an attribute of the data structure of the NumPy


array?
(a) data
(b) shape
(c) strides
(d) all of the above

9. Which of the following can be used to create a NumPy array?


(a) arange
(b) zeros
(c) empty
(d) all of the above

10. Which of the following is used to create a diagonal array in NumPy?

654
(a) eye
(b) empty
(c) full
(d) None of the above

11. Which of the following is not true about the array indexing?
(a) Indexing starts with 0
(b) Indexing starts with 1
(c) -1 can be used in indexing
(d) The indices can be given either within a square bracket separated by
commas or in separate square brackets

12. Which of the following is true about the slicing for NumPy arrays?
(a) Syntax of slicing is [start: end: step]
(b) In slicing, start, end and step are optional
(c) The default value of start is 0
(d) all of the above

13. Which of the following is true about indexing?


(a) Lists can be used for indexing
(b) Ellipsis can be used for indexing
(c) Array can be used for indexing
(d) All of the above

14. Which of the following is not an array reduction operation?


(a) sum
(b) mean
(c) std
(d) None of the above

15. Which of the following can be used to change the shape of an array?
(a) reshape
(b) ravel
(c) resize
(d) All of the above

16. What is the output of the following code?


import numpy as np

655
a = np.arange(6)
print(a[2:-2])

(a) [2 3]
(b) [1 2]
(c) [2]
(d) None of the above

17. What is the output of the following code?

import numpy as np
a = np.array([[1, 2], [3, 4]])
print(a.ndim)

(a) 2
(b) 2,2
(c) 1
(b) None of the above

18. What is the output of the following code?


import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.stack((a, b))
print(c)

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


(b) [[1, 2, 3], [4, 5, 6]]
(c) [1, 2, 3, 4, 5, 6]
(d) Error

19. What is the output of the following code?


import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c=a*b
print(c)

656
(a) [ 4 10 18]
(b) 32
(c) 90
(d) None of the above

20. Which of the following function is used to find the index of the maximum
element in a NumPy array?

(a) argmax
(b) max
(c) amax
(d) None of the above

21. What is the output of the following code?


import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.dot(a, b)
print(c)

(a) [[19, 22], [43, 50]]


(b) [[5, 6], [7, 8], [1, 2], [3, 4]]
(c) [[1, 5], [2, 6], [3, 7], [4, 8]]
(d) The dot function is not defined

22. What is the output of the following code?

import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.vstack((a, b))
print(c)

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


(b) [[1, 4], [2, 5], [3, 6]]
(c) [1, 2, 3, 4, 5, 6]
(d) The vstack is not defined

657
23. What is the output of the following code?

import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
c = np.concatenate((a, b))
print(c)

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


(b) [[1, 4], [2, 5], [3, 6]]
(c) [1, 2, 3, 4, 5, 6]
(d) The concatenate function is not defined

24. Which of the following is used to find the inverse of a matrix, m, in NumPy?

(a) np.linalg.inv(m)
(b) m.inverse()
(c) m.inv()
(d) inv(m)

25. What is the output of the following code?


import numpy as np
a = np.array([[1,2,3],[0,1,4]])
print (a.size)

(a) 6
(b) [2,3]
(c) [3,2]
(d) None of the above

Review Questions

1. State whether the following statements are true or false:


a. NumPy stands for Numerical Python.
b. NumPy is widely used for scientific computations.
c. NumPy array is an ordered collection of heterogeneous data elements.

658
d. NumPy is written in C programming language.
e. NumPy array index starts with 1.
f. Each dimension of an array is called axis.
g. C- contiguous and F-contiguous are two approaches to store data in a
NumPy array.
h. The shape of an array can be changed by using metadata without changing
the actual array data.
i. The arange method creates a multi-dimensional array from a range.
j. The empty method creates an array of a specified shape with garbage
values of its elements based on the state of the memory.
k. The eye method creates a diagonal array of a specified shape.
l. The linspace method creates a 1D array of evenly spaced numbers for a
given interval and the number of items.
m. The default value of number of elements in linspace is 50.
n. The random.randint(a, b, sh=1) method returns an array of random
integers between a (included) and b (included).
o. NumPy arrays can store and process complex numbers.
p. The index value -1 is an invalid value for an axis.
q. We cannot use slicing in NumPy to get a sub-array.
r. For accessing noncontiguous multiple elements in an array, we can use lists
of indices for each axis.
s. Ellipsis (…) can be used for indexing.
t. NumPy permits Boolean arrays for indexing.
u. The numpy.argmax(a, axis=None) method finds the maximum element in
the specified axis.

659
v. NumPy uses broadcasting to perform elementwise operations on two
arrays of different shapes.
w. Structured NumPy Arrays can be used to store and process compound and
heterogeneous data.

Programming Assignments

1. Write a program to add two matrices.

2. Write a program for the matrix multiplication and elementwise multiplication of


two matrices.

3. Write a program to generate 5x5 matrix of random integers between 0 and 100.

4. Write a program to generate 100 normally distributed random numbers.

5. Write a program to horizontally stack two matrices.

6. Write a program to create a 5x2 integer array of random numbers where the
difference between any two column elements is more than 5.

7. Write a program to list all the 2D diagonals of a 3D array.

8. Write a program to add border of n zeros in a square matrix of size m.

9. Write a program to sum leading diagonal elements of a matrix.

10. Write a program to count frequency of unique values in an array.

11. Write a program to calculate determinant of a matrix.

12. Write a program to calculate matrix multiplication of two matrices of complex


numbers.

13. Write a program to calculate elementwise multiplication of two matrices of


complex numbers.

660
14. Write a program to replace all the values in an array greater then n by m.

15. Write a program to find QR decomposition of a given matrix using NumPy.

16. Write a program to create an array of random numbers of size NxM between 10
and 100.

17. Write a program to create an array of Gaussian distributed random numbers of


size NxM with mean= 0 and standard deviation = 1.

661
662
Chapter 15

Introduction to Matplotlib
Learning outcomes

1. Understand the features of Matplotlib


2. Learn steps to create a plot in Python using Matplotlib
3. Create various types of plots
4. Learn to customize plots
5. Learn to create subplots

Visualization of data helps to determine patterns in the data and is an important tool in
engineering and scientific computations and research. Matplotlib is a widely used cross-
platform data visualization, and graphical plotting library of the Python programming
language. It can be used for creating static, animated, and interactive visualizations of data.
Typically, Matplotlib is used along with NumPy, SciPy, and many other packages for
creating a variety of plots, such as Line Plot, Bar Plot, Scatter Plot, Histogram, etc. It also
provides functions to create variety of 3D plots. This chapter briefly introduces the basic
functionalities of Matplotlib. The Matplotlib module can be installed using the pip install
Matplotlib command. Before using it, we have to import it in our program using any one
of the following syntaxes: from matplotlib import pyplot as plt or import
matplotlib.pyplot as plt. Most of the Methods of the Matplotlib module has a number of
parameters to customize the methods. However, in this brief introduction to the Matpotlib
module, we will only discuss the commonly used parameters of the commonly used
methods. For other methods and parameters, we encourage readers to see the online
documentation of the module. Figure 15.1 shows the common components of a plot.

15.1 Steps to Create a Plot in Matplotlib

Following are the typical steps to create a plot in Matplotlib:


1. Prepare data to be ploted. For a 2D plot, define the x-axis values and the
corresponding y-axis values. We can use lists or NumPy arrays to store data.
Similarly, for a 3D plot, such as 3D surface plot, 3D mesh,, etc. we create a meshgrid
of x and y values and the corresponding z values.

663
2. Create the plot using a built-in plotting function, such as plot(), scatter(),
histogram(), bar(), contour3D(), plot_surface(), etc, from the Matplotlib module. The
Matplotlib module has a big list of plotting functions for different types of plots. We
can plot more than one series of data in a single plot by either calling plot functions
more than once or giving more than one data set to the same function.
3. Customize the plot by creating labels for various axes, creating the plot title and sub-
title, creating a grid, creating legends, etc. The Matplotlib module has many buit-in
functions, such as xlabel(), ylabel(), title(), etc., to meet the specific customization
requirement. There are more than 100 parameters through which we can achieve the
required appearance of a plot.
4. Show the plot. Plots are created in the memory and finally we use the show() method
to show it on the screen. We can also save the plot into different formats in a file for
future uses.

Figure 15.1: Common components of a plot

Example 15.1 illustrates the creation of a simple 2D plot.

664
Example 15.1(a)

import matplotlib.pyplot as plt #Import mappaltlib module


x = [1,2,3,4,5,6] #x axis values
y = [1,4,2,6,3,8] #The corresponding y axis values
plt.plot(x, y) #Plot the points
plt.xlabel('x - axis') #Label the x axis
plt.ylabel('y - axis') #Label the y axis
plt.title('A Line Plot!')#Give a title to the graph
plt.show() # Show the plot
Output

665
15.2 The plot Method
The plot() method, which creates a line plot, is one of the most widely used methods
in the Matplotlib module. It has the following syntax:

matplotlib.pyplot.plot([x], y, [fmt], *, data=None, **kwargs)

matplotlib.pyplot.plot([x], y, [fmt], [x2], y2, [fmt2], ..., **kwargs)

where x and x2 are x-coordinate values, y and y1 are y coordinate values, fmt and fmt2 are
formatting strings for plots, and kwargs are optional keyword-value parameters. The
formatting string has the following syntax:

fmt = '[marker][line][color]'

where, marker is a character that represents a symbol, such as a triangle, square, circles,
etc., to be plotted at data points, see table 15.1 for marker symbols; line is a set of characters
used to create different line styles, such as solid line, dash line, etc. and color is a character
that creates lines of different colors, see table 15.2 for different line styles and line colors.
The default color of a Matplotlib plot is blue and line type is solid line. By default, no morker
for the data points is used. For example, fmt= 'v-.r' will create a plot with a red-colored
dash-dot line with downward triangle markers at each data point. Example 15.2(a)
illustrates the above.

Table 15.1: Some characters used as markers in the plot function

Marker Description Marker Description


'.' Point marker 'p' Pentagon marker
',' Pixel marker 'P' Plus (filled) marker
'o' Circle marker '*' Star marker
'v' Triangle down marker 'h' Hexagon1 marker
'^' Triangle up marker 'H' Hexagon2 marker
'<' Triangle left marker '+' Plus marker
'>' Triangle right marker 'x' X marker
'8' Octagon marker 'X' X (filled) marker
's' Square marker 'D' Diamond marker
'|' Vertical line marker 'd' Thin_diamond marker
'_' Horizontal line marker

666
Table 15.2: Characters used as line style and color in the plot function

Line style Line color


character description character color
'-' Solid line style 'b' Blue
'--' Dashed line style 'g' Green
'-.' Dash-dot line style 'r' Red
':' Dotted line style 'c' Cyan
'm' Magenta
'y' Yellow
'k' Black
'w' White

Example 15.2(a): Setting marker, line style and color of a plot

import matplotlib.pyplot as plt #Import mappaltlib module


x = [1,2,3,4,5,6] #x axis values
y = [1,4,2,6,3,8] #The corresponding y axis values
plt.plot(x, y, 'v-.r') #Plot the points
plt.show() # Show the plot
Output

667
The plot() method is typically used to visualize functions of the form y = f(x), where,
x is a set of values of x-coordinates, in ascending order, and y is the corresponding y
coordinate values. We can plot more than one line plot in a single plot by providing more
than one set of x and y values. Either we can use a separate plot method for each set of data
or we can use a single plot method to plot different sets of data. We can set different
markers, line styles, and colors for a different set of data. Example 15.2(b) illustrates plots
of y=x2 and y=x2-10 for the values of x in the range of -5 to 5 with a step size of 1.

Example 15.2(b): Multiple plots in a plot

import matplotlib.pyplot as plt #Import mappaltlib module


import numpy as np #Import numpy module
x = np.arange(-5,6) #x axis values
y = x*x #The corresponding y values for the first plot
y1=y-10 #The corresponding y values for the second plot
plt.plot(x, y1,'o-g', x,y, 'x--b') #Plotting the points
plt.title('Plots of y=x^2 and y=x^2-10')#Giving a title to the graph

668
plt.show() # Show the plot
The code below will produce the same result as the above code
import matplotlib.pyplot as plt #Import mappaltlib module
import numpy as np #Import numpy module
x = np.arange(-5,6) #x axis values
y = x*x #The corresponding y axis values
y1=y-10
plt.plot(x, y1,'o-g') #Plot the first set of data
plt.plot(x,y, 'x--b') #Plot the second set of data
plt.title('Plots of y=x^2 and y=x^2-10')#Giving a title to the graph
plt.show() # Show the plot

Output

669
15.3 Creating sub-plots
We can create a number of subplots in a figure and each subplot can have different
types of plots and different types of appearances with the subplots () method, which has
the following syntax:

fig, ax =matplotlib.pyplot.subplots(nrows=1, ncols=1, *, sharex=False,


sharey=False, squeeze=True, subplot_kw=None, gridspec_kw=None, **fig_kw)

where nrows and ncols are integers and control the numer of rows and the number of
columns , respectively, of subplots. The default values of these parameters is 1. Other
parameters are used to control the properties of subplots. The function returns handle of
the figure as fig and an NumPy array, ax, of all the axes of the subplots. For subplots
consisting of multi-rows and multiple-columns, the array will be 2D. Each subplot will have
an independent plot. The figsize parameter can be used to control the size of the figure. We
can use the fig.tight_layout() method to automatically maintains the proper spaces between
subplots. However, we can use the plt.subplots_adjust(left=0.1,bottom=0.1,
right=0.9,top=0.9,wspace=0.3,hspace=0.4) method to customise the spaces between
Matplotlib subplots. The parameters wspace and hspace specify the gaps between the
columns and rows of subplots, respectively. The values of these parameters are the fraction
of the average width and the average height of subplots, respectively. And the parameters
left, right, top and bottom parameters specify four sides of the subplots’ positions. The
values left and right are the fractions of the figure width and values top and bottom are the
fractions of the figure height. Example 15.3 illustrates the subplots() method.

Example 15.3: Sub-plots

import matplotlib.pyplot as plt


fig,axs = plt.subplots(2,2) #Create sub-plots
import numpy as np
x = np.arange(1,30)
fig.suptitle("Creating sub-plots") #Super title
axs[0][0].plot(x,x*x) #Create the first sub-plot
axs[0][0].set_title('square') #Title of the first sub-plot
axs[0][0].set_xlabel('x',loc='right')
axs[0][0].set_ylabel('y')
axs[0][1].plot(x,np.sqrt(x)) #Create the second sub-plot
axs[0][1].set_title('square root') #Title of the second sub-plot
axs[0][1].set_xlabel('x', y='left')
axs[0][1].set_ylabel('y')
axs[1][0].plot(x,np.exp(x)) #Create the third sub-plot

670
axs[1][0].set_title('exp') #Title of the first sub-plot
axs[1][0].set_xlabel('x')
axs[1][0].set_ylabel('y')
axs[1][1].plot(x,np.log10(x)) #Create the fourth sub-plot
axs[1][1].set_title('log') #Title of the first sub-plot
axs[1][1].set_xlabel('x')
axs[1][1].set_ylabel('y')
#fig.tight_layout() #Automatically adjust the gaps among subpots
plt.subplots_adjust(left=0.1,bottom=0.1,
right=0.9,top=0.9,wspace=0.3,hspace=0.4)
plt.show()
Output

671
15.4 Customizing a Plot
We can customise a plot by adding additional details as as axes labels, the plot title
and sub-title, creating grids, creating axes ticks, etc. using various buit-in methods. We will
describe commonly used methods in this section.

15.4.1 Adding Axis Labels and Plot Titles

We can label x-axis by the xlable() method, y-axis by the ylabel() method. These
method have the following syntaxes:

matplotlib.pyplot.xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)

matplotlib.pyplot.ylabel(ylabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)

where, xlabel and ylabel are strings use to label the axes. The parameter loc controls the
location of the label and it can take the flowing values: 'left', 'center', 'right'. The default is
'center'.

If we are using axes object to create a sub-plot, we can use the following functions
for axes labelling:

axes.set_xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)

axes.set_ylabel(ylabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)

We can give a title and a sub-title to a plot by the sutitle() and title () methods. The title()
method has the following syntax:

matplotlib.pyplot.title(title, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)

where title is a string, which is used as the title of the plot. The parameter loc controls the
horizontal location of the title and it can take any of the following values: 'left', 'center',
'right'. The default is 'center'. The parameter y controls the vertical location of the title. The
value y=0 is the bottom and y=1 is the top of the plot. The values of y are on the figure
coordinate system, which has values in the range of 0 and 1, for both x and y axes.

If we are using axes object to create a sub-plot, we can use the following functions
to insert a title:

672
axes.set_title(label, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)

We can add a super title by the suptitle () method which has the following syntax:

matplotlib.pyplot.suptitle(title, **kwargs)

where title is a string storing the main title of the plot. The location of the main title is
controlled through the parameters x and y, which has default values of 0.5 and 0.98 in the
figure coordinates. Additionally, we can use the ha parameter for the horizontal allignment
and the va parameter for the vertical alignment. The ha parameter can be set to 'center',
'left', or 'right' and the default is 'center'. Similarly, the va parameter can be set to 'top',
'center', 'bottom', 'baseline' and the default is 'top'.
We can use fig object returned by the subplots() method to give a super title to a plot, which
has the following syntax:

fig.suptitle(t, **kwargs)

Example 15.4(a) illustrates how to label axes and give a title and a super title to a
plot. See example 15.3(b) above which uses axes object and figure object to label axes and to
give title to each plot and to give super title to the plot.

Example 15.4(a): Axes labels and plot title

import matplotlib.pyplot as plt #Import mappaltlib module


import numpy as np #Import numpy module
x = np.linspace(0,2*np.pi,50) #Generate x-axis values
y = np.sin(x) #Generate y axis values
plt.plot(x, y,'o-g') #Plot the data
plt.xlabel("x-values", loc='right') #Add x axis label
plt.ylabel("y-values", loc='center') #Add y axis label
plt.title('Title:A Plot of y=sin(x)')#Give a title to the plot
plt.suptitle("Super Title: A Line Plot") #Give a super title
plt.show() # Show the plot
Output

673
15.4.2 Adding a Grid to a Plot

We can add a grid to a plot using the grid () method, which has the following syntax:

matplotlib.pyplot.grid(b=None, which='major', axis='both', **kwargs)

where the b parameter can take True, False or None. To show a grig, we set b=True. The
which parameter takes any value from 'major', 'minor',and 'both'. The value 'both' will
show both major and minor grids. The axis parameter takes any value from 'both', 'x', and
'y'. The value 'both' will create grids for both x and y axes. We can also set the color, linestyle
and line width of grid lines through the respective parameters. The default values are
color='r', linestyle='-', and linewidth=2.

Similarly, we can use the grid () method of the axis object to set gids for sub-plots,
which has the following syntax:

674
axes.grid(self, b=None, which='major', axis='both', **kwargs)

Example 15.4(b) illustrates setting of grids in sub-plots.

Example 15.4(b): Grids in subplots

import matplotlib.pyplot as plt


fig,axs = plt.subplots(2,2, squeeze=False)
import numpy as np
x = np.arange(1,30)
fig.suptitle("Creating grids in sub-plots")
axs[0][0].plot(x,x*x)
axs[0][0].set_title('Default grid')
axs[0][0].grid(True) #Setting default grid
axs[0][1].plot(x,np.sqrt(x))
axs[0][1].set_title('Green grid')
axs[0][1].grid(True, color='g') #Setting green color grid
axs[1][0].plot(x,np.exp(x))
axs[1][0].set_title('Only y grid')
axs[1][0].grid(True, axis='y') #Setting only y grid
axs[1][1].plot(x,np.log10(x))
axs[1][1].set_title('No grid') #No grid
axs[1][1].grid(b=False)
plt.subplots_adjust(left=0.1,bottom=0.1,
right=0.9,top=0.9,wspace=0.3,hspace=0.4)
plt.show()
Output

675
15.4.3 Adding ticks and tick-labels

Ticks are values shown on an axis of a plot. They a very helpful in reading the plot.
Matplotpli automatically puts ticks on various axis. Matplotlib's default ticks and its
formatting are generally acceptable in most situations. However, we can customise ticks
and tick-labels with the following methods:

axes.set_xticks(ticks, *, minor=False
axes.set_xticklabels(labels, *, fontdict=None, minor=False, **kwargs)
axes.set_yticks(ticks, *, minor=False
axes.set_yticklabels(labels, *, fontdict=None, minor=False, **kwargs)

where, ticks is a list of axis values where ticks lables will be shown, labels is a list of values
which will be shown as ticks. Example 15.3(c) illustrates customidation of ticks.

676
Example 15.3(c): Customizing axis ticks

import matplotlib.pyplot as plt


import numpy as np
fig,axs = plt.subplots(1,2, figsize=(6,3))
x = np.arange(0,6,0.2)
fig.suptitle("Creating axis ticks")
#Use default axis ticks
axs[0].plot(x,np.sin(x))
axs[0].set_title('Default ticks')
axs[0].grid(True)

#Use customised axis ticks


axs[1].plot(x,np.sin(x))
axs[1].set_title('Customised ticks')
axs[1].set_xticks([0,2,4,6]) #Axis tick values
axs[1].set_xticklabels(['zero','two','four','six']) #Axis tick labels
axs[1].grid(True)
fig.tight_layout() #Automatically adjust the gaps among sub-plots
plt.show()
Output

677
15.3.4 Adding Legends

The legend in a plot is a tool to describe the meaning of various lines and symbols
used in the plot. It is specifically very useful in a plot that consists of many series of data.
Legends are used to describe various data series. We can use the legend() method of
matplotlib to add a legend in a plot, which has the following syntax:

matplotlib.pyplot.legend([legend1,legend2, …, legendN], bbox_to_anchor=(x, y),


loc=location)

where legend1, legend2, …, legendN are the labels of various legends, loc is the location of
the legend on the plot. It can take any one of the following values: 'best', 'upper right', 'upper
left', 'lower left', 'lower right', 'right', 'center left', 'center right', 'lower center', and 'upper
center', and 'center'. The 'best' option places the legend at the location, among the other nine
locations, with the minimum overlap with plots. The location of the legend can also be
decided by the parameter bbox_to_anchor, where x=0 indicates the left border, x=1
indicates the right border, y=0 indicates the bottom border and y=1 indicates the top border
of the plot.

We can also use the legend() method of the axes object to create legends in subplots,
which has the following syntax:

axes.legend(self, *args, **kwargs)

Example 15.4(d) illustrates the creation of legends in sub-plots.

Example 15.4(d): Adding legends in sub-plots

import matplotlib.pyplot as plt


fig,axs = plt.subplots(2,2, squeeze=False)
import numpy as np
x = np.arange(0,6,0.2)
fig.suptitle("Creating legends in sub-plots")
axs[0][0].plot(x,np.sin(x))
axs[0][0].set_title('Legend default')
axs[0][0].grid(True)
axs[0][0].plot(x,np.cos(x))
axs[0][0].legend(['square','root']) #Create a default legend

678
axs[0][1].plot(x,np.sin(x))
axs[0][1].set_title('Legend lower right')
axs[0][1].grid(True)
axs[0][1].plot(x,np.cos(x))
axs[0][1].legend(['square','root'], loc='lower right')

axs[1][0].plot(x,np.sin(x))
axs[1][0].set_title('Legend lower left')
axs[1][0].grid(True)
axs[1][0].plot(x,np.cos(x))
axs[1][0].legend(['square','root'], loc='lower left')

axs[1][1].plot(x,np.sin(x))
axs[1][1].set_title('Legend upper left')
axs[1][1].grid(True)
axs[1][1].plot(x,np.cos(x))
axs[1][1].legend(['square','root'], loc='upper left')
plt.subplots_adjust(left=0.1,bottom=0.1,
right=0.9,top=0.9,wspace=0.3,hspace=0.4)
plt.show()
Output

679
15.3.5 Twin axis

Sometimes, we plot more than one curves in a plot which has different units or
scales. We use the twin axis concept to include additional axis for such plots. We use the
method Axes.twinx() to create the second y-axis that shares the same x-axis with the origil
y-axis. Similarly, we can create the second x-axis by using the Axes.twiny() method.
Example 15.3(e) illustrates the twin-axis concept.

Example 15.3(e): Twin-axis

import numpy as np
import matplotlib.pyplot as plt
t = np.arange(0.01, np.pi*2, 0.001)
data1 = np.exp(t)
data2 = np.cos(0.4 * np.pi * t)
data3 = np.sin(0.4 * np.pi * t)

680
fig, ax1 = plt.subplots() #Create axis and figure
ax1.set_xlabel('time (s)')
ax1.set_ylabel('exp', color = 'r') #Customize the first y-axis
ax1.plot(t, data1, color = 'r') #Plot the first curve
ax1.tick_params(axis ='y', labelcolor = 'r')
ax2 = ax1.twinx() #Create a second y axis which will share the same x-
axis
ax2.set_ylabel('cos', color = 'g') #Customize the second y-axis
ax2.plot(t, data2, color = 'g') #Plot the second curve
ax2.tick_params(axis ='y', labelcolor = 'g')
fig.legend(labels = ('exp','cos'),loc='lower right')#Add legend
fig.suptitle('Twin axis', fontweight ="bold")
fig.tight_layout() #Automatically adjust the gaps among sub-plots
plt.show()
Output

681
15.4 Bar Charts
A bar chart is used to present categorical data with rectangular bars with heights or
lengths proportional to the values of the data. Bar charts can be simple, grouped or stacked
charts. In a grouped bar chart, rectangles are grouped together, whereas in a stacked bar
chart, rectangles are stacked one over other. The bars can be plotted vertically or
horizontally. Vertical bar charts are created with the bar() method and horizontal bar charts
are created using the barh() method. The syntaxes of these two methods are as given below:

matplotlib.pyplot.bar(x, height, width=0.8, bottom=None,*, align='center', **kwargs)

where x is the location of bars on the x-axis, height is the value of the data, width is the
width of bars (default is 0.8), bottom is the y-value of the bottom of the boars (default is 0)
and align is the alignment of the bar at x values. If x is non-numeric, bars are evenly
distributed along the x-axis.

matplotlib.pyplot.barh(y, width, height=0.8, left=None, *, align='center', **kwargs)

where y is the location of bars on the y-axis, width is the value of the data, height is the
height of bars (default is 0.8), left is the x-value of the left of the boars (default is 0) and align
is the alignment of the bar at y values. If y is non-numeric, bars are evenly distributed along
the y-axis.

Example 15.4(a) illustrates various types of vertical bar charts and figure 15.4(b)
illustrates various types of horizontal bar charts.

We can create a polar bar plot in Matplotlib by setting the polar property of the axes
object to true, with the following syntax:

ax = matplotlib.pyplot.axes(polar=True)

Example 15.4(c) illustrates a polar bar plot.

Example 15.4(a): Various types of bar charts

import numpy as np
import matplotlib.pyplot as plt
fig,axs = plt.subplots(1,3)

682
# creating the dataset
x=np.array([1,2,3,4])
course_names = ['C','C++','Java','Python']
no_students = np.array([15,40,25,50])
no_jobs =np.array([14,35,20,45])
boys=np.array([10,30,20,25])
girls=no_students-boys
#Creating a column bar plot
axs[0].bar(course_names, no_students, color ='red',width = 0.25)
axs[0].set_xlabel("Courses offered")
axs[0].set_ylabel("No. of students enrolled")
axs[0].set_title("Simple bar chart")
axs[0].grid(True)
#Creating a column grouped bar plot
axs[1].bar(x, no_students, color ='red',width = 0.25)
axs[1].bar(x+.25, no_jobs, color ='green',width = 0.25)
axs[1].set_xlabel("Courses offered")
axs[1].set_ylabel("No. of students enrolled and placed")
axs[1].set_title("Grouped bar chart")
axs[1].set_xticks(x) #Axis tick values
axs[1].set_xticklabels(course_names) #Axis tick labels
axs[1].legend(['Registred','Placed'])
#Creating a column stacked bar plot
axs[2].bar(x, boys, color ='red',width = 0.25)
axs[2].bar(x, girls, color ='green', bottom=boys, width = 0.25)
axs[2].set_xlabel("Courses offered")
axs[2].set_ylabel("No. of boys and girls enrolled")
axs[2].set_title("Stacked bar chart")
axs[2].set_xticks(x) #Axis tick values
axs[2].set_xticklabels(course_names) #Axis tick labels
axs[2].legend(['Boys','girls'])
fig.suptitle("Different types of column bar charts")
fig.tight_layout()
plt.show()
Output

683
Example 15.4(b): Various types of horizontal bar charts

import numpy as np
import matplotlib.pyplot as plt
fig,axs = plt.subplots(1,3)
# creating the dataset
x=np.array([1,2,3,4])
course_names = ['C','C++','Java','Python']
no_students = np.array([15,40,25,50])
no_jobs =np.array([14,35,20,45])
boys=np.array([10,30,20,25])
girls=no_students-boys
#Creating a horizontal bar plot
axs[0].barh(course_names, no_students, color ='red',height = 0.25)
axs[0].set_ylabel("Courses offered")
axs[0].set_xlabel("No. of students enrolled")
axs[0].set_title("Simple bar chart")
axs[0].grid(True)
#Creating a horizontal grouped bar plot
axs[1].barh(x, no_students, color ='red',height = 0.25)
axs[1].barh(x+.25, no_jobs, color ='green',height = 0.25)

684
axs[1].set_ylabel("Courses offered")
axs[1].set_xlabel("No. of students enrolled and placed")
axs[1].set_title("Grouped bar chart")
axs[1].set_yticks(x) #Axis tick values
axs[1].set_yticklabels(course_names) #Axis tick labels
axs[1].legend(['Registred','Placed'])
#Creating a horizontal stacked bar plot
axs[2].barh(x, boys, color ='red',height = 0.25)
axs[2].barh(x, girls, color ='green', left=boys, height = 0.25)
axs[2].set_ylabel("Courses offered")
axs[2].set_xlabel("No. of boys and girls enrolled")
axs[2].set_title("Stacked bar chart")
axs[2].set_yticks(x) #Axis tick values
axs[2].set_yticklabels(course_names) #Axis tick labels
axs[2].legend(['Boys','girls'])
fig.suptitle("Different types of horizontal bar charts")
fig.tight_layout()
plt.show()
Output

Example 15.4(c): A polar bar chart

import numpy as np
import matplotlib.pyplot as plt

685
ax = plt.axes(polar=True) #Set polar coordinate system
N = 10 #Number of bars
theta = np.arange(0.0, 2 * np.pi, 2 * np.pi / N)
radii = np.random.randint(0,10,size=10)#Random radii of bars
width = np.pi / 4 * np.random.rand(N) #Random widht of bars
bars = plt.bar(theta, radii, width=width, bottom=0.0)#Bar plot
#Setting color of each bar based on the radii
for r,bar in zip(radii, bars):
bar.set_facecolor(plt.cm.jet(r/10.))
#Label axes
ax.set_xticklabels(['0','45','90','135','180','225','270'])
ax.set_yticklabels([1,2,3,4,5,6,7,8,9])
plt.show()# Show chart
Output

686
15.6 Histogram Plots

A histogram is a frequency/percentage distribution of data. It is like a bar chart,


where data range is divided into bins and each bin is represented by a rectangle and the
height of the rectangle represents the count/percentage of data falling in the corresponding
bin. We use the hist() method to plot a histogram, which has the following syntax:

matplotlib.pyplot.hist(x, bins=None, range=None, density=False, weights=None,


cumulative=False, bottom=None, histtype='bar', align='mid',
orientation='vertical', rwidth=None, log=False, color=None, label=None,
stacked=False, *, data=None, **kwargs)

The important parameters are x, which contains the data, and bins, which sets the
number of bins (default is 10) to be created for the histogram plot. The function returns
frequency of each bin, which can be used to create a line plot over the histogram. For the
other parameters, please see the online documentations. Example 15.5(a) illustrate the
creation of a histogram plot. The hist() method also returns the individual patches of a
histogram, which we can use to assign different colors to different patched. Example 15.5(b)
illustrates the creation of a colored histogram.

Example 15.5: A histogram plot

import matplotlib.pyplot as plt


import numpy as np
# Generate normally distributed random numbers
#np.random.seed(23685752)
x = np.random.randn(10000)
n=20 #Number of bins
fig, axs = plt.subplots(1, 1, tight_layout = True)
# Creating histogram plot, it returns the frequency of each bin.
f, bins, patches=axs.hist(x, bins = n)
l=np.min(x)
m=np.max(x)
x1=np.linspace(l,m,n)
axs.plot(x1,f,'r') #Creating a line plot over the histogram
axs.set_xlabel('x')
axs.set_ylabel('Frequency')
axs.set_title("Histogram plot")
axs.grid(True)
plt.show() # Show plot
Output

687
Example 15.5(b): A colored histogram plot

import matplotlib.pyplot as plt


import numpy as np
# Generate normally distributed random numbers
#np.random.seed(23685752)
x = np.random.randn(10000)
n=20 #Number of bins

fig, axs = plt.subplots(1, 1, tight_layout = True)


# Creating histogram plot, it returns the frequency of each bin.
f, bins, patches=axs.hist(x, bins = n)
m=np.max(f) #Get the maximum frequency
c=plt.cm.jet(f/m)#Generate color in proportion to the frequency

for c1, p1 in zip(c, patches):


#color = c1
p1.set_facecolor(c1) #Assign color to each patch
688
axs.set_xlabel('x')
axs.set_ylabel('Frequency')
axs.set_title("Colored histogram plot")
plt.show() # Show plot
Output

15.7 Pie Chart

A pie chart is a pictorial represention of data in the form of slices of a circle. The sizes
of slices are in proportion to the values of data. We create a pie chart in Matplotlib using the
pie() method, which has the following syntax:

matplotlib.pyplot.pie(x, explode=None, labels=None, colors=None,


autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=0,
radius=1, counterclock=True, wedgeprops=None, textprops=None, center=0, 0,
frame=False, rotatelabels=False, *, normalize=None, data=None)

689
where x is the data to be plotted. Other parameters are used to control the appearance of a
plot. For details about the other parameters, please refer online documentations of the
matplolib module. Example 15.6 illustrates different types of pie charts.

Example 15.6: Pie charts

import numpy as np
import matplotlib.pyplot as plt
fig,axs = plt.subplots(1,2)
#Create data
course_names = ['C','C++','Java','Python']
no_students = np.array([15,40,25,50])
explode = (0, 0.1, 0, 0) #Explode the 2nd slice
color=['red','green','blue','cyan'] #Define colors
axs[0].pie(no_students,labels=course_names) #Default pie chart
axs[0].set_title("Default Pie chart")
#Customised pie chart
axs[1].pie(no_students,labels=course_names, explode=explode,
colors=color)
axs[1].set_title("Exploded Pie chart")
fig.suptitle("Different types of Pie charts")
plt.show()
Output

690
15.8 Scatter Plots
A scatter plot plots relationship between two variables in the form of dots in a
castesian coordinate system. This is typically used to observe and visualise patterns in large
number of data. In this chart, we can have more than one value of the dependent variable
for the same value of the independent variable. We use scatter method to plot a scatter plot
in Matplotlib, which has the following syntax:

matplotlib.pyplot.scatter(x, y, s=None, c=None, marker=None, cmap=None,


norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, *,
edgecolors=None, plotnonfinite=False, data=None, **kwargs)

where x and y are the pair of data to be plotted. We can control the size and color of dots
through the s and c parameters respectively. We can control transparency of colors by the
alph parameter. Other parameters are used to customise the appearance of a scatter plot.
See online documentation for their details. Example 15.7 illustres different types of scatter
plots.

Example 15.5(b): A colored scatter plot

import matplotlib.pyplot as plt


import numpy as np

# Generate random data


x = np.random.rand(50)
y = np.random.rand(50)
colors = np.random.rand(50)
sizes = 100 * np.random.rand(50)

# Create a colored scatter plot


plt.scatter(x, y, c=colors, s=sizes, alpha=0.7, cmap='viridis')

# Add title and axis labels


plt.title("Colored Scatter Plot")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")

# Display color scale


plt.colorbar(label='Color Scale')

691
# Show the plot
plt.show()
Output

15.9 Contour Plots


A contour plot is used to show a three-dimensional surface on a two-dimensional
plane by using different colors or curves of different colors to represent the third dimension.
It plots a surface of the form z=f(x,y). The independent variables x and y are a rectangular
grid, which is created by the numpy.meshgrid() method. The contour() and contourf()

692
functions are used to create curve contours and filled contours plots, respectively, which
have the following syntaxes:

matplotlib.pyplot.contourf([X, Y,] Z, [levels], **kwargs)

matplotlib.pyplot.contour([X, Y,] Z, [levels], **kwargs)

where X and Y are meshgrid points and Z is the corresponding values at each grid point.
The parameter levels decides the number of contour curves in a contour plot or the number
of color shades used to plot a filled contour plot. Example 15.8 illustrates the creation of a
curve contour plot and a filled contour plot.

Example 15.8: Contour plots

import numpy as np
import matplotlib.pyplot as plt
xlist = np.linspace(-3.0, 3.0, 100)
ylist = np.linspace(-3.0, 3.0, 100)
#Create a meshgrid from x and y values
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2) #Calculate Z values at each mesh grid
fig,ax=plt.subplots(1,2)
#Create a filled contour plot
cp1 = ax[0].contourf(X, Y, Z, levels=10)
fig.colorbar(cp1, ax=ax[0]) # Add a colorbar to a plot
ax[0].set_title('Filled Contours Plot')
ax[0].set_xlabel('x')
ax[0].set_ylabel('y')
#Create a curve contour plot
cp2 = ax[1].contour(X, Y, Z, levels=10)
fig.colorbar(cp2, ax=ax[1]) # Add a colorbar to a plot
ax[1].set_title('Curve Contours Plot')
ax[1].set_xlabel('x')
ax[1].set_ylabel('y')
fig.tight_layout() #Automatically adjust the spaces between sub-plots
plt.show()
Output

693
15.10 Box Plots
A box plot, also called whisker plot, visually summarises the vital information, such
as the minimum, first quartile, median, third quartile, and maximum, of a data set. In a box
plot, a box is created from the first quartile to the third quartile and the median is marked
by a line in the box. The box is connected with the minimum and maximum with lines. The
boxplot method has the following syntax:

matplotlib.pyplot.boxplot(x, notch=None, sym=None, vert=None, whis=None,


positions=None, widths=None, patch_artist=None, bootstrap=None,
usermedians=None, conf_intervals=None, meanline=None, showmeans=None,
showcaps=None, showbox=None, showfliers=None, boxprops=None,
labels=None, flierprops=None, medianprops=None, meanprops=None,
capprops=None, whiskerprops=None, manage_ticks=True, autorange=False,
zorder=None, *, data=None)

where x is an array or sequence of vectors. For each vector, the method creates on box plot.
Through other parameters, we can show meanlines and customise the plot as per our
requirements. For other parameters, please refer online documentations. Example 15.9
illustrates box plots.

694
Example 15.9: Box plots

import matplotlib.pyplot as plt


import numpy as np
# Creating data series
np.random.seed(10)
data_1 = np.random.normal(10, 2, 100)
data_2 = np.random.normal(20, 3, 100)
data_3 = np.random.normal(30, 6, 100)
data_4 = np.random.normal(40, 10,100)
data = [data_1, data_2, data_3, data_4] #Create dataset
fig, axs=plt.subplots(1,2) #Create subplots
axs[0].boxplot(data) # Create default box plot
axs[0].set_xlabel('n')
axs[0].set_ylabel('data')
axs[0].set_title("Default box plot")
# Create horizontal box plot with meanlines
axs[1].boxplot(data,meanline=True, vert=False, showmeans=True)
axs[1].set_xlabel('data')
axs[1].set_ylabel('n')
axs[1].set_title("Horizontal box plot")
fig.suptitle("Box plots")
fig.tight_layout()
# show plot
plt.show()
Output

695
15.11 Violin Plots
Violin plots are similar to box plots and it plots the probability density of the data at
different values. Primarly, it is used to visualize the distribution of variables. We use the
violinplot() method to generate a violin plot. It has the following syntax:

Axes.violinplot(dataset, positions=None, vert=True, widths=0.5,


showmeans=False, showextrema=True, showmedians=False, quantiles=None,
points=100, bw_method=None, *, data=None)

Where dataset is an array of vectors. For each vector, a separate violin plot is created. Other
parameters are used to customize a violin plot. See online documentation for more details
about other parameters. Example 15.10 illustrates voiline plots.

696
Example 15.10: Violin plots

import matplotlib.pyplot as plt


import numpy as np
# Creating data series
np.random.seed(10)
data_1 = np.random.normal(10, 2, 100)
data_2 = np.random.normal(20, 3, 100)
data_3 = np.random.normal(30, 6, 100)
data_4 = np.random.normal(40, 10,100)
data = [data_1, data_2, data_3, data_4] #Create dataset
fig, axs=plt.subplots(1,2) #Create subplots
axs[0].violinplot(data) # Create default violin plot
axs[0].set_xlabel('n')
axs[0].set_ylabel('data')
axs[0].set_title("Default violin plot")
# Create horizontal violin plot with meanlines
axs[1].violinplot(data, vert=False, showmedians=True, showmeans=True)
axs[1].set_xlabel('data')
axs[1].set_ylabel('n')
axs[1].set_title("Horizontal violin plot")
fig.suptitle("Violin plots")
fig.tight_layout()
# show plot
plt.show()

Output

697
15.12 Quiver Plots
A quiver plot is used to visualize dynamic processes such as particle flow, electrical
potential, stress gradients, etc. It shows the dynamic quantities with the help of directional
vectors. Vectors have both magnitude and direction. Vectors are plotted as arrows in a
quiver plot. The quiver () method is used to create a quiver plot. It has the following syntax:

matplotlib.pyplot.quiver([X, Y], U, V, [C], **kw)

where X, Y define the arrow locations, U, V defines the arrow directions, and C optionally
sets the color of arrows. Other parameters can be used to customize the plot as per
requirement. Please, see the online documentation for the same. Example 15.11 illustrates a
quiver plot.

Example 15.11: Quiver plots

import matplotlib.pyplot as plt


import numpy as np
#Create a meshgrid

698
x,y = np.meshgrid(np.linspace(-np.pi,np.pi,10), np.linspace(-
np.pi,np.pi,10))
#x and y components of vectors
u = np.sin(y);
v = np.cos(x);
fig, ax = plt.subplots(1,2)
ax[0].quiver(x,y,u,v)
ax[0].set_title("Default quiver plot")
r = np.random.rand(100) #Generate random numbers
m=np.max(r) #Get the maximum
c=plt.cm.jet(r/m)#Generate color from the random numbers
ax[1].quiver(x,y,u,v, color=c)
ax[1].set_title("Colored quiver plot")
fig.tight_layout()
plt.show()
Output

699
15.13 3D Plots
Though primarly designed for 2D plots, the Matplotlib module can be used to create
different types of 3D plots, such as 3D curve plots, 3D scatter plots, 3D surface plots, 3D
mesh plots, etc., by creating 3D Axes. A 3D axes can be created by passing the parameter
projection="3d" to Axes.add_subplot(projection="3d") method. Prior to Matplotlib 3.2.0, to
create 3D plots, we need to explicitly import the mpl_toolkits.mplot3d module but now it
is not required.

Once a 3D axes has been created, we can create a simple 3D line plot by using the
plot3D () method or the plot () method, with the following syntaxes:

Axes3D.plot(x, y, z, *args, zdir='z', **kwargs)

Axes3D.plot3D(x, y, z, *args, zdir='z', **kwargs)

where x,y and z are the 1D arrays containing the coordinates of points. Other positional and
keyword parameters are similar to the 2D plot() method. The zdir parameter sets the
orientation of the plot. Its possible values are 'x', 'y' and 'z', and default is 'z'. Example
15.12(a) illustrates simple 3D line plots.

We can create 3D scatter plot with the scatter3D method or scatter() method, with
the following syntaxes:

Axes3D.plot(x, y, z, *args, zdir='z', **kwargs)

Axes3D.plot3D(x, y, z, *args, zdir='z', **kwargs)

where x,y and z are the 1D arrays containing the coordinates of points. Other positional and
keyword parameters are similar to the 2D scatter() method. The zdir parameter sets the
orientation of the plot. Its possible values are 'x', 'y' and 'z', and default is 'z'. Example
15.12(b) illustrates simple 3D scatter plots.

Example 15.12(a): 3D line plots

import numpy as np
import matplotlib.pyplot as plt
#Create a spiral curve data
z = np.linspace(0, 1, 100)
x = z * np.sin(20 * z)

700
y = z * np.cos(20 * z)
fig = plt.figure() #Create a figure
#Add sub-plots to a figure and create a 3D axes
ax = fig.add_subplot(1,2,1, projection='3d')
ax.plot3D(x, y, z)
ax.set_title('Default 3D line plot')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#Create another 3D axes
ax1 = fig.add_subplot(1,2,2, projection='3d')
#Plot a customised 3D line plot
ax1.plot3D(x, y, z, 'g--', zdir='x')
ax1.set_title('Customised 3D line plot')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('z')
plt.show()
Output

701
Example 15.12(b): 3D scatter plots

import numpy as np
import matplotlib.pyplot as plt
#Create a spiral curve data
z = np.linspace(0, 1, 100)
x = z * np.sin(20 * z)
y = z * np.cos(20 * z)
fig = plt.figure() #Create a figure
#Add sub-plots to a figure and create a 3D axes
ax = fig.add_subplot(1,2,1, projection='3d')
ax.scatter3D(x, y, z)
ax.set_title('Default 3D scatter plot')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#Create another 3D axes
ax1 = fig.add_subplot(1,2,2, projection='3d')
#Plot a customised 3D scatter plot
ax1.scatter(x, y, z,c='red')
ax1.set_title('Customised 3D scatter plot')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('z')
plt.show()
Output

702
15.14 3D Pontour Plots
We can create 3D contour plots, both curve contour and filled contour plots, using
the contour() and contourf() methods (contour3D() and contourf3D() methods) of Axes3D
class, respectively. These methods have the following syntaxes:

Axes3D.contour(self, X, Y, Z, *args, extend3d=False, stride=5, zdir='z',


offset=None, **kwargs)

Axes3D.contourf(self, X, Y, Z, *args, zdir='z', offset=None, **kwargs)

where X, Y is a meshgrid points and Z is the values of the function at various grid points.
X, Y and Z are 2D arrays of the same size. Other parameters are used to customise the plots.
Please see the online documentation for their details. Example 15.13 illustrates 3D curve
contour and filled contour plots.

703
Example 15.13: 3D contour plots

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm #Import color maps
#Create a dataset for a 3D contour plot
def f(x, y):
return np.sin(np.sqrt(x ** 2 + y ** 2))

x1 = np.linspace(-6, 6, 30)
y1 = np.linspace(-6, 6, 30)
x,y = np.meshgrid(x1, y1) #Create meshgrid
z = f(x, y) #Calculate z value for each grid point

fig = plt.figure() #Create a figure


#Add sub-plots to a figure and create a 3D axes
ax = fig.add_subplot(1,2,1, projection='3d')
ax.contour3D(x, y, z, 20)
ax.set_title('Curve 3D contour plot')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#Create another 3D axes
ax1 = fig.add_subplot(1,2,2, projection='3d')
#Plot a filled 3D contour plot
ax1.contourf3D(x, y, z, 50, cmap=cm.coolwarm)
ax1.set_title('Filled 3D contour plot')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('z')
plt.show()
Output

704
15.15 Wireframe and Surface Plots
We can create a wireframe plot and a surface plot of 3D points using the methods
plot_wireframe() and plot_surface() methods, respectively. These plots help in visualising
the topology of a surface. A surface plot is like a wireframe plot, but each face of the
wireframe is a filled polygon. Following are the syntaxes of these functions:

Axes3D.plot_wireframe(X, Y, Z, *args, **kwargs)

Axes3D.plot_surface(X, Y, Z, *args, norm=None, vmin=None, vmax=None,


lightsource=None, **kwargs)

where X, Y, and Z are 2D arrays of the same size. X and Y are rectangular grid of points and
Z contains the z values at each grid points. Other parameters are used to customize the
plots. See the online documentation for more details of these parameters. Example 15.14
illustrates wireframe and surface plots.

705
Example 15.14: Wireframe and surface plots

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
#Create a dataset for a 3D contour plot
x1 = np.linspace(0,2*np.pi,20)
y1 = np.linspace(0,2*np.pi,20)
x,y = np.meshgrid(x1, y1)
z = np.sin(x)*np.cos(y)

fig = plt.figure() #Create a figure


#Add sub-plots to a figure and create a 3D axes
ax = fig.add_subplot(1,2,1, projection='3d')
ax.plot_wireframe(x, y, z,cmap=cm.coolwarm)
ax.set_title('Mesh plot')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
#Create another 3D axes
ax1 = fig.add_subplot(1,2,2, projection='3d')
#Plot a surface plot
ax1.plot_surface(x, y, z, cmap=cm.coolwarm)
ax1.set_title('Surface plot')
ax1.set_xlabel('x')
ax1.set_ylabel('y')
ax1.set_zlabel('z')
plt.show()
Output

706
15.16 Animation using Matplotlib
For more vivid representation of data, Matplotlib provides facilities to generate
animations of various plots using animation module. Animation of a Matplotlib plot is
possible as elements of a plot are stored as dynamic and editable items, called artist. For
example, the artist in a line plot is Line2D, which is nothing but collection of all the end poit
coordinates of all the line segment, line type, line color, etc. An artist can be updated by
updating the data behind the artist using the corresonidng set method. For example, we can
use set_data method to update the coordinate points. The animation module uses two
classes to create animation: FuncAnimation and ArtistAnimation.

FuncAnimation: In FuncAnimation, we start by generating the data for the first plot and
then update the data for the next frame by calling a function which updates the data. The
update function calculates the data for the next frame and uses the set methods of various
plots to update the data.

707
ArtistAnimation: In ArtistAnimation, the data for all the frames are generated before the
start of animation and is stored in an interable. The ArtistAnimation method uses these data
to create animation.

The FuncAnimation approach is more efficient in terms of memory as it calculated


data for the next frame and does not store data for all the frames. On the other hand, the
ArtistAnimation approach generates a smoother animation but require a large amout of
memery to store data of all the frames.

15.16.1 Steps to create an animation plot using FuncAnimation:

Following are the steps to create animation using FuncAnimation:

1. Create the initial plot including all the artists (parameters) required for the animation.
Also get the handle of the plot.
2. Define an animation function that will calculate the values of the artists for the next
frame.
3. Call the constructor of the FuncAnimation object and pass the plot handle, animation
function and other parameters.
4. Either show the animation by using pyplot.show method or save the animation by using
the animation. Animation.save method.

Example 15.15(a) uses the above method to show the animation of trajectory of a
projectile.

Example 15.15(a): Use of FuncAnumation to simulate the trajectory of a projectile

import numpy as np #Import NumPy module


import matplotlib.pyplot as plt #Import Matplotlib module
import matplotlib.animation as animation #Impiurt animation module
theta =45 #Throw angle in degree
theta = theta*np.pi/180 #Convert the angle into radian
v= 20 #Throw velocity
tof= 2*v*np.sin(theta)/9.81 #Calculate the time of flight
tf = np.linspace(0, tof, 40) #Time array for frame updation
x=[0]
y=[0]
fig, ax = plt.subplots()
scat = ax.scatter(x[0],y[0], c="b") #Plot the starting point
#Set the limits of the chart

708
ax.set(xlim=[0, 45], ylim=[-1, 12], xlabel='Time [s]', ylabel='Z [m]')

def update(frame):
t=tf[frame]
x.append(t*v*np.cos(theta)) #Next x-coordinate
y.append(v*np.sin(theta)*t-0.5*9.81*t*t) #Next y coordinate
data = np.stack([x, y]).T
scat.set_offsets(data) #Update the plot data
return (scat)
#Create animation
ani = animation.FuncAnimation(fig=fig, func=update, frames=40,
interval=300, repeat = False)
plt.show() #Show animation
Output

709
15.16.2 Steps to create animation plot using ArtistAnimation:

ArtistAnimation can be used only for plots that returns iteratble artists, such as bar charts,
line plot, etc. It cannot be used to the scatter plot as the returned path collection is not
iterable. Following are the steps to create animation using FuncAnimation:

1. Create an empty plot


2. Create a list of values of various artist at different frame.
3. Call the constructor of the ArtistAnimation object
4. Show the animation by using pyplot.show method.
5. If needed, save the animation by using the animation. Animation.save method.

Example 15.15(b) uses the above method to show the animation of trajectory of a projectile
using a line plot.

Example 15.15(b): Use of ArtistAnumation to simulate the trajectory of a projectile

import numpy as np #Import NumPy module


import matplotlib.pyplot as plt #Import Matplotlib module
import matplotlib.animation as animation #Impiurt animation module
theta =45 #Throw angle in degree
theta = theta*np.pi/180 #Convert the angle into radian
v= 20 #Throw velocity
tof= 2*v*np.sin(theta)/9.81 #Calculate the time of flight
tf = np.linspace(0, tof, 40)
x=[0]
y=[0]
fig, ax = plt.subplots()

#Set the limits of the chart


ax.set(xlim=[0, 45], ylim=[-1, 12], xlabel='Time [s]', ylabel='Z [m]')

artists = [] #Empty artists


#Create artists for different frames
for t in tf:
x.append(t*v*np.cos(theta)) #Next x-coordinate
y.append(v*np.sin(theta)*t-0.5*9.81*t*t) #Next y coordinate
data = np.stack([x, y]).T
scat = ax.plot(x,y, c='r', linestyle = 'dotted')
artists.append(scat) # Add artists for the next frame.

#Create animation
ani = animation.ArtistAnimation(fig=fig, artists=artists, interval=30,
repeat = True)
710
plt.show() #Show animation
ani.save(filename="d:/example.gif", writer="pillow") #Save animation
Output

Sample Program 15.1: Write a program to generate 10000 normally distributed random
numbers and plot their histogram with 100 bins
Solution Steps:
1. Import numpy, numpy.random and Matplotlib modules
2. Generate 10000 normally distributed random numbers using numpy.random.randn
method with default parameters.
3. Plot a histogram using hist method

711
import numpy as np #Import NumPy module
import numpy.random #Import random number generators
import matplotlib.pyplot as plt #Import Matplotlib module
r=numpy.random.randn(10000) #Generate random numbers
plt.hist(r,100) #Plot the histogram
plt.show()#Show the plot
Output

Sample Program 15.2: Write a program to plot the projectile of a ball thrown at 45 degree
at the velocity 20 m/s.
Solution Steps:
1. Calculate x and y coordinates of some points on the projectile path using Newton’s
second law of motion
2. Use a scatter plot to plot the calculated points
import numpy as np #Import NumPy module
712
import matplotlib.pyplot as plt #Import Matplotlib module
theta =45 #Throw angle in degree
theta = theta*np.pi/180 #Convert the angle into radian
v= 20 #Throw velocity
tof= 2*v*np.sin(theta)/9.81 #Calculate the time of flight
t=np.linspace(0,tof,100) #Generate time series
x=t*v*np.cos(theta) #Calculate x co-ordinate of the projectile
y=v*np.sin(theta)*t-0.5*9.81*t*t #Calculate y- co-ordinate
plt.scatter(x,y)#Create a scatter plot
plt.show() #Show the plot
Output

Sample Program 15.3: Write a program to create a scatter plot of random points with
random coloured balls of random sizes
Solution Steps:
1. Generate random x and y coordinates for various points
2. Generate random sizes for various points
3. Generate random colours for various points

713
4. Use scatter plot to plot these points.
import matplotlib.pyplot as plt #Import Matplotlib
import numpy.random #Import numpy.random
x = numpy.random.randint(0,100,10) #x-coordinates
y = numpy.random.randint(0,100,10) #y-coordinates
points_size = numpy.random.randint(0,1000,10) #Point sizes
c = numpy.random.randint(0,100,10) #Color of points
plt.scatter(x,y,s=points_size,c=c, cmap='viridis')
plt.title("Coloured Scatter Plot with random size of scatter points ",
fontsize=12)
plt.xlabel('x-axis',fontsize=12) #Add label to x-axis
plt.ylabel('y-axis',fontsize=12) #Add label to y-axis
plt.show()
Output

714
Sample Program 15.4: Write a program to animate the price variations of five stocks using
a vertical bar chart
Solution Steps:
1. Generate labels for various stocks
2. Generate initial height of bars showing the prices of the stocks
3. Assign colors to each stock bar
4. Use bar plot function to show the bars
5. Create a function to calculate the price variations in each frame and assign the new
prices to each bar
6. Use FuncAnimation function of animation module to animate the bar for each frame
import numpy as np #Import NumPy module
#import animation, pyplot module of Matplotlib
from matplotlib import animation as animation, pyplot as plt, cm

fig = plt.figure() #Create an empty figure

data = [1, 4, 2, 3, 5] #Initial heights of bars


label = ["A","B","C", "D","E"]#Labels of bars
colors = ['red', 'yellow', 'blue', 'green', 'black'] #Colors
#Create the initial bar chart
bars = plt.bar(label, data, facecolor='green', alpha=0.75)

def animate(frame): # Update function for the bar animation


global bars
index = np.random.randint(0, 4)
bars[frame].set_height(index+2)
bars[frame].set_facecolor(colors[index])
#Call animation function
ani = animation.FuncAnimation(fig, animate, frames=len(data))
plt.show() #Show the animation
Output

715
Chapter Summary

1. Matplotlib is a widely used cross-platform data visualization, and graphical


plotting library of the Python programming language.
2. Matplotlib is used to plot variety of 2D and 3D plots.
3. The plot method creates a line plot.
4. We can create a number of subplots in a figure and each subplot can have
different types of plots and different types of appearances with the subplots
method

716
5. We can label x-axis by the xlable method, y-axis by the ylabel method.
6. We can give a title and a sub-title to a plot by the suptitle and title methods.
7. We can add a grid to a plot using the grid method.
8. We can use the legend method to add a legend in a plot.
9. Vertical bar charts are created with the bar method and horizontal bar charts are
created using the barh method.
10. We can create a polar bar plot in Matplotlib by setting the polar property of the
axes object to true.
11. We use the hist method to plot a histogram.
12. We create a pie chart using the pie method.
13. We use scatter method to plot a scatter plot.
14. The contour and contourf functions are used to create curve contours and filled
contours plots
15. The boxplot method create a boxplot, which visually summarises the vital
information, such as the minimum, first quartile, median, third quartile, and
maximum, of a data set.
16. We use the violinplot method to generate a violin plot.
17. The quiver method is used to create a quiver plot which is used to visualize
dynamic processes such as particle flow, electrical potential, stress gradients, etc.
18. Matplotlib module can be used to create different types of 3D plots, such as 3D
curve plots, 3D scatter plots, 3D surface plots, 3D mesh plots, etc., by creating 3D
Axes.
19. We can create a wireframe plot and a surface plot of 3D points using the methods
plot_wireframe() and plot_surface() methods, respectively.

717
Multiple Choice Questions

1. Which of the following is true about Matplotlib?


(a) A programming language
(b) A data visualization library
(c) A database management system
(d) An operating system

2. Which of the following is used to add a title to a Matplotlib plot?


(a) the title() function
(b) the label() function
(c) the text() function
(d) the legend() function

3. Which of the following function can be used to save a Matplotlib plot as an


image file?
(a) the save() function
b) the export() function
c) the savefig() function
d) None of the above.

4. The savefig() function can save a Matplotlib plot in the following format?
(a) PNG
(b) PDF
(c) SVG
(d) All of the above.

5. Which of the following function can be used to set the limit of x-axis of a plot?
(a) xlim()
(b) xlimit()
(c) xtrim()
(d) All of the above.

6. Which of the following is the default color for Matplotlib plots?


(a) Black
(b) Blue
(c) Green
(d) Red

718
7. Which of the following can be used to change the color of a Matplotlib plot?
(a) the color() function
(b) the hue() function
(c) By specifying the color parameter in the plot() function
(d) all of the above

8. Which of the following is the correct syntax for the formatting string?
(a) fmt = '[marker][line][color]'
(b) fmt = '[color] [marker][line]'
(c) fmt = '[marker] [color] [line]'
(d) None of the above.

9. Which of the following is used to manage spaces between sub plots?


(a) tight_layout()
(b) subplots_adjust()
(c) Both (a) and (b)
(d) None of the above

10. Which of the following is used to automatically adjust the spaces among
subplots?
(a) tight_layout()
(b) auto_layout()
(c) subplots_adjust()
(d) None of the above

11. Which of the following function can be used to label x-axis in a plot?
(a) labelx()
(b) xlable()
(c) xtext()
(d) None of the above

12. Which of the following is used to give main title of a group of subplots?
(a) title()
(b) suptitle()
(c) maintitle()
(d) None of the above.

13. Which of the following is used to add minor grid to a plot?

719
(a) grid()
(b) minor_grid()
(c) mgrid()
(d) None of the above.

14. Which of the following is used to customize ticks in a plot?


(a) set_xticks()
(b) set_yticks()
(c) set_xticklables
(d) None of the above.

15. Which of the following is used to describe the meaning of various lines and
symbols used in the plot?
(a) legend
(b) ticks
(c) title
(d) None of the above.

16. By default, the legend is placed at?


(a) top right corner
(b) top left corner
(c) bottom right corner
(d) bottom left corner

17. Which of the following is used add second y-axis in a plot?


(a) twinx()
(b) twiny()
(c) It is not possible to add second axis
(d) None of the above.

18. The bar() method is used to create ____.


(a) horizontal bar chart
(b) vertical bar chart
(c) both horizontal and vertical bar charts
(d) None of the above.

19. How can we create a polar chart in Matplotlib?


(a) using polar method

720
(b) setting polar property of the axis() method to true
(c) It is not possible to create a polar chart
(d) None of the above

20. What is a histogram plot?


(a) a vertical bar chart
(b) a horizontal bar chart
(c) an interval frequency distribution chart
(d) None of the above.

21. The number of default bins in a histogram chart is ________.


(a) 10
(b) 20
(c) 100
(d) 50

22. Which of the following chart cannot be created in Matplotlib?


(a) Scatter chart
(b) Pie chart
(c) Contour plots
(d) None of the above.

23. Which of the following is not contained in a box plot?


(a) Minimum
(b) Maximum
(c) First quartile
(d) None of the above.

24. Which of the following is used to visualise a dynamic process such as flow of
particles?
(a) quiver plot
(b) scatter plot
(d) Violin plot
(d) None of the above.

25. Which of the following cannot be created in Matplotlib?


(a) 3D curve plots

721
(b) 3D scatter plots
(c) 3D surface plots
(d) None of the above.

Review Questions

1. State whether the following statements are true or false:


a. Matplotlib can be used for creating static, animated, and interactive visualizations
of data
b. Matplotlib can be used for creating only 2D plots.
c. Matplotlib can create 3D plots.
d. Matplotlib can create subplots.
e. 2D curve can be created using plot method.
f. Matplotlib can create different line types.
g. The default color of Matplotlib plots is black.
h. tight_layout() method automatically maintains the proper spaces between
subplots.
i. We cannot add grid to a plot.
j. We can add a minor grid to a plot.
k. We cannot change color of grid lines.
l. The default location of legend in a plot is top-left corner.
m. Matplotlib provides facility to add secondary axis to a plot.
n. The bar () method creates a horizontal bar chart.
o. Matplotlib cannot create a polar bar chart.
p. The number of default bins in a histogram plot is 10.
q. The sizes of slices in a pie char are in proportion to the values of data.
r. In a box plot, a box is created from the first quartile to the third quartile.

722
s. A quiver plot can visualize a dynamic process, such as particle flow.

Programming Assignments

1. Write a program to draw a horizontal line in Matplotlib.

2. For the following data, plot a line plot, scatter plot and vertical bar chart.

x 1 2 3 4 5 6 7 8 9 10 11
3.
y 31 11 10 17 21 16 26 21 28 34 33

4. For the following data, create a grouped horizontal bar chart.

x 1 2 3 4 5 6 7 8 9 10 11
y1 28 18 30 10 17 12 32 13 24 37 13
y2 24 40 16 27 13 11 26 19 32 13 19

5. For the data given in question 4, draw a scatter diagram for y1 and y2.

6. For the data given in question 4, plot a multi line plot with legend located at the
bottom right corner of the plot.

7. For the data given in question 4, create a box plot for y1 series.

8. Write a program to plot y=sin(x) for 0<=x<=4p with 0.2 step size.

9. Write a program to plot the trajectory of a projectile thrown at angle f and


velocity v.

10. The following is the montly unit sale data of a store for few items:

723
Total
Month Shampoo Toothpaste Soap Moisturiser
Units
1 1381 1654 1412 1288 5735
2 1336 1994 1325 1165 5820
3 1745 1868 1714 1145 6472
4 1205 1593 1402 1180 5380
5 1758 1150 1221 1782 5911
6 1171 1071 1166 1605 5013
7 1389 1237 1199 1519 5344
8 1969 1263 1230 1701 6163
9 1041 1228 1804 1927 6000
10 1651 1197 1687 1459 5994
11 1071 1242 1955 1954 6222
12 1171 1154 1417 1376 5118

11. For the above data, write a program to plot the monthly total sale of the store
using a line plot.

12. For the above data, write a program to show montly sale of different items using
a multiline plot.

13. For the above data, plot a scatter plot for shampoo and moisturizer sales.

14. For the above data, plot a monthly sale of various items using a vertical bar chart.

15. For the above data, plot a pie chart to show the contribution of various items on
the total annual sale.

16. For the above data, plot a box plot for toothpaste.

724
17. Write a program to plot a 3D spiral.

x/y 1 2 3 4 5 6 7 8 9 10
18.
1 16 22 40 38 10 15 29 36 10 17
2 34 35 20 38 28 39 38 21 30 18
3 36 28 28 15 13 18 38 25 10 25
4 13 25 26 39 15 22 29 19 10 24
5 35 26 33 27 40 24 30 27 27 13
6 10 15 34 21 12 22 39 34 26 24
7 30 32 38 32 40 32 18 23 40 35
8 25 14 31 25 40 40 13 40 11 13
9 29 15 13 23 25 31 35 28 37 33
10 23 35 12 23 38 27 37 11 34 37

19. For the above data, plot a 3D mesh plot.

20. For the above data, plot a 3D scatter plot.

725
726
Chapter 16

GUI Programming using tkinter


Learning outcomes

1. Understand the concept of GUI programming.


2. Learn steps to create a GUI Python program unsing tkinter
3. Learn features of various types of wigets
4. Learn the concept of event driven programming
5. Learn to customize application window

16.1 Introduction to Graphics User Interface


Until now, we have written programs that accept command and input data in the
form of text-only through the Python shell and print the output in the Python shell. This
type of input and output system is called the character user interface (CUI). The CUI is also
called a text-based user interface (TUI). The CUI is good for learning programming
concepts, but most commercial software uses the graphical user interface (GUI) to interact
with the users. The GUI uses visual objects such as boxes to type in data and buttons that
initiate actions. These visual objects are called widgets. Widgets are active elements and
respond to events such as mouse clicks and pressing of keys. Since events control the
sequence execution of GUI programs, GUI programs are called event-driven programming.
The main advantage of the GUI in a program is its ease of use for the average person. Figure
16.1 shows CUI and GUI versions are a BMI calculator. Further, most modern operating
systems use GUI, making learning a new GUI application easy and fast.

Python has many graphical user interfaces, such as tkinter, wxPython, and JPython,
to develop GUI-based Python applications. However, this chapter describes how to create
GUI programs in Python using the tkinter module. The tkinter module is a Python binding
to the Tk GUI toolkit, the original GUI library for the Tcl language. Further, this module is
bundled with almost all the Python distributions and is very easy to use. Example 16.1
shows a GUI program that prints the string "Welcome to Python GUI program !" in the
shell when clicking the Message button in the application.

727
(a) CUI based BMI calculator (b) GUI based BMI calculator

Figure 16.1: CUI and GUI applications

Example 16.1: A GUI Python program

import tkinter as tk #Import tkinter module

def myFun(): #An event listener function

print("Welcome to Python GUI program !")

root=tk.Tk() #Create the main application window

root.geometry("100x50") #Size the main window

button=tk.Button(root, text= "Message", command = myFun) #Create a


button

button.pack(padx=10, pady=10) #Arrange the button in the main window

root.mainloop() #Run the event loop

GUI

728
Output

16.2 Components of Event-Driven Programming


In the event-driven programming paradigm, the execution flow of a program is
controlled by a sequence of events. When a user performs an action on a graphical
component (called widgets), such as clicking a button, pressing a key, moving the mouse
pointer, and selecting an item in a list, events are generated. Events can also be generated
from inside the program or by the operating system, such as the program is about to start
and a window is going to be destroyed. The operating system maintains a queue of events
and passes it to the relevant applications. Typically, every GUI application has an event
loop that listens to relevant events and triggers event handlers. For example, in the BMI
calculator, given in figure 16.1(b), a user can enter height and weight in any order, and when
the user clicks on the calculate BMI button, the BMI calculation function is called, and the
result is shown. Hence, the components of typical GUI-based applications are (1) widgets,
(2) events, and (3) event listener functions.

16.2.1 Widgets
Widgets are graphical components, such as buttons, textboxes, and lists. The tkinter
module supports several widgets. The commonly used widgets are shown in table 16.1,
along with their brief descriptions. Figure 16.1 shows the appearances of some widely used
widgets.

729
Table 16.1: Commonly used widgets

Widget Description
Button The Button widget is used to create a button.
Canvas The Canvas widget is used to create a canvas to draw shapes, such as
lines, ovals, polygons, and rectangles.
Checkbutton The Checkbutton widget is used to create checkboxes to select multiple
options.
Entry The Entry widget is used to create a single-line text entry field for
accepting values from a user.
Frame The Frame widget is a container widget and is used to organize and
group other widgets.
Label The Label widget is used to create a single-line text or image that can be
used as the caption for other widgets.
Listbox The Listbox widget is used to create a list of items that a user can select.
Menubutton The Menubutton widget is used to create different types of menus in an
application.
Menu The Menu widget is used to create a drop-down menu in an application.
Message The Message widget is used to create a multiline text display field.
Radiobutton The Radiobutton widget is used to create multiple option radio buttons
and permits to select only one option at a time.
Scale The Scale widget is used to create a slider widget to generate different
values based on the option of the slider.
Scrollbar The Scrollbar widget is used to create scroll bars for various widgets to
scroll the content.
Text The Text widget is used to create a multiple lines input box.
Toplevel The Toplevel widget is used to create additional container window.
Spinbox The Spinbox widget is used to create a spin button to generate numbers
between a specified range.
messagebox This messagebox widget is used to display message boxes (for example,
OK, Cancel box, Yes, No box, and True, False box) in GUI applications.

730
Figure 16.1: Commonly used widgets

16.2.2 Events
Events in a program can be user-generated or system-generated. A user-generated
event is generated when a user interacts with a widget with any input device, such as
pressing a mouse's button, moving the mouse pointer, and pressing a key. On the other
hand, system-generated events are automatically generated by the operating system, such
as timer events. These events are recorded by the operating system and passed on to the
concerned applications. The application responds to an event if the event is bonded with an
event listening function of a widget. Otherwise, the event is ignored.

Typically, a user interacts with widgets by using either a keyboard or a mouse.


When a user presses a key, a keypress event is generated. A keypress event contains the
identity of the key pressed. When a combination of a special key such as the control key and
a normal key is pressed, the event includes the information about the special key and the
normal key.

In the case of a mouse or touchpad on a laptop, events are generated by clicking or


double-clicking a mouse button, rotating the scrolls, or moving the mouse pointer. A mouse
event contains information about the x and y coordinate of the mouse pointer and the button

731
which is pressed. The Tkinter module assigns names to events generated by the keyboard
and the mouse. The names can be generic or specific. For example, if a programmer is
interested in handling a keypress, he can use the event name "<Key>". However, if he is
interested in handling a specific key, such as A, or B, he can use "A" or "B", respectively.
Similarly, if a programmer wants to take action on the click of any mouse button, he can use
"<Button>", but if he wants to take action of the left button click, then he can use the name
"<Button-1>" or "<1>". Table 16.2 lists the commonly used mouse and keypress event
names supported by the tkinter module, along with their brief descriptions.

Table 16.2 list the commonly used events in the tkinter module

Event name Description

"<Button>" The event name "<Button>" handles any mouse click, i.e., click of
any mouse button. Whereas "<Button-1>", "<Button-2> and
"<Button-3>" hands the left button, the middle button, and the right
button, respectively.

For a mouse with a scroll, "<Button-4>" handles the scroll-


up event, and "<Button-5>" handles the scroll-down event of a
mouse.

In tkinter, the names "<Button>" and "<ButtonPress>" are


synonyms. Similarly, "<Button-1>", "<ButtonPress-1>" and "<1>"
are synonyms and refers to the left mouse buttion click.

"<Motion>" The name "<Motion>" handles the motion of the mouse pointer.

If we want to handle the pointer motion with the left mouse


button being held down, we use "<B1-Motion>". Similarly, for the
middle mouse button and right mouse button, we use "<B2-
Motion>" and "<B3-Motion>", respectively.

"<ButtonRelease>" When we release a pressed mouse button, a button release event is


generated. This release event is handled by the event name
"<ButtonRelease>". To specify the release of the left, middle or right

732
mouse button, we use "<ButtonRelease-1>", "<ButtonRelease-2>",
and "<ButtonRelease-3>", respectively.

"<Double-Button>" When we press a mouse button twice quickly, it is called a double


click. We can handle a double click using "<Double-Button>". To
handle the double click of a specific button, we use "<Double-
Button-1>", "<Double-Button-2>", and "<Double-Button-3>" for the
left, middle and right buttons, respectively.

"<Enter>" An enter event is generated when the mouse pointer enters a


widget. We use "<Enter>" to handle an enter event.

"<Leave>" A leave event is generated when the mouse pointer leaves a widget.
We use "<Leave>" to handle a leave event.

"<FocusIn>" When a widget gets the keyboard focus for typing characters in it,
a focus-in event is generated. This event is handled by
"<FocusIn>".

"<FocusOut>" When the keyboard focus of a widget is moved from it to some


other widget, a focus-out event is generated. This event is handled
by "<FocusOut>".

"<Return>" When we press the enter key, the tkinter module generates a return
event. This event is handled by "<Return>". Similarly, special keys,
such as Tab and Backspace, are handled with unique event names.
For example, "<Cancel>" for the break key, "<BackSpace>" for the
backspace key, "<Tab>" for the tab key, "<Shift_L>" for the shift
key, "<Control_L>" for the control key, "<Alt_L>" for the alt key,
"<Pause>" for the pause key, "<Caps_Lock>" for the caps lock key,
"<Escape>" for the esc key, "<Prior>" for the page up key, "<Next>"
for the page down key, "<End>" for the end key, "<Home>" for the
home key, "<Left>" for the left arrow key, "<Up>" for the up arrow
key, "<Right>" for the right arrow key, "<Down>" for the down
arrow key, "<Print>" for the print key, "<Insert>" for the insert key,
and "<delete>" for the delete key.

Similarly, function keys F1, F2, F3, F4, F5, F6, F7, F8, F9, F10,
F11, and F12 are maped to "<F1>", "<F2>", "<F3>", "<F4>", "<F5>",
733
"<F6>", "<F7>", "<F8>", "<F9>", "<F10>", "<F11>", and "<F12>",
respectively.

"<Key>" The event name "<Key>" handles a keypress event of any key on
the keyboard.

"a" The printable character keys, such as a, b, c, A, B, C, 1, 2, 3, are


handled by their equivalent string. For example, the lower case a
key is mapped to "a", the upper case A key is mapped to "A", and
the numeric key 1 is mapped to "1". The other printable keys are
mapped similarly except for the space key and the < key, which are
mapped to "<space>" and "<less>", respectively.

"<Shift-Up>" Events generated by holding down a special key and then pressing
another key, called combination key, such as a shift + up arrow key,
control + c key are handled by "<Shift-Up>" and "<Shift-c>"
respectively. We can use prefixes like Alt, Shift, and Control with
other keys to handle other combination keys.

16.2.3 Event Listener Functions


An event listener function is a function that gets executed when a widget receives
an event. When we bind an event listener function with an event of a widget, the event
information, such as the mouse pointer's location, is automatically passed to the function.
We can bind one or more events of a widget to the same event listener function. Example
16.2 shows a listener function that prints (in the Python shell) the location of the mouse
pointer and the mouse button number when a user presses a mouse button on the button
widget.

Example 16.2: Event listener function

import tkinter as tk
def myFun(event=None): #An event listener function
print("The current location of the mouse pointer is:")
print("x = ", event.x) #Get x location of the mouse pointer
print("y = ", event.y) #Get x location of the mouse pointer
print("Button number = ", event.num) #Get button number

root=tk.Tk()
734
root.geometry("100x100")
button=tk.Button(root, text= "Click to get the mouse pointer position")
button.bind("<Button>", myFun) #Binding an event with a listener
button.pack(padx=10, pady=10)
root.mainloop()
GUI

Output

16.3 Creating a GUI Application using the tkinter Module


Following are the steps to create a GUI application using the tkinter module:

1. Import the tkinter module. Preferred ways to call the module are import tkinter as
tk, from tkinter import *, or from tkinter import Button, Label.

2. Initialize the main application window and set its title, size, and appearance. The
main window of an application is created by calling the Tk() function of the tkinter
module. For example, the statement root = tk.Tk() creates the application's main

735
window and returns the handle root for its future reference. The appearance of the
window is specified through various attributes (discussed later in the chapter).

3. Create widgets and set their caption, size, appearance, and other properties. We can
create a widget by calling the construction of its widget class. For example, to create
a button, we call the constructor Button of the button widget. The statement button
= tk.Button(root, text="Click Me") creates a button with the caption "Click ME", and
it will be placed inside the main window. The creation of commonly used widgets
and their appearance control will be discussed later.

4. Create a layout of widgets. Once widgets are created, we need to arrange their
placement on the containing window. The tkinter module has geometry managers
to create the desired layout. For example, button.grid(row=1, column=1) places the
button in the second row and the second column. Different geometry managers
available in the tkinter module will be discussed later.

5. Write event listener functions for events of interest of widgets.

6. Bind the event listener functions and widgets.

Example 16.3 shows the above steps for the BMI GUI application shown in figure 16.1.
Steps 3, 4, and 6 are repeated for each widget used in the application.

Example 16.3: The structure of a GUI Python program

import tkinter as tk #Importing the tkinter module (Step 1)

def calBMI(event=None): #Defining a call back function (Step 5)


global bmi_str
h = entry1.get() #Getting the widget data
w = entry2.get() #Getting the widget data
if h.isnumeric() and w.isnumeric(): #Validating widget data

736
h=float(h)/100 #converting to meter
w=float(entry2.get())
if h>0:
bmi=w/(h*h) #BMI formula
#Setting the widget data
bmi_str.set(str(round(bmi,2)))
else:
bmi_str.set("Invalid data")
else:
bmi_str.set("Invalid data")

#Creating and initialising the main application window (Step 2)


root=tk.Tk()
root.geometry("300x150") #Seeting the size of the main window

bmi_str = tk.StringVar() #Creating a tkinter string variable


bmi_str.set("Not Calculated yet")

#Creating a Label widget (Step 3)


lable1=tk.Label(root,text="Enter yout height (in cm)", padx=5, pady=5)
#Placing the widget in the main window in the first row and first
column (Step 4)
lable1.grid(column=0, row=0,padx=5, pady=5)

#Creating a Label widget (Step 3)


lable2=tk.Label(root,text="Enter yout weight (in kg)", padx=5, pady=5)
#Placing the widget in the main window in the second row and first
column (Step 4)
lable2.grid(column=0, row=1,padx=5, pady=5)

#Creating an Entry widget (Step 3)

737
entry1=tk.Entry(root)
#Placing the widget in the main window in the first row and second
column (Step 4)
entry1.grid(column=1, row=0,padx=5, pady=5)

#Creating an Entry widget (Step 3)


entry2=tk.Entry(root)
#Placing the widget in the main window in the second row and second
column (Step 4)
entry2.grid(column=1, row=1,padx=5, pady=5)

#Creating a Button widget (Step 3)


button = tk.Button(root, text="Calculate BMI", command = calBMI) #Bind
left click with the calBMI function
#Binding the right button click with the calBMI call back function
(Step 6)
button.bind("<Button-3>", calBMI)
#Placing the widget in the main window in the third row and first &
second column (Step 4)
button.grid(row=2, column=0, columnspan=2) #First and second columns
merged

#Creating a Label widget (Step 3)


lable3=tk.Label(root,text="Your BMI is ", fg="red", padx=5, pady=5)#Red
foreground color
#Placing the widget in the main window in the fourth row and first
column (Step 4)
lable3.grid(column=0, row=3,padx=5, pady=5)

#Creating a Label widget with green background (Step 3)

738
lable4=tk.Label(root, textvariable=bmi_str,
bg="green",justify="left",relief= tk.SUNKEN, padx=5, pady=5)
#Placing the widget in the main window in the fourth row and second
column (Step 4)
lable4.grid(column=1, row=3, sticky=tk.W, padx=5, pady=5)#Text is left
aligned
GUI

16.4 Creating and Customizing the Main Application Window


By default, the main application window created by the Tk() function has a title tk
and has three system buttons, including Minimize, Maximize, and Close. However, we can
customize its appearance by setting various attributes. Table 16.3 lists the commonly used
attribute setting methods for an application window. Example 16.4 illustrates these
methods.

Table 16.3: Commonly used methods to set attributes of the root window

title It is used to change the title of the window. For example,


root.title('MyFirstApp') sets the title of the root window to 'MyFirstApp'.

geometry It is used to change the size and location of the window. The size and
location are specified as a string of the form ‘widthxheight+x+y’, where
width and height are the window's width and height in the number of
pixels, x is the horizontal offset, and y is the vertical offset in the number of

739
pixels. If x is positive, the left edge of the screen is used as the reference, and
if it is negative, the right edge of the screen is used as the reference.
Similarly, a positive y value uses the top edge of the screen, and a negative
y value, the bottom edge. For example, root.geometry(‘300x200+50+50')
sets the width=300 and heigh=200 pixels of the root window and places the
window 50 pixels from the left and top edges of the screen.

We can get the width and height of the screen with


root.winfo_screenwidth() and root.winfo_screenheight(), respectively.

resizable It is used to specify whether a window can be resized or not. For example,
root.resizable(False, False) makes the root window of fixed size, both
horizontally and vertically. We can control the minimum and maximum
size of a resizable window with root.minsize(min_width, min_height) and
root.maxsize(min_height, max_height) functions, respectively.

attributes It is used to other attributes, such as transparency, of a window. For


example, root.attributes('-alpha', 0.5) sets the transparency for the window
to 50% and root.attributes('-topmost', 1) keep the window always on top.

config It is used to configure the native attributes, such as the background color,
cursor of the window. For example, root.configure(background='green')
sets the background color to green and root.config(cursor='gumby') sets
the cursor to Gumby.

iconbitmap It is used to change the window icon. It requires the icon image to be in the
.ico format.

Example 16.4: Appearance control of the main window

import tkinter as tk
root=tk.Tk() #Create the main application window
root.title("MyFirst GUI Application") #Set the title of the window
root.geometry("400x400+50+50") #Set the size of the window and its
location
#Make the window resizable vertically and fixed horizontally

740
root.resizable(False, True) #Set the resizable flag
root.iconbitmap('./python_104451.ico') #Set the icon of the window
root.attributes('-alpha',0.9) #Set the transparency of the window
root.configure(background='green')#Set the background color
root.config(cursor='gumby')#Set the background color
root.mainloop() #Start the event loop
Output

16.5 Creating Widgets


A widget is created using the constructor of the widget class using the following
syntax:

widget = tkinter.WidgetClass(parent_window, **options)

where widget is the handle of the created widget, WidgetClass is the constructor of the
Widget Class, parent_window is the container window/widget handle in which the widget
will be added, and options are the customization parameters. For example, the statement
button = tkinter.Button(root, text= "Click Me", bg= "green", command=myFun) will
create a button widget in the root window with the caption Click Me, and background color
green and will call the function myFun on the left mouse button click.

The appearance of a widget is controlled through various attributes. Attributes can


be set through passing them in the constructors or setting them after creating a widget

741
object. For example, to set the background color (i.e. the attribute bg) to green of a button
widget, we can use any one of the following:

(1) button = tk.Button(root, text= "Click Me", bg = "green") #Using the constructor

(2) button = tk.Button(root, text= "Click Me")


button["bg"] = "green" #Using an object

Some attributes are common to all the widgets (called standard attributes), and some
are specific to a widget. The common attributes are discussed in section 16.5.1, and the
specific attributes are discussed separately for each widget.

16.5.1 Standard Attributes of Widgets


Standard attributes, such as cursors, reliefs, colors, and fonts, are common to all the
widgets of the tkinter module. The standard widget attributes are keywords used in widget
constructors.

Table 16.3 lists common standard attributes along with their brief descriptions.
Example 16.5 illustrates some standard attributes.

Table 16.3: Standard attributes of widgets

Attribute Description
state The state attribute sets the state of a widget. A widget can be in the
following states: normal, active, and disabled. A widget is in the
normal state when it responds to the user actions; otherwise, it is in
the disabled state. When a normal state widget gets the focus of an
input device, it goes into the active state. The tkinter module has
three constants - NORMAL, ACTIVE, and DISABLED,
representing normal, active, and disabled states, respectively. In
place of these constants, we can also use strings "normal", "active",
and "disabled". Example 16.5(a) illustrates various states for the
button widget.
padx and pady The padx and pady attributes add extra spaces (in pixels) around
the widget. The padx attribute adds equal spaces to the left and the
ipadx and ipady right of the widget. At the same time, the pady attribute adds equal
spaces on the top and the bottom of the widget. Example 16.5(b)
illustrates padding around a widget.

742
The attributes ipadx and ipady allocate the spaces around the text
inside the widget boundary in the x and y directions, respectively.
background or bg The background colors of widgets can be set with the background
foreground or fg attribute. We can also use bg as an abbreviation of background.
Similarly, the foreground colors of widgets can be set with the
activebackground foreground attribute, which can also be abbreviated to fg.
activeforground
In the active state of a widget, the background and foreground can
be changed using the activebackground and activeforground
attributes, respectively.

In tkinter, color values can be a string specifying the proportion of


red, green and blue in hexadecimal digits. For example, "#ffffff" is
white, "#000000" is black, "#00ff00" is green, "#ff0000" is red and
"#00ffff" is cyan. we can also use standard color names such as
"white", "black", "red", "green", "blue", "cyan", "yellow", and
"magenta".

Example 16.5(c) illustrates these attributes.


width and height The width and height attributes set the width and height of the
widget. Width and height are specified in the number of characters.
Example 16.5(d) illustrates these attributes.
relief A relief is a border decoration to produce different visual
appearances. The tkinter module supports the following relief
values: SUNKEN, RAISED, GROOVE, RIDGE, and FLAT. The
value of the relief attribute can also be set using strings, such as
"sunken", "raised", "groove", "ridge", and "flat". Example 16.5(e)
illustrates various types of relief.
font The font attribute set the font of the text of the widget. A font is
created with the Font class with the following syntax:
myfont=tkinter.Font(family="font family", size=n, style="style")

For example, font=tk.Font('Times', '18', 'italic')) creates a font from


the Times family with size 18 pixels of italic style. If the font family
is not available on the platform, the tkinter uses the default font.
Further, the tkinter module has few built-in fonts such as
TkTooltipFont, TkDefaultFont, or TkTextFont.
Example 16.5(f) illustrates the font attribute.

743
cursor The cursor is a small icon that shows where the mouse pointer is
located on the screen. We can use different shapes for different
widgets. Commonly used cursor shapes available in the tkinter
module are "arrow", "circle", "clock","cross", "dotbox", "exchange",
"fleur", "heart", "man", "mouse", "pirate", "plus", "shuttle", "sizing",
"spider", "spraycan", "star", "target", "tcross", "trek", "watch". We
use the cursor attribute to change the shape of the cursor for a
widget. Example 16.5(g) illustrates cursor setting.
activeforeground It is used to set the color of the text when the widget is activated.
activebackground It is used to set the color of the background when the widget is
activated.
image It is used to set an image to be displayed on the widget.

Example 16.5(a): Various states of widgets

import tkinter as tk
root=tk.Tk() #Create the main application window
root.title("Demo of standard attributes") #Set the title of the window
root.geometry("250x130") #Set the size of the window and its location

#Setting states using string constants


label=tk.Label(root, text="Normal", activebackground="green")#Normal
widget
label.grid(row=0,column=0, padx=10, pady=10)
label1=tk.Label(root, text="Active",
state="active",activebackground="green")#Active widget
label1.grid(row=0,column=1, padx=10, pady=10)
label1=tk.Label(root, text="Disabled") #Disabled widget
label1.grid(row=0,column=2, padx=10, pady=10)

#Setting states using tkinter constants


button=tk.Button(root, text="Normal", state=tk.NORMAL) #Normal widget
button.grid(row=1,column=0, padx=10, pady=10)
button1=tk.Button(root, text="Active",state=tk.ACTIVE,
activebackground='blue')#Active widget
button1.grid(row=1,column=1, padx=10, pady=10)
button=tk.Button(root, text="Disabled", state=tk.DISABLED) #Disabled
widget
button.grid(row=1,column=2, padx=10, pady=10)

checkbutton=tk.Checkbutton(root, text="Normal", state=tk.NORMAL)


#Normal widget
checkbutton.grid(row=2,column=0, padx=10, pady=10)

744
checkbutton1=tk.Checkbutton(root, text="Active",
activebackground='blue')
checkbutton1["state"]=tk.ACTIVE #Activating widget
checkbutton1.grid(row=2,column=1, padx=10, pady=10)
checkbutton2=tk.Checkbutton(root, text="Disabled")
checkbutton2["state"]=tk.DISABLED #Disabling widget
checkbutton2.grid(row=2,column=2, padx=10, pady=10)

root.mainloop() #Start the event loop


GUI

Example 16.5(b): Padding around widgets

import tkinter as tk
root=tk.Tk() #Create the main application window
root.title("Demo of standard attributes") #Set the title of the window
root.geometry("250x130") #Set the size of the window and its location

#Labels without padding


label=tk.Label(root, text="Label 1")
label.grid(row=0,column=0)
label1=tk.Label(root, text="Label 2")
label1.grid(row=0,column=1)
label1=tk.Label(root, text="Label 3")
label1.grid(row=1,column=0)
label1=tk.Label(root, text="Label 4")
label1.grid(row=1,column=1)

#Labels with padding


label=tk.Label(root, text="Padded Label 5")
label.grid(row=2,column=0, padx=15, pady=10)

745
label1=tk.Label(root, text="Padded Label 6")
label1.grid(row=2,column=1, padx=15, pady=10)
label1=tk.Label(root, text="Padded Label 7")
label1.grid(row=3,column=0, padx=15, pady=10)
label1=tk.Label(root, text="Padded Label 8")
label1.grid(row=3,column=1, padx=15, pady=10)

root.mainloop() #Start the event loop

GUI

Example 16.5(c): Setting colors of widgets

import tkinter as tk
root=tk.Tk() #Create the main application window
#Setting background, foreground, active background and active
foreground colors of widgets
button=tk.Button(root, text="Red background", bg="red")
button.grid(row=0,column=0, padx=15, pady=10)
button1=tk.Button(root, text="Blue foreground", fg="#0000FF")
button1.grid(row=0,column=1, padx=15, pady=10)
button2=tk.Button(root, text="Green active background", state="active",
activebackground='green')
button2.grid(row=1,column=0, padx=15, pady=10)
button3=tk.Button(root, text="Magenta active
foreground",state="active", activeforeground='magenta')
button3.grid(row=1,column=1, padx=15, pady=10)

root.mainloop() #Start the event loop


GUI

746
Example 16.5(d): Setting the width and height of a widget

import tkinter as tk
root=tk.Tk() #Create the main application window
#Setting the width and heigth of a widget
button=tk.Button(root, text="Default Button")
button.grid(row=0,column=0, padx=15, pady=10)
button1=tk.Button(root, text="30 characters wide button",width=30)
button1.grid(row=0,column=1, padx=15, pady=10)
button2=tk.Button(root, text="Button with three lines height",height=3)
button2.grid(row=1,column=0, padx=15, pady=10)
button3=tk.Button(root, text="Button(30x3)",width=30, height=3)
button3.grid(row=1,column=1, padx=15, pady=10)
root.mainloop() #Start the event loop
GUI

747
Example 16.5(e): Various types of widget reliefs

import tkinter as tk
root=tk.Tk() #Create the main application window
#Setting border decoration using the relief attribute
button=tk.Button(root, text="Flat Button", relief=tk.FLAT)
button.grid(row=0,column=0, padx=15, pady=10)
button1=tk.Button(root, text="Sunken Button",relief="sunken")
button1.grid(row=0,column=1, padx=15, pady=10)
button2=tk.Button(root, text="Raised Button",relief="raised")
button2.grid(row=0,column=2, padx=15, pady=10)
button3=tk.Button(root, text="Grooved Button",relief= tk.GROOVE)
button3.grid(row=1,column=0, padx=15, pady=10)

button4=tk.Button(root, text="Ridge Button",relief=tk.RIDGE)


button4.grid(row=1,column=1, padx=15, pady=10)

root.mainloop() #Start the event loop


GUI

Example 16.5(f): Setting fonts of widgets

import tkinter as tk
root=tk.Tk() #Create the main application window
#Setting fonts of widgets
button=tk.Button(root, text="Times 18 italic", font=('Times', '18',
'italic'))
button.grid(row=0,column=0, padx=15, pady=10)
button1=tk.Button(root, text="Times 12 bold",font=('Times', '12',
'bold'))
button1.grid(row=0,column=1, padx=15, pady=10)
button2=tk.Button(root, text="Arial 15 underline",font=('Arial', '15',
'underline'))

748
button2.grid(row=0,column=2, padx=15, pady=10)
button3=tk.Button(root, text="TkTextFont",font="TkTextFont")
button3.grid(row=1,column=0, padx=15, pady=10)

button4=tk.Button(root, text="TkTooltipFont",font="TkTooltipFont")
button4.grid(row=1,column=1, padx=15, pady=10)
button5=tk.Button(root, text="TkDefaultFont",font="TkDefaultFont")
button5.grid(row=1,column=2, padx=15, pady=10)

root.mainloop() #Start the event loop


GUI

Example 16.5(g): Setting cursors for widgets

import tkinter as tk
root=tk.Tk() #Create the main application window
#Setting cursors of widgets
button=tk.Button(root, text="Circle cursor", cursor = "circle")
button.grid(row=0,column=0, padx=15, pady=10)
button1=tk.Button(root, text="Clock cursor",cursor ="clock")
button1.grid(row=0,column=1, padx=15, pady=10)
button2=tk.Button(root, text="Cross cursor",cursor ="cross")
button2.grid(row=0,column=2, padx=15, pady=10)
button3=tk.Button(root, text="Man cursor",cursor ="man")
button3.grid(row=1,column=0, padx=15, pady=10)

button4=tk.Button(root, text="Shuttle cursor",cursor ="shuttle")


button4.grid(row=1,column=1, padx=15, pady=10)
button5=tk.Button(root, text="Spraycan cursor",cursor ="spraycan")
button5.grid(row=1,column=2, padx=15, pady=10)

root.mainloop() #Start the event loop


GUI

749
16.5.2 Geometry Layout Managers
For organizing widgets throughout the parent widget area, the tkinter module
provides the following geometry managers: pack, grid, and place. The place geometry
manager positions a widget using the absolute value of x and y coordinates. The pack
geometry manager organizes widgets in horizontal and vertical boxes utilizing an
algorithm. The grid geometry manager places widgets in a tabular two-dimensional grid.
We can use any one geometry manager to create the desired layout. We should not mix grid
and pack geometry managers in a program.

The pack layout manager: The pack geometry manager is a relative position manager that
places widgets in horizontal and vertical boxes in the main window or container widget. It
is called relative as when we resize the container; widgets automatically adjust their
positions base on the size of the container. The layout is controlled with the fill, expand, and
side options. These options are briefly described in Table 16.4.

Table 16.4: Options of the pack layout manager

Option Description
side The side option decides the location of the widget in the available space for
the widget. There are four possible locations: top, bottom, left, and right.
The default is the top option. The top option places the widget adjacent to
the top edge of the container. If there is already a widget, the new widget
will be placed just below that. Similarly, the left, right, and bottom options
place the widget along the container window's left, right, and bottom edges.
Example 16.5(h) illustrates the side option.
To create a complex playout, we usually use container widgets, such as
frames to place other widgets properly. Each frame uses its own geometry
manager. Example 16.5(i) uses frames to create a data entry form.

750
expand The expand option controls how much of the available space of the container
is allocated to widgets. If the expand options of all the widgets are set to
false or 0, the pack manager allocates the minimum space required to
display each widget. However, if the expand option is set to true, the extra
available space is equally distributed among all the widgets with expand=1.
Example 16.5(j) illustrates the expand options.
fill The fill option increases the size of the widget to occupy the available space
to a widget. It can take the following three values, tk.X, tk.Y, and tk.BOTH.
The value tk.X, or "x", increases the size in the x-direction; the value tk.Y, or
"y", increases the size in the y-direction and the value tk.BOTH, "both",
increase the size in both directions. Example 16.5(k) illustrates the fill
options. You can notice that if expand is set to false, the fill in y-direction
will do nothing as the pack manager only allocate the minimum height
required to show the widget. However, the x-direction has no such limit.

Example 16.5(h): The side option of the pack layout manager

import tkinter as tk
root = tk.Tk()
root.geometry('300x200') #Available space
b1 = tk.Button(root, text="Left", width=15)
b1.pack(side='left') #Place adjacent to the left edge
b2 = tk.Button(root, text="Right", width=15)
b2.pack(side='right') #Place adjacent to the right edge
b3 = tk.Button(root, text="Top", width=15)
b3.pack(side='top') #Place adjacent to the top edge
b4 = tk.Button(root, text="Bottom", width=15)
b4.pack(side='bottom') #Place adjacent to the bottom edge
b5 = tk.Button(root, text="Top1", width=15)
b5.pack(side='top') #Place adjacent to the last widget placed at the
top edge
b6 = tk.Button(root, text="Bottom1", width=15)
b6.pack(side='bottom') #Place adjacent to the last widget placed at the
bottom edge

root.mainloop()
GUI

751
Example 16.5(i): The side attribute

import tkinter as tk

root = tk.Tk()
root.geometry('300x200')
#Using frames to properly align widgets
frame1=tk.Frame(root) #Frame 1
frame1.pack(pady=10)
label1 = tk.Label(frame1,text="Name", width=20)
label1.pack(side="left")
entry1=tk.Entry(frame1)
entry1.pack(side="right")
frame2=tk.Frame(root) #Frame 2
frame2.pack(pady=10)
label2 = tk.Label(frame2,text="Class", width=20)
label2.pack(side="left")
entry2=tk.Entry(frame2)
entry2.pack(side="right")
frame3=tk.Frame(root) #Frame 3
frame3.pack(pady=10)
label3 = tk.Label(frame3,text="Age", width=20)
label3.pack(side="left")
entry3=tk.Entry(frame3)
entry3.pack(side="right")
frame4=tk.Frame(root) #Frame 4

752
frame4.pack()
b1=tk.Button(frame4, text="Save")
b1.pack(side="right", padx=10)
b2=tk.Button(frame4, text="Discard")
b2.pack(side="right", padx=10)
b3=tk.Button(frame4, text="Help")
b3.pack(side="right", padx=10)
root.mainloop()

GUI

Example 16.5(j): Uses of the expand option

import tkinter as tk

root = tk.Tk()
root.geometry('200x200')

frame1 = tk.Frame(root, width=200, height=100, bg="green")


frame1.pack(expand=1, fill=tk.BOTH)
#Widgets occupy the minimum space in the frame
tk.Button(frame1, text='Expand = 0').pack(expand=0)
tk.Button(frame1, text='Expand = 0').pack(expand=0)
#The first widget occupy the minimum space required for its display but
the second widget expand to the remaining available space in the frame
frame2 = tk.Frame(root, width=200, height=100, bg="red")

753
frame2.pack(expand=1, fill=tk.BOTH)
tk.Button(frame2, text='Expand = 0').pack(expand=0)
tk.Button(frame2, text='Expand = 1').pack(expand=1)
#Widgets expand equally in the total space in the frame
frame = tk.Frame(root, width=100, height=100, bg="blue")
frame.pack(expand=1, fill=tk.BOTH)
tk.Button(frame, text='Expand = 1').pack(expand=1)
tk.Button(frame, text='Expand = 1').pack(expand=1)
root.mainloop()

GUI

Example 16.5(k): Effects of the fill attribute

import tkinter as tk

root = tk.Tk()
root.geometry('200x300')
#Effect of combination of fill and expand settings
frame = tk.Frame(root, width=100, height=100, bg="black")
frame.pack(expand=1, fill=tk.BOTH)
tk.Button(frame, text='Fill = not set, expand=0').pack(expand=0)
tk.Button(frame, text='Fill = not set, expand=0').pack(expand=0)

frame1 = tk.Frame(root, width=200, height=100, bg="green")


frame1.pack(expand=1, fill=tk.BOTH)

754
#Widgets occupy the minimum space in the frame
tk.Button(frame1, text='Fill = x, expand=0').pack(expand=0, fill='x')
tk.Button(frame1, text='Fill = y, expand=0').pack(expand=0, fill='y')

#The first wiget occupy the minimum space required for its display but
the second widget expand to the remaining available space in the frame
frame2 = tk.Frame(root, width=200, height=100, bg="red")
frame2.pack(expand=1, fill=tk.BOTH)
tk.Button(frame2, text='Fill = x,expand=0').pack(expand=0, fill='x')
tk.Button(frame2, text='Fill = y, expand=1').pack(expand=1, fill='y')

#Widgets expand equally in the total space in the frame


frame3 = tk.Frame(root, width=100, height=100, bg="blue")
frame3.pack(expand=1, fill=tk.BOTH)
tk.Button(frame3, text='Fill = both, expand=1').pack(expand=1,
fill='both')
tk.Button(frame3, text='Fill = both, expand=1').pack(expand=1,
fill='both')

root.mainloop()

GUI

755
The grid layout manager: The grid geometry manager is the most widely used layout
manager as it can be used to create complicated layouts easily. It divides the available space
of a container into a two-dimensional grid. We can place widgets in grid cells. The
individual grid cell can be accessed with its row and column indices. It also allows merging
adjacent grid cells to accommodate larger widgets. Table 16.5 shows the attributes that
control the layout in the grid manager.

Table 16.5: The grid layout manager attributes

Parameters Meaning
row and column The attributes row and column specifies the row and column index
where the widget will be placed. The index of the first row and the
first column is 0. The grid manager automatically determines the

756
maximum number of rows and columns based on the index used.
We can keep some grid cells blank. Example 16.5(l) illustrates the
row and column attributes.
rowspan, When we want to spread a widget in more than one cell, we can
columnspan use the rowspan to spread in more than one row and use
columnspan to spread in more than one column. We can use both
simultaneously to cover more than one row and more than one
column. Example 16.5(m) illustrates the rowspan and the
columnspan attributes.
sticky If the cell is larger than the widget size, the sticky option is used to
specify the location within the cell where the widget will be placed.
The possible values of sticky are N, S, E, W, NW, NE, SW, and SE.

NW N NE

W Default location E

SW S SE

Example 16.5(n) illustrates the use of the sticky option.

padx The padx attribute adds external padding above and below the
pady widget. The pady adds external padding to the left and right of the
ipadx widget. The ipadx adds internal padding inside the widget from
ipady the left and right sides. The ipady adds internal padding inside the
widget from the top and bottom sides.

757
Example 16.5(l): The row and column attributes of the grid layout manager

import tkinter as tk

root = tk.Tk()
#The grid layout manager. Location is decided by the row and column
values

tk.Button(root, text='Button in Cell (0, 0)').grid(row=0,column=0)


tk.Button(root, text='Button in Cell (0, 1)').grid(row=0,column=1)
tk.Button(root, text='Button in Cell (0, 2)').grid(row=0,column=2)
tk.Button(root, text='Button in Cell (1, 0)').grid(row=1,column=0)
#tk.Button(root, text='Button in Cell (1, 1)').grid(row=1,column=1)
tk.Button(root, text='Button in Cell (1, 2)').grid(row=1,column=2)
tk.Button(root, text='Button in Cell (2, 0)').grid(row=2,column=0)
tk.Button(root, text='Button in Cell (2, 1)').grid(row=2,column=1)
tk.Button(root, text='Button in Cell (2, 2)').grid(row=2,column=2)

root.mainloop()

GUI

Example 16.5(m): Uses of rowspan and columnspan attributes

import tkinter as tk

root = tk.Tk()
#The grid layout manager. use of rowspan and column span to merge
cells.
bt1=tk.Button(root, text='Cell (0, 0), columnspan=2')
bt1.grid(row=0,column=0,columnspan=2, padx=5, pady=5)
bt2=tk.Button(root, text='Cell (0, 2)')
bt2.grid(row=0,column=2, padx=5, pady=5)
bt3=tk.Button(root, text='Cell(1, 0)\n rowspan=2')

758
bt3.grid(row=1,column=0, rowspan=2, padx=5, pady=5)
bt4=tk.Button(root, text='Cell (1, 1) columnspan=2\nrowspan=2')
bt4.grid(row=1,column=1, rowspan=2, columnspan=2, padx=5, pady=5)

root.mainloop()

GUI

Example 16.5(n): Uses of the sticky attribute

import tkinter as tk

root = tk.Tk()
#Uses of the sticky attribute to locate widgets in their available
spaces

tk.Button(root, text='Cell (0, 0), sticky=


default').grid(row=0,column=0)
tk.Button(root, text='Cell (0, 1), sticky=W',
height=3).grid(row=0,column=1, sticky="W")
tk.Button(root, text='Cell (0, 2), sticky=NE').grid(row=0,column=2,
sticky="NE")
tk.Button(root, text='Cell (1, 0), sticky = N',
width=25).grid(row=1,column=0, sticky="N")
tk.Button(root, text='Cell (1, 1)',height=3,
width=25).grid(row=1,column=1)
tk.Button(root, text='Cell (1, 2), sticky=S',
width=25).grid(row=1,column=2, sticky="S")
tk.Button(root, text='Cell (2, 0) sticky =NW').grid(row=2,column=0,
sticky="NW")
tk.Button(root, text='Cell (2, 1), sticky=E',
height=3).grid(row=2,column=1, sticky="E")

759
tk.Button(root, text='Cell (2, 2) sticky=SE').grid(row=2,column=2,
sticky="SE")

root.mainloop()

GUI

Example 16.5(o): Padding widgets to create extra spaces

import tkinter as tk

root = tk.Tk()
#External and internal padding
tk.Button(root, text='Cell (0, 0)').grid(row=0,column=0, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (0, 1)').grid(row=0,column=1, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (0, 2)').grid(row=0,column=2, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (1, 0)').grid(row=1,column=0, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (1, 1)').grid(row=1,column=1, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (1, 2)').grid(row=1,column=2, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (2, 0)').grid(row=2,column=0, padx=5,pady=5,
ipadx=5,ipady=5)

760
tk.Button(root, text='Cell (2, 1)').grid(row=2,column=1, padx=5,pady=5,
ipadx=5,ipady=5)
tk.Button(root, text='Cell (2, 2)').grid(row=2,column=2, padx=5,pady=5,
ipadx=5,ipady=5)
root.mainloop()

GUI

The place layout manager: The place geometry layout manager is an absolute layout
manager where we can explicitly specify the position and the size of a widget in the
container window. This geometry manager is the simplest layout manager, but the size and
the position of a widget do not change if we resize the window. Further, changing the
caption and the font of the caption may require a re-layout. Hence, it is not recommended
as a general-purpose layout manager. However, it has the ability to create any complex
layout. Table 16.6 lists the attributes of the place manager and briefly describes them.

Table 16.6: The attributes of the place layout manager

anchor The attribute anchor is the reference location on a widget used to place
the widget in the container window. The tkinter module supports the
following locations: north ("n"), east("e"), south("s"), west("w"), north-
east("ne"), north-west("nw"), south-east("se"), south-west("sw"), and
"center". These values are also defined in the tkinter module as tk.N, tk.E,
tk.S, tk.W, tk.NE, tk.NW, tk.SE, tk.SW and tk.CENTER, respectively.
These positions are shown in the following figure. Example 16.5(p)
illustrates the anchor attribute.

761
nw n ne

w center e

sw s se

bordermode The bordermode attribute decides the origin of the pixel coordinate
system to place widgets in the container. It can be set to either tk.INSIDE
("inside") or tk.OUTSIDE ("outside"), where "inside" means the border
width of the parent widget is ignored during the calculation of the offsets
and "outside" means the border width of the parent widget will be
included. The figure below shows how this attribute affects the origin.
See example 16.5(q).

Origin when bordermode="outside"

Origin when bordermode="inside"

Widget

Border parent widget


Parent widget

762
x, y The attributes x and y specify the horizontal and vertical offsets of the
relx, rely selected anchor point (by default, the anchor point is the northwest
corner, i.e., nw) of the widget (in pixels) from the pixel coordinate origin.
By default, the origin is the northwest (i.e., upper left) corner of the
container window/widget.
The attributes relx and rely are the horizontal and vertical offset of the
anchor point from the northwest corner of the container widget and are
specified as a float between 0.0 and 1.0, as a fraction of the height and
width of the container widget/window. Example 16.5(q) illustrates the
attributes x, y, relx, and rely.
height, The attributes height and width specify the height and width of the
width, widget in pixels. The attribute relheight and relwidth specify the height
relheight, and width as a float between 0.0 and 1.0, as a fraction of the height and
relwidth width of the parent widget. The relative dimensioning automatically
adjust itself when we re-size the parent window. Example 16.5(q)
illustrates the attributes height, width, relheight, and relwidth.

Example 16.5(p): The anchor attribute

import tkinter as tk

root = tk.Tk()
#Setting anchor points for widgets
f1 = tk.Frame(root, relief=tk.RAISED,bg='red', width=200, height=100)
f1.grid(row=0,column=0)
b1=tk.Button(f1,text="Anchor = default")
b1.place(x=20,y=20)

f2 = tk.Frame(root, relief=tk.RAISED, bg='green',width=200, height=100)


f2.grid(row=0,column=1)
b2=tk.Button(f2,text="Anchor = north")
b2.place(x=20,y=20, anchor='n')

f3 = tk.Frame(root, relief=tk.RAISED, bg='blue',width=200, height=100)


f3.grid(row=1,column=0)
b3=tk.Button(f3,text="Anchor = east")
b3.place(x=20,y=20, anchor='e')

f4 = tk.Frame(root, relief=tk.RAISED, bg='black',width=200, height=100)


f4.grid(row=1,column=1)
b4=tk.Button(f4,text="Anchor = south-east")
b4.place(x=20,y=20, anchor='sw')

763
root.mainloop()
GUI

Example 16.5(q): Absolute and relative positioning and sizing

import tkinter as tk

root = tk.Tk()
#Absolute and relative positioning and sizing of widgets
f1 = tk.Frame(root,bg='red', width=200, height=100)
f1.grid(row=0,column=0)
b1=tk.Button(f1,text="Absolute reference")
b1.place(x=20,y=20)

f2 = tk.Frame(root, bg='green',width=200, height=100)


f2.grid(row=0,column=1)
b2=tk.Button(f2,text="Relative reference")
b2.place(relx=.25,rely=.25)

f3 = tk.Frame(root, bg='blue',width=200, height=100)


f3.grid(row=1,column=0)
b3=tk.Button(f3,text="Absolute size")
b3.place(x=20,y=20, width=150, height=30)

f4 = tk.Frame(root, bg='black',width=200, height=100)


f4.grid(row=1,column=1)
b4=tk.Button(f4,text="Relative size")
b4.place(x=20,y=20,relwidth=.75, relheight=.3)

764
root.mainloop()
GUI

16.6 Button Widget


A button widget is used to trigger an action, such as calling a function, closing a
window. A button widget is created using the Button class. The appearance of a button is
controlled through various attributes described in table 16.3. It has a specific attribute
command that links the click event of the mouse. We can also use the bind method to link
other events with functions for the widget. Example 16.6(a) illustrates the command
attribute and the bind () method.

We can create a hotkey for a button by binding the keypress event of the hotkey
with the parent window. Note, don’t bind the hotkey with the button. The hotkey of a
widget is normally shown as an underlined letter and is activated by the user as a
combination of Alt + hotkey_letter. A letter can be underlined with the attribute underline.
The concept of the hotkey can be used with some other widgets also. Note, the hotkey for a
widget should be unique on a form. Example 16.6(b) illustrates the hotkey concept.

We can change the caption of a button during run-time using the attribute
textvariable. We cannot directly change the values of widget variables. For changing values
of widget variables, we have to create the corresponding tkinter variable types using the

765
following methods tk.BooleanVar(), tk.StringVar(), tk.IntVar(), and tk.DoubleVar(). Once
a tkinter variable is created, its set () method is used to assign the corresponding type of
values, and its get () method is used to get the current value of the widget variable. This
concept is true for all the widgets that support the variables. Example 16.6(c) illustrates how
to change the caption of a button at run-time. The number of clicks on the button is reflected
in its caption.

Example 16.6(a): Event binding with button

import tkinter as tk

def funLeftClick(event=None): #The left click handler


print("The left mouse button clicked")

def funRightClick(event=None): #The right click handler


print("The right mouse button clicked")

root = tk.Tk()
#The button widget
b1=tk.Button(root,text="Handling the Left and the Right
clicks",command=funLeftClick)#Left click
root.bind("<Button-3>",funRightClick) #Binding the right click
b1.pack(padx=10,pady=10)
root.mainloop()
GUI

Output
The left mouse button clicked
The right mouse button clicked

Example 16.6(b): Creating a hotkey for a widget

import tkinter as tk

def hotKey(event=None): #The hotkey handler

766
print("The hotkey H is pressed")

def leftClick(event=None): #The left click handler


print("The left button clicked")

root = tk.Tk()
#A button with a hotkey
b1=tk.Button(root,text="Button with a Hot key",underline=14,
command=leftClick)#Left click
root.bind("<Alt-H>",hotKey) #Binding a hotkey
root.bind("<Alt-h>",hotKey) #Binding a hot key
b1.pack(padx=10,pady=10)
root.mainloop()

GUI

Example 16.5(c): Changing the caption of a button at runtime

import tkinter as tk

def clickCount(): #Click handler


global c
global click_count
c=c+1
#Reseeting the value of the caption
click_count.set("The number of clicks on this button = " + str(c))

root = tk.Tk()
#Creating a tkinter string variable
click_count= tk.StringVar(None,"The number of clicks on this button =
0")
c=0 #Initialising a counter
#A button with a variable caption
b1=tk.Button(root,textvariable=click_count,command=clickCount)#Left
click

b1.pack(padx=10,pady=10)
root.mainloop()

767
GUI

16.7 Canvas Widget


The canvas widget is used to create a rectangular graphical area for drawing objects
such as lines, circles, arcs, texts, and embed images. It can be used as a graphics editor. A
canvas can be created using the Canvas class. It provides methods to create different types
of geometrical objects. The widget provides a method to save the created graphics a .ps file.
The commonly used attributes and methods are briefly described in Table 16.7.

Table 16.7: Attributes and methods of the canvas widget

Name Description
width and The attributes width and height specify the width and height of the
height canvas in pixels. Example 16.7(a) creates a canvas and draws two
ovals.
scrollregion By default, the size of the canvas is infinite in x and y directions.
However, we can limit the canvas scrolling in x and y directions using
xscrollcommand the attribute scrollregion. It takes a tuple of four numbers, (x1, y1, x2,
yscrollcommand y2), where (x1, y1) is the left-top corner of the canvas and (x2, y2) is
the right-bottom corner. When the canvas widget size is smaller than
xscrollincrement the scrollregion, we use horizontal and vertical scroll bars to scroll the
yscrollincrement canvas. The xscrollcommand and yscrollcommand attributes are
used to collect horizontal and vertical scroll bars, respectively. The
attributes xscrollincrement and yscrollincrement specify the step size
of the scroll in x and y directions, respectively. Example 16.7(b) creates
a scrollable canvas.
Create_line() The create line () method draws a chain of lines between given points.
Its syntax is given as below:

create_line(x1, y1, x2, y2, …, xn, yn, **options)

768
where (x1, y1), x2, y2), …, (xn, yn) are endpoints of line segments. The
options arguments control the color and appearance of lines. The fill
attribute specifies the color, width specified the thickness, and dash
specifies various dash line patterns. The dash attribute is a tuple of
integers or a string of dashes and dots. For example, dash = (2,4) or
dash = "." means a pattern of two solid and four transparent pixels.
We cannot create any arbitrary dash patterns as dash line patterns are
limited to the patterns supported by the operating system. On
Windows operating system, the following four patterns are available:
(2, 4), (6, 4), (6, 4, 2, 4,) and (6, 4, 2, 4, 2, 4). The string equivalents of
these patterns are: ".", "-", "-.", and "-..". If we specify any other line
patterns, the nearest available matching pattern will be used. Example
16.7(c) illustrates the create_line () method.
create_arc() The create_arc() method is used to create an arc. Its syntax is:

create_arc(bb, start=start_angle, extent=end_angle, fill=color,


*options)

where, bb is the bounding box of the ellipse of which the arc is a part.
To create a circular arc, take a square bounding box. It is a tuple of 4
integers (x1, y1, x2, y2). Where (x1, y1) is the upper left corner and (x2,
y2) is the lower corner of the bounding box. The parameter start is the
start angle, and extend is the angle from start to the end angle of the
arc in degree (See the figure given below). Zero degrees represent the
x-axis, and a positive value is in the counterclockwise direction, and a
negative value is in the clockwise direction. The fill parameter is the
fill color of the arc. Example 16.7(d) illustrates the method.

769
create_polygon() The create_polygon method creates a polygon from the given vertex
points. The start point and endpoint are connected. The syntax of the
method is:

create_polygon (x1, y1, x2, y2, ... xn, yn, **options)

Where (x1, y1), (x2, y2), …, (xn, yn) are vertices of the polygon. The
options attributes are used to control the appearance of the polygon.
Example 16.7(e) illustrates the create_polygon method.
create_oval() The create_oval method creates an oval from a given bounding box.
The syntax of the method is:

create_oval (x1, y1, x2, y2, **options)

Where (x1, y1) and (x2, y2) are the diagonally opposite corners of the
rectangular bounding box. The options attributes are used to control
the appearance of the oval.
Example 16.7(f) illustrates the create_oval method.
create_rectangle The create_rectangle method creates a rectangle. The syntax of the
method is:

create_rectangle(x1, y1, x2, y2, **options)

Where (x1, y1) and (x2, y2) are the diagonally opposite corners of the
rectangular. The options attributes are used to control the appearance
of the oval.
Example 16.7(g) illustrates the create_rectangle method.
create_image The create_image method is used to add an image on the canvas. Its
syntax is:

create_image(x, y, anchor=anchor_location, image=image_id )

where x, y is the location on the canvas where the anchor point of the
image will be located. The possible anchor points are N, S, E, W, NW,
NE, SW, SE, and center points of the image. The image argument is
the image handle returned by the PhotoImage method, which loads
the image in memory. However, the tkinter PhotoImage () method
only supports the GIF, PGM, PPM, and PNG file formats. The syntax
of the PhotoImage() method is:

770
image_id = PhotoImage(file = image_address)

Example 16.7(h) illustrates the create_image method.


create_text The create_text method writes texts at a specified location on the
canvas. Its syntax is:
text_id = create_text(x, y, **option)
where (x,y) is the location of the text, the option parameter includes
text, font, and other attributes to control the appearance of the text.
The text attribute is the text that will be shown on the canvas. Example
16.7(i) illustrates the create_text method.

Example 16.7(a): Create a canvas

import tkinter as tk
parent = tk.Tk()
#Create a canvas of size 100x100 with green background
canvas = tk.Canvas(parent, width=100, height=100, bg="green")
canvas.create_oval(0,0, 100, 100, fill="blue") #Draw an oval
canvas.create_oval(25, 25, 75, 75, fill="red") #Draw an oval
canvas.pack()
parent.mainloop()
GUI

Example 16.7(b): Create a scrollable canvas

import tkinter as tk
parent = tk.Tk()
parent.geometry("150x150")
#Scrollable canvas

771
canvas = tk.Canvas(parent, width=100, height=100,
xscrollincrement=50,yscrollincrement=50)
canvas.create_oval(0, 0, 50, 50, fill="red")
canvas.create_oval(100, 100, 250, 250, fill="blue")
canvas.grid(row=0, column=0)
#Creatting a horizontal scroll bar
scroll_x = tk.Scrollbar(parent, orient="horizontal",
command=canvas.xview)
scroll_x.grid(row=1, column=0, sticky="ew")
#Creating a vertical scroll bar
scroll_y = tk.Scrollbar(parent, orient="vertical",
command=canvas.yview)
scroll_y.grid(row=0, column=1, sticky="ns")
#Connecting scroll bars with canvas
canvas.configure(yscrollcommand=scroll_y.set,
xscrollcommand=scroll_x.set)
#Setting scrollable size
canvas.configure(scrollregion=(0,0,300,300))
parent.mainloop()
GUI

Example 16.7(c): Create a canvas

import tkinter as tk
parent = tk.Tk()
#Create arcs
canvas = tk.Canvas(parent, width=300, height=100, bg="white")

772
canvas.create_line(10,10,100,10) #Default line
canvas.create_line(10,20,100,20, fill="red") #Coloured line
canvas.create_line(10,30,100,30, width=4) #Thick line
canvas.create_line(10,40,100,40, dash=(2,4))#Dashed line
canvas.create_line(10,50,100,50, dash=(6,4), fill="#00FF00")#Long dash
line
canvas.create_line(10,60,100,60, dash=(6,4,2,4))#Long and small dashes
canvas.create_line(10,70,100,70, dash=(6,4,2,4,2,4))#Long and small-
small dashes
canvas.create_line(10,80,100,80, dash="-..")#Long and small-small
dashes
canvas.create_line(110,10,200,10,200,80,110,80)#Multiple line segments
canvas.create_line(250,10,300,80,210,80,250,10, dash=".", fill="blue")
canvas.pack()
parent.mainloop()
GUI

Example 16.7(d): Create arcs

import tkinter as tk
parent = tk.Tk()
#Create a canvas
canvas = tk.Canvas(parent, width=300, height=300, bg="white")
#Create arcs
bounding_box = 0,0, 300, 300 #Specify the bounding box of the ellipse
canvas.create_arc(bounding_box, start=0, extent=45, fill="red")#Create
a filled arc
canvas.create_arc(bounding_box, start=180, extent=-30,
fill="blue")#Create a filled arc
canvas.create_arc(bounding_box, start=-90, extent=30,
fill="black")#Create a filled arc
canvas.create_arc(bounding_box, start=-135, extent=-30)#Create an
unfilled arc

773
canvas.pack()
parent.mainloop()
GUI

Example 16.7(e): Draw polygons

import tkinter as tk
parent = tk.Tk()
#Create polygons
canvas = tk.Canvas(parent, width=310, height=100, bg="white")
canvas.create_polygon(10,10,100,10,100,80,10,80)#Draw a polygon
#Draw a polygon with a fill color and specified outline
canvas.create_polygon(150,10,200,80,110,80, dash=".",fill="blue",
outline='red')
canvas.create_polygon(250,10,300,80,210,80, dash="-",fill="white",
outline='red')
canvas.pack()
parent.mainloop()
GUI

774
Example 16.7(f): Draw ovals

import tkinter as tk
parent = tk.Tk()
#Create ovals
canvas = tk.Canvas(parent,width=400, height=150, bg="white")
canvas.create_oval(10,100,150,10)#Draw an oval
#A filled oval with border
canvas.create_oval(160,10,230,150, fill='red', width=4)
#Draw an unfilled oval with dashed outline
canvas.create_oval(250,10,350,110,width=4, fill='',dash="-..",
outline='green')
canvas.pack()
parent.mainloop()

GUI

775
Example 16.7(g): Draw rectangles

import tkinter as tk
parent = tk.Tk()
#Create rectangles
canvas = tk.Canvas(parent,width=400, height=150, bg="white")
canvas.create_rectangle(10,100,150,10)#Draw a rectangle
#A filled rectangle with a border
canvas.create_rectangle(160,10,230,150, fill='red', width=4)
#Draw an unfilled rectangle with dashed outline
canvas.create_rectangle(250,10,350,110,width=4, fill='',dash="-..",
outline='green')
canvas.pack()
parent.mainloop()
GUI

Example 16.7(h): Adding an image to a canvas

import tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root, width = 200, height = 200, bg='green')
canvas.pack()
img = tk.PhotoImage(file="Python.png") #Create image handle
canvas.create_image(30,30, anchor=tk.NW, image=img)#Put image on the
canvas
mainloop()

GUI

776
Example 16.7(i): Write texts on a canvas

import tkinter as tk
root = tk.Tk()
colors=['','red','green','blue','yellow','cyan']
canvas = tk.Canvas(root, width = 500, height = 200, bg='white')
canvas.pack()
for i in range(1,5):
font_name =('Helvetica',25-2*i,'bold') #Create font
#Write texts on the canvas
canvas.create_text(30,30*i,fill=colors[i], font=font_name,
anchor=tk.NW, text="Welcome in the world of canvas")#Put image on the
canvas
root.mainloop()
GUI

777
16.8 Checkbutton Widget
A checkbox button is a GUI widget used to choose an option from two mutually
exclusive options. It is used to answer the yes/no type of questions, such as, do you know
Python programming? A checkbox button is created from the class Checkbox and has the
following syntax:

check_button = tk.Checkbutton (root, **options)

where root is the container widget, or application window handle and options are used to
control the widget's appearance. The methods and attributes specific to the checkbox button
are listed in table 16.8, along with a brief description of each. For the standard attributes,
see table 16.3.

Table 16.8: Attributes and methods specific to the checkbox button

offvalue, The offvalue (i.e., the checkbox is unchecked/cleared) and onvalue


onvalue, (i.e., the checkbox is checked/selected) attributes are used to set the
variable off and on values, respectively. By default, offvalue and onvalue
are set to 0 and 1, respectively. Example 16.8(a) illustrates these
attributes.

778
deselect, The deselect () method clears (turn off) the Checkbutton through
flash, code.
invoke, The flash () method flashes the Checkbutton several times between
select, its active and normal colors but leaves it the way it started. This is
toggle used to get the attention of the user.
The invoke () method simulates the mouse click event through the
program. We can use it to change the state of a Checkbutton
through the program.
The select () method sets (turns on) the Checkbutton through the
program.
The toggle () method toggles the state of the Checkbutton. Example
16.8(b) illustrates these functions.

Example 16.8(a): Checkbutton attributes

import tkinter as tk
languages=["","Python","C++","Java"]

def printChoices(): #Print choices


print("Your choices are:")
for choice in check_values: #Iterate over checkboxes
if choice.get() > 0: print("Choice No:", choice.get(),",
Language:", languages[choice.get()])

root = tk.Tk()
label =tk.Label(root, text="Select the languages you know")
label.pack(padx=5)

check_values=list() #Create a list of control variables


check_values.append(tk.IntVar())
check_values.append(tk.IntVar())
check_values.append(tk.IntVar())

#Create checkboxes
check1=tk.Checkbutton(root, text="1. Python", variable=check_values[0],
onvalue=1)
check1.pack(anchor='nw',padx=5)
check2=tk.Checkbutton(root, text="2. C++", variable=check_values[1],
onvalue=2)
check2.pack(anchor='nw',padx=5)
check3=tk.Checkbutton(root, text="3. Java", variable=check_values[2],
onvalue=3)

779
check3.pack(anchor='nw',padx=5)
b1=tk.Button(root, text="Print Choices", command=printChoices )
b1.pack(padx=5, pady=5)

root.mainloop()
GUI

Output
Your choices are:
Choice No: 1, Language: Python
Choice No: 3, Language: Java

Example 16.8(b): Checkbutton methods

import tkinter as tk
languages=["Python","C++","Java"]

def clearChoices(): #Reset choices


check1.deselect()
check2.deselect()
check3.deselect()

def selectAll(): #Select All


check1.select()
check2.select()
check3.select()

def toggleChoices(): #Toggle choices


check1.toggle()
check2.toggle()
check3.toggle()

780
def invokeChoices(): #Invoke checkbuttons
check1.invoke()
check2.invoke()
check3.invoke()
root = tk.Tk()
label =tk.Label(root, text="Select the languages you know")
label.pack()

check_values=list()
check_values.append(tk.IntVar())
check_values.append(tk.IntVar())
check_values.append(tk.IntVar())

check1=tk.Checkbutton(root, text="1. Python", variable=check_values[0],


onvalue=1)
check1.pack(anchor='nw')
check2=tk.Checkbutton(root, text="2. C++", variable=check_values[1],
onvalue=2)
check2.pack(anchor='nw')
check3=tk.Checkbutton(root, text="3. Java", variable=check_values[2],
onvalue=3)
check3.pack(anchor='nw')
b1=tk.Button(root, text="Clear Choices", command=clearChoices )
b1.pack(side='left',padx=2)
b2=tk.Button(root, text="Select All", command=selectAll )
b2.pack(side='left',padx=2)
b3=tk.Button(root, text="Toggle Choices", command=toggleChoices )
b3.pack(side='left',padx=2)
b4=tk.Button(root, text="Invoke Choices", command=invokeChoices )
b4.pack(side='left',padx=2)
root.mainloop()
GUI

781
16.9 Entry Widget
The Entry widget is used to get one-line text input from the user. For a long input
text, the arrow keys can be used to move to scroll the text. We can also use the entry widget
to display and modify a single-line text. The following syntax is used to create an entry
widget:

entry = tk.Entry(root, **options)

where root is the parent window/widget, and options control the appearance and behavior
of the entry widget. Table 16.9 lists commonly used specific attributes and methods of the
entry widget. For the standard attributes, see table 16.3.

Table 16.9: Commonly used entry widget attributes and methods

Attribute/method Description
textvariable The textvariable attribute links the StringVar object with the content
of the entry widget. We can use the StringVar object to retrieve the
current text from your entry widget.
show The show attribute is used to make a password entry widget by
showing a specified character in place of the entered characters. For
example, show= '*', will display * for each entered character.
However, internally, the widget stores the actual characters.
delete, The delete () method is used to delete a part of the entry widget text.
get, Its syntax is delete(first, last = None ). The method will delete all the
insert characters between the indices first and last. If the last argument is
omitted, only the single character at the index first is deleted.
The get () method is used to get the current text of the widget as a
Python string.
The insert method inserts a string at a specified index. Its syntax is
insert (index, string), where index is the index where the string is
inserted.
Example 16.9 illustrates these methods.

782
Example 16.9: Entry widget attributes and methods

import tkinter as tk

def clearForm(): #Crear form data


user.set("")
password.set("")
password1.set("")
entry4.delete(0,tk.END)
entry4.insert(0,'$')

def defaultForm(): #Fild the form with the default values


user.set('DEFAULT')
password.set('123456')

def insertText(): #Insert the text in the user name field at index 1
entry1.insert(1, entry4.get())

def showPass(): #Display the password


password1.set(password.get())

root =tk.Tk()
user =tk.StringVar(root,'DEFAULT') #Initialise the default user name
password = tk.StringVar(root,'123456') #Initialise the default password
password1 = tk.StringVar(root,'')
text1 = tk.StringVar(root,'$') #Initialise the insert text
#Create user data entry fields
label1 = tk.Label(root, text="Enter your name:",anchor='nw',
width=30,justify=tk.LEFT)
label1.grid(row=0,column=0, padx=5,pady=5 )
entry1 = tk.Entry(root,textvariable=user, width=30)
entry1.grid(row=0,column=1, padx=5,pady=5)

label2 = tk.Label(root, text="Enter your password:",anchor='nw',


width=30,justify=tk.LEFT)
label2.grid(row=1,column=0, padx=5,pady=5, sticky='n')
entry2 = tk.Entry(root,show='*',textvariable=password, width=30)
entry2.grid(row=1,column=1, padx=5,pady=5)

label3 = tk.Label(root, text="Show password:", anchor='nw',


width=30,justify=tk.LEFT)
label3.grid(row=2,column=0, padx=5,pady=5, sticky='n')
entry3 = tk.Entry(root,textvariable=password1,state='disabled',
width=30)
entry3.grid(row=2,column=1, padx=5,pady=5)

783
label4 = tk.Label(root, text="Text to insert in name:", anchor='nw',
width=30,justify=tk.LEFT)
label4.grid(row=3,column=0, padx=5,pady=5, sticky='n')
entry4 = tk.Entry(root,textvariable=text1, width=30)
entry4.grid(row=3,column=1, padx=5,pady=5)
#Create different buttons
button1 = tk.Button(root, text = "Clear form", command=clearForm)
button1.grid(row=4,column=0,padx=30,pady=5,sticky = 'e')
button2 = tk.Button(root, text = "Set to default", command=defaultForm)
button2.grid(row=4,column=0,padx=30,pady=5,sticky = 'w')
button3 = tk.Button(root, text = "Show password", command=showPass)
button3.grid(row=4,column=1,padx=10,pady=5, sticky = 'e')
button4 = tk.Button(root, text = "Insert text", command=insertText)
button4.grid(row=4,column=1, padx=5,pady=5, sticky = 'w')

root.mainloop()
GUI

16.10 Frame Widget


The frame widget is a rectangular container widget, typically used to group and
layout other widgets in the application window or other container widgets. Each frame has
its own independent grid layout, which helps to make GUI design modular. A frame is
created using the Frame class and has the following syntax:

frame = tk.Frame ( root, *options)

where root is the parent container widget or application window, and options are attributes
to set the frame's appearance, such as frame size, background color, cursor shape, and relief.
By default, the frame shrinks or grows to fit its contents. However, we can override this by
784
using the method frame.grid_propagate(arg). The arg value 1 shrinks the frame, and the
value 0 expands to the specified size. See table 16.3 for the standard attributes. Example
16.10 illustrates the frame widget.

Example 16.10: Creating frames

from tkinter import *

root = Tk()
#Creating frames
frame1 = Frame(root,width=200, height=200,bg='green', bd=3,
relief='sunken')
frame1.grid(row=0, column=0, padx=5, pady=5)
frame1.grid_propagate(0)
label1= Label(frame1,text= "Frame 1")
label1.grid(row=0,column=0,padx=5, pady=5)
label1= Label(frame1,text= "Frame colour=green")
label1.grid(row=1,column=0,padx=5, pady=5)

frame2 = Frame(root, width=200, height=200, bg='red',bd=3,


relief='raised' )
frame2.grid(row=0, column=1, padx=5, pady=5)
frame2.grid_propagate(0)
label2= Label(frame2,text= "Frame 2")
label2.grid(row=0,column=0,padx=5, pady=5)
label2= Label(frame2,text= "Frame colour=red")
label2.grid(row=1,column=0,padx=5, pady=5)

root.mainloop()

GUI

785
16.11 Label Widget
The label widget is used to show non-editable single or multiline texts or an image.
It is typically used to create captions for other widgets or to display results. We can create
a label widget using the Label class with the following syntax:

label = tk.Label(root, **option)

where root is the parent container window or widget, and options are the attributes to set
the widget's appearance. Example 16.11 illustrates the label widget.

Example 16.11: Label widgets

import tkinter as tk
def changeLabel(): #Change label text
var.set(str(int(var.get())+1))
root = tk.Tk()
#Create a text label
var = tk.StringVar(root,"0")
label1 = tk.Label( root, text='Raised label', relief=tk.RAISED )
label1.grid(row=0,column=0,padx=5, pady=5)
label2= tk.Label(root,text= "Colored label", bg='green', fg='yellow')
label2.grid(row=0,column=1,padx=5, pady=5)
#Create a image label

786
logo = tk.PhotoImage(file="Python.png")
label3= tk.Label(root,image=logo, text="Image")
label3.grid(row=1,column=0,padx=5, pady=5)
#Create a text label with border
frame=tk.Frame(root, bg='red')
frame.grid(row=1,column=1,padx=5, pady=5)
label2= tk.Label(frame,text= "Label with border", bd=0)
label2.grid(padx=2,pady=2)
#Change the text of a label
button=tk.Button(root, text="Increase label value",
command=changeLabel)
button.grid(row=2, column=1, padx=2, pady=2)
label3= tk.Label(root,textvariable= var) #Label with a variable text
label3.grid(row=2, column=0, padx=2,pady=2)
root.mainloop()
GUI

16.12 Listbox Widget


The Listbox widget is used to show a list of items from which the user can select one
or multiple items. A listbox is created using the Listbox class and has the following syntax:

listbox = tk.Listbox (toot, **option )

787
where root is the parent window or container widget, and options are attributes to control
the appearance and behavior of the listbox. Table 16.10 lists commonly used specific
attributes and methods of the listbox widget. For the standard attributes, see table 16.3.

Table 16.10: Commonly used listbox widget attributes and methods

Attribute/method Description
listvariable The listvariable attribute stores a StringVar object which is
connected to all the list items in the listbox. Through this StringVar
object, we can modify the list items. The listvariable StringVar object
is a space-delimited string, i.e., the space acts as the separator of the
list items. To include a list item with spaces, we have to use the raw
Python string, and the spaces should be replaced with ASCII
sequence. For example, the string "Python Program JavaScript" will
create three list items, one for each word in the string. But the string
r"Python\x20Program JavaScript " will create two list items in the
listbox. Example 16.12(a) illustrates the listvariable.
activestyle The activestyle attribute controls the appearance of the active line
(the last clicked list item). It can take any of the following values:
'underline': The active line is underlined. This style is the default
option.
'dotbox': The active line is enclosed in a dotted box.
'none': No special appearance for the active line.
See example 16.12(a).
selectmode The selectmode attribute determines the ways we can select list
items using the mouse. We can use any one of the following modes:

tk.SINGLE: In this mode, we can only select one list item by clicking
on it. If we click on any other item in the list, the previous item is
deselected. We can't drag the mouse to select multiple items.
tk.MULTIPLE: In this mode, we can select multiple items by clicking
on different list items. A selected item is deselected by clicking on it
again, i.e., a click acts as a toggle. We can't drag the mouse to select
multiple items.

tk.BROWSE: In this mode, we click and drag the mouse to select a


different item. Only one item is selected at a time. As we drag the

788
mouse, the previously selected item is deselected. This mode is the
default.
tk.EXTENDED: In this mode, we click and drag the mouse to select
multiple contiguous list items. This mode does not permit the
selection of multiple non-contiguous items.
See example 16.12(a).
curselection The curselection () method returns the indices of the currently
selected list items as a tuple. The index of the first item is 0. If nothing
is selected, it returns an empty tuple. See example 16.12(a).
delete The delete method removes multiple continuous list items specified
by a range of indices. It has the following syntax:
delete (first, last=None)
where first is the start index of the range, and last is the end index. If
the second argument is omitted, the single line with index first is
deleted. See example 16.12(b).
get The get () method returns the list items specified by a range. It has
the following syntax:
list_items = get ( first, last=None )

where first is the start of the range and last is the end. The list items
are returned as a tuple. If the argument last is omitted, the method
returns the nearest list item to the index first. See example 16.12(b).
size The size() method returns the number of lines in the listbox.
insert The insert () method inserts list items before a specified list index. It
has the following syntax:
insert (index, *elements)
To insert items at the end of the list, use tk.END as the first argument.
The index tk.END refers to the last line in the listbox and the index
tk.ACTIVE refers to the last selected list item. See example 16.12(b).
see The see (index) method adjusts the view of the list so that the list
item with the specified index is visible in the listbox.
xview, The methods yview() and xview()make the listbox vertically
yview scrollable and horizontally scrollable, respectively. We use these
methods to link the listbox view with scrollbars. Example 16.12(c)
illustrates a vertically scrollable listbox.

789
Example 16.12(a): Creating and populating a listbox

import tkinter as tk
root = tk.Tk()
def printList(): #print all the list items
items = var.get()
print(items)
def printSelected(): #Print selected items
indices = listbox.curselection()
if len(indices)==0: print("No selection")
for i in indices:
print( listbox.get(i))
#Create a StringVar object
var=tk.StringVar()
var.set(r"Python\x20Program Perl PHP JavaScript Ruby")
#Populate the list with the StringVar object
listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, listvariable=var,
activestyle='dotbox')
listbox.pack(padx=10, pady=10)
button= tk.Button(root, text= "Print all the list items",
command=printList)
button.pack(padx=10, pady=10)
button= tk.Button(root, text= "Print the selected items",
command=printSelected)
button.pack(padx=10, pady=10)
root.mainloop()
GUI

790
Output
('Python Program', 'Perl', 'PHP', 'JavaScript', 'Ruby')
Perl
JavaScript

Example 16.12(b): Managing list items

import tkinter as tk
root = tk.Tk()
def printList(): #print all the list items
print(listbox.get(0,tk.END))

def printFirst10(): #print the first 10 items


print(listbox.get(0,9))

def deleteFirst10(): #Delete the first 10 items

listbox.delete(0,9)

def insertPrevious10(): #Insert back the previous 10 items


n = int(listbox.get(0))
for i in range(n-10,n):
listbox.insert(0,n-i-1)
791
def printSelected(): #Print selected items
indices = listbox.curselection()
if len(indices)==0: print("No selection")
for i in indices:
print( listbox.get(i))

#Create a listbox
listbox = tk.Listbox(root, selectmode=tk.MULTIPLE)
for i in range(100):
listbox.insert(tk.END, str(i)) #Insert list items
listbox.pack(padx=10, pady=10)
#Create buttons
button= tk.Button(root, text= "Print all the list items",
command=printList)
button.pack(padx=10, pady=5, side='top')
button= tk.Button(root, text= "Print first 10 items",
command=printFirst10)
button.pack(padx=10, pady=5, side='top')
button= tk.Button(root, text= "Delete first 10 items",
command=deleteFirst10)
button.pack(padx=10, pady=5, side='left')
button= tk.Button(root, text= "Insert Previous 10 items",
command=insertPrevious10)
button.pack(padx=10, pady=5, side='left')
button= tk.Button(root, text= "Print the selected items",
command=printSelected)
button.pack(padx=10, pady=5, side='left')
root.mainloop()
GUI

792
Example 16.12(c): A listbox with a scrollbar

import tkinter as tk
root = tk.Tk()
frame= tk.Frame(root)
frame.pack(padx=10,pady=10)
scrollbar = tk.Scrollbar(frame) #Create a scrollbar
scrollbar.pack( side = tk.RIGHT, fill = tk.Y )
#Create a listbox and attach the vertical scrollbar
mylist = tk.Listbox(frame, yscrollcommand = scrollbar.set)

for line in range(100):


mylist.insert(tk.END, "This is line number " + str(line))

mylist.pack( side = tk.LEFT, fill = tk.BOTH )


#Link the scrollbar with the vertical view of the list
scrollbar.config( command = mylist.yview )

label=tk.Label(root,text="A listbox with a vertical scroll")


label.pack(padx=5,pady=5)
root.mainloop()

793
GUI

16.13 Menu Widget


The menu widget is used to create menus in GUI applications. A menu is a collection
of commands or options from which a user can choose to trigger actions or set options.
Examples of the menu are the file menu, edit menu, view menu. The syntax used to create
a menu is as given below:

menu = tk.Menu (root, **options )

where root is the container window/widget and options are key-value pairs that control
the menu's appearance and functionalities. The menu widget's commonly used specific
attributes and methods are given in table 16.11, along with their brief descriptions; for the
standard attributes, see table 16.3. Example 16.13 illustrates these attributes and methods.

Table 16.11: Commonly used menu widget attributes and methods

Attribute/method Description
tearoff The tearoff attribute controls the tearing off of the menu from its
parent. For tearoff =0, the menu does not permit tearing off, and for
tearoff=1, the menu permits tearing off. When tearing is permitted,
the first entry in the submenu is a dashed line. A copy of the
submenu as an independent window is created by clicking on the

794
dashed line, which we can place anywhere on the screen. It is
possible to create more than one independent copy of the menu. See
example 16.13.
postcommand The postcommand attribute is used to call a function whenever the
user activates the menu. See example 16.13.
title The title attribute is used to assign the title of the torn-off submenu.
By default, the title of a tear-off menu window is the same as the text
of the menubutton or cascade menu that leads to this menu. See
example 16.13.
add_command The add_command (options) method adds a command submenu. A
command submenu is linked to a method that will be called
whenever the user selects this menu. A typical syntax of the method
is:

add_command(label='Menu label', command=myFun)

See example 16.13.


add_radiobutton The add_radiobutton () method is used to add a radiobutton sub
menu. In a group of radiobutton menu, a user can select only one
radio option. A typical syntax of the method is:

add_radiobutton (label="Radiobutton label", value =


Value_when_selected, variable =Var, command=fun_to_call)

See example 16.13.


add_checkbutton The add_checkbutton (options) method is used to add a checkbox
submenu. In a group of checkboxes menu, a user is allowed to choose
multiple options. A typical syntax of the method is:

add_checkbutton (label="Checkbutton label", onvalue =


On_Value, offvalue= Off_Value, variable =Var,
command=fun_to_call)

See example 16.13.


add_cascade The add_cascade(options) method creates a new hierarchical menu
in the menubar. A typical syntax of the method is:

add_cascade(label='Menu label', menu=parent_menu)

795
See example 16.13.
add_separator The add_separator() method is used to add a separator line in the
submenu. A typical syntax of the method is:

add_separator()

See example 16.13.

Example 16.13: Creating a menubar using the menu widget

from tkinter import * # import Module


root = Tk() # creating tkinter window
root.geometry("400x200")# set geometry

def myFun(): #Call back function


for i in range(4):
if checkVar[i].get()>0:
print(f"Checkbox[{i}] is selected")
else:
print(f"Checkbox[{i}] is not selected")
print(f"Radiobutton[{optionVar.get()}] is selected")

#Create tkinter variables


checkVar=list() #Create a list of integer variables
for i in range(4):
checkVar.append(IntVar(root, 0))#Create an integer variable and add
to the list
optionVar = IntVar(root, 1) #Create an integer variable

menubar = Menu(root)# Creating Menubar

# Adding File Menu and SubMenus


command_menu = Menu(menubar, tearoff=1, postcommand=myFun) #Create menu
menubar.add_cascade(label='Command Menu ', menu=command_menu) #Create
main menu
command_menu.add_command(label='Print your choices', command=myFun)
#Add a command sub menu
command_menu.add_separator() #Add a sperator line
command_menu.add_command(label='Exit',command = root.quit) #Add a
command sub menu

# Adding checkbox menu and its submenus


796
check_menu = Menu(menubar, tearoff=1) #Create menu
menubar.add_cascade(label='Checkbox Menu', menu=check_menu) #Create
main menu
#Add checkbox submenus
check_menu.add_checkbutton(label='Check box 1', variable=checkVar[0],
onvalue=1)
check_menu.add_checkbutton(label='Check box 2', variable=checkVar[1],
onvalue=2)
check_menu.add_checkbutton(label='Check box 3', variable=checkVar[2],
onvalue=3)
check_menu.add_checkbutton(label='Check box 4', variable=checkVar[3],
onvalue=4)

# Adding redio button Menu and SubMenus


radio_menu = Menu(menubar, tearoff=1) #Create a menu
menubar.add_cascade(label='Radio Button Menu', menu=radio_menu) #Create
the main menu
#Create radio button menus
radio_menu.add_radiobutton(label='Radio button 1', variable=optionVar,
value=1)
radio_menu.add_radiobutton(label='Radio button 2', variable=optionVar,
value=2)
radio_menu.add_radiobutton(label='Radio button 3', variable=optionVar,
value=3)

# display Menu
root.config(menu=menubar)

# Execute Tkinter main loop


root.mainloop()

GUI

797
Output
Checkbox[0] is selected
Checkbox[1] is not selected
Checkbox[2] is selected
Checkbox[3] is not selected
Radiobutton[2] is selected

16.14 Menubutton Widget


The Menubutton widget creates a drop-down menu that stays on the screen at a
specified location in contrast to the menubar attached with the container window just below
the title bar. The menubutton works as the parent widget for the menu widget. The
submenus of the menubutton become visible when the user clicks on it. The direction
attribute controls the direction in which the submenu will appear. It can be set to above,
below left, and right. The menu attribute is used to associate the menubutton with a menu.
Example 16.14 shows the menubutton widget.

Example 16.14: Creating a menubutton

from tkinter import * # import Module


root = Tk() # creating tkinter window
root.geometry("400x200")# set geometry

798
def myFun(): #Call back function
for i in range(4):
if checkVar[i].get()>0:
print(f"Checkbox[{i}] is selected")
else:
print(f"Checkbox[{i}] is not selected")
print(f"Radiobutton[{optionVar.get()}] is selected")

#Create tkinter variables


checkVar=list() #Create a list of integer variables
for i in range(4):
checkVar.append(IntVar(root, 0))#Create an integer variable and add
to the list
optionVar = IntVar(root, 1) #Create an integer variable

#Creating a menubutton
menubar = Menubutton ( root, text = "Menubutton", relief = RAISED,
direction='above' )
menubar.place(x=100, y=100)

#Create Menu and SubMenus


menu = Menu(menubar, tearoff=1) #Create menu
menu.add_command(label='Print your choices', command=myFun) #Add a
command sub menu

menu.add_command(label='Exit',command = root.quit) #Add a command sub


menu
menu.add_separator() #Add a sperator line
#Add checkbox menus
menu.add_checkbutton(label='Check box 1', variable=checkVar[0],
onvalue=1)
menu.add_checkbutton(label='Check box 2', variable=checkVar[1],
onvalue=2)
menu.add_checkbutton(label='Check box 3', variable=checkVar[2],
onvalue=3)
menu.add_checkbutton(label='Check box 4', variable=checkVar[3],
onvalue=4)
menu.add_separator() #Add a sperator line
#Add radio button menus
menu.add_radiobutton(label='Radio button 1', variable=optionVar,
value=1)
menu.add_radiobutton(label='Radio button 2', variable=optionVar,
value=2)
menu.add_radiobutton(label='Radio button 3', variable=optionVar,
value=3)

799
menubar["menu"]=menu

root.mainloop()

GUI

Output
Checkbox[0] is not selected
Checkbox[1] is selected
Checkbox[2] is selected
Checkbox[3] is not selected
Radiobutton[3] is selected

16.15 Message Widget


The message widget is used to show a multiline and non-editable label to display
texts, in contrast to the label widget, which permits only one line of text. The message
widget provides facilities to automatically breaking lines and justifying their contents.
Using the following syntax, we can create a message widget:

message = tk.Message (root, **option)

Where root is the parent window or container widget, and options control the appearance
of the widget. Example 16.15 illustrates the Message widget.

800
Example 16.15: The Message widget

import tkinter as tk

root = tk.Tk()

var = tk.StringVar()
#Create a Message widget, set the text justification to right
label = tk.Message( root, textvariable = var, relief = tk.RAISED,
justify=tk.RIGHT )

var.set("This is message widget. it is used to show multiline label


text. This text is non-editable")
label.pack(padx=10,pady=10)
root.mainloop()

GUI

16.16 Radiobutton Widget


The Radiobutton widget creates multiple-choice options, out of which the user is
allowed to choose only one. If he chooses another option, the previously selected option is
automatically deselected. One group of radio buttons are associated with the same variable.
The value of the variable reflects the choice made by the user. We can have more than one
group of radio buttons, each lined with separate variables. The following syntax is used to
create a Radiobutton widget:

radio = Radiobutton (root, **option)

where root is the parent window or widget, and options control the appearance and
behavior of the widget.

801
The value attribute stores the value assigned to the control variable of the radio
button group when the radiobutton is turned on by the user. The value can be an IntVar or
a StringVar. The variable attribute is the control variable of the group of radio buttons. Its
current value is equal to the currently selected radio button in the group. Example 16.16
illustrates the radiobutton widget.

Example 16.16: The radio button widget

# !/usr/bin/python3
import tkinter as tk
gender = ["Male", "Female"]
income = ["0-1000","1001-2000",">2000"]
def yourChoice():
selection = "You gender is " + gender[var1.get()] + " and your
income is in the range" + income[var2.get()]
L3.config(text = selection)

root = tk.Tk()
var1 = tk.IntVar(0)
var2 = tk.IntVar(0)

frame = tk.Frame(root)
frame.grid(row=0, column=0, sticky="n")

L1= tk.Label(frame, text="Select your gender")


L1.grid(row=0, column=0, sticky="w")

#Create radio button widgets


R1 = tk.Radiobutton(frame, text = "Male", variable = var1, value = 0,
justify="left")
R1.grid(row=1, column=0 , sticky="w")
R2 = tk.Radiobutton(frame, text = "Female", variable = var1, value = 1,
justify="left")
R2.grid(row=2, column=0, sticky="w")

frame1 = tk.Frame(root)
frame1.grid(row=0, column=1)

L2= tk.Label(frame1, text="Select your income group")


L2.grid(row=0, column=1, sticky="w")

#Create radio button widgets another group


R3 = tk.Radiobutton(frame1, text = "0-1000", variable = var2, value =
0, justify="left")

802
R3.grid(row=1, column=1, sticky="w" )
R4 = tk.Radiobutton(frame1, text = "1001-2000", variable = var2, value
= 1, justify="left")
R4.grid(row=2, column=1, sticky="w")
R5 = tk.Radiobutton(frame1, text = ">2000", variable = var2, value = 2,
justify="left")
R5.grid(row=3, column=1, sticky="w")

B1= tk.Button(root, text="Get your choice", command=yourChoice)


B1.grid(row=2, column=0, sticky="w")

L3= tk.Label(root, text="Your choice", )


L3.grid(row=2, column=1, sticky="w")

root.mainloop()

GUI

16.17 Scale Widget


The Scale widget is used to provide a graphical scale with a pointer. We can move
the pointer to get a value in the given range. The syntax used to create a scale is as given
below:

scale = tk.Scale (root, **options)

where root is the parent window and options are key-value pairs that control the scale's
appearance and functionality.
The commonly used specific attributes and methods of the scale widget are given in table
16.12, along with their brief descriptions. Example 16.17 illustrates the scale widget.

803
Table 16.12: Commonly used attributes and methods of scale widget

Name Description
from_ The from_ and to attributes sets the lower and upper range of the scale.
to

orient The orient attribute sets the orientation of the scale. To create a horizontal
scale, set orient = tk.HORIZONTAL and for a vertical scale, set orient =
tk.VERTICAL. The default orientation is vertical.
showvalue The showvalue attribute controls the display of the current value on the
screen. If showvalue = 1, the current value of the scale is displayed. Set
showvalue=0 to suppress the display of the current value.
tickinterval The tickinterval attribute controls the gap between two intermediate scale
tick marks. For example, if from_ = 0, to = 100, and tickinterval = 25, tick
marks will be shown at values 0, 25, 50, 75, and 100. The default value is 0,
which suppresses the display of ticks.
variable The variable attribute is used to link a control variable with the scale. We
can use IntVar, DoubleVar (float), or StringVar as control variables.
get, The get and set methods are used to get and set the current value of the
set scale.

Example 16.17: The scale widget

import tkinter as tk

def sel():
current_value = "Value = " + str(var.get()) #Get the current value
label.config(text = current_value)

root = tk.Tk()
var = tk.DoubleVar()
#Create a horizontal scale
scale = tk.Scale( root, variable = var, orient=tk.HORIZONTAL,
tickinterval=25, length=200)
scale.pack(anchor = tk.CENTER)

button = tk.Button(root, text = "Get Scale Value", command = sel)


button.pack(anchor = tk.CENTER)

804
button = tk.Button(root, text = "Set scale pointer in the mid", command
= lambda:scale.set(50))
button.pack(anchor = tk.CENTER)

label = tk.Label(root)
label.pack()

root.mainloop()

GUI

16.18 Scrollbar Widget


The scrollbar widget is used to slide the content of a widget such as Listbox, Text,
and Canvas. We can attach a vertical scrollbar to scroll the content up and down and use a
horizontal slide to scroll the content left and right. The following syntax is used to create a
scrollbar widget:

scroll = tk.Scrollbar (root, **option)

where root is the parent window and options are key-value pairs that control the scrollbar
widget's appearance and functionality. For the standard attributes and methods, see table
13.3. The attribute orient decides the orientation of the slider widget. For, orient =
tk.HORIZONTAL, a horizontal scrollbar is created and for orient = tk.VERTICAL, a vertical
one, is created. Example 16.18 illustrates the scrollbar.

805
Example 16.18: The scrollbar

import tkinter as tk

root = tk.Tk()
frame=tk.Frame(root) #Create a frame
frame.pack(padx=10,pady=10)

scrollbar = tk.Scrollbar(frame) #Create a vertical scrollbar


scrollbar.pack( side = tk.RIGHT, fill = tk.Y )

scrollbar1 = tk.Scrollbar(frame, orient=tk.HORIZONTAL) #Create a


horizontal scrollbar
scrollbar1.pack( side = tk.BOTTOM, fill = tk.X )

#Create a list box and link scrollbars with it


mylist = tk.Listbox(frame, yscrollcommand = scrollbar.set,
xscrollcommand = scrollbar1.set )

#Polulate the list with list items


for line in range(100):
mylist.insert(tk.END, "Using vertical and horizontal scroll bars.
This is line number " + str(line))

mylist.pack( side = tk.LEFT, fill = tk.BOTH)

#Configure the scrollbars


scrollbar.config( command = mylist.yview)
scrollbar1.config( command = mylist.xview)
root.mainloop()
GUI

806
16.19 Text Widget
The text widget is used to create a multi-line text area. The text widget is used as a
text editor to write and display texts and insert images. The following syntax is used to
create a text widget:

text = tk.Text(root, **options)

where root is the parent window and options are key-value pairs that control the text
widget's appearance and functionality. For the standard attributes and methods, see table
13.3. The width and height of the text widget are specified in the number of lines and the
number of characters, respectively. We can attach scrolls to scroll the content of the widget
horizontally and vertically. The wrap attribute controls how a long line wraps in the
available width of the text widget. For wrap = tk.WORD, the line will break after the last
word that will fit in the given width, and for wrap = tk.CHAR, the line will break at any
character. The default is wrap = tk.CHAR. Example 16.19(a) illustrates a text widget with a
vertical scroll. We can also add images along with the text in a text widget. Example 16.19(b)
illustrates the same.

807
Example 16.19(a): The text widget

import tkinter as tk

root = tk.Tk()
S = tk.Scrollbar(root) #Create a vertical scroll
T = tk.Text(root, height=6, width=50, wrap = tk.WORD)
S.pack(side=tk.RIGHT, fill=tk.Y) #Pack the scroll to the right side of
the root window
T.pack(side=tk.LEFT, fill=tk.Y, padx=10,pady=10)
S.config(command=T.yview) #Link the yview of the text widget with the
scroll
T.config(yscrollcommand=S.set)
#Long text
text = """The text widget is used to create a multi-line text area.
The text widget can be used as a text editor to write and display texts
and insert images. The following syntax is used to create a text
widget:
text = tk.Text(root, **options)
where root is the parent window and options are key-value pairs that
control the text widget's appearance and functionality. For the
standard attributes and methods, see table 13.3. The width and height
of the text widget are specified in the number of lines and the number
of characters, respectively. We can attach scrolls to scroll the
content of the widget horizontally and vertically."""
T.insert(tk.END, text)
tk.mainloop()

GUI

808
Example 16.19(b): A text widget with images

import tkinter as tk

root = tk.Tk() #Create application window


photo = tk.PhotoImage(file='./Python.png')#Load image in the memory
S = tk.Scrollbar(root) #Create a vertical scroll

T = tk.Text(root, height=15, width=50, wrap = tk.WORD) #Create a text


widget
S.pack(side=tk.RIGHT, fill=tk.Y) #Pack the scroll to the right side of
the root window
T.pack(side=tk.LEFT, fill=tk.Y, padx=10,pady=10)
S.config(command=T.yview) #Link the yview of the text widget with the
scroll
T.config(yscrollcommand=S.set)

#Long text
text = """We can insert images along with the text at any cursor
position in a text widget. This example illustrates the same.\n"""

T.insert(tk.END, "Welcome to the ") #Insert a text at the end of the


document
T.image_create(tk.END, image=photo) #Insert a image
T.insert(tk.END, " Text widget") #Insert text
T.insert(tk.END, '\n')
T.insert(tk.END, text)
T.image_create(tk.END, image=photo) #Insert an image
T.insert(tk.END, '\n')
T.insert(tk.END, "End of the document")
tk.mainloop()

GUI

809
16.20 Toplevel Widget
The Toplevel widget is used to create another independent window that will work
as a container for widgets. We can create any number of top-level windows. Following is
the syntax to the Toplevel widget :

top = tk.Toplevel ( **option)

where options are key-value pairs that control the appearance and functionality of the text
widget. Example 16.20 illustrates the Toplevel widget.

Example 1620: The Toplevel widget

from tkinter import *


root = Tk() #Create the main application window
root.title("hello")
label = Label(root, text="This is the parent window")
label.pack(padx=20, pady=20)

top = Toplevel() #Create another independent window


top.title("Python")
810
label1 = Label(top, text="This is another independent window")
label1.pack(padx=20, pady=20)
top.mainloop()

GUI

16.21 Spinbox Widget


The Spinbox widget generates integer numbers between a specified range or from a
given tuple of integers. By clicking on the up-arrow of the widget, the next number is
generated, and by clicking on the down-arrow of the widget, the previous number is
generated. A Spinbox is created using the following syntax:

spin = tk.Spinbox( root, **option)

where root is the parent window and options are key-value pairs that control the text
widget's appearance and functionality. For the standard attributes and methods, see table
13.3. The attributes from_ and to sets the lower limit and the upper limit, respectively. For
a tuple of integers, the attribute values is used. The wrap attribute is used to control the
behavior of the spin at the limits of the range. If wrap = 1, the spin cycles through the range,
i.e., after reaching the upper limit, the spin starts from the lower limit. If wrap =0, the spin
stops generating new output on reaching the limit, i.e., after reaching the upper limit, no
action will be taken on clicking the up-arrow of the spin. However, if we click the down-
arrow, it will generate the previous number. Example 16.21 illustrates the spin widget.

811
Example 16.21: Spin widgets

import tkinter as tk
def curValue(): #Get the current values of spin widgets
var.set("Spin1=" + str(spin.get()) + " Spin2 = " +
str(spin1.get()))

master = tk.Tk() #Create the application window

var = tk.StringVar()
spin = tk.Spinbox(master, from_ = 0, to = 10) #Create a spinn widget
spin.pack(padx=10, pady=10)

#Create a spin widget from a tupple


spin1 = tk.Spinbox(master, from_=0, to =5, values = (1,9,2,5,8,3),
wrap=1)
spin1.pack(padx=10, pady=10)

b= tk.Button(master, text="Get the current values of the spin",


command= curValue)
b.pack(padx=10, pady=10)

l= tk.Label(master, textvariable=var)
l.pack(padx=10, pady=10)
mainloop()
GUI

812
16.22 Messagebox
The messagebox widget is used to create a dialog box. Dialog boxes are used to
display information, warning messages, and error messages. It can also be used to ask
questions such as Yes-No, OK-Cancel, Yes-No, Retry-Ignore. The question message boxes
return values based on the responses of the user. The following syntax is used to create this
widget.

return_value = messagebox.FunctionName(title, message [, options])

where title and message are strings, and options are used to customize the message box.
FunctionName decides the type of dialog box that will be created. The possible function
names are showinfo, showwarning, showerror, askquestion, askokcancel, askyesno, and
askretrycancel. Example 16.22 illustrates different types of message boxes.

Example 16.22: The message widget

import tkinter as tk
from tkinter import messagebox

top = tk.Tk()

def showInfo():
messagebox.askquestion("Message box", "World is a beautiful place")

def askQuestion():
x= messagebox.askyesno("Question", "Do you agree that world is a
beautiful place?")
if x == tk.YES :
messagebox.showinfo("Message", "Welcome in this beautiful word")
else:
messagebox.showinfo("Message", "Let us join hand to make the
world beautiful")

B1 = tk.Button(top, text = "Show information dialog box", command =


showInfo)
B1.pack(padx=10, pady=10)

B2 = tk.Button(top, text = "Show question dialog box", command =


askQuestion)
B2.pack(padx=10, pady=10)

813
top.mainloop()

GUI

Chapter Summary

1. The Graphical User Interface (GUI) uses visual objects such as boxes to type in
data and buttons that initiate actions.
2. There are many options, such as Tkinter, wxPython, and JPython, that can be
used to develop GUI-based Python applications
3. In the event-driven programming paradigm, the execution flow of a program is
controlled by a sequence of events
4. The operating system maintains a queue of events and passes it to the relevant
applications.
5. Widgets are graphical components, such as buttons, textboxes, and lists.
6. A user-generated event is generated when a user interacts with a widget with
any input device, such as pressing a mouse's button, moving the mouse pointer,
and pressing a key.

814
7. System-generated events are automatically generated by the operating system,
such as timer events.
8. When a user presses a key, a keypress event is generated. A keypress event
contains the identity of the key pressed.
9. In the case of a mouse or touchpad on a laptop, events are generated by clicking
or double-clicking a mouse button, rotating the scrolls, or moving the mouse
pointer. A mouse event contains information about the x and y coordinate of the
mouse pointer and the button which is pressed.
10. An event listener function is a function that gets executed when a widget receives
an event.
11. Preferred ways to import the tkinter module are import tkinter as tk, from
tkinter import *, or from tkinter import Button, Label.

12. In Tkinter, the main window of an application is created by calling the Tk()
function of the tkinter module.

13. By default, the main application window created by the Tk() function has a title
tk and has three system buttons, including Minimize, Maximize, and Close.

14. For organizing widgets throughout the parent widget area, the tkinter module
provides the following geometry managers: pack, grid, and place.

15. The canvas widget is used to create a rectangular graphical area for drawing
objects such as lines, circles, arcs, texts, and embed images.

16. A checkbox button is a GUI widget used to choose an option from two
mutually exclusive options.

17. The Entry widget is used to get one-line text input from the user.

18. The frame widget is a rectangular container widget, typically used to group
and layout other widgets in the application window or other container widgets.

19. The label widget is used to show non-editable single or multiline texts or an
image.

20. The Listbox widget is used to show a list of items from which the user can
select one or multiple items.

815
21. The menu widget is used to create menus in GUI applications. A menu is a
collection of commands or options from which a user can choose to trigger
actions or set options.

22. The Radiobutton widget creates multiple-choice options, out of which the user
is allowed to choose only one.

23. The text widget is used to create a multi-line text area.

24. The Spinbox widget generates integer numbers between a specified range or
from a given tuple of integers.

Multiple Choice Questions

1. Which of the following tool can be used to create a GUI in python?


(a) NumPy
(b) SciPy
(c) Tkinter
(d) OpenCV

2. Which of the following widget can be used for entry of data by user?
(a) Text
(b) Frame
(c) Label
(d) None of the above

3. Which of the following is not a widget Tkinter?


(a) Text
(b) Entry
(c) Scale
(d) None of the above

4. Which of the following can be used to choose multiple options?


(a) Checkbutton
(b) Radiobutton
(c) Spinbox
(d) None of the above

5. Which of the following widget can be used for drawing shapes?

816
(a) Graphics
(b) Canvas
(c) Paint
(d) All of the above

6. Which of the following is not an event?


(a) Motion
(b) Enter
(c) Return
(d) None of the above

7. Which of the following can be used to import the Tkinter module?


(a) import tkinter as tk
(b) from tkinter import *
(c) tkinter import Button, Label
(d) All of the above

8. The correct way to draw a line in canvas Tkinter?


(a) draw_line()
(b) canvas.create_line()
(c) create_line(canvas)
(d) None of the above

9. The back ground color of a widget can be changed by which of the following?
(a) background
(b) fg
(c) bg
(d) bground

10. Which of the following is a non-clickable widget in Tkinter GUI programming?


(a) Button
(b) Checkbutton
(c) Label
(d) None of the above

11. The default window created by the Tk () function has the following:
(a) A title
(b) Minimize button
(c) Maximize button
(d) All of the above

817
12. In Tkinter, we can make an application window resizable in
(a) Horizontal direction
(b) Vertical direction
(c) Both, (a) and (b)
(d) All of the above

13. In Tkinter, a widget can have following state


(a) Normal
(b) Active
(c) Disabled
(d) All of the above

14. In Tkinter, which of the following is not a correct value of relief of a widget?
(a) Sunken
(b) Raised
(c) Flat
(d) None of the above

15. Which of the following a geometry manager to organize widgets?


(a) Pack
(b) Grid
(c) Place
(d) All of the above

16. In grid geometry manager, the individual grid cell can be accessed using which of the
following?
(a) Row and column indices
(b) Row and Colum coordinates
(c) Both, (a) and (b)
(d) None of the above

17. In grid geometry manager, a widget can occupy how many cells
(a) 1
(b) 2
(c) 3
(d) All of the above

18. In a canvas widget, the attributes width and height are specified in
(a) Pixels
(b) MM
(c) CM

818
(d) All of the above

19. Which of the following is not a method of canvas widget?


(a) Create_polygon
(b) Create_oval
(c) Create_circle
(d) None of the above

20. The entry widget can be used to input which of the following?
(a) Single line text
(b) Multiline text
(c) Both (a) and (b)
(d) None of the above

21. Which of the following is true about a Frame widget?


(a) It is a container
(b) Each frame has its own independent grid layout
(c) It is used to group and layout other widgets in the application window
(d) All of the above

22. A label widget is used for which of the following?


(a) To show non-editable single line text
(b) To show non-editable multi line text
(c) To show an image
(d) All of the above

23. In a listbox widget, a user can select which of the following?


(a) One item
(b) Multiple items
(c) Both, (a) and (b)
(d) None of the above

24. In a spinbox widget, which of the following is possible?


(a) Cycle through 1 to 10
(b) Cycle through a tuple
(c) Do not cycle through a tuple
(d) All of the above

25. The messagebox widget is used for which of the following?


(a) To display information
(b) To ask questions such as Yes-No

819
(c) Both, (a) and (b)
(d) All of the above

Review Questions
1. State whether the following statements are true or false:
a. GUI programs use event driven programming
b. GUI stands for graphical user interface
c. The tkinter module is used for developing GUI applications
d. Tkinter has no option to draw shapes
e. Radiobutton is a multiple item selection widget
f. Spinbox generates numbers in a sequence only
g. Entry widget can accept multi-line text
h. An event listener function is a function that gets executed when a widget
receives an event.
i. An application window is created by calling the Tk () function of the tkinter
module.
j. A widget can be in the following states: normal, active, and disabled.
k. The tkinter module supports the following relief values: SUNKEN,
RAISED, GROOVE, RIDGE, and FLAT.
l. We cannot change the font of a widget text.
m. We cannot display an image on a widget
n. The grid geometry manager divides the container into rectangular gird
cells.
o. A widget can occupy only one cell in a grid of cells.
p. We can draw a circle on a canvas using create_oval () method.

820
q. The Checkbutton widget is used for selecting multiple options.
r. The entry widget can accept multiline text.
s. Users can edit the text of a label widget.
t. The listbox widget does not permit the selection of non-contiguous items in
the list.
u. The Radiobutton permits multiple selections.
v. The scale widget is used to get a value from a specified range.
w. The spin widget returns value in an ascending sequence only.
x. The spin widget can return values as specified in a tuple.
y. The messagebox widget cannot return a value.
z. Tkinter only support a single window GUI applications.

Programming Assignments

1. Write a program to create a window of size 200x200 and set the window
background RED.

2. Write a GUI program with a button with label Welcome. On pressing the
welcome button, generate a message “Hello, Welcome to Tkinter GUI
programming’.

3. Write a GUI program to create a digital couter.

4. Write a GUI program to calculate the areas of a circle, a rectangle and a triangle.

5. Write a program to create a window of size 200x200 and draw a circle in the
centre of the window of diameter 100 in blue color.

6. Write a GUI program for the currency converter for INR to Dollor. Store the data
into a file and provide facility to update the conversion rate.

821
7. Write a GUI program to create a color pallete. Arrange the colors in a column.
Also modify the program to arrange the color pallete in a 2D grid.

8. Create a GUI user login page with facility to add a new user. Use a file to store
the user ID and password.

9. Create a GUI user login page with facility to add a new user. Use a file to store
the user ID and password.

10. Write a GUI based program to manage contact details of an organisation. The
program should provide the facility to add a new contact, search a contact and
display all contacts.

11. Write a GUI based Python program to manage the reservation system of an
auditorium with 36 seats arranged in a grid of 6x6 to show filled and unfilled
seats.

12. Write a program to create a simple CAD system to draw lines and circles of
different colors.

13. Write a program to show the calender of a chosen month and year.

14. Write a Python program using tkinter to create a simple calculator with facility
of addition, subtraction, multiplication and division using grid layout manager.

822
Index
3D contour plots
3D plots
Accessing a dictionary element
Accessing an element of a list
Accessing binary files
Accessing characters in a string
Adding a grid to a Plot
Adding axis labels and plot titles
Adding legends
Adding ticks and tick-labels
Algorithms and Flowcharts
Animation using Matplotlib
Arithmetic Expressions
Arithmetic Operators
Array shape manipulation
Assertions
Assigning a string literal to a variable
Assignment Operators
Attributes of the ndarray class
Bar charts
Basics of Python Programming
Bitwise operators
Boolean Literals
Box plots
break statement
Broadcasting NumPy arrays
Built-in functions for dictionaries
Built-in functions for sets
Built-in functions for strings
Built-in functions for tuples

823
Button Widget
Calling a function
Canvas Widget
Catching Specific Exceptions
Central Processing Unit
Character Set
Checkbutton Widget
Coding Style
Collection Literals
Command line arguments
Comments in Python
Commonly used built-in function for lists
Complex Number Literals
Components of a Computer
Components of Event driven programming
Computer Software
Constructors and destructor
continue statement
Contour plots
Converting other data types to lists
Create tuples
Creating a GUI Application using the tkinter Module
Creating a matrix from data
Creating an array from data
Creating and Customizing the Main Application Window
Creating arrays in NumPy
Creating Copies of a list
Creating dictionaries
Creating sets
Creating string objects
Creating sub-plots
Creating Widgets
824
CSV files
Customizing a plot
Data Encapsulation
Data structure of NumPy arrays
Decision Making and Branching
Decorator Classes
Deep copy
Define a class in Python
Defining a user-defined function
Delimiters
Dictionaries
Dictionary Literals
Display class attributes and instance methods
Dynamic Binding
Element-wise operations
else statement
Encapsulation in Python
Entry Widget
Eval Function
Event Listener Functions
Events
Exception Handling in Python
Expressions
File and Directory Management
File Handling
Floating-Point Literals
Flowchart
for loop
Format Function
Formatting Numbers and Strings
Formatting with The Format Method of The Str Object
Frame Widget
825
Frozenset
F-String in Python
Generator functions
Geometry Layout Manager
Global variables
Graphics User Interface
GUI Applications using tkinter
Guidelines to Write Algorithms
Handling a general exception
Histogram Plots
History of Python
Identifier Naming Convention
Identifiers
Identity operators
if statement
if-else statement
Importing Mathematic Functions
Indexing and slicing NumPy arrays
Indexing of tuple elements
Inheritance
Inheritance in Python
Input and Output Functions
Input Devices
Input Function
Installing Python
Instance methods
Integer Literals
Introduction to Matplotlib
Iterating over lines in a file
json module
Keyword arguments
Keywords
826
Label Widget
Ladder if (if-elif-else) statement
Lambda function
Line Continuation
List comprehension to create a new list
List creation
List Literals
List operators
List slicing
List traversal
Listbox Widget
Lists
Lists and other mutable sequences as elements of tuples
Lists from data
Literals and Datatypes
Local and global functions
Local variables
Logical Expressions
Logical Operators
Loop Control Statements
Matrix and linear algebra functions
max () and min () functions with a list of complex numbers
max() and min () functions for a list of lists or iterables
Membership Operators
Membership operators: in and not in
Memory
Menu Widget
Menubutton Widget
Message Passing
Message Widget
Messagebox Widget
Method Overloading
827
Method Resolution Order in Python
Methods of the dict class
Methods of the list class
Name mangling
Nested Dictionary
Nested if statement
Nested list comprehension to process matrices
Nested loops
Numeric literals
NumPy
NumPy Arrays
object Class
Object Oriented Programming in Python
Object-Oriented Programming
Objects and classes
Opening a file
Operations on NumPy arrays
Operations on tuples
Operator Overloading
Operator Precedence and Associativity
Operators and Expressions
Operators in Python
Output Devices
Overloading Built-in Python Functions
Overview of Python
Parameters and arguments in a Function
Parameters with default values
pass statement
Passing and returning function objects to a function
Passing arguments to a function
pickle module
Pie chart
828
plot method
Polymorphism
Polymorphism in Python
Positional Parameters
Print Function
Programming Languages
Proper Indentation
Pseudocode
Python Built-in Exceptions
Python built-in functions
Python Command Prompt
Python Distributions
Python IDEs
Python Implementations
Python Programs
Python Statements
Python Token
quit () and exit () functions
Quiver plots
Radiobutton Widget
Raising exceptions
Random reshuffle of the elements of a list
Reading a matrix from the keyboard
Reading from a text file
Reading Multiple Numeric Data Separated with a Delimiter
Reading numbers from a file
Reading Single Numeric Data
Recursive functions
Reduction operations on arrays
Reference copy
Relational (Comparison) Operators
Removing an element from a dictionary
829
Return values from functions
Returning multiple values from a function
Rules for Naming Identifiers
Scale Widget
Scatter plots
Scope and life of a variable
Scrollbar Widget
Seek and tell methods
Serialization in Python
Set Literals
Set methods
Sets
Shallow copy
Slicing of tuple
Slicing operation with a string
Sorting a tuple
Sorting data
Special Literal None
Spinbox Widget
Split a string into a list of words
Standard Attributes of Widgets
Starting Python In Windows
Statements vs Expressions
Steps in file handling
Steps to create a plot in Matplotlib
Steps to create an animation plot using FuncAnimation
Steps to create animation plot using Artist Animation
String class methods
String Expressions
String Literals
String operators
Strings
830
Structure of a Python Program
Structured NumPy Arrays
Structuring Python Programs
Ternary Operator
Text Widget
Toplevel Widget
Traditional % Formatting Operator
Traversing a dictionary
Traversing a string
Traversing sets
Traversing sliced list
Traversing tuples
Tuple
Tuple Literals
Tuple methods
Tuple vs List
Tuples from data
Tuples from other iterables
Tuples, Sets and Dictionaries
Twin axis
Type and Class Membership Tests
Types of Computer Programming Languages
Types of files
Types of Inheritance in Python
Types of System Software
User-defined exception
User-Defined Functions
Using a list as a matrix and an array
Using Comprehension
Using the construction of the string class
Variable number of parameters
Variables
831
Violin plots
While loop
Why Python?
Widgets
Wireframe and surface plots
Writing into a text file
Writing numbers and Booleans in a file
Zipping tuples together

832

You might also like