Copy of Introduction to Computer Programming With Python - Harris Wang
Copy of Introduction to Computer Programming With Python - Harris Wang
com
Introduction
to
Computer Programming
with
Python
OceanofPDF.com
Introduction
to
Computer Programming
with
Python
Harris Wang
OceanofPDF.com
Copyright © 2023 Athabasca University
1 University Drive, Athabasca, AB Canada
DOI: https://doi.org/10.15215/remix/9781998944088.01
Published by Remix, an imprint of Athabasca University Press. For more information, please
visit aupress.ca or email [email protected].
Remix name, Remix logo, and Remix book covers are not subject to the Creative Commons
license and may not be reproduced without the prior and express written consent of Athabasca
University.
OceanofPDF.com
Contents
Chapter 1 Introduction
Learning Objectives
1.1 A Brief History of Computers
1.2 Fundamentals of Computing and Modern Computers
Number Systems and the Foundation of Computing
Computability and Computational Complexity
The Construction of Modern Computers
Analog Computers
Digital Computers
Mechanic-Based Components
Vacuum Tube–Based Components
Transistors
Integrated Circuits and Very Large-Scale Integrated Circuits
1.3 Programming and Programming Languages
1.4 Python Programming Language
The Development and Implementation of Python
Advantages of Python
Resources for Python and Python Education
1.5 Getting Ready to Learn Programming in Python
Installing and Setting Up the Python Programming Environment
Installing Python
Setting Up a Virtual Environment for a Python Project
Installing Jupyter Notebook
Installing Visual Studio Code
Additional Tools Supporting Software Development in Python
Buildbot
Trac
Roundup
1.6 Getting a Taste of Programming with Python
Program Interactively with Python Interactive Shell
Program with VS Code IDE
Use Jupyter Notebook Within VS Code to Program Interactively
Write Documentation in Markdown
Headings
Paragraphs
New Lines
Italic, Bold, and Strikethrough Texts
Horizontal Rules
Keyboard Keys
Unordered Lists
Ordered Lists
Definition Lists
Links
Links to Internal Sections
Images
Blockquotes
Tables
Inline Program / Script Code
Code Block
Mathematical Formulas and Expressions
To-Do List
Escape Sequence for Special Characters
Programming Interactively with Jupyter Notebook Within VS Code
Run Python Programs Outside IDE
Make the Python Program File Executable
Errors in Programs
1.7 Essentials of Problem Solving and Software Development
Design Algorithms to Solve Problems
Phases of Software System Development
Phase 1. Understand the Project
Phase 2. Analyze the Requirements to Identify Computer-Solvable Problems and Tasks
Phase 3. Design the System
Phase 4. Implement the System
Phase 5. Test the System
Phase 6. Maintain the System
1.8 Manage Your Working Files for Software Development Projects
Set Up Git on Your Computer and Version-Control Locally
Set Up an Account on GitHub and Version-Control with Remote Repositories
Chapter Summary
Exercises
Projects
OceanofPDF.com
Chapter 1
Introduction
This chapter prepares you to learn how to program with Python. Preparation
includes a brief introduction to computers and computing, programming, and
programming languages, as well as the installation of Python and Python
interactive programming and integrated development environments (IDEs),
including Jupyter Notebook for interactive programming and VS Code as a
required IDE.
Learning Objectives
After completing this chapter, you should be able to
The exact origin of the abacus is unknown, but before the adoption of the
written Hindu-Arabic numeral system, the abacus had already been widely
used in many countries, including China, Russia, and some European
countries. Abacuses continued to be widely used by almost all accountants in
China before the adoption of modern computers and calculators.
Today, although abacuses are rarely used in real applications such as
accounting, their working principles are still used to train people to do mental
math, such as in programs like the Universal Concept of Mental Arithmetic
System (UCMAS; see ucmas.ca). UCMAS holds annual competitions
worldwide, including in Canada.
The invention and development of today’s modern computers can be
attributed to the invention and development of all previous relevant concepts,
principles, and technologies. The concept of a digital, programmable computer
originated with Charles Babbage, an English mathematician, philosopher,
inventor, and machine engineer. In 1822, he designed a steam-driven
calculating machine for automatically computing tables of numbers. Although
his government-funded project failed, the many ideas he developed and used
in his analytical engine were adopted and used in the world’s first modern
programmable computer, built a century later. That is why Charles Babbage is
considered to be one of the “fathers of computers.”
In 1847, George Boole, an English mathematician introduced Boolean logic,
propositional calculus, and Boolean algebra as the laws of thinking, which
later became the foundation of modern electronic computers and digital
devices in general. For that reason, George Boole is regarded as a founder of
computer science.
In 1890, Herman Hollerith successfully designed and built a punch-card-
based system for the US government to calculate its 1890 census. It saved the
US government US$5 million by finishing the calculation in one year instead
of 10 years it would have taken using traditional methods, as in the previous
census. In 1896, Herman Hollerith established a company called the
Tabulating Machine Company to make the machines. This company ultimately
became IBM.
The central concept and theory of modern computers were conceived in
1936 by English mathematician Alan Turing in his “universal machine,” which
became known as the Turing machine in his honour. He successfully proved
that his universal machine could calculate anything that is computable. Alan
Turing is also considered by some to be “a father of computers”—or more
precisely, “a father of computing”—for his seminal paper on the theory of
computation. In the eyes of the general public, Alan Turing is more famous for
his role in cracking the so-called unbreakable codes used by the German army
during World War II, as presented in The Imitation Game, a well-known
Hollywood movie.
Until 1937, all computing machines or computers were mechanically based,
using gears, cams, belts, or shafts. John Vincent Atanasoff, an American
mathematician and physician at Iowa State University, attempted in 1937 to
build the first electronic computer. He and Clifford Berry, one of his graduate
students at the time, designed and built a special-purpose digital computer,
ABC. For that reason, he is considered to be “the father of the modern
computer.” It was in the ABC machine that binary math and Boolean logic
were successfully used for the first time.
In 1943, across the Atlantic Ocean in England, Colossus Mark I, a prototype
of a special-purpose computer, was built. A year later, in 1944, Colossus Mark
II was built and used to break the encrypted radiotelegraphy messages
transmitted by the German army at the end of World War II.
In 1946, the first general-purpose digital computer, the Electronic
Numerical Integrator and Computer (ENIAC), was built by two professors at
the University of Pennsylvania: John Mauchly and J. Presper Eckert. The
computer had over 18,000 vacuum tubes and weighed 30 tons. A rumour at the
time said that whenever the computer was turned on, the lights in some
districts of Philadelphia would dim.
During the same time, the same group of people at the University of
Pennsylvania also designed and built EDVAC (the Electronic Discrete Variable
Automatic Computer, completed in 1949), BINAC (the Binary Automatic
Computer, also completed in 1949), and UNIVAC I (the Universal Automatic
Computer I, completed in 1950), which were the first commercial computers
made in the US. Although the computing power of these computers was not
even comparable to that of today’s smartphone, their contributions to the
development of today’s modern computers are enormous. These contributions
include the concepts, principles, and technology of stored programs,
subroutines, and programming languages.
Around the same time that ENIAC was built, the Harvard Mark I automatic
sequence-controlled calculator was also built at Harvard University. It is
believed that John von Neumann, a mathematician and physicist working at
the Los Alamos National Laboratory, was the first user of the Harvard Mark I,
which he used to run programs on the machine to calculate for the Manhattan
Project.
In 1944, Von Neumann had an opportunity to join a discussion with J.
Presper Eckert and John Mauchly, who were developing ENIAC and EDVAC
machines at the time. He wrote up a report on the EDVAC, First Draft of a
Report, in which he described a computer architecture later known as
Von Neumann architecture (see Figure 1-2). The key idea behind the
architecture is a stored-program computer that includes the following
components:
The unpublished report was widely circulated. It had great impact on the
later development of modern computers, although to many people, Turing was
the originator of this key idea and architecture, and many others, including J.
Presper Eckert and John Mauchly, made significant contributions to its
evolution as well. Regardless, it is Von Neumann architecture that has guided
the design of modern computers. All computers we use today are essentially
still Von Neumann computers.
Modern computers can be categorized into three generations based on the
core hardware technology used. The first generation of computers (1937–46)
used vacuum tubes, the second generation (1947–62) used transistors, and the
third generation (1963–present) used integrated circuits (IC).
https://en.wikipedia.org/wiki/Computer
https://www.computerhistory.org/timeline/computers/
https://www.explainthatstuff.com/historyofcomputers.html
https://www.britannica.com/technology/computer/History-of-computing
In fact, a number system can be based on any whole number other than 0
and 1. There is a base-7 system for weeks, a base-12 system for the Chinese
zodiac and imperial foot and inch, and a base-24 number system for the 24-
hour clock. A long list of different numbering systems that have appeared
since prehistory can be found at
https://en.wikipedia.org/wiki/List_of_numeral_systems.
In general, a base-Q number system will require Q unique symbols
representing 0, 1, … Q−1, respectively. The base-10 equivalence of an n-digit
base-Q number dn−1dn−2…d1d0 can be represented as
The evaluation of the expression above will result in its base-10 equivalence.
This is how we convert a number from base-Q to base-10.
For Q = 2, the numbers 0 and 1 are used to represent digits; for Q = 3, the
numbers 0, 1, and 2 are used; for Q = 8, the numbers 0, 1, 2, 3, 4, 5, 6, and 7
are used; for Q = 16, the numbers 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a/A, b/B, c/C, d/D,
e/E, and f/F are used.
The expression above also shows how to convert a number from base-10 to
base-Q: divide the number by Q repeatedly, and the remainders will be the
digits. The details of these conversions can be found on the internet.
For a number dn−1dn−2…d1 d0 in a base-Q number system, it is often
necessary to add Q as a subscription of the sequence, as shown below:
dn−1dn−2…d1d0Q or (dn−1dn−2…d1d0)Q
This explicitly indicates that the number is in a base-Q number system. For
example, number 657 in a base-8 number system will be written as 6578 or
(657)8, especially if the context does not indicate which number system the
number is in.
All number systems have the same operations that we are already familiar
with in a base-10 system, such as addition, subtraction, multiplication, and
division. The only difference is that in a base-Q number system, a 1 carried to
or borrowed from a higher digit is equal to Q instead of 10.
For example, in a base-2 number system, 101 can be written as 1 * 22 + 0 *
21 + 1 * 20, and its 10-base equivalence is 1 * 4 + 0 + 1 = 5, and for 101 +
110, the operation is
101 110
+ 110 − 101
______ ______
1011 001
a * rm * b * rn = a * b * rm+n
and
a * rm / b * rn = a / b * rm−n
(n − 1) + (n − 2) + (n − 3) … + 2 + 1 = (n − 1 + 1) / 2 * (n
− 1) = n * (n − 1) / 2 = (n2 − n) / 2 = O(n2)
You may have noted in the big-O notation that we have kept only the
highest-order term and have removed the constant ½ as well. This is because,
with the big-O asymptotic notation, only the scale of complexity increased
when the size of the problem increases is of interest.
In computer science, problems can be classified as P (for polynomial), NP
(for nondeterministic polynomial), NP-complete, or NP-hard problems. A
problem is said to be in P if it can be solved using a deterministic algorithm in
polynomial time—that is, if the complexity is a big O of a polynomial. A
problem is said to be in NP if it can be solved with a nondeterministic
algorithm in polynomial time. A problem is NP-complete if a possible solution
can be quickly verified but there is no known algorithm to find a solution in
polynomial time. A problem is NP-hard if every NP problem can be
transformed or reduced to it within polynomial time.
In the above, a deterministic algorithm refers to the one in which, given the
same input, the output would always be the same, whereas a nondeterministic
algorithm may give different outputs even for the very same input.
The complexity of algorithms, which is closely related to the response and
processing speed of programs and computer systems, is the concern of good
programmers, especially when dealing with resource-intensive applications. It
is also an important topic to be studied in senior or graduate courses in
computing and computer science. When writing a program or just a function
for assignments or an application, always think about the time and space
complexity and ask yourself, Is there a better way to get the job done?
ANALOG COMPUTERS
As a computing machine, an analog computer uses the properties of certain
objects or phenomena to directly analogize the values of variables (such as the
speed of a vehicle) of a problem to be solved. Examples of the properties
include the voltage and amperage of electricity, the number of teeth of a gear,
or even the length of a wood or metal stick.
Analog computing machines were often built for some special purpose, with
a very wide range of difficulties and complexities. A simple analog computer
could be built with three gears for addition and subtraction. For addition, using
both operands to drive the third gear in the same direction will yield the sum
of the two operands on the third gear, whereas for subtraction, the difference
can be calculated by driving the two gears in two different directions.
Historically, even as early as 100 BC, complicated analog computing
machines were built for various applications, from astronomy in ancient
Greece to the differential machine for solving differential equations in the late
1800s and early 1900s. Some of the most complicated analog computing
machines in modern history include those for flight simulation and gunfire
control. Analog computing machines continued well into the early age of
modern digital computers because the special applications analog computers
were developed for were still too hard for digital computers in the 1960s or
even 1970s.
DIGITAL COMPUTERS
Different from analog computers, digital computers use sequences of digits to
represent the values of variables involved in the problems to be solved. In
digital computers, the machine representation of a problem is often abstract,
with no analogy to the original problem.
Theoretically, in accordance with the earlier discussion about general
number systems, digital computers’ digits can be in any base, from 2 up.
Hence a digital computer could be base-2, base-3, … base-10, base-16, and so
on. The digital computers we are using today are all base-2, or binary,
computers, although it has been proved that base-3 computers would be even
more efficient than base-2 computers.
This is because it is more convenient and cheaper to build components with
the two easily distinguishable states needed to represent base-2 numbers.
Also, in a binary system, signed numbers can be naturally represented using
the highest sign bit: 0 for positive numbers and 1 for negative numbers, for
example. Moreover, the addition and subtraction of signed binary numbers can
be easily done by using 2’s complements to represent negative numbers.
For example, to do −2−3, we would do
(−2) + (−3)
or
(−00000010)b + (−00000011)b
(11111110)b + (11111101)b
which is equal to
(11111011)b
The 1 on the highest bit of the result means that the result is 2’s complement
representation of a negative number. Interestingly, the magnitude of the
negative number is the complement of (11111011)b, which is
MECHANIC-BASED COMPONENTS
Mechanical components such as levels, gears, and wheels can be used to build
analog computers. In fact, digital computers can also be built with mechanical
components. The earliest special-purpose mechanic-based digital computer
was the difference engine designed by Charles Babbage. A general-purpose
mechanic-based digital computer, called the analytical engine, was also first
proposed by Charles Babbage. In the design, the machine has memory and
CPU. It would have been programmable and, therefore, would have become a
general-purpose digital computer, if ever actually built.
TRANSISTORS
Recall that in the construction of computers, the ALU or CPU requires two-
state switches to represent 0 and 1 and logical gates to perform additions and
subtractions of binary number systems. Vacuum tubes could be made to
construct electronic computers, but the computers became too bulky and too
heavy to be more useful.
https://en.wikipedia.org/wiki/History_of_programming_languages
http://www.softschools.com/inventions/history/computer_programming_history/369/
https://www.datarecoverylabs.com/company/resources/history-computer-programming-
languages
https://www.computerhistory.org/timeline/software-languages/
https://www.thecoderschool.com/blog/the-history-of-coding-and-computer-programming/
Advantages of Python
Python was designed with the principle of “programming for everyone.”
Programs written in Python are clean and easy to read. Yet Python is a general-
purpose programming language and very powerful to code in. Programming in
Python has the least overhead, especially when compared to Java. Let’s take
the famous “Hello World!” application as an example. In Java, to create this
application, you need to write a class with a main method like the following:
class first {
public static void main(String args[]){
System.out.println("Hello World!");
}
}
Then save it to a file and compile the file into Java bytecode by running the
following command, provided you have a JDK correctly installed:
javac myhelloworld.java
This command will generate a file named first.class. You can then run
command java first to have “Hello World!” spoken out.
In Python, however, you only need to write the following code and save to a
file, say, myhelloworld.py:
print("Hello World!")
For learners who love to watch videos and lectures, the following are
recommended:
In this section, we will learn how to install Python, Jupyter Notebook, and
Visual Studio Code IDE on our computer. A standard distribution of Python
includes a large volume of libraries for general programming needs. Special
applications such as those in data science and machine learning will require
special libraries to be installed. We will learn about that in later units when we
need them.
INSTALLING PYTHON
The first package we need to install is Python. The steps are as follows:
1. To ensure a clean installation of Python, uninstall all old versions of
Python that may have previously been installed on your computer
and check the value of the PATH environment variable to delete all
those, and only those, related to Python. To ensure that all have been
deleted properly, open a shell terminal such as CMD or PowerShell
on Windows and check if a Python installation still exists by trying
to run it. You should be told that Python is not recognized.
2. Go to https://www.python.org/downloads/ and look for the newest
release of Python for your platform. For example, if you want to
install Python on your Windows machine, download the latest
release for Windows. Normally, the website should be able to detect
the type of system you are using to access the website and show you
the right Python package for you to download. You should, however,
be aware of what you will be getting from the website.
3. Run the installer to install it. If installing Python on a Windows
platform, all you need to do to start the installation is to double-click
the downloaded file or press the run button if it does not start the
installation automatically.
After the installation has started, a window will pop up, as shown
here:
→ Install Now
C:\Users\james\AppData\Local\Programs\Python\Python311
→ Customize installation
Choose location and features
You can either let it install Python automatically for you by clicking
“Install Now” or choose “Customize installation.” When you choose
“Customize installation,” you have the opportunity to choose where
Python will be installed on your computer and what optional
modules and features will be installed.
In either case, you must check the box to add Python to the PATH
environment variable. Choose yes to add Python to the system PATH
environment variable so that Python and other related commands
can be found.
Do a customized installation so that you will see what is to be
installed and where. When doing customized installation, remember
to check the box to install pip, Python package manager, and other
components within the distribution, as shown here:
Optional Features
☑ Documentation
Installs the Python documentation files.
☑ pip
Installs pip, which can download and install other Python packages.
Advanced Options
1. Check whether you have a tool called pipenv installed with your
Python installation by running the following command on Windows:
where.exe pipenv
If you are running the shell terminal as a regular user, pipenv will be
installed under your home directory, so that you will have to add the
location to the environment variable PATH. It is better to start a shell
terminal as an administrator, then run the above command as
root/administrator to ensure that pipenv will be installed globally
and be accessible for all users with the already set value for PATH.
3. Once you are sure that pipenv is installed, create a directory for your
new project and change the work directory to that directory, say
c:\dev\testproject as an example, by running the following
commands in sequence:
c:\dev> mkdir testproject
c:\dev> cd testproject
Once the virtual environment has been activated, the prompt of the
shell terminal will become something similar to the following:
(testproject-UCP5-sdH)c:\dev\testproject>
Please note the text within the parentheses. It contains the name of
the project directory. It means that you are now working in a
subshell terminal invoked by pipenv.
6. From now on, any package installed by running the pip command on
this subshell terminal will be only part of this virtual environment,
without interfering with installations elsewhere for other projects.
7. To get out of the virtual environment, simply type “exit” to close the
subshell, as shown below:
(testproject-UCP5-sdH)c:\dev\testproject>exit
The command will start a web service on your computer, then launch
Jupyter Notebook Service within your default web browser.
Start a new notebook by clicking “New” and “Choose Python 3.”
You can then start the program interactively within the notebook, as
shown in Figure 1-3.
To run Visual Studio Code on Windows, click the Start menu, scroll down to
find Visual Studio Code, and click.
BUILDBOT
Buildbot is a framework intended to automate all aspects of software
development. It supports parallel and distributed job execution across multiple
platforms, with version control and job status reporting and automated job
scheduling when required resources become available. It is hosted at
https://buildbot.net/. An introductory section can be found at
http://docs.buildbot.net/current/tutorial/firstrun.html.
TRAC
Compared to Buildbot, Trac is a simpler web-based software project
management system that can track issues and bugs. It requires access to a
database such as SQLite or MySQL. Trac is hosted at
https://trac.edgewall.org/, but the latest release can be found at
https://pypi.org/project/Trac/.
ROUNDUP
Compared to Trac, Roundup is an even simpler tool to track issues in a
software development project. You can do so via the command line, the web,
or email. The system can be found at https://pypi.org/project/roundup/.
As can be seen above, this program in Python needs only one statement
made of one line of code, whereas in C/C++ or Java, it would need a dozen
lines of code.
Please note that in the previous example, the characters behind the Python
prompt >>> are Python statements you need to type, and the rest are output
from Python interpreter or Python Virtual Machine (PVM).
Our next sample program within the Python interactive shell is to assign 8
to variable x and assign 9 to variable y, then print out the sum of x and y, as
shown here:
PS S:\Dev> python
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec 6 2022, 19:58:39) [MSC v.1934
64 bit (AMD64)] on win32
Type .help., "copyright", "credits" or "license" for more information.
>>> print("Hello World!")
Hello World!
>>> x = 8 # assign 8 to variable x
>>> y = 9 # assign 9 to variable y
>>> print(f'{x} + {y} = {x+y}')
8 + 9 = 17
>>>
Within this interactive programming environment, you can type any Python
expression directly behind >>>, and it will then be evaluated. An example is
shown here:
PS S:\Dev> python
Python 3.11.1 (tags/v3.11.1:a7a450f, Dec 6 2022, 19:58:39) [MSC v.1934
64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> 1350-789*3/26
1258.9615384615386
>>>
At this time, you are not required to fully understand the program, but if you
are interested, you may type the code line by line into your VS Code and run it
by clicking the play button at the top-right corner of the VS Code window, just
to get a taste of programming in VS Code with Python.
Please note that if you have multiple Python program files open in VS Code
and want to run a particular one within the IDE, you will need to click the file
to make it active; then, within the editing area, click the right button of the
mouse to pop up a menu and select run for your particular program. This is
even more important if you have multiple editing tabs open for different
programs.
HEADINGS
In Markdown documents, headings are simply led by one or more hash
symbols. As we have seen in previous sections, a Level 1 heading is led by a
single hash symbol, a Level 2 heading is led by two hash symbols, and a Level
3 heading is led by three hash symbols. You can have up to six levels of
headings in a document, as shown below:
# This is a Level 1 heading
Please note the space between the formatting symbol or symbols and the text
to be formatted. A single space should be placed between the formatting
symbol and the text being formatted in Markdown.
PARAGRAPHS
In Markdown, paragraphs are separated with one or more blank lines.
This is a paragraph.
This is a paragraph.
NEW LINES
In Markdown, to break a line like you would with <br/> in HTML, use more
than one single space to break the line.
This line will break. This line starts on a new line.
** Bold **
Bold
~~ strikethrough ~~
Strikethrough
HORIZONTAL RULES
To add a horizontal line within a document, like <hr /> in HTML, use three
hyphens ---. Most of the time, this has the same effect in Word.
---
KEYBOARD KEYS
In computing documentation, we often need to explain what key is used on the
keyboard. To represent a key on the keyboard, we use HTML kbd tags
directly, as shown below:
<kbd> Ctrl </kbd> <kbd> A </kbd>
Ctrl+A
Ctrl+Shift+F3
UNORDERED LISTS
With Markdown, writing an unordered list is rather straightforward, as shown
below:
* first list item
* second list item
* first item of sublist
* second item of sublist
* third list item
The rendered result will be the following:
ORDERED LISTS
To write an ordered list in Markdown is straightforward too, as shown below:
1. first list item
2. second list item
* first item of sublist
* second item of sublist
3. third list item
DEFINITION LISTS
The simple Markdown syntax for a definition list does not work in Jupyter
Notebook within VS Code. However, we can use HTML <dl> tags directly to
make such a list, as shown below:
<dl>
<dt> Python </dt>
<dd> It is a popular programming language, widely used in AI and Data
Science. </dd>
<dt> AI </dt>
<dd> Short for Artificial Intelligence.
It is the study of how to design and develop smart artifacts.</dd>
</dl>
Python
It is a popular programming language, widely used in AI and Data Science.
AI
Short for Artificial Intelligence. It is the study of how to design and develop smart artifacts.
LINKS
To add a link with Markdown, put the anchor name in a square bracket, and
put the URL in a pair of parentheses, as shown below:
[Markdown Home](https://www.markdownguide.org/)
The rendered result will be the following text, which will take the user to
https://www.markdownguide.org/ when clicked:
Markdown Home
Assignment 1
IMAGES
To add an image to your documentation, use a syntax similar to that used for
adding links, but with an exclamation mark at the front of the open square
bracket, as shown below:

BLOCKQUOTES
To include a blockquote in your documentation, use an angle bracket at the
start of each line, as shown in the following example:
> COVID-19 UPDATES
>
> EXAMS
>
> HELP & SUPPORT
>
> FACULTY OF BUSINESS STUDENTS
>
> FACULTY OF SCIENCE STUDENTS
COVID-19 UPDATES
EXAMS
HELP & SUPPORT
FACULTY OF BUSINESS STUDENTS
FACULTY OF SCIENCE STUDENTS
TABLES
To create a table in Markdown, use the pipe character | to divide columns and a
sequence of dashes/hyphens to separate the header of a table, as shown below:
| Markdown symbol | Description | HTML equivalent |
| # | Level 1 heading | h1 |
| ## | Level 2 heading | h2 |
# Level 1 heading h1
## Level 2 heading h2
Please note the colons used in the formatting syntax. A single colon to the
left of dashes means to align all the text in the column to the left, a single
colon to the right of dashes means to align all the text in the column to the
right, and adding a colon to both sides means to align the text at centre. You
can also use other Markdown syntax on the text in the table, such as italic,
bold, and so on.
The range(start, end, step) function is used to produce a sequence of integer numbers.
CODE BLOCK
In Markdown, a block of program code can be marked up using a pair of triple
backticks ```, as shown below:
```Python
for i in range(1, 10):
for j in range(1, i + 1):
print(f'{i} * {j} = {i * k}')
```
Please note that the name of the programming language right behind the
opening triple backticks is optional, though with the name, the code will be
automatically highlighted in a way specific for the language.
The rendered result of the above Markdown code is shown in Figure 1-5.
You can get the same result if you export the notebook file to PDF or HTML
format.
Figure 1-5: Rendered result of the Markdown code
TO-DO LIST
You may wish to have a to-do list in your learning notebook. With Markdown,
you can get that accomplished as follows:
- [ ] a bigger project
- [x] first subtask
- [x] follow-up subtask
- [ ] final subtask
- [ ] a separate task
"""
brief documentation
"""
or
'''
brief documentation
'''
This is called a docstring. Different from comments made
on program code using a single hash symbol #, docstrings
are meant to be formal documentation of the code that can
be retrieved from an object.
This results in the notebook printing, outside of the code cell, the following:
Hello world!
In Jupyter Notebook, there are two types of cells for input. One is the code
cell for you to write actual program code in. The other is the Markdown cell
for you to write more detailed notes or reports about your work within the
notebook using the Markdown language we have introduced in the previous
section.
When a new cell is created in a Jupyter Notebook within VS Code, by
clicking the plus sign + on the left side of the notebook window, you will get a
code cell by default. To change a code cell to a Markdown cell, click the M↓
button at the top of the cell; to change a Markdown cell back to code cell, click
the {} button at the top of the cell.
Please note that when using Jupyter Notebook within a web browser, to
switch a code cell to Markdown cell you will need to click “Code” at the top
of the cell, and then choose “Markdown” from the pop-up menu.
In the Jupyter Notebook example above, two cells are used. The first is a
Markdown cell, in which we explain in more detail what we are going to do
for our first Python program and how we will do it, whereas the second cell is
a code cell, in which actual Python code is written, together with docstring and
inline comments, for the program.
In the simple program above, a pair of triple quotation marks is used to
enclose some string literals, called docstrings, as the formal documentation for
the program or module. In addition to each program file or each module file, a
docstring is also recommended, and even required, for each function, class,
and method. Docstrings should be placed at the very beginning of a program
file, module file, or right after the header of the definition of a class, function,
or method. The docstrings will be retrieved and stored as the __doc__ attribute
of that respective object and can be displayed when help is called on that
object. Python also has a utility program called pydoc that can be used to
generate documentation from Python modules by retrieving all the docstrings.
Right after the docstring is a print statement that will print out Hello World!
when the program is executed by pressing Shift+Enter while the cell is still
active. A cell is active if there is a vertical blue bar on the left side of the cell.
To execute statements inside an active cell, we can also click the play button
(the thick right-facing arrow) at the top of the cell.
Our next sample program is to assign integers to two variables and then
print the sum, difference, product, quotient, integer quotient, remainder, power,
and root. The Python statements to accomplish these operations are as follows:
#Operators
5+3=8
5−3=2
5 x 3 = 15
5 / 3 = 1.6666666666666667
5 // 3 = 1
5%3=2
5 ** 3 = 125
root 3 of 5 = 1.7099759466766968
As you can see, in this interactive programming environment, you can write
and edit many Python statements within a single cell. You may simply write
some statements to accomplish certain calculation or data analysis tasks that
cannot be done even on an advanced scientific finance calculator.
This next example in Jupyter Notebook within VS Code calculates the sum
and the product of 1, 2, 3, … 100:
"""
This is to calculate the sum of 1,2,…,100.
"""
s=0
for i in range(100):
s+=i+1
print(f"Sum of 1,2…,100 is {s})
"""
This is to calculate the product of 1,2,…,100
"""
p=1
for i in range(100):
p*=i+1
print(f"The product of 1,2,…,100 is {p}")
x = ['D','C-','C','C+','B-','B','B+','A','A','A+']
y = [6,9,12,19,23,28,15,13,7,5]
plt.bar(x,y)
plt.title('A showcase')
plt.xlabel('Letter Grade')
plt.ylabel('# of Students')
plt.show()
As you can see, with only 11 lines of code, you can produce a nice graph to
visualize the data in Python.
Note that to run a Python program from a terminal, two conditions must be
met: (1) The location of the Python interpreter (python.exe) must be in the
PATH system variable, so that Windows is able to find it. (2) The Python
program file should be in the current working directory of the terminal. If that
is not the case, you must either change your current working directory to
where the Python program file is located or specify the path to the program
file. Assume we change the current working directory from the one shown at
the end of the list above to the one shown here using the command cd:
PS S:\Dev\Learn_Python>
Because now the primetest.py program is one-level down from the current
working directory at .\samples, where the leading dot (.) refers to the current
directory, to run the program, you will have to specify the path to the program,
as shown here:
PS S:\Dev\Learn_Python> python .\samples\primetest.py
give me an integer that is greater than 1, and I will tell you if it is
a prime: 91
91 is divisible by 7, so that 91 is not a prime
PS S:\Dev\Learn_Python> python .\semples\primetest.py
give me an integer that is greater than 1, and I will tell you if it is
a prime: 23
23 is a prime
PS S:\Dev\Learn_Python>
Before you can use the pyinstaller tool to make the conversion, you will
need to copy the Python library into Windows’ system32 directory, as shown
below:
PS C:\WINDOWS\system32> cp S:\Python\Python311\python311.dll .
PS C:\WINDOWS\system32>
Now you can simply run the command pyinstaller <Python program file
name> to make the conversion, as shown here.
PS S:\Dev\Learn_Python\samples> pyinstaller .\primetest.py
1435 INFO: PyInstaller: 5.7.0
1435 INFO: Python: 3.11.1
1445 INFO: Platform: Windows-10-10.0.22621-SPO
1445 INFO: wrote S:\Dev\Learn_Python\samples\primetest.spec
1460 INFO: UPX is not available.
1460 INFO: Extending PYTHONPATH with paths
['S:\\Dev\\\Learn_Python\\samples']
pygame 2.3.0 (SDL 2.24.2, Python 3.11.1)
Hello from the pygame community. https://www.pygame.org/contribute.html
5243 INFO: checking Analysis
5254 INFO: Building because inputs changed
5254 INFO: Initializing module dependency graph…
5254 INFO: Caching module graph hooks…
5285 WARNING: Several hooks defined for module 'numpy'.
PS S:\Dev\Learn_Python\samples> cp S:\Python\Python311\python3.dll
.\build\primetest\
PS S:\Dev\Learn_Python\samples>
Once you have done all the steps above, you can run the program like all
other apps on your computer, as shown here:
PS S:\Dev\Learn_Python\samples> .\build\primetest\primetest.exe
give me an integer that is greater than 1, and I will tell you if it is
a prime: 31
31 is a prime
PS S:\Dev\Learn_Python\samples>
Errors in Programs
Errors in programs are hardly avoidable, and you should be prepared to see a
lot of errors in your programs, especially at the beginning. The nice thing
about programming within an IDE such as Visual Studio Code is that the IDE
can point out many syntax errors and coach you to code along the way by
showing you a list of allowable words or statements that you may want to use
in that context, although you will have to decide which one to use for your
program by highlighting the words that are problematic.
Syntax errors often include the following:
def findBest():
pass # the pass statement is used to hold the place for a
code block
The second type of errors you may encounter are runtime errors. While syntax
errors may be easily avoided when programming within VS Code IDE,
runtime errors can only be found during runtime. Examples of runtime errors
include dividing a number with 0 and using a variable that has not been
defined or that has no value before it is used. The discussion of error and
exception handling, covered in Chapter 4, is mostly about runtime errors.
The following are some common runtime errors in Python programs:
In addition to syntax and runtime errors, you can also have logical errors in
your programs. These errors can be found only by you or users of the program.
An example of logical errors is when you are supposed to add two numbers,
but you subtract one from the other instead.
Throughout the text, you will learn and gradually gain the ability to make
your programs logically correct and to identify logical errors in your programs.
[algorithm 1] Get two numbers from user, calculate, and print out the sum.
Step 1. Get the first number to n1.
Step 2. Get the second number to n2.
Step 3. Calculate the sum of n1 and n2, and store the result to s.
Step 4. Print out s.
[end of algorithm 1]
Describing the steps of operations as shown above is just one way to present
algorithms. In computing and software development, algorithms can also be,
and more often are, presented using pseudocode or a flowchart.
Pseudocode is a language that is easier for humans to understand but that is
written like a computer program. There is no widely standard vocabulary and
grammar for pseudocode. However, within an organization or even a class, the
same pseudocode language should be used for collaboration and
communication.
The above algorithm can be described in pseudocode as follows:
Start
Input from user → n1 # get an input from user and assign it to n1
Input from user → n2 # get another input from user and assign it to n2
n1 + n2 → s # n1 + n2 and assign the sum to s
print(s)
End
[algorithm 2] Calculate the sum of all positive integers that are no greater than 10000.
Step 1. 1 → i, 0 → s
Step 2. s + i → s, i +1 → i
Step 3. If i <= 10000 go to step 2 # loop back and make repetition under condition
Step 4. Print s
[end of algorithm 2]
In pseudocode, the algorithm can be described as follows:
Start
Initialization: i = 1, s = 0
Repeat
s=s+i
i=i+1
Until i > 10000
End
1. how to install and set up Git on your computer and use it to version-
control your project files locally.
2. how to set up an account at GitHub and version-control your project
files using Git and remote repositories on GitHub.
3. how to use Git and GitHub within VS Code to version-control your
project files.
Within this Git-Bash shell window, you can run the following command to
initialize:
$ git init
You have to run this Git command once to create a local repository for a
project. It will create an empty Git repository on your local computer, which is
a directory named .git with specific subdirectories and files that Git will use to
version-control your project files. It will also create a master/main branch for
the project. Other branches can be created if the project is divided into smaller
ones to be worked on in parallel and then later merged.
Before running the command, you can set up an environment variable called
$GIT_DIR to determine where the local repository will be placed on your
computer. If $GIT_DIR is not set, the local Git repository—that is, the .git
subdirectory—will be created right under the current working directory; if
$GIT_DIR is set in a different location of your choosing, .git will be created
right under $GIT_DIR. The common location of .git for a project is right
under the project directory.
For the system to know who has made changes to the files and how to
communicate with them, the following two commands need to run to config
the Git that you installed on your computer:
$ git config -global user.name "Jon Doe"
$ git config -global user.email "[email protected]"
These commands will configure the user’s name and email address. Please
keep in mind that this username is different from the username that you will
use to sign up for your account with GitHub later in this section.
When changes have been made to a file and you want Git to manage the
changes to the file, the first step is to stage the file by running the following
command:
$ git add <file/files>
This is called “staging changes to the file,” which is the first step Git takes
to version-control files.
For example, if you want to stage changes to all Python program files under
the current project directory, run the following command:
$ git add *.py
To stage changes to all files and even subdirectories under the current
working directory, run the following command:
$ git add .
The next step Git will take to version-control your project files is called
commit. It is done by running the following command:
$ git commit -m "A brief message about this commitment"
Now changes to the files have been committed to the local repository. Please
note that the stuff inside the quotation marks behind option -m are the
comments or notes about the changes. If you run Git commit without option -
m, a text editor will pop up to let you enter comments.
You can check the status of your Git system by running the following
command:
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>…" to unstage)
new file: start.py
This shows that the file start.py has been staged but not committed yet. You
can still use the git rm command to unstage the file (remove it from the staged
list).
In the above, we basically described a process of making changes to a file,
staging the files for the changes, and committing the changes to the repository.
You may, and most likely want to, reverse the process to undo some changes.
To a file that has been staged but not committed, use the following
command to unstage it:
$ git rm -cached <file>
or
$ git reset HEAD <file>
To a file that has not been staged, use the following command to discard the
changes to the file:
$ git checkout -- file
To revert a commit that has been made, run the following command:
$ git revert HEAD
To restore a file to one that is n versions back in the master branch of the
repository, run the following command:
$ git restore -source master~n <file>
There are some other Git commands available for various needs of version
control, and each has many options providing powerful functionalities. A list
of these commands can be found at https://git-
scm.com/docs/git#_git_commands. You can also get the GitHub-Git cheat
sheet at https://training.github.com/downloads/github-git-cheat-sheet/.
For Git, files that have been staged or committed for changes are called
tracked, and those that have not been staged or committed are called
untracked. In software development, some files, such as those objects and
executable files derived from code files, do not need to be tracked for changes,
so they should be ignored by Git. To tell Git what files under a project
directory can be ignored, especially when running the command to stage all,
you can add the file names or ignore patterns to a special file called .gitignore
right under the project directory. You need to manage the list in the .gitignore
file by editing the file using a text editor. Details of ignored file patterns can be
found from Git documentation at https://git-scm.com/docs/gitignore. For our
purposes, it may be sufficient to just describe the files based on what you
already know, such as a file name or file names with a wildcard such as *.log.
Note that unlike other version-control systems, Git does not work with files
for different versions, but works only with the changes that led to the current
version of the file. For each file, Git will only keep one copy of the file for its
current version in its repository and keep only the changes that led to the
current version for all older versions.
To view which remote repository is configured for the current project, use
the following Git command:
$ git remote -v
The command below initializes a git repository and adds remote notebooks:
$ git init
Initialized empty Git repository in S:/Dev/Learn_Python/.git/
Between the local repository and the remote repository, project files can go
in two directions. Moving files from the local to the remote repository is
referred to as a push; moving files from the remote to the local repository is a
pull or fetch. Between pull and fetch, pull is the default mode of moving files
from remote to local, and fetch provides additional power, such as is needed
when moving files from several repositories at the same time.
Please note that pull or push operations are not just transferring files. Key
points of the operation are merging the changes to files in the target repository
and versioning. Git has special commands for those key operations, but those
operations often run behind the scenes without anyone noticing.
After you have added a remote repository to your project, you can push the
already committed changes to the local repository by running the git push
command in a shell terminal within the project directory, as shown here:
$ git push --set-upstream notebooks master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 6 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 545 bytes | 272.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/jamesatau/comp21B-notebooks/pull/new/master
remote:
To https://github.com/jamesatau/comp218-notebooks.git
* [new branch] master -> master
branch 'master' set up to track 'notebooks/master'.
You will then have all the code samples on your computer.
To work with Git and GitHub, you can use Git GUI, a GUI-based system, by
invoking Git GUI on the project folder within Windows File Explorer.
Another way, our preferred way to use Git and GitHub for versioning on
both local and remote repositories, is to operate within VS Code, which has
native support for Git and GitHub, as long as Git is properly installed on the
local computer, as shown earlier in this section.
If you have already created a repository for the project on GitHub, you can
copy the URL of the repository and add the remote repository to the project in
VS Code by running git add remote in the command palette. You will also be
asked to provide a name for the remote repository after entering the URL.
Chapter Summary
• The first chapter has introduced you to computers and programming
languages and guided you in setting up the programming
environment.
• The introduction to modern computers included a brief history as well
as a description of the fundamental architecture of modern
computers. Knowing who made significant contributions to the
development of computers, what contributions they made, and how
they made those contributions can be very inspiring.
• The computers we use today are called Von Neumann machines
because they are based on Von Neumann architecture, which
consists of a control unit, an arithmetic logic unit (ALU), registers,
and a memory unit (collectively called CPU) plus inputs and
outputs. That’s why Von Neumann is often credited as one of the
fathers of modern computers.
• The key features of modern computers are that they are digital,
programmable, and automatic, with stored programs, although these
features were already in the design of the analytical engine by
British mathematician Charles Baggage in the 1800s. Hence Charles
Babbage is also credited as a father of modern computers, although
his machines were not electronic.
• Binary or Boolean algebra is one of the important theories behind
today’s modern computers. It can be proved that computing with a
ternary number system would be more efficient, but it would be
more costly to make computing components to build computing
machines based on a ternary number system than on a binary
number system.
• Signed numbers, including both integers and real numbers, need to
and can be represented by a sequence of digits, using the highest bit
to represent the sign (0 for positive, 1 for negative). A certain
number of digits are assigned for decimals.
• To apply arithmetic operations more easily and efficiently on
computers, 2’s complements are used to represent signed numbers.
With 2’s complements, the addition of signed numbers can be easily
done.
• How do you know what modern computers are and are not capable
of? Alan Turing, independently from Alonzo Church, laid the
foundational work on computability with his Turing machine.
Because of that, Alan Turing is credited as a father of modern
computing.
• There is also the question of how difficult it is to solve a problem
with computers, which is the study of computational complexity.
The computational complexity of a problem is often measured in
terms of the total number of basic computations, such as addition
and multiplication, which can be converted into the time needed to
solve the problem on specific computers. The space required to solve
a problem can be a concern as well, but most of the time, when
people are talking about computational complexity, they are talking
about the steps or time required to solve the problem.
• Problems to be solved on computers are often divided into three
classes of problems: P, NP-complete, and NP, in which P is short for
polynomial and NP is short for nondeterministic polynomial.
• If, on a deterministic and sequential machine like a computer, for a
problem of size n, if the time or number of steps needed to find the
solution is a polynomial function of n, the problem is said to be in
the P class. If a problem can be solved in polynomial time on a
nondeterministic machine, the problem is in the NP class. A problem
is said to be NP-complete if proposed answers can be verified in
polynomial time, and if an algorithm can solve it in polynomial time,
the algorithm can also be used to solve all other NP problems.
• Programs are the computers’ soul. The task of writing programs for
computers is called programming. Languages in which programs can
be written for computers are programming languages.
• Programming languages play important roles in building soul into
computers. Programming languages can be machine languages,
assembly languages, and high-level languages.
• Ada Lovelace, who wrote code for Charles Babbage’s analytical
engine, was credited as the first programmer of modern computers.
The Ada programming language was named in her honour.
• An algorithm describes the steps a computer needs to take to solve a
problem or complete a task.
• Pseudocode and flowcharts are two ways of describing algorithms.
• System analysis and design are the steps taken to design and develop
an information system for real-world application.
• The official website for the Python programming language is at
www.python.org. Use the Anaconda package to install Python,
Jupyter Notebook, Visual Studio Code IDE, and other tools for your
study of programming with Python.
• Python interactive shell and Jupyter Notebook are recommended for
learning Python programming interactively.
• Create a Jupyter Notebook for each chapter and/or section, and work
through all the examples within that part of the course in that
notebook to keep a record of your learning activities for review and
evaluation.
• Visual Studio Code (VS Code) is the IDE recommended for you to
complete the projects and programming projects in the assignments.
Exercises
In [ ]: first_name = 'John'
last_name = 'Doe'
print(full_name)
In [ ]: for i in range(11):
p = (2**i)
print(f'{bin(p)}')
Projects
1. Research the history of computers online, then write a summary
about each of the following:
a. The computing machines designed and developed in history
that are significant to the development of today’s computers
b. The people in history who have made significant
contributions to the development of computers
c. The concepts, theories, designs, and technologies in history
that are important to the development of modern computers
2. Research the history of programming languages online, then write a
summary for each of the following:
a. Machine languages that have been important to the
development of computer systems
b. The differences between machine languages, assembly
languages, and high-level programming languages
c. The essence (what defines it and differentiates it from others)
of structural programming, the pros and cons of structural
programming, and some well-known programming
languages that support structural programming
d. The essence of imperative programming, the pros and cons
of imperative programming, and some well-known
programming languages that support imperative
programming
e. The essence of declarative programming, the pros and cons
of declarative programming, and some well-known
programming languages that support declarative
programming
f. The essence of functional programming, the pros and cons of
functional programming, and some well-known
programming languages that support functional
programming
g. The essence of logical programming, the pros and cons of
logical programming, and some well-known programming
languages that support logical programming
h. The essence of object-oriented programming, the pros and
cons of object-oriented programming, and some well-known
programming languages that support object-oriented
programming
OceanofPDF.com
Chapter 2
Essential Building Blocks of Computer Programs
Learning Objectives
After completing this chapter, you should be able to
In [ ]: x = 'John'
y = x
Out [ ]: John
In [ ]: x = 'Smith'
Please note that in the examples above and other examples in the
remainder of the textbook, the box behind In [ ] represents a code cell in
Jupyter Notebook, whereas everything behind Out [ ] is the output from the
code contained in the code cell when you press Shift+Enter or click the play
button.
In Python, identifiers shown in Table 2-1 are reserved and hence called
reserved words or keywords, with predefined special meaning in the
language, which means that you must not use them to name your variables,
functions/methods, classes, or modules.
Reserved Reserved
word Special meaning word Special meaning
In addition to the reserved words in Table 2-1, you should also avoid
using names that have been used by Python for built-in types and built-in
functions, classes, and modules. These names are collectively called built-in
names. It is grammatically fine to use built-in names as user-defined
identifiers, but using them may cause confusion.
Furthermore, Python also uses the underscore _ as an identifier for a very
special variable to hold the result of the last evaluation when Python is
running in interactive mode, as shown in the following example:
>>> sum ([1,2,3,4,5,6])
21
>>> sum (list(range(1000)))
499500
>>> _
499500
>>> |
In [ ]: pow(9, 3)
Out [ ]: 729
In [ ]: _
Out [ ]: 729
variable n
1. Lower case identifiers are usually used for variables and function
names.
2. Capitalized identifiers are used for class names.
3. Upper case identifiers are used for constants, such as PI =
3.1415926, E = 2.7182, and so on.
4. When an identifier has multiple words, the underscore _ is used to
separate the words. So we use your_name instead of yourname,
use to_be instead of tobe. Some programmers prefer not to use an
underscore, but to capitalize each word, except for the first word,
when an identifier is used as a variable or the name of a function
or method.
__MAIN__
Used as a special value. When a Python program/script file runs as the main
program other than a module, the special variable __name__ will be
assigned special value __main__.
__NAME__
Used as a special variable in a Python program to hold special value
indicating how the program file is called or used. If the program file is used
as the main program, __name__ will hold __main__. If it is used as a
module, __name__ will hold the name of the module.
__PACKAGE__
Used as a special variable to hold the package’s name if a module imported
is a package. Otherwise, __package__ will hold an empty string.
__SPEC__
Used as a special variable to hold the module specification used when the
module is imported. If the Python program file is not used as a module, it
will hold the special value None.
__PATH__
Used as a special variable to hold the path to the module in a package. If the
module is not within a package, __path__ is not defined.
__FILE__
Used as a special variable to hold the name of a Python program file.
__CACHED__
A special variable often used together with the special variable __file__,
referring to a precompiled bytecode. If the precompiled bytecode is not
from a program file, __file__ is not defined.
__LOADER__
Used as a special variable to hold the object that loads or imports the
module so that you would know who is using the module.
__DOC__
Used as a special variable to hold the documentation of a module or Python
program if it is used as the main program, documentation of a class, or
function or method of a class.
Dunder names used for special functions and methods will be discussed in
Chapter 6 and Chapter 7.
The following sample shows how matching local and global names are
resolved:
In [ ]: g_name = 'John' # global name g_name
display_names()
You may have noted in the example above that variable l_name is
defined both locally in definition of the function display_names() and
globally. When it is used within the function, its local definition is used;
variable g_name, on the other hand, is only defined globally, and when it is
used within the function, it is resolved to its global definition.
In addition to the LEGB rules, please keep in mind the following:
addition (x + y)
subtraction (x − y)
multiplication (x * y)
division (x / y)
negation (−x)
exponentiation (x ** y)
modular (x % y)
integer division (x // y)
You should be able to use the above operations, which you should
already be familiar with, as well as the following bitwise operations you
may never have heard about:
bitwise or (x | y)
>>> 1 | 4
5
bitwise exclusive or, often called XOR (x ^ y)
>>> 1 ^ 2
3
bitwise and (x & y)
>>> 1 & 5
1
shifted left (x << n)
>>> 2 << 3
16
shifted right (x >> n)
>>> 256 >> 5
8
invert (~x)
>>> ~128
-129
The following are a few more samples from the Python interactive shell
that show how these operators are used:
>>> 12 + 23
35
>>> 35 - 12
23
>>> -123
-123
>>> 123 * 567
69741
>>> 69741/123 # the result is a real or float-point number
567.0
>>> 69741//123 # get the quotient of two integers
567
>>> 69741%12 # operation % will get the remainder
9
The next few examples are about bitwise operations. The first two
operations on the first line show the binary form of the two numbers. In
Python, you can have two or multiple statements on a single line, but you
are not encouraged to do so.
>>> bin(123); bin(567) # how to have two or more statements on one
line
'0b1111011'
'0b1000110111'
>>> bin(123 | 567) # it will be 0001111011 | 1000110111
'0b1001111111'
>>> bin(123 ^ 567) # it will be 0001111011 ^ 1000110111
'0b1001001100'
>>> bin(123 & 567) # it will be 0001111011 & 1000110111
'0b110011'
>>> bin(123 << 5) # it will be 1111011 << 5
'0b111101100000'
>>> bin(123 >> 5) # it will be 1111011 >> 5
'0b11'
>>> bin(~123)
'-0b1111100'
N.BIT_LENGTH()
This returns the number of necessary bits representing the integer in binary,
excluding the sign and leading zeros.
>>> n = -29
>>> print(f'Binary string of {n} is {bin(n)}')
binary string of -29 is -0b11101
>>> print(f'# of significant bits of {bin(n)} is {n.bit_length()}')
# of significant bits of -0b11101 is 5
b'\xff\xa3\xf1'
Note that when two bytes are used to represent integer 256, 0b100000000
will be expanded to 00000001 00000000. In Big Endian, it represents 256,
but in Little Endian, 00000001 becomes the less significant byte, while
00000000 becomes the most significant byte, and the corresponding
number for 256 becomes 00000000 00000001.
For more advanced operations on integers, there are some special
modules such as the standard math module, math; the free open-source
mathematics software system SAGE; (https://www.sagemath.org/); SymPy
(https://www.sympy.org/en/index.html); and, for operations in number
theory, eulerlib (https://pypi.org/project/eulerlib/).
FLOAT (FLOAT)
Float numbers are numbers with decimals, in the form of 12.5 in decimal
notation or 1.25e1 in scientific notation, for example. Operations on float
numbers include addition (+), subtraction (−), multiplication (*), division
(/), and exponentiation (**), as shown below:
Out [ ]: x = 8762.31728619258
Using an underscore to separate the digits has made it much easier to tell
how big the number is.
R.AS_INTEGER_RATIO()
This returns a pair of integers whose ratio is exactly equal to the original
float r and with a positive denominator. It will raise OverflowError on
infinities and a ValueError on NaNs.
>>> r.as_integer_ratio()
(7093169413108531, 562949953421312)
R.IS_INTEGER()
This returns True if r is finite with integral value, and False otherwise.
>>> r.is_integer()
False
R.HEX()
This returns a representation of a floating-point number as a hexadecimal
string. For finite floating-point numbers, this representation will always
include a leading 0x and a trailing p and exponent.
>>> r.hex()
'0x1.9333333333333p+3'
FLOAT.FROMHEX(S)
This returns the float represented by a hexadecimal string s. The string s
may have leading and trailing whitespace.
>>> float.fromhex('0x1.9333333333333p+3')
12.6
BOOLEAN (BOOL)
Boolean data have only two values: True and False. They are used to
represent the result of a test or an evaluation of logical expressions, as we
will see. Technically, Python does not need a special Boolean data type,
since it treats 0 and None as Boolean False, and treats everything else as
Boolean True, as shown below:
'no value'
print(f"b = {b}") # print out what b holds
Out [ ]: b = None
Print this out when b is None!
However, having a Boolean data type with two Boolean values of True
and False does clearly remind Python programmers, especially beginners,
that there are special types of data and expressions called Boolean data and
Boolean expressions.
COMPLEX (COMPLEX)
If you have never heard about complex numbers, quickly search the internet
for complex numbers and read some articles or watch some videos.
Briefly, a complex number is a representation of a point on a plane with
X and Y axes that take the form of x + yj, in which x and y are float
numbers that represent and define the location of a point on the plane.
Examples of complex numbers are 1 + 1j, 3 − 6j, 2.5 − 8.9j, and so on.
The same operations on float numbers can also be applied to complex
numbers, as shown below:
STRING (STR)
Sequences are a group of data in order, and a string is a good example of a
sequence.
Like numbers, strings are very important in all programming languages.
It is hard to imagine what a number means without its context. For that
reason, in most programming languages, strings are also considered a
primary data type in terms of their importance and the role that they play.
In Python, strings are sequences of characters, symbols, and numbers
enclosed in a pair of double quotation marks or a pair of single quotation
marks. Table 2-2 is a list of ASCII characters that can be used in strings.
The following are some examples of strings:
When a string is too long and needs to span more than one line, a pair of
triple quotation marks can be used, as shown in the following example:
Information Interchange.
ASCII was developed a long time ago, and now the nonprinting
If someone says they want your CV in ASCII format, all this means
"""
This can be very useful in cases such as when you want to print out
instructions for users to use with an application you developed.
Otherwise, you would need to use backslash at the end of each line
except the last one to escape the invisible newline ASCII character, as
shown below:
In [ ]: s0 = 'Demo only. This string is not too long \
print(f's0 = {s0}')
This is OK if the string only spans across two or three lines. It will look
clumsy if the string spans across a dozen lines.
In the example above, we use backslash \ to escape or cancel the invisible
newline ASCII character. In Python and almost all programming languages,
some characters have special meanings, or we may want to assign special
meaning to a character. To include such a character in a string, you need to
use a backslash to escape from its original meaning. The following are
some examples:
8 BS (backspace) 40 ( 72 v 104 h
s0 = f"Your
name is
{name}."
print(s0)
Out:
Your name
is John.
s0 = r"Your
name is\t
{name} \""
print(s0)
Out:
Your name
is \t
{name} \"
Code sample
in Jupyter
Flag What it does Notebook
print(" 秦时
明月汉时
关")
Out:
秦时明月
汉时关:秦
时明月汉
时关
10458.68")
Out:
b"2005-05-
26-
10458.68"
LIST
List is a very useful compound data type built into Python. A list of
elements, which can be different types of data, is enclosed in square
brackets. The following are some examples of lists:
[1, 2, 3, 4, 5]
['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
Assume that
week = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday',
'Saturday', 'Sunday']
The term week[0] refers to the first element of the list, and week[1] refers to
the second element of the list, where 0 and 1 are called index. An index can
be negative as well, meaning an item counted from the end of the list. For
example, week[-1] will be Sunday, the first item from the end; week[-2]
will be Saturday, the second item from the end.
To get a sublist of a list L we use notation L[s: e], where s is the starting
point in the list, e is the ending point within the list, and the sublist will
include all items from s till e but excluding the item at e. For example, to
get all weekdays from the list week, we use week[0,5], as shown below:
'Saturday', 'Sunday']
week[0:5]
'Saturday', 'Sunday']
week[0:-2]
In [ ]: week[:]
We can then combine weekdays and weekend into one list and assign the
new list to week using operator +, as shown below:
'Friday']
weekend = ['Saturday', 'Sunday']
print(week)
We can create a list from a string using the built-in function list():
print(l0)
Out [ ]: ['H', 'o', 'w', ' ', 'a', 'r', 'e', ' ', 'y', 'o', 'u', '?']
We can also create a list using the built-in function list() and range():
In [ ]: l1 = list(range(10))
l2 = list(range(10, 20))
print(l1, l2)
Out [ ]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [10, 11, 12, 13, 14, 15, 16, 17,
18, 19]
We can use the built-in function len() to find out how many elements are
in the list:
In [ ]: print(len(week))
Out [ ]: 4
TUPLE
Tuple is another type of sequence, but members of a tuple are enclosed in
parentheses. The following are some sample tuples:
(12, 35)
('Canada', 'Ottawa')
('China', 'Beijing')
You can create a tuple from a list by using the tuple() function. For
example,
TPL = TUPLE(WEEK)
This will create a tuple, as shown below:
('Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
'Sunday')
Members of a tuple can be accessed in the same way as lists because the
members are also indexed. For example, tpl[0] refers to Monday.
Moreover, most of the operations used on lists can be applied to tuples,
except those that make changes to the member items, because tuples are
immutable.
Why are tuples immutable? You may consider it like this: A tuple is used
to represent a specific object, such as a point on a line, or even a shape. If
any member of the tuple is changed, it will refer to a different object. This
is the same for numbers and strings, which are also immutable. If you
change any digit of a number, or any character of a string, the number or
string will be different.
SET
In Python, a set is a collection of elements or objects enclosed in a pair of
curly brackets. Like sets in mathematics, members in a set are unordered
and unindexed. The following are two examples of sets:
grades = {'A', 'A+', 'A−', 'B', 'B+', 'B−', 'C', 'C+', 'C−', 'D',
'D+', 'D−'}
My_friends = {'John', 'Jack', 'Jim', 'Jerry', 'Jeromy'}
You can use built-in function set() to build a set from a list or tuple:
week_set = set(('Monday', 'Tuesday', 'Wednesday', 'Thursday',
'Friday', 'Saturday', 'Sunday'))
Built-in functions set(), list(), tuple(), float(), int(), str() are also called
constructors or converters, because they are used to construct or convert to
one respective type of data from another type.
You can use membership operator in to test if an object is a member of a
set. For example,
'John' in My_friends
will give you a True value because John is a member of set My_friends
constructed above.
You can use built-in function len() to get the size of a set—that is, how
many members are in the set. So len(grades) will be 12.
DICTIONARY
In Python, a dictionary is a collection of comma-separated key-value pairs
enclosed in curly brackets and separated by a colon :. The members of a
dictionary are unordered and unindexed. The following is an example:
In [ ]: weekday = {'Mon':'Monday', 'Tue':'Tuesday', 'Wed':'Wednesday',
'Thu':'Thursday', 'Fri':'Friday'}
Because the keys are used to retrieve the values, each key must be unique
within a dictionary. For example, we use Weekday['Mon'] to retrieve its
corresponding value, Monday.
In this case, you can also use integer numbers as keys, as shown below:
5:'Friday'}
OBJECT
Although you can code almost any application in Python without object-
oriented thinking, you should be aware that Python fully supports object-
oriented programming. In fact, Python treats everything as an object,
including classes, functions, and modules. For example, numbers are treated
as objects in the following statements:
In [ ]: print((2.35).hex())
print((23).bit_length())
Out [ ]: 0x1.2cccccccccccdp+1
5
There are some special types of objects in Python, as shown in Table 2-4.
VARIABLES
A variable is a name that identifies a location in computer memory to store
data. A variable must conform to the rules of naming discussed earlier in
this section, and it also must not be used for other purposes within the same
context of the program. For example, you cannot use reserved words or
keywords as variables.
An important operation on a variable is to assign a value to it or put a
value into the memory location identified by the variable. In Python, this is
done by using the assignment operator =.
For example, the following statement assigns COMP 218 to the variable
course, assigns Smith to the variable student, and assigns 99 to the variable
grade:
In [ ]: course = 'COMP 218'
student = 'Smith'
grade = 99
student, grade))
In [ ]: type(grade)
Out [ ]: int
You may convert the value of a variable into another type using specific
built-in functions, such as int(), float(), str(), etc.
to variable int_mark
print(int_mark)
Out [ ]: 90
Coding Practice
Task 1
In a Jupyter Notebook cell, type the following code and run it by
hitting Shift+Enter to see what you will get:
pi = 3.1415
r = 6
area = pi * r ** 2
print(F"The type of pi is {type(pi)}, and its value is {pi}")
print("The type of r is ", type(r), ", its value is ", r)
print("The type of area is {:^10}".format(str(type(area))),
end='')
print(", and its value is {:^12}.".format(area))
Task 2
In a new cell of Jupyter Notebook, write and run the following
statements, which calculate the circumference of a circle with radius r
= 10, and print the result:
pi = 3.1415
r = 10
circumference = 2 * pi * r
print("The circumference of a circle with radius {:d} is
{:f}".format(r, circumference))
Please note that in Jupyter Notebook, if you need a new cell, simply click
the plus sign button under the notebook menu.
Please also note that the type of variable area is the same as the type of
variable pi, but not of variable r. We can check what type the result will be
when a different arithmetic operator is applied to a pair of numbers of the
same or different types, as shown in Tables 2-5a and 2-5b:
In [ ]: i = 12
cx = 23 + 35j
icx = i / cx
print(icx, type(icx))
BUILT-IN CONSTANTS
We have seen some values of various data types. Some values have special
meanings in Python. We call them constants. The following table lists all
the constants you may see and use when programming with Python.
>>> if x:
… print(f"x is {x}")
x is True
>>> if not x:
… print(f"x is {x}")
x is False
Constant Code sample in Python
name Meaning interactive mode
>>> if not x:
… print(f"{x} is
treated as False")
None is treated as
False
>>> Ellipsis is …
Python 3.7.2
>>> __debug__
False
Ctrl+Z+Enter to exit
Constant Code sample in Python
name Meaning interactive mode
Ctrl+Z+Enter to exit
Python Software
Foundation.
BeOpen.com.
Corporation for
National Research
Initiatives.
Stichting Mathematisch
Centrum, Amsterdam.
BeOpen.com, Zope
of thousands for
supporting Python
development. See
information.
ARITHMETIC OPERATORS
Arithmetic operators are used on numbers. These operators are well-known.
Table 2-7 provides a list of these operators, their meaning, and code
samples you may take and practise in Python interactive mode. Please copy
only the expressions or statements behind >>>, which is the Python prompt
for your input.
Code samples in
Python interactive
Operator Operation mode
>>> +y
20
Code samples in
Python interactive
Operator Operation mode
-10
>>> -y
-20
>>> y * x
200
2.0
(32, 7)
>>> x // y
4
Code samples in
Python interactive
Operator Operation mode
(32, 7)
>>> x % y
of right >>> x, y
(32, 7)
>>> x ** y
34359738368
COMPARISON OPERATORS
Comparison operators are used to compare two objects. It is easy to
understand how they work on numbers and even strings. When a
comparison is applied to lists or tuples, the comparison will be applied to
pairs of items, one from each list or tuple, and the final result is True if
there are more Trues; otherwise it will be False, as shown in the example
below:
l1 < l2
Out [ ]: True
Code sample in
Python interactive
Operator Operation mode
False
>>> l1 = ('apple',
'orange', 'peach')
>>> l2 = ('tomato',
'pepper', 'cabbage')
>>> l2 > l1
True
Code sample in
Python interactive
Operator Operation mode
(23, 53)
>>> x < y
True
>>> s1 = "Albert"
>>> s2 = "Jeremy"
>>> s1 < s2
True
>>> x, y
(23, 53)
>>> x == y
False
equal >>> x, y
(23, 53)
>>> x != y
True
Code sample in
Python interactive
Operator Operation mode
>>> x >= y
True
(23, 53)
>>> x <= y
True
LOGICAL OPERATORS
Logical operators are used to form logical expressions. Any expression
whose value is a Boolean True or False is a logical expression. These will
include expressions made of comparison operators discussed above. Table
2-9 summarize the details of these logical variables.
False
>>> x, y, m, n
True
(23, 53)
False
For example, suppose you are writing a program to control the furnace at
home, and you want to heat the home to 25 degrees Celsius. The code for
this should be
if t < 25 : heating()
the consequence would be either the home will not heat at all (if the initial
temperature is below 25 when the program starts) or it will overheat (if the
initial temperature is greater than 25).
BITWISE OPERATORS
We know that data in computer memory are represented as sequences of
bits, which are either 1 or 0. Bitwise operators are used to operate bit
sequences bit by bit. These bitwise operations may look strange to you, but
you will appreciate these operations when you need them. Table 2-10
provides a summary of bitwise operators. Please note that built-in function
bin() converts data into their binary equivalents and returns a string of their
binary expressions, with a leading 0b.
('0b1100', '0b1111')
'0b1100'
('0b1100', '0b1111')
>>> bin(m | n)
'0b1111'
-13
>>> bin(~ m)
'-0b1101'
('0b1100', '0b1111')
>>> bin(m ^ n)
'0b11'
Operator Meaning Code sample in Python interactive mode
'0b1100'
>>> bin(m>>2)
'0b11'
'0b1100'
>>> bin(m<<2)
'0b110000'
ASSIGNMENT OPERATORS
In Python, and all programming languages, the assignment operation is one
of the most important operations because assignment operations store data
in variables for later use.
In previous sections, we have seen many examples of using the
assignment operator =, the equal sign. However, Python provides many
augmented assignment operators. Table 2-11 lists all the assignment
operators you can use in your Python programs.
Code samples in
Python
Operator Operation interactive mode
Code samples in
Python
Operator Operation interactive mode
assigned to variable x. 12
>>> x
35
x=x+e >>> x, m, n
>>> x += m + n
>>> x
70
>>> x, m, n
x=x−e >>> x, m, n
>>> x -= m + n
>>> x, m, n
x=x*e >>> x, m, n
>>> x *= m + n
>>> x, m, n
x=x/e >>> x, m, n
>>> x /= m + n
>>> x, m, n
x=x%e >>> x, m, n
>>> x %= m + n
>>> x, m, n
x = x // e >>> x, m, n
>>> x //= m + n
>>> x, m, n
x = x ** e >>> x **= m + n
>>> x, m, n
(9039207968, 3,
2)
Code samples in
Python
Operator Operation interactive mode
is assigned to variable x. 3, 2
bin(m), bin(n)
('0b1001',
'0b11', '0b10')
>>> x &= m * n
>>> bin(x),
bin(m), bin(n)
('0b0', '0b11',
'0b10')
assigned to variable x. 3, 2
bin(m), bin(n)
('0b1001',
'0b11', '0b10')
>>> x |= m * n
>>> bin(x),
bin(m), bin(n)
('0b1111',
'0b11', '0b10')
Code samples in
Python
Operator Operation interactive mode
assigned to variable x. 3, 2
bin(m), bin(n)
('0b1001',
'0b11', '0b10')
>>> x ^= m * n
>>> bin(x),
bin(m), bin(n)
('0b1111',
'0b11', '0b10')
e is assigned to variable x. 3, 2
bin(m), bin(n)
('0b1001',
'0b11', '0b10')
>>> x >>= m * n
>>> bin(x),
bin(m), bin(n)
('0b0', '0b11',
'0b10')
Code samples in
Python
Operator Operation interactive mode
e is assigned to variable x. 3, 2
bin(m), bin(n)
('0b1001',
'0b11', '0b10')
>>> x <<= m * n
>>> bin(x),
bin(m), bin(n)
('0b1001000000',
'0b11', '0b10')
Coding Practice
IDENTITY OPERATORS
Identity operators are used to test if two operands, usually two identifiers,
are identical, which in most implementations of Python means that they are
referring to the same memory block of the computer. The examples Table 2-
12 tell you more about this. Note that in the example, the built-in function
id(o) is used to get the id of object o.
is not True if the operands are not identical (do not >>> x =
refer to the same object). list(range(3))
Note that when assigning variable y to variable >>> x = y
x, the operation points x to the same memory >>> id(x),
block y is pointing to (so that the two have the id(y)
id) and shares the same memory block.
(10049016,
However, when a new assignment is made to x 10049016)
or y, the two will have different ids, unless they
>>> x is y
both hold the same integer or string.
True
>>> y =
list(range(3))
>>>
id(x),id(y)
(10090256,
10090336)
>>> x, y
([0, 1, 2], [0,
1, 2])
>>> x is not
y
True
SEQUENCE OPERATORS
In 2.1, we learned that sequences include strings, lists, and tuples because
elements in strings, lists, and tuples are ordered and indexed. Sets and
dictionaries are not sequences because elements in dictionaries and sets are
not ordered, or not in sequence.
Sequence operators are made available for operations on strings, lists and
tuples, as shown in Table 2-13.
>>> [1, 2, 3] * 5
[1, 2, 3, 1, 2, 3, 1, 2,
3, 1, 2, 3, 1, 2, 3]
[1, 2, 3, 5, 6, 7]
'o'
'John'
>>> name[1:3]
'oh'
MEMBERSHIP OPERATOR
Membership operators are used to test whether an element is a member of a
sequence. There are three membership operators in Python, and two of them
are shown in Table 2-14.
>>> l
[0, 1, 2, 3, 4, 5, 6,
7, 8, 9]
>>> 3 in l
True
>>> 2 + 1 in l
True
COMP218"
False
7, 8, 9]
>>> 30 in l
False
>>> 30 not in l
True
The third membership operator is used to access members of objects,
modules, or packages. It is the dot (.) operator. The example in Table 2-15
shows how to access a function in module math.
<class
'builtin_function_or_method'>
>>> math.sqrt(35)
5.916079783099616
Built-In Functions
As with operators, built-in functions are also important in processing and
testing data in programs. As the name implies, built-in functions are built
into Python Virtual Machine (PVM). A built-in function can be used
directly without importing any module or noting what it belongs to.
Built-in functions, and functions or methods in general, can be put into
two categories. One is based on the data they return, whereas the other is
based on the operations performed, although sometimes the returned data
from a built-in function in the second category may still be useful in
subsequent executions of the program.
We will first explain built-in functions in the first category, followed by
built-in functions in the second category. To best understand these
functions, read through these built-in functions and test the sample code in a
Python interactive shell or Jupyter Notebook.
ABS(X)
This returns the absolute value of x, which can be any number.
>>> abs(-99)
99
>>> abs(-b110010) # a binary number
50
>>> abs(-0o32560) # an octal number
13680
>>> abs(0xdef21a) # a hexadecimal(16) number
13610970
POW(X, P)
This returns the value of x to the power of p.
>>> pow(2.9, 12.8)
829266.980472172
FLOAT(S)
This converts s to float. s can be a number, or a string of numbers.
>>> float('18.23')
18.23
>>> float(19)
19.0
MAX(ITERABLE, *[, DEFAULT = OBJ, KEY = FUNC])
ROUND(F)
This rounds number f to the closest integer and returns the integer.
>>> round(3.1415926)
3
ORD(C)
This finds and returns the order of a character, as a single char string, in the
ASCII table.
>>> ord('c')
99
SUM(…)
This calculates and returns the sum of numbers in a list, a tuple, or a range()
call.
>>> sum([23, 56, 67, 12, 89])
247
>>> sum((23, 56, 67, 12, 89))
247
>>> sum(range(88))
3828
SET(S)
This converts a set from a list or tuple.
>>> set([23, 56, 67, 12, 89])
{23, 56, 67, 12, 89}
DICT()
DICT(ITERABLE)
DICT(A = V,…)
These convert an empty dictionary, construct a dictionary from the iterable
of (k, v) tuples, and from key=value pairs, respectively.
>>> dict()
{}
>>> dict([(1,'Turing'), (2,'Bool'), (3,'Babbage'), (4,'Neumann'),
(5,'Knuth')])
{1: 'Turing', 2: 'Bool', 3: 'Babbage', 4: 'Neumann', 5: 'Knuth'}
>>> dict(a = 1, b = 2, c = 3)
{'a': 1, 'b': 2, 'c': 3}
BIN(N)
This converts a number to its binary equivalence as a string.
>>> bin(98)
'0b1100010'
HEX(N)
This converts a number to its hex equivalence as a string.
>>> hex(19)
'0x13'
OCT(N)
This converts a number to its oct equivalence as a string.
>>> oct(28)
'0o34'
BOOL(O)
This converts o to Boolean True or False. In Python, 0, '', and None are
equivalent to False, everything else is equivalent to True.
>>> bool(1)
True
>>> bool('school')
True
>>> bool(0)
False
TUPLE(S)
This constructs a tuple from a list, a string, or range() call.
>>> tuple("this is tuple")
('t', 'h', 'i', 's', ' ', 'i', 's', ' ', 't', 'u', 'p', 'l', 'e')
LEN(S)
This returns the length of a sequence.
>>> len(my_tuple)
13
>>> len("I like Python so much!")
22
LIST(S)
This constructs a list from a sequence or range() call.
>>> list(range(5))
[0, 1, 2, 3, 4]
COMPLEX(A, B)
This constructs a complex number from a pair of numbers and returns the
complex number.
>>> complex(1, 8)
1 + 8j
HASH(S)
This generates a hash for a given string s and returns the hash. One use is
for transmitting and saving passwords.
>>> hash("Python is a great language for programming")
6145305589036905122
DIVMOD(A, B)
This returns a tuple of the quotient and the remainder of one integer or float
number divided by another integer or float number.
>>> divmod(23, 5)
(4, 3)
STR(X)
This converts object x literally to a string and returns the converted string.
>>> str([23, 56, 67, 12, 89])
'[23, 56, 67, 12, 89]'
CHR(N)
This returns the character n with its code in the Unicode table. Note that 0
<= n <= 0x10ffff as a legitimate code.
>>> chr(90)
'Z'
>>> chr(99)
'c'
TYPE(O)
class named X
ALL(ITERABLE)
This returns True if all the elements of iterable are true.
>>> all(range(9))
False
>>> all(range(1,9))
True
ANY(ITERABLE)
This returns True if any of the arguments true.
>>> any(range(9))
True
>>> any([0,0,0,0])
False
DIR()
DIR(O)
dir() returns a list of names in the current namespace. dir(o) returns a list of
the attributes of object o.
>>> dir()
['__annotations__', '__builtins__', '__doc__', '__loader__',
'__name__', '__package__', '__spec__']
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__',
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil',
'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp',
'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum',
'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf',
'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf',
'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt',
'tan', 'tanh', 'tau', 'trunc']
NEXT(IT)
This returns the next element of an iterable such as list, string, tuple, and so
on.
>>> l=iter(list(range(3,99)))
>>> next(l)
3
>>> next(l)
4
ASCII(O)
This returns a string containing a printable ASCII representation of an
object.
>>> ascii(math)
"< module 'math' (built-in)>"
>>> ascii(int)
"<class 'int'>"
ID(O)
This returns object o’s “identity,” which is a unique integer within a given
context, usually the address of the object in memory.
>>> i = 10
>>> id(i) # return the id of variable i
263313728
>>> i *= 98
>>> id(i) # id is different, but still the same i
2809440
SORTED(S)
This returns a new sorted list of elements in iterable s.
>>> il = [12, 0, 9, 32, 8, 5, 3, 99] # il is a list of integers
>>> sorted(il) # default is to sort in ascending order
[0, 3, 5, 8, 9, 12, 32, 99]
>>> sorted(il, reverse = 1) # sorted in descending order
[99, 32, 12, 9, 8, 5, 3, 0]
REVERSED(S)
This returns a reversed iterator.
>>> il = [0, 3, 5, 8, 9, 12, 32, 99]
>>> list(reversed(il))
[99, 32, 12, 9, 8, 5, 3, 0]
>>> list(reversed(range(9))) # range(9) return a sequence of 0,1,…9
[8, 7, 6, 5, 4, 3, 2, 1, 0]
ENUMERATE(S, START = 0)
This returns a list of tuples from a sequence in which the elements are
counted and each element is paired with its count to form a tuple.
>>> list(enumerate("this is")) # default value for optional
argument start is 0
[(0, 't'), (1, 'h'), (2, '€'), (3, 's'), (4, ' '), (5, '€'), (6,
's')]
>>> list(enumerate("this is", 2)) # now counting start from 2
[(2, 't'), (3, 'h'), (4, '€'), (5, 's'), (6, ' '), (7, '€'), (8,
's')]
>>>
EXEC(S)
This executes the statement in string s and provides a way to dynamically
execute the Python code.
>>> exec("print('Hello World!')")
Hello World!
In [ ]: def cubbie(n):
return n * n * n
src = "print(cubbie(23))"
exec(src)
Out [ ]: 12167
ZIP(*ITERABLES)
This returns a list of tuples by taking one element from each of the iterables
to make a tuple until reaching the end of the shortest iterable, and then
returning the tuple. In Python, *p notation means p takes multiple
arguments. In this case, multiple iterables such as lists, tuples, or strings are
expected.
>>> grade_n = [50, 70, 80, 90, 100]
>>> grade_c = ['F', 'D', 'C','B', 'A']
>>> list(zip(grade_n, grade_c))
[(50, 'F'), (70, 'D'), (80, 'C'), (90, 'B'), (100, 'A')]
print(coding)
Out [ ]: (32, ' ') (33, '!') (34, '"') (35, '#') (36, '$') (37, '%') (38, '&')
(39, "'")(40, '(') (41, ')') (42, '*') (43, '+') (44, ',') (45, '-')
(46, '.') (47, '/') (48, '0') (49, '1') (50, '2') (51, '3') (52, '4')
(53, '5') (54, '6') (55, '7') (56, '8') (57, '9') (58, ':') (59, ';')
(60, '<') (61, '=') (62, '>') (63, '?') (64, '@') (65, 'A') (66,
'B') (67, 'C') (68, 'D') (69, 'E') (70, 'F') (71, 'G') (72, 'H')
(73, 'I') (74, 'J') (75, 'K') (76, 'L') (77, 'M') (78, 'N') (79,
'O') (80, 'P') (81, 'Q') (82, 'R') (83, 'S') (84, 'T') (85, 'U')
(86, 'V') (87, 'W') (88, 'X') (89, 'Y') (90, 'Z') (91, '[') (92,
'\\') (93, ']') (94, '^') (95, '_') (96, '`')
The code sample above prints a portion of ASCII table showing the
codes from 32 to 96 and their corresponding characters. It is only to show
how zip function is used. There is a much simpler way to print such a table
using just one for loop.
MAP(F, *ITERABLES)
This applies function f to every item of an iterable and returns the resulted
iterator.
>>> import math
>>> list(map(math.sqrt, range(17))
[0.0, 1.0, 1.4142135623730951, 1.7320508075688772, 2.0,
2.23606797749979, 2.449489742783178]
>>> list(map(sum, ([1, 2, 3], [4, 5, 6], [7, 8, 9, 10])))
[6, 15, 34]
GETATTR(O, ATTR)
This returns the value of object o’s attribute attr, the same as o.attr.
>>> getattr(math, 'sqrt')
<built-in function sqrt>
>>> getattr(math, 'e')
2.718281828459045
HASATTR(O, ATTR)
This tests if object o has attribute attr and returns True if it does.
>>> hasattr(math, 'e')
True
>>> hasattr(math, 'sqrt')
True
>>> hasattr(math, 'power')
False
SETATTR(O, A, V)
This sets or adds an attribute a to object o and assigns value v to the
attribute.
>>> class Student: # defining a class named Student. By convention,
class names should be capitalized
…pass # this defines a class without any attribute
…
>>> s1 = Student() # create an instance of Student
>>> setattr(s1, 'name', 'John') # add an attribute called name, and
assign 'John' to it
>>> s1.name
'John'
>>> hasattr(s1, 'name')
True
DELATTR(O, A)
This deletes attribute a from object o.
>>> delattr(s1, 'name') # delete attribute name from object s1
>>> hasattr(s1, 'name') # check if s1 has attribute name
False
ISINSTANCE(O, C)
This returns True if o is an instance of class c or a subclass of c.
>>> class Student:
…pass
…
>>> s1 = Student()
>>> isinstance(s1, Student)
True
ISSUBCLASS(C, C)
This returns True if class c is a subclass of C.
>>> class Graduate(student):
…pass
…
>>> issubclass(Graduate, Student)
True
REPR(O)
This returns a string representation of object o.
>>> repr(Graduate)
"<class "__main__.graduate'>'
FILTER(F, ITERATOR)
This returns an iterator containing only the elements of the iterable for
which the function returns true.
>>> def even(n):
…return not n%2 # return True if n can be divided by 2
…
>>> list(filter(even, range(9))) # odd numbers will be taken out
[0, 2, 4, 6, 8]
CALLABLE(O)
This returns True if o is a callable object such as a defined function.
>>> callable(even) # it will return True since even is defined
True
LOCALS()
This updates and returns a dictionary of local names/symbols.
>>> locals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module
'builtins' (built-in)>, 'math': <module 'math' (built-in)>, 'l':
<list_iterator object at 0x00370230>, 'student': <class
'__main__.student'>, 's1': <__main__.student object at 0x00CE3DB0>,
'graduate': <class '__main__.graduate'>, 'even': <function even at
0x0029F7C8>}
VARS()
VARS(O)
vars() returns the same as locals(), whereas vars(o) returns the _dict_
attribute of object o.
>>> setattr(s1, 'name', 'John')
>>> vars(s1)
{'name': 'John'}
GLOBALS()
This updates and returns a dictionary of global names/symbols in the
current scope.
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None,
'__loader__': <class '_frozen_importlib.BuiltinImporter'>,
'__spec__': None, '__annotations__': {}, '__builtins__': <module
'builtins' (built-in)>, 'math': <module 'math' (built-in)>,
'student': <class '__main__.student'>, 's1': <__main__.student object
at 0x00CE3DB0>, 'graduate': <class '__main__.graduate'>, 'even':
<function even at 0x0029F7C8>}
BREAKPOINT(*ARGS, **KWS)
This function break the program and takes it into debug mode, calls
sys.breakpointhook(), and passes a list of arguments (args) and a list of
keyword arguments (**kws) to the system function.
@CLASSMETHOD
The at sign @ is called a decorator in Python. This particular decorator is
used to declare a method as class method, which receives the class as its
first argument.
# define a class Person
class Person:
# define a class attribute
species = "human"
The code above was taken from a code cell in Jupyter Notebook. The
output is as follows when you hit the Ctrl+Enter key to run the code:
Alice
28
Human
FORMAT(VALUE[, FORMAT_SPEC])
This is used to convert a value to a “formatted” representation, as controlled
by format_spec.
>>> print("Modern computers have over {h:3d} years of
history".format(h = 80))
Modern computers have over 80 years of history
FROZENSET([ITERABLE])
This returns a new frozenset object, with the option to display it with
elements taken from an iterable. frozenset is also a built-in class.
>>> l = list(range(10))
>>> print(frozenset(l))
frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) # {…} is a set
HELP([OBJECT])
This invokes the built-in help system on the object.
>>> help(frozenset)
INPUT([PROMPT])
This is used to read a line from input, convert it to a string with trailing
newline characters stripped, and return the string. The optional prompt
argument will be displayed without a trailing newline character so that the
cursor will just wait at the end of the prompt for input.
>>> s = input("please give me an integer:")
please give me an integer:
ITER(OBJECT[, SENTINEL])
This returns an iterator object. If the second argument doesn’t exist, the first
argument must be a collection object.
>>> for c in range(6): print(next(l))
…
P
y
t
h
o
n
MEMORYVIEW(OBJ)
This returns a “memory view” object of obj. Note that obj must be a bytes-
like object.
>>> mv = memoryview(b"Hello Python Lover")
>>> print(mv)
<memory at 0x000001B932AD4A00>
OBJECT
This returns a new featureless object, a base for all classes.
>>> O = object
>>> print(O)
<class 'object'>
The example opens a file named scoresheet.txt for writing and assigns
the handle to f.
SLICE(STOP)
@STATICMETHOD
This function decorator is used to declare a method as static. A static
method can be called on the class or an instance.
In [ ]: class FTool():
@staticmethod
def percentage(a, b):
return a/b
r = FTool.percentage(13, 265)
print(f"{13}/{256} is {r}")
SUPER([TYPE[, OBJECT-OR-TYPE]])
This returns a proxy object that delegates method calls to a parent or sibling
type class. It is used for accessing inherited methods that have been
overridden in a class.
In [ ]: class FTool():
@staticmethod
return a/b
print(super(FTool))
The superclass is NULL because FTool is not a subclass of any class except
object, which doesn’t count.
Expressions
Expressions are important program constructs. An expression is made up of
data items, variables, constants, and function calls joined by proper
operators. The precedencies of the operators are as follows:
1. Within arithmetic operators, other operators take precedence over
addition and subtraction.
2. Arithmetic operators take precedence over comparison operators.
3. Membership operators, identity operators, and comparison
operators take precedence over logic operators.
4. Among logic operators, the order of precedence, from high to
low, is not > and > or.
Coding Alert
ARITHMETIC EXPRESSIONS
An arithmetic expression’s value is always one of the following: an integer,
float, or complex. An arithmetic expression can be made of data, variables,
function calls, and arithmetic operators. When mixed data types appeared in
an expression, the value type of the expression will be the most general data
type. For example, the value of 3 + 5.6 will be a float number.
STRING EXPRESSIONS
The string expression’s value is a string. String expressions are made of
strings, string operators, functions and methods that return a string.
BOOLEAN EXPRESSIONS
The Boolean expression’s value is either True or False. Boolean expressions
can be made of data, comparison operators, and logical operators. Note that
although Python has True and False defined as logical true and false, it
treats 0, None, empty string, empty list, empty tuple, set, and dictionary as
False and treats everything else as True.
OTHER EXPRESSIONS
The values of some expressions may be a list, tuple, set, dictionary or even
a complex object. For example, some functions and methods can return a
list or an object of a user-defined class, and the operator + can be used to
combine two strings or lists together.
The following are some examples of expressions in Python:
12 + 35.6 - 36 * 3 + x # integer and float numbers can be mixed
235 + x ** k # 235 plus x to the power of k
2 < j and j in list_x # 2 is less than j and j is a member of list
x
Coding Alert
1 """
input as
8 Version: 1.0
9 """
10
11
12
radius = int(input("tell me the radius:")) # take input from user
15
Please note the triple quotation marks on line 1 and line 9. The triple
quotation marks on line 1 mark the start of the docstring, whereas the triple
quotation marks on line 10 mark the end of the docstring. The quotation
marks can be single or double, but they must be the same. You can also add
docstrings for functions, classes, class methods, or other code blocks in the
program as needed, but the opening triple quotation marks and ending triple
quotation marks must be indented the same amount as the code block. You
will see how this should be done in later chapters, with examples.
Please also note the comments starting with a # at the end of lines 13, 14,
and 15. They are called end-of-line comments or block notes. An end-of-
line comment is usually used to explain what the code on the line does.
Everything behind the # mark on that line is ignored by Python Virtual
Machine (PVM) and intended for only humans to read. An end-of-line
comment can also be started at the beginning of a line.
The difference between docstrings and end-of-line comments is that
docstrings are formal documentation of the program or module and are
accessible through the built-in help() function, with the _doc_ variable
automatically attached to each module, function, class and method, whereas
end-of-line comments are not. As well, utility tools such as pydoc are
available for generating formal documentation for a program or module
from the docstrings within each Python file. The revised version of program
circle.py is shown below, in which we defined a function named area, with
docstrings added to the function and the program.
1 """
11 Version: 1.0
12 """
13
14 def area(r):
18
printout
21
Coding Trick
Simple Statements
Normally, a simple statement is contained within a single logical line,
though Python allows several simple statements to appear on one line
separated by semicolons. There will be examples of this later.
EXPRESSION STATEMENT
Simply put, expression statements in Python programs are just expressions
in mathematical terms. Any expression can be used as a statement, and
PVM will evaluate every expression statement, but the result is only
displayed in Python interactive mode, as shown in the following code
sample in the Python Shell:
2 >>> 2 * 3.14 * 15
Code sample in Python interactive mode
3 94.2
4 >>> 3.14 * 15 ** 2
5 706.5
6 >>>
So if you are using Python in interactive mode, you can simply type
expressions without using the print statement to see the result of the
calculation, just like a powerful calculator.
We can also have expression statements in Jupyter Notebook, but when
there are several expression statements in the same cell, it will only show
the result of the last expression, as shown in the following example:
In [ ]: 2 * 3.14 * 15
3.14 * 15 ** 2
Out [ ]: 706.5
We mentioned earlier in this subsection that you can also put several
simple statements on the same line, but you must separate them with
semicolons. This is shown in the following examples:
3 94.2
4 706.5
5 >>>
Out [ ]: 706.5
ASSIGNMENT STATEMENT
The assignment statement is one of the most important statements and is
used most often in programs because it is a common requirement to keep
the result of computing or information processing in the computer memory
for future uses. It does so by assigning the result to a variable.
In section 2.1, we saw a list of assignment operators. Formally, an
assignment statement is made of a variable on the left and an expression on
the right of an assignment operator, either = or an augmented one such as
+=. We have already seen some examples of assignment statements before,
but the following code sample includes a few more examples:
In [ ]: d = 15
r = d / 2
x = d * 3.14
a = r * r * 3.14
is {a}")
In [ ]: y = 10
n = 5
y *= n # y * n is assigned to y; it is equivalent to y = y * n
n += 2
y /= n
Out [ ]: y is 10; n is 5
y is 50; n is 5
y is 7.142857142857143; n is 7
To understand these augmented assignment statements, we need to
consider the memory location referred to by a variable, such as y with
respect to time. Take y *= n as an example. At time t0 before the actual
assignment starts, the value of y (data stored in the memory referred to by y,
which is 10 at time t0) is taken out, and multiplied by n, whose value is 5 at
time t0; then time t1—the result, which is 50 (from 10 * 5)—is stored in the
memory location referred to by variable y.
Coding Alert
MULTIPLE ASSIGNMENTS
Also, for convenience and efficiency, you can assign values to multiple
variables in a single assignment statement. There are several ways of doing
multiple assignments, as shown in the following examples:
In [ ]: x, y = 1, 2 # assign 1 to x, assign 2 to y
z, [2, 3, 5, 6] to y
CONDITIONAL ASSIGNMENTS
Additionally, in Python, you may even assign different values to a variable
under different conditions, as shown in the following example:
1 >>> marks = 90
2 >>> gr = 'pass' if marks >= 60 else 'fail' # note that elif clause does not
3 >>> gr
4 'pass'
5 >>> marks = 50
7 >>> gr
8 'fail'
As you will see throughout the text, there are many fancy ways of making
statements in Python, and that’s why Python is a very powerful language.
Indeed, the full power of a programming language can only be materialized
by the best programmers.
ANNOTATED ASSIGNMENT STATEMENT
We know that variables in Python are dynamically typed. Sometimes,
however, it is nice to indicate what type of data is expected for a variable. In
Python, this is done by annotating the variable using a colon followed by
the name of the data type, as shown in the following example:
marks: float = 86.5 # variable marks will hold a float number
However, Python will not complain if other types of data are assigned, as
shown below:
>>> marks: float = "Python"
>>> marks
'Python'
>>>
To annotate the type of value returned from a function, you need to use -
> followed by the data type, right before the colon, as shown in the
following example:
print(literal_grade(88))
Out [ ]: pass
The print statement can evaluate multiple arguments and print out the
values. If the arguments are all constant strings, there will be no need to
separate them into multiple arguments. Separate arguments are needed only
when some arguments are expressions, like the round(300/110) in the above
example. If you do not like separations, introduced in release 3.0, Python
provides a neat way to include expressions all in a single pair of quotation
marks, as shown in the following example:
Edmonton to Calgary")
Edmonton to Calgary")
flag
backslash
Edmonton to Calgary")
Formally, a print statement may take the following form when used:
print(value0, value1, value2,…, sep=' ', end = '\n', file =
sys.stdout, flush = False)
Keyword Default
argument Values that can be taken value
Please note that a program may need to output different types of data not
only correctly but also nicely. In 5.1, we will learn how to construct well-
formulated strings from various types of data.
INPUT STATEMENT
The input statement is another important one you must learn and use
correctly and effectively. Contrary to the print statement, the input
statement is used to get information from users through the keyboard, as
shown in the following example in Jupyter Notebook:
In [ ]: your_age = input("Please tell me your age:")
Please note that everything taken from users through the input statement
is treated as a string. If you are expecting a number, such as an integer, you
must convert the string into its respective data type, as shown in the
following example:
your_age = int(your_age)
As you may have guessed already, the input statement takes one
argument as a prompt to tell users what to do and what the program is
expecting from the user.
If you want to provide more detailed instructions in the prompt to the
user, you may use the triple quotation marks to include multiple lines of
instruction as prompt:
In [ ]: sl = input("""Your choices
Please select___""")
As you can see, this can be a good way to make a menu for some
terminal-based applications.
ASSERT STATEMENT
The assert statement is used to test if a condition is true in a program. It
may take one of two forms, as shown in Table 2-17.
Syntax Meaning
In [ ]: def average_incomes(incomes):
incomes = []
PASS STATEMENT
As the name implies, this statement does nothing. It is used as a placeholder
in places where you don’t have the actual code yet. As an example, assume
you have the class Student in your design for a project, but the
implementation details of the class, except the name, are yet to be worked
out. You can use the pass statement to hold the place of the details, as
shown below:
In [ ]: class Student():
pass
s1 = Student()
s2 = Student()
With the pass statement in place, this piece of code can run as part of a
big program without raising an exception.
Note that a pass statement won’t let you get out of a loop. You will need
to use the break statement to get out of a loop.
DEL STATEMENT
This statement is used to delete an object. Because Python treats everything
as an object, you can use this statement to delete everything you’ve defined.
In [ ]: grade = 99
print(f"grade = {grade}")
del grade
print(f"grade = {grade}")
Out [ ]: grade = 99
----------------------------------
NameError Traceback (most recent call last)
<ipython-input-9-2b1bea6f987e> in <module>
3
4 del grade
-- 5 print(f"grade = {grade}")
NameError: name 'grade' is not defined
In [ ]: def cube(n):
return n ** 3
return a // b, a % b
print(modular(13, 6))
Out [ ]: (2, 1)
OPEN STATEMENT
The open statement is used to open a file for writing, reading, appending, or
updating (reading and writing). The following is an example:
f = open("c:\\workbench\\myprimes.txt", 'r')
When a file is opened for writing, the old data will be overwritten if there is
already data in the file. To keep the old data and append new data to the file,
use a for the second argument instead:
f = open("c:\\workbench\\myprimes.txt", 'a')
If you want to create a file only if the file doesn’t exist, use x for the second
argument, to mean exclusive creation of the file:
f = open("c:\\workbench\\myprimes.txt", 'x')
YIELD STATEMENT
The yield statement is used in place of the return statement in some special
circumstances when defining a function. When the yield statement is used
in defining a function, the function becomes a generator in Python terms, as
shown in the following example:
In [ ]: def odds(n):
for i in range(n):
r
yield 2 * i + 1 # yield makes the function a generato
odd_numbers = odds(12)
for i in odd_numbers:
If we run
for i in Object_generator:
print(i)
However, if we try to get the length of the generator object with the
following statement:
print(f"{len(object_generator)}")
RAISE STATEMENT
When some errors occur in a Python program, exceptions will be
automatically raised and the program will stop running, unless the
exception is handled with the try-except statement. Such errors include
operations deemed illegal by Python. In some cases, an exception needs to
be explicitly applied when a certain condition is met. In the previous
section, we saw how an exception can be raised with the assert statement.
In the following example, we show how to raise an exception with the raise
statement.
In [ ]: total = 0
for i in range(39):
if mark < 0:
total += mark
BREAK STATEMENT
The break statement is used to get out of a loop and continue to the next
statement. Here is an example:
In [ ]: for i in range(10):
if i == 8:
break
Out [ ]: 012345678
get out of the loop when i = 8
CONTINUE STATEMENT
The continue statement is used within a loop code block to continue to the
next iteration of the loop and ignore the rest of the code block. This
statement can be very useful if you don’t want to run some statements when
some condition is met.
IMPORT STATEMENT
The import statement is used to import modules into a program file or a
specific class within the module. The following is an example of how to
import the standard math module into the program:
In [ ]: import math
Out [ ]: 98 ** 3 = 941192.0
GLOBAL STATEMENT
A global statement simply declares, within a code block such as function or
class, that some identifiers/names such as variables should be treated as
globally writable. Without a global statement, a variable defined outside of
a function or class may be read, but writing to the variable will raise an
exception, as shown in the following examples:
variable
gravity by 2
return gravity
Out [ ]: ----------------------------------
UnboundLocalError Traceback (most recent call last)
<ipython-input-36-7f10379e5fb0> in <module>
6 return gravity
7
-- 8 print(g_force(99999))
<ipython-input-36-7f10379e5fb0> in g_force(m)
3
4 def changed_gravity(m):
-- 5 gravity = gravity * (r_earth/(r_earth+m))**2
6 return gravity
7 UnboundLocalError: local variable 'gravity' referenced
before assignment
In the code above, gravity is first introduced outside the function definition.
It became a global variable by the rule of naming scopes. Inside the
definition of function changed_gravity, the name was defined again by
putting it on the left side of the assignment, but only locally by default,
according to the rules. However, this local variable is used on the right side
of the same assignment statement. That is how the exception has occurred.
Since what we actually want is to use the globally defined variable
gravity on both sides of the assignment statement within the function
definition, we need to explicitly declare that, as shown in the following
example revised from above:
In [ ]: gravity = 9.807 # gravity on the earth's surface, global
variable
global gravity
return gravity
As you can see, the value of global variable gravity has now been
changed within the function.
NONLOCAL STATEMENT
We have seen global variables and local variables, and how global variables
are accessible globally, whereas local variables are only accessible within a
local scope such as a function. There is something between global and local
called nonlocal. The nonlocal statement can be used to declare a list of
variables that are not local but refer to variables defined in the nearest
enclosing scope but excluding global variables. This may happen when
defining a function within another function, as shown in the following
example:
In [ ]: def outer_logger():
nonlocal event
inner_logger()
outer_logger()
HELP STATEMENT
The help statement is used to invoke a helping system and is often used in
Python interactive mode to get help on modules, statements, functions, or
methods.
1 >>> help(str)
4 class str(object)
Code sample in Python interactive mode
7 |
8 | Create a new string object from the given object. If the encoding or
9 | any errors are specified, then the object must expose a data buffer
10 | that will be decoded using the given encoding and error handler.
12 | or repr(object).
15 |
17 |
Code sample in Python interactive mode
18 | __add__(self, value, /)
19 | Return self+value.
20 |
21 | __contains__(self, key, /)
23 |
24 | __eq__(self, value, /)
25 | Return self==value.
26 |
27 | __format__(self, format_spec, /)
29 |
30 |
Code sample in Python interactive mode
31 | __ge__(self, value, /)
32 -- More --
Compound Statements
In the previous section, we studied individual statements that can be used in
programming with Python. In this section, we study compound statements
and ways to make various compound statements in Python.
In Python, a compound statement consists of at least one clause, and each
clause is made of a header and a suite, or code block. A header starts with a
keyword such as if, for, while, class, def, try, else, except, finally, and so on
and ends with a colon :, as described below:
<header>:
<code block>
What can be on the header line depends on the keyword leading the
header. You will learn more about this in the following chapters.
CODE BLOCKS
In programs, some statements are grouped and run in sequence as a unit or a
suite. We call such a group of statements a code block.
Unlike C, C++, Java, and some other languages that use curly brackets to
make code blocks, Python uses indentation to form code blocks. In Python,
a program can have multiple code blocks, and code blocks can be nested
with proper indentation. Statements intended to be in the same code block
must use the same indentation. The following is an example:
Code sample
Code sample
3 while I <= 100: # this compound statement is in the same code block
The sample program above has two simple statements on lines 1 and 7, and
one compound statement on lines 3 to 5. The header of the compound
statement begins with the keyword while, and its suite is a code block that
consists of two simple statements. Because statements on lines 1, 3, and 7
are in the same code block, they must be indented the same, whereas
statements on lines 4 and 5 must be further indented to form a code block as
a suite for the while compound statement.
RULES OF INDENTATION
To ensure that your programs are properly indented, follow the following
rules:
1. The first line of code of a program must start at the very first
column of line, though there can be some blank lines before the
first line of code, for better readability, if you like.
2. All lines of code in the same code block must be indented the
same.
3. The suite of a compound statement must be indented further than
the header of the compound statement.
4. All code blocks that are at the same level must use the same
indentation.
5. All lines of code in the same suite must use the same indentation.
RULES OF SPACING
The rules of spacing are about how to space out words within a line of
script or code and how to space lines of scripts. Some of the rules must be
followed, while other rules are for readability or are merely convention
among Python programmers:
Code sample
3 while I <= 100: # this compound statement is in the same code block
Please note the blank line between line 1 and line 3, as well as between
lines 5 and 7.
IF STATEMENT
An if statement is used to run a block of statements under a condition. The
header of an if statement begins with the keyword if, followed by a logical
expression of a condition, and then a colon, as shown below:
if <condition>:
<suite or code block>
Figure 2-6: Flowchart of an if statement
Here is an example:
Code sample
3 if mark >= 0:
Note that although Python allows the suite to be on the same line as the
header, as shown in the following sample, for readability, that is not
preferable.
if mark >= 0: print(f"The mark is {mark}.") # allowed but not
preferred
IF-ELSE STATEMENT
In the example above, the if statement can only make one selection. To do
something in particular if the condition is not met, the else clause can be
added. The syntax of if-else statement is shown below, and the
corresponding flowchart is shown in Figure 2-7.
if <condition>:
<code block 1>
else:
<code block 2>
Code sample
5 else:
IF-ELIF STATEMENT
The if-else statement can only handle double selections. How can we
handle multiple selections in Python? For example, in addition to telling
whether a mark is legitimate or not, we may also want to convert the
percentage mark to a letter grade. In Python, that can be done with an if-elif
or if-elif-else statement. The syntax of the if-elif statement is shown below:
if <condition 1>:
< suite 1 >
elif <condition 2>:
< suite 2 >
elif <condition 3>:
< suite 3 >
…
Code sample
and 100:")))
26 else:
IF-ELIF-ELSE STATEMENT
An else clause can be added to the end of an if-elif statement in case
something special needs to be done if all the conditions are not met.
WHILE STATEMENT
The while statement is used to run a block of code repeatedly as long as a
given condition is met. The syntax of the statement is as follows:
while <condition>:
< a suite >
Figure 2-9: Flowchart of an if-elif-…elif-else statement
Code sample
1 i = 1
Code sample
5 i += 1
The loop is ended when not (I <= 10). The while statement is more
advantageous when used to form a loop if we only know when the loop
should end, as shown in the following word-guessing program:
Code sample
6 cnt += 1
Code sample
FOR STATEMENT
A for statement provides another way to form a loop and is best for when
the loop runs through an iterable, such as a list, a tuple, a string, a generator,
a set, or even a dictionary. The syntax of the for statement is as follows:
for <iteration variable(s)> in <iterable>:
< a suite >
Note that there can be more than one iteration variable if needed, but it is
more common to have only one iteration variable.
The following is an example:
1 cnt = 0
3 for c in my_string:
4 print(c)
5 cnt += 1
6
Code sample: for statement with a string
2 for w in week_set:
3 print(w)
'Sun'}
2 for w in week.keys():
DEF STATEMENT
The def statement is used to define new functions or methods if defined
within a class definition. The syntax of def statement is as follows:
def <function_name>(<list of arguments>):
< code block >
In [ ]: def power10(x):
s = x
for i in range(9):
s *= x
return s
print(f'power10({2}) = {power10(2)}')
CLASS STATEMENT
The class statement is used to define new classes. The syntax of defining a
new class that only inherits from the base class (object) is as follows:
Class class_name:
< suite >
or
Class class_name(object):
< suite >
To define a new class that inherits from classes other than object, the
syntax is as follows:
Class Class_name(<list of base classes>):
< suite >
TRY-EXCEPT STATEMENT
The try-except statement is used to handle errors and exceptions, especially
when certain errors are expected. The following are some common types of
errors that you may encounter in your programs:
1 try:
2 a = int(input("give me a number:"))
5 except ZeroDivisionError:
7
The details of error and exception handling in programs will be discussed
in Chapter 4.
WITH STATEMENT
The with statement is used to provide a context for the execution of a code
block. The mechanism is a bit complex, but the following may provide
some help. Remember that the with statement works only on objects that
have special methods __enter__() and __exit__() implemented in
accordance with Python context management protocol (PEP 343). For the
mechanisms behind the with statement, read https://effbot.org/zone/python-
with-statement.htm or search the internet for more details.
The general syntax of the with statement is as follows:
1 """
2 This program will get an input of a big integer from user, and
3 find all the prime numbers not greater than the integer input from the
user, and
Code sample: with statement
5 """
6 m = int(input("""
10 import math as mt
12 i = 2
13 while i <= m:
14 flag = True
15 j = 2
17 if i % j == 0:
18 flag = False
19 j += 1
20 if flag:
21 p.write(str(i)+ "\n")
22 i += 1
Chapter Summary
• Vocabulary is important for any language, and even more
important for computer languages, because computers will not
understand your programs at all if you have used the wrong
vocabulary.
• For programming languages, including Python, vocabulary
includes various types of data, operators, built-in functions,
reserved words (including keywords), and variables identified by
user-defined names (also called identifiers).
• Identifiers must begin with a letter or underscore in the ASCII
table, then be followed by letters, digits, and/or an underscore.
• Identifiers in Python are case-sensitive, which means that A1 and
a1 are two different identifiers.
• Within the Python community, there are conventions for how
identifiers should be made and used for identifying different
things in Python programs.
• Simple data types include integer numbers, float numbers, Boolean
numbers, and complex numbers.
• Complex numbers are represented as a + bj or a − bj, where a and
b are integers or float numbers.
• Compound data are made of other data that can be of two types:
simple or compound.
• A string is a sequence of characters within a pair of single or
double quotation marks.
• Some special characters in a string must be represented using an
escape sequence, such as \n for newline, \t for tab, and \\ for a
backslash, and so on.
• In a string, all characters are indexed starting from 0, so that each
individual character can be accessed using its index.
• There are many functions available to manipulate strings.
• There are three ways of formatting strings: using placeholders,
using the format method, and using the f prefix before a string.
The last one is preferred.
• A list is a sequence of data within a pair of square brackets.
• Members of a list are also indexed, and each individual member
can be accessed through its index.
• A tuple is a sequence of data within a pair of parentheses.
• Members of a tuple are also indexed, and each individual member
can also be accessed through its index.
• While individual members of a list can be deleted or changed,
individual members in a tuple cannot be deleted or changed.
• A set is a collection of data within a pair of curly braces.
• Members in a set are not indexed, so individual members in a set
cannot be accessed through the index.
• A dictionary is a collection of key-value pairs within a pair of
curly braces.
• Keys are used to access the values of a dictionary.
• In Python, everything can be treated as an object.
Exercises
Projects
1. Write a program to read a float number from the user into variable
s, then calculate and print the area of a square with s as the length
of its side.
2. Write a program to read two numbers and calculate the product of
the two numbers.
3. A parking lot charges $2.50 per hour. Write a program to read the
number of hours a vehicle has parked, then calculate and print the
total to be paid for parking.
4. The arithmetic mean of several numbers is the sum of all these
numbers divided by the number of these numbers. For this
project, write a program that will generate three numbers from
users and calculate and display the arithmetic mean of these three
numbers.
5. A cube has 6 faces and 12 edges, all of the same length. Write a
program that takes a number from the user as the length of an
edge and calculate and display the total surface area of the cube.
OceanofPDF.com
Chapter 3
Flow Control of Statements
If you praise computers for their diligence when they iterate operations tirelessly
trillions of trillions of times, you must also appreciate their intelligence when they
do certain things only if certain conditions are met, because decision making is
important for all intelligent beings, including modern computers. All computer
programming languages provide constructs for decision making—to run a
statement or a block of statements only under certain conditions. Python does the
same.
In Chapter 3, you will learn how to use the if, if-else, if-elif, and if-elif-else
statements to instruct computers to do certain things only under certain conditions.
Learning Objectives
After completing this chapter, you should be able to
1 """
2 Code sample showing how to use an if statement to have a code block run under a
certain condition
3 this piece of code is used to calculate the square root of number n only if it is a
positive number.
4 """
7 if n >= 0:
10
11
Note that a code block for if statements must begin on the next line after a colon :
and be properly indented, as shown below:
n = int(input("n = ?"))
if n >= 0:
Code block
Note: Each code block must be properly indented to indicate what the code
block belongs to.
The conditions for an if statement can be any Boolean expression, as discussed
in 2.1.
1 """
2 Code sample showing how to use an if statement have a code block run under a certain
condition
3 this piece of code is used to calculate the square root of number n only if it is a
positive number
4 """
6 n = float(input('Tell me a number and I will calculate the square root for you:'))
7 if n >= 0:
9 else:
Note that no condition needs to be specified for an else clause because it implies
that the condition is the negation of the condition for that if clause—that is, not n
>= 0.
With the if and if-elif statements studied above, you can make single- or two-
branch selections, which are depicted in Figures 3-1 and 3-2.
Now, you are ready to tackle a real problem: to decide what letter grade should
be assigned for a given numeric mark of a student in a course, according to Table
3-1.
1 90–100 A+
2 85–89 A
3 80–84 A−
4 76–79 B+
5 73–75 B
6 70–72 B−
Number of selections needed Numeric grade (%) Alpha/letter grade
7 67–69 C+
8 64–66 C
9 60–63 C−
10 55–59 D+
11 50–54 D
12 0–49 F
The table shows only integer numeric grades, but decimal inputs, automatically
rounded to the nearest integer, are also allowed. The case study is shown in Table
3-2.
The """
"""
number_grade = round(float(input("Please tell me a numeric grade between 0
and 100:")))
else:
print("Numeric grade must be a positive integer!")
The code above didn’t explicitly specify the upper bounds of the intervals
shown in the grade conversion table because it takes advantage of the if-elif-elif
statement—that is, the upper bound of the current if condition has been implicitly
satisfied when the previous if condition is not satisfied, and the program flow gets
into the current elif selection. Taking the first elif statement as an example, since
the previous if condition is number_grade >= 90, when the condition is not
satisfied and the program flow goes to the elif, the number_grade must be less
than 90, which is equal to number_grade <= 89, the upper bound of the first elif
condition.
After you run the code on your computer, you may notice that for each
conversion, you have to rerun the program to get another chance to input a
numeric grade. How can you do as many conversions as you want until you tell
the program to stop? You’ll be able to do that after learning how to put a code
block in a loop in the next chapter.
Coding Trick
How would you specify the conditions for the elif if you began from the
lowest numeric grade to make number_grade <= 49 for the if?
in which for and in are keywords, and the iteration variable is used to take items
one by one from the sequence, which can be a list, a tuple, a string, or an iterable
object or generator, as you will see. The code block is a block of Python code to
be executed in each iteration of the loop. The following example loops through a
list of integers and calculates the cube of each.
The task Print a multiplication table from 1 * 1 to 9 * 9, and the result table
should be a right triangle.
Analysis The resulting multiplication table should be a right triangle like this:
and 1x1=1
design 1x2=2 2x2=4
1x4=3 2x3=6 3x3=9
…
so we will need two loops: the outer one is used to loop through the
row, whereas the inner one loops through the column of each row.
The algorithm is as follows:
Step 1: Start a row I, I = 1, 2,…, 9
Step 2: Start a column j of row I, j = 1,…i
Step 3: Print j × I = j * i on the same line until I * i
Step 4: Go back to step 1 and finish all rows
1 """
3 The table will be displayed nicely as a right triangle. It uses two loops,
4 an outer loop for the rows and an inner loop for the columns.
5 """
10 if j == i:
11 print("\n")
12
Output 1x1=1
in 1x2=22x2=4
terminal 1x3=32x3=63x3=9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6 = 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7
= 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8 = 48 7 x 8
= 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9 = 54 7 x 9
= 63 8 x 9 = 72 9 x 9 = 81
Our next problem, in Table 3-4, is to find all the Pythagorean triples of integers
less than an integer given by the user.
1 """
= A * A + B * B.
3 This program will take an integer input by the user and find all the
4 """
11 if k * k == j * j + i * i:
12 plist.append((i, j, k))
13 for i in plist:
14 print(i)
15
16
17
A for statement can have multiple iteration variables if needed. In order to make
it work, however, each item of the iteration sequence needs to have multiple
values for the multiple iteration variables, as shown in the following example:
for i, j in [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]:
print(f"{i} * {j} = {i * j}")
or
for i, j in zip(range(5), range(5)): # zip is a special function
print(f"{i + 1} * {j + 1} = {(i + 1) * (j + 1)}")
In the above, zip is a built-in function that takes an element from each iterable
and forms a tuple, as shown below:
>>> list(zip(range(5), range(5), range(6)))
[(0, 0, 0), (1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)]
The function zip will stop making tuples when the shortest iterable has reached
the end.
Note that the following two statements are totally different:
for i in range(5):
for j in range(5):
print(f"{j + 1} * {i + 1} = {(i + 1)*(j + 1)}")z
versus
for i, j in zip(range(5), range(5)):
print(f"{i + 1} * {j + 1} = {(i + 1)*(j + 1)}")
The first statement is two loops nested, whereas the second is a single loop.
You may copy and paste the code into Jupyter Notebook to find out why and
how.
Using break and continue Statements and an else Clause Within Loops
Chapter 2 discussed what the break statement and continue statement do. Within a
for loop, if you want to get out of the iteration immediately when something has
occurred, you can use a break statement; if you want to go to the next item in the
iteration sequence right away, you can use a continue statement.
A for statement can also have an else clause whose code block will be executed
when the iteration sequence is used up. The following code example taken from
the Python documentation explains how the break statement and else clause can
be used on a for loop.
if n % x == 0:
never be reached
In the example above, pay particular attention to the indentation of else. The
else block is treated as a clause of the inner for statement because it has the same
indentation as the inner for. If it were indented the same as the if statement, the
else block would become part of the if statement.
The code
1 """
3 The table will be displayed nicely as a right triangle. The two loops are coded with
5 """
The code
7 i = 1
9 j = 1
10 while j <= i:
13 print("\n")
14 j += 1
15 i += 1
16
17
Figure 3-6: Flowchart illustrating the while loop
While a for loop can always be replaced with a while loop, a while loop cannot be
replaced with a for loop in cases where the number of iterations is unknown.
Consider the problem of calculating the average of the student marks taken
from user input. Either the total number of marks is unknown or you do not expect
the user to count how many marks they input, so it is not possible to use a for loop
to solve the problem. However, you do know there will be no negative marks,
which can then be used to indicate the end of the input. Hence, you can use a
while loop to take input from the user until you get a negative number from the
user. The program is shown in Table 3-5.
The task Get student marks from user input and calculate the average mark,
using a negative number input by the user to indicate the end of
marks.
Code sample in VS Code IDE
Analysis You don’t know how many marks will be input from the user, but
and you do know there will be no negative marks. You can then use a
design negative number, input by the user, to end the application and use
the while loop to iterate.
To calculate the average, you need to know the sum of all the marks
as well as the total number of marks. For the former, you need to
add each mark to the total, whereas for the latter, you need to use a
counter to count every mark. Use the variable total to keep the sum
and use the variable count to keep the number of marks. Both need
to be initialized to 0. The algorithm is below:
Step 1: Initialize both count and total to 0
Step 2: Take an input from user and convert it to a float number
Step 3: If the number is a mark (>= 0), then do the following:
Step 3.1: Increase count by 1
Step 3.2: Add mark to total
Step 3.3: Get another input from user and convert to float
Step 3.4: Go back to Step 3
Step 4: Calculate the average using total/count and print out the
result.
Step 5: End the program
1 """
3 Application: this application takes marks from user input and calculates the
average mark.
4 A negative number from user input is used to indicate the end of the
program.
Code sample in VS Code IDE
"""
statement
10 total += mark
11 count += 1
14
Code sample in VS Code IDE
Similarly, we can also write a program that takes a list of student marks and
identify the lowest marks, the highest marks, and the mean, as shown in Table 3-6.
The problem In this problem, you will get a list of student marks and find
out the lowest, the highest, and the mean.
"""
marks = []
while mark >= 0:
marks.append(mark)
marks = sorted(marks)
ln = len(marks)
{marks[ln - 1]}")
print(marks)
The next programming task for using a while loop is to write a program that can
take an integer from a user and decide whether the integer is a prime number or
not (see Table 3-7).
The task Take an integer from a user and decide whether the integer is a
prime number or not.
Code sample in VS Code IDE
1 """
3 Application: this program takes an integer from user input and determines
5 """
Code sample in VS Code IDE
8 flag = True
9 if m < 2:
11 flag = False
12 else:
13 i = 2
15 if m % i == 0:
17 flag = False
18 break
Code sample in VS Code IDE
19 else:
20 i += 1
21 if flag:
22 print(f"{m} is a prime")
23 else:
25
26
27
Output Give me an integer that is greater than 1, and I will tell you if it is a
in prime: 911
terminal 911 is a prime
Please note the break statement in the example above. It is used to get out of the
loop immediately by ignoring all the code before it without going back to test the
looping condition. This is a way to get out of a loop in the middle of an iteration
and is applicable to both the while loop and for loop.
Somewhat related to the break statement, the continue statement is used within
a loop to go back directly to the beginning of the iteration—testing the looping
condition in a while loop or taking the next item of the sequence in a for loop.
Common Coding Mistakes with a while Loop
As mentioned, the while loop is good for iterations in which the number of
iterations is unknown but the condition of looping is known. To ensure that the
loop will end as expected, the looping condition must be changed within the code
block of the while statement. Otherwise, the loop will go on forever. To ensure
that, there must be at least one variable within the code block of the loop whose
value needs to be changed during iterations. Such a variable is called an iteration
variable.
There are two common mistakes when using the while statement. The first one
is not correctly writing the looping condition, which could be coded so that it is
always true (hence, the iteration will keep going forever) or incorrectly coded to
become false at the wrong time. For example, if x < 0 is written in place of x > 0
as the looping condition, the iteration would not finish as desired or wouldn’t run
at all.
The other common mistake people often make when using the while statement
is not coding the code block correctly to ensure that the following conditions hold:
1. There will be at least one iteration variable within the code block of the
while loop.
2. The value(s) of iteration variable(s) must change within the code block.
3. The logical expression of the looping condition is not correctly written.
This mistake may occur when inequal operators are involved in the
logical expression of the looping condition. For example, using > in
place of >=, or using < in place <=, will cause the program to miss one
iteration of the loop.
In the example we just mentioned above, if x is never changed within the code
block of the while loop, the value of the looping condition will remain the same,
and the iteration will keep going forever as well.
In [ ]: total = 0
for i in range(30):
total += mark
When the number of iterations is unknown, the while loop must be used, in
which case the condition for exiting from the loop must be known. In this
particular application, because no mark will be a negative number, we can use
negative numbers to signify the end of input, to end the iteration, as shown in the
following example:
total += mark
count += 1
In the example above, we use mark as an iteration variable to control the loop.
Initializing it with 0 = ensures that the looping condition (logical expression mark
>= 0) is satisfied to start the iteration.
Since we know the logical expression (mark >= 0) is true when 0 is assigned to
mark, we can also simply use constant True in place of mark >= 0 and then use an
if statement with the break statement to get out of the loop when a certain
condition (condition to exit the loop) is met. The revised version of the program is
shown below:
while True:
total += mark
count += 1
else:
break
Since we know how to put a code block in a while loop, we can improve the
grade conversion program written in the previous chapter so that we do not have
to rerun the program for each conversion (see Tables 3-8 and 3-9).
Table 3-8: Conversion between numeric grade and letter grade in Alberta
A+ 90–100%
Letter grade Percentage
A 95–89%
A− 80–84%
B+ 77–79%
B 73–76%
B− 70–72%
C+ 67–69%
C 63–66%
C− 60–62%
D 55–59%
D 50–54%
F 0–49%
The In this case study, you are required to design a program using an if-
problem elif-else statement to convert as many numeric grades to alpha/letter
grades as needed until the user inputs -1 to stop.
The """
"""
number_grade = 0
number_grade = round(float(number_grade))
else:
The Please input a numeric grade between 0 and 100 to convert; input -1
result to exit:96
alpha/letter grade for 96% is A+
Please input a numeric grade between 0 and 100 to convert; input -1
to exit:79
alpha/letter grade for 79% is B+
Please input a numeric grade between 0 and 100 to convert; input -1
to exit:67
alpha/letter grade for 67% is C+
Please input a numeric grade between 0 and 100 to convert; input -1
to exit:-1
Thank you for using this grade converter!
Chapter Summary
• Knowing what to do at a given time and under certain conditions is
important for any intelligent being.
• Conditional statements are necessary and important constructs in all
programming languages.
• if, if-else, if-elif, if-elif-else are the constructs for conditional statements.
• Each if, if-else, if-elif, if-elif-else statement represents a flow of program
execution.
• The if statement is for one selection. It will execute a code block if the
condition is met.
• The if-else statement is good for two selections.
• The if-elif and if-elif-else statements are good for multiple selections.
• The conditions behind if and elif are logical or Boolean expressions.
• Python has two constructs for iteration, the for statement and the while
statement.
• The for statement can be used to repeat a code block through each
member of an iterable, such as a list, tuple, or string, or an iterable
object such as range(…).
• When the iteration includes a for statement, the number of iterations can
be determined most of the time, unless the break statement is used
within the code block to break out from the loop.
• The while statement is used to iterate under certain conditions.
• The number of repetitions needed when using a while statement is often
unknown. One can be used with or without a break statement within the
code block.
• The continue statement can be used within the code block of a for or
while statement to directly go to the next iteration.
• Any for statement can be rewritten as a while statement.
Exercises
1. Mentally run the following code blocks and write down the
output of each code block.
a. m, n = 10, 20
if m * n < 1000:
b. m, n = 10, 3
if m // n == m / n:
else:
c. m, n = 13, 5
if m * 2 > n**2:
else:
2. Mentally run each of the code blocks below and write down
the output of each code block:
b. i, s = 1, 1
while i<=10:
s *= i
i += 1
for i in range(10):
total += i*2 +1
d. number = 32
factors = []
if number % d == 0:
factors += [d]
Projects
1. Write a program that gets three numbers from the user and displays the
biggest number among the three.
2. Write a program that gets a number from the user then says whether the
number is an even number or odd number.
3. Write a program that takes three numbers from the user as the lengths of
three lines, then determines if the three lines can make a triangle.
4. Write a program that takes three numbers from the user as the lengths of
three lines, then determines if the three lines can make a triangle. If the
three lines can make a triangle, the program should further determine if
the triangle is an equilateral triangle or an isosceles triangle.
5. Write a program that takes three numbers from the user as the lengths of
three lines, then determines if the three lines can make a triangle. If the
three lines can make a triangle, the program should further determine if
the triangle will be a right triangle.
6. Compound interest is a common practice in finance and banking,
allowing you to earn interest on interest as well as on the principal.
Assume that your bank offers a savings account with which you can
earn compound interest. The amount you deposit into the account is p,
and annual compound interest is r. By the end of n years after your
initial deposit, the account balance will be a = p(1 + r)n. For this project,
write a program that takes three numbers from the user as the initial
deposit, the annual interest, and the number of years that the user wants
the money to stay in the account. Calculate and display how much
money the user will have by the end of the nth year.
7. In some countries like Canada, tax on taxable personal income for a year
is calculated progressively according to a calculation table set for the
year, such as the one shown below:
Write a program that takes taxable income from a user and calculates the
total income tax payable according to the table above.
8. A mortgage is the money borrowed from a lender for the purchase of a
property. Mortgages and mortgage payments are a big thing for almost
everyone. For a mortgage with principal of P at a fixed monthly interest
rate of r that needs to be paid off in Y years or 12 * Y = N months, the
monthly payment would be:
Write a program that takes the principal, fixed annual interest rate, and
years of amortization then calculates and displays the monthly payment
amount. Hint: You will need to work out the number of months from
number of years, and the monthly interest rate from the annual interest
rate.
9. In the world of science and mathematics, the existence of some
constants has attracted the attention of many scientists and
mathematicians. Among those constants, pi π is the most well-known.
Many great efforts have been made to get a more precise value for π.
The following is a formula developed by Gottfried Leibniz for the
calculation of π.
Write a program that takes an integer from the user to specify the
number of terms used to calculate π. Calculate and display the
approximate value.
10. Three integers—A, B and C—are called a Pythagorean when C * C =
A * A + B * B. Write a program to take an input of integer from the user
and find all the Pythagorean triples of integers, none of which are bigger
than the integer taken from the user. For example, if the number from
the user is 6, then 5, 4, and 3 are a Pythagorean triple because 52 = 42 +
32 = 25.
11. Compound interest is a common practice in finance and banking to
earn interest on interest as well as on the principal. Assume that your
bank offers you a deposit account through which you can earn
compound interest, the amount you deposit into the account is p, and
annual compound interest is r. By the end of n years after your initial
deposit, the account balance will be a = p(1 + r)n. For this project, get p,
r, and n from the user, then calculate and display a table showing the
balance, the interest earned each year, and the total interest earned so far.
12. An integer is called a perfect number* if the sum of its factors,
excluding itself, is equal to the integer itself. For example, 6 is a perfect
number because 6 = 1 + 2 + 3, and 1, 2, and 3 are all its factors. Write a
program to get a number from a user, then determine if the number is a
perfect number. If yes, display all its factors.
13. For a given integer n, if another integer m can divide n, then m is called
a factor of n. In mathematics, finding all factors of a given integer is an
important operation, especially for cryptography. Write a program that
takes an integer from the user and determine and display all the factors
of the number given by the user.
14. Read a series of float numbers from the user and calculate and display
the average of all the numbers given by the user. Assume that the
number of float numbers is unknown but that a negative number is used
to indicate the end of the input.
15. For a mortgage with a principal of P at a fixed monthly interest rate of
r that needs to be paid off in Y years or 12 * Y = N months, the monthly
payment would be:
Continuing the project you did above for project 8, calculate a table
showing the interest and principal paid each month and the principal
balance at each month’s end.
* By definition, a perfect number is a positive integer that is equal to the sum of all its divisors, excluding
itself but including 1. The smallest perfect number is 6, which is equal to the sum of 1, 2, and 3.
OceanofPDF.com
Chapter 4
Handle Errors and Exceptions in Programs
Errors in programs are inevitable but must be handled elegantly when they
occur. In this chapter, you will learn how to raise and handle exceptions
when errors occur in programs.
Learning Objectives
After completing this chapter, you should be able to
Exception
This is the superclass of all exception classes to be detailed below. In the
code sample below, any error will be caught and treated the same because it
has “Exception” in the list of exceptions behind the except clause.
In [ ]: try:
n = int(input('Give me an integer:'))
n /= m # divide n by m
except Exception:
In [ ]: n = int(input('Give me an integer:'))
n /= m # divide n by m
The use of the try-except statement will be explained in the next section.
For now, just remember the code lines between try and except are part of
the program to be executed for the application, while the code under the
except header tells what to do when a given exception has occurred.
ArithmeticError
The base class of all arithmetic errors, including OverflowError,
ZeroDivisionError, and FloatingPointError, which means except
ArithmeticError would be the same as except (OverflowError,
ZeroDivisionError, FloatingPointError). Note that when there are multiple
error names behind the except keyword, a pair of parentheses is used to
enclose them.
OverflowError
This subclass of ArithmeticError is raised when the result of an arithmetic
operation is too large to be represented.
A coding example of catching arithmetic errors like this is shown below:
In [ ]: try:
x = pow(123567,999999)
except OverflowError:
The code in the try clause calculates the power of 123567 to 999999 or
123567**999999. The code is put in a try-except statement because the
result is expected to be very big and may overflow. Though the result has
over five million digits, no exception is raised because the design and
implementation of Python can handle very big numbers.
ZeroDivisionError
ZeroDivisionError is raised when the divisor of a division or module
operation is 0. With this very specific exception/error name, the earlier
example of this section can be rewritten as shown below:
In [ ]: try:
n = int(input('Give me an integer:'))
n /= m # divide n by m
except ZeroDivisionError:
FloatingPointError
FloatingPointError is raised when a floating-point operation fails. However,
Python does not raise such errors by default in its standard distribution. You
will need a Python built with the -- with-fpectl flag, and import a module
called fpectl when you want to turn the floating-point error control on or
off.
AssertionError
AssertionError is raised when the assert statement fails. The assert
statement is used to make an assertion on an assumed fact, such as whether
a variable is defined, whether a variable is holding a specific value, or
whether a value is a member of a sequence or set. If the assumed fact is not
True, an AssertionError will be raised so that we know the assumed fact is
untrue and we may need to deal with it, such as doing something else in the
absence of the assumed fact.
from 0 to 18
Out [ ]: ----------------------------------
AssertionError Traceback (most recent call last)
<ipython-input-14-5a912881af6c> in <module>
1 vs = list(range(19)) # create a list with 19 members
indexed from 0 to 18
----> 2 assert(20 in vs) # 19 is out of the range > 18
AssertionError:
AttributeError
AttributeError is raised when an attribute assignment or reference fails.
Such an error will occur if you use an attribute of an object but the attribute
itself does not exist.
In [ ]: class Student:
pass
s0 = Student()
s0.firstname = 'John'
s0.lastname = 'Doe'
print(s0.fullname)
Out [ ]: ----------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-15-5dc5b1212e9f> in <module>
6 s0.lastname = 'Doe'
7
----> 8 print(s0.fullname)
AttributeError: 'Student' object has no attribute 'fullname'
BufferError
BufferError is raised when a buffer-related operation cannot be performed.
This often happens when working directly with computer memory and
making restricted changes to a given memory area (buffer). The following
is an example:
In [ ]: import io
the bytearray
exported
is not changeable
Out [ ]: ----------------------------------
BufferError Traceback (most recent call last)
<ipython-input-23-dc2c4a5f6bbd> in <module>
3 darray = io.BytesIO(data) # this creates a read-write
copy of the bytearray.
4 dbuff = darray.getbuffer() # the memory of the
bytearray is exported
--> 5 darray.write(b'Hello World!') # raise error because
the buffer is not changeable
BufferError: Existing exports of data: object cannot be re-
sized
EOFError
EOFError is raised when the input() function hits the end-of-file condition.
GeneratorExit
GeneratorExit is raised when a generator’s close() method is called.
ImportError
ImportError is raised when the imported module is not found.
IndexError
IndexError is raised when the index of a sequence is out of range.
from 0 to 18
Out [ ]: ----------------------------------
IndexError Traceback (most recent call last)
<ipython-input-3-47e31ad8b75b> in <module>
1 vs = list(range(19))
----> 2 vs[19] *= 3
IndexError: list index out of range
KeyError
KeyError is raised when a key is not found in a dictionary.
Out [ ]: ----------------------------------
KeyError Traceback (most recent call last)
<ipython-input-4-3011ee6a346e> in <module>
1 vdict = {1:'One', 2:'Two', 3:'Three'}
----> 2 vdict[5]
KeyError: 5
KeyboardInterrupt
KeyboardInterrupt is raised when the user hits the interrupt key (Ctrl+C or
Delete).
MemoryError
MemoryError is raised when an operation runs out of memory.
ModuleNotFoundError
ModuleNotFoundError is raised by import when a module could not be
located, or None is found in sys.modules.
control
round(14.5/0, 3)
Out [ ]: -----------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-8-3808b892163e> in <module>
----> 1 import fpectl
2 round(14.5/0, 3)
ModuleNotFoundError: No module named 'fpectl'
NameError
NameError is raised when a variable is not found in the local or global
scope.
Out [ ]: ----------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-8b57ddde6300> in <module>
----> 1 print(what)
NameError: name 'what' is not defined
NotImplementedError
NotImplementedError is raised by abstract methods such as when an
abstract method is called.
OSError
OSError is raised when a system operation causes a system-related error.
BlockingIOError
BlockingIOError is a subclass of OSError, raised when an operation would
block on an object (e.g., a socket) set for a nonblocking operation.
ChildProcessError
ChildProcessError is a subclass of OSError, raised when an operation on a
child process fails.
ConnectionError
ConnectionError is a subclass of OSError and a base class for connection-
related issues.
BrokenPipeError
BrokenPipeError is a subclass of ConnectionError, raised when trying to
write on a pipe while the other end has been closed or when trying to write
on a socket that has been shut down for writing.
ConnectionAbortedError
ConnectionAbortedError is a subclass of ConnectionError, raised when a
connection attempt is aborted by the peer.
ConnectionRefusedError
ConnectionRefusedError is a subclass of ConnectionError, raised when a
connection attempt is refused by the peer.
ConnectionResetError
ConnectionResetError is a subclass of ConnectionError, raised when a
connection is reset by the peer.
FileExistsError
FileExistsError is a subclass of OSError, raised when trying to create a file
or directory that already exists.
FileNotFoundError
FileNotFoundError is a subclass of OSError, raised when a file or directory
is requested but does not exist.
IsADirectoryError
IsADirectoryError is a subclass of OSError, raised when a file operation is
requested on a directory.
NotADirectoryError
NotADirectoryError is a subclass of OSError, raised when a directory
operation is requested on something that is not a directory.
PermissionError
PermissionError is a subclass of OSError, raised when trying to run an
operation without adequate access rights such as filesystem permissions.
ProcessLookupError
ProcessLookupError is a subclass of OSError, raised when a given process
doesn’t exist.
TimeoutError
TimeoutError is a subclass of OSError, raised when a system function has
timed out at the system level.
RecursionError
RecursionError is a subclass of Exception, raised when the maximum
recursion depth set by the system is exceeded. The set recursion depth can
be found by calling sys.getrecursionlimit().
ReferenceError
ReferenceError is a subclass of Exception, raised when a weak reference
proxy is used to access a garbage collection referent.
RuntimeError
RuntimeError is raised when an error does not fall under any other category.
StopIteration
StopIteration is raised by the next() function to indicate that there is no
further item to be returned by the iterator.
StopAsyncIteration
StopAsyncIteration is raised by the __anext__() method of an asynchronous
iterator object to stop the iteration.
SyntaxError
SyntaxError is raised by the parser when a syntax error is encountered.
In [ ]: s = 0
syntax error
s += i
IndentationError
IndentationError is raised when there is an incorrect indentation. Such
errors may occur quite often at the beginning of your study of Python
programming. You must pay great attention to it because indentation
matters a lot in Python programs/scripts.
In [ ]: s = 0
s += i
SystemError
SystemError is raised when the interpreter detects an internal error.
SystemExit
SystemExit is raised by the sys.exit() function.
TypeError
TypeError is raised when a function or operation is applied to an object of
an incorrect type.
Out [ ]: ----------------------------------
TypeError Traceback (most recent call last)
<ipython-input-19-a90f29de94a2> in <module>
----> 1 sm = 10 + 'twenty'
TypeError: unsupported operand type(s) for +: 'int' and
'str'
UnboundLocalError
UnboundLocalError is 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
UnicodeError is raised when a Unicode-related encoding or decoding error
occurs.
UnicodeEncodeError
UnicodeEncodeError is raised when a Unicode-related error occurs during
encoding.
UnicodeDecodeError
UnicodeDecodeError is raised when a Unicode-related error occurs during
decoding.
UnicodeTranslateError
UnicodeTranslateError is raised when a Unicode-related error occurs during
translation.
ValueError
ValueError is raised when a function gets the correct type of argument but
an improper value.
Out [ ]: ----------------------------------
ValueError Traceback (most recent call last)
<ipython-input-20-6bbb9f319a0e> in <module>
----> 1 i = int('ten')
ValueError: invalid literal for int() with base-10: 'ten'
The following is a sample program to show how errors should be handled
in a Python program:
# a python program to show how errors and exceptions are handled
The following exception will be raised when you run the code but input a
literal instead of an integer:
Invalid input. Please enter numbers only.
If you type a 0 for the second input, the following exception will be
raised:
Cannot divide by zero. Please enter a nonzero number.
Note that in real applications, you may not want a user to restart the
program when an error has occurred. Instead, you may want to let the
program continue until the user has given a valid input.
# a python program to show how errors and exceptions are handled
# use a while loop to keep asking for inputs until success is True
while not success:
# ask the user to enter two numbers
num1 = input("Enter the first number: ")
num2 = input("Enter the second number: ")
This will ensure the program will continue until two integer numbers are
received and the division is successful.
Now let us solve a real problem: write a Python program to find all
perfect numbers in a given range set by a user. A perfect number is an
integer number that is equal to the sum of all factors, including 1 but
excluding itself. For example, 6 is a perfect number because 6 = 1 + 2 + 3,
and 1, 2, and 3 are all its factors.
So basically, the steps to take, or the algorithm, will be as follows:
1. Get two integers from user to set the range, assigned to a and b,
respectively. If a is greater than b, then we swap their values.
2. Loop through all the numbers between a and b, including a and b,
and test each number to see if it is a perfect number; if yes, we
add it to a list holding perfect numbers found so far. The list
should be set as empty at the beginning.
3. Print out all the perfect numbers in the list, and stop.
To test a number to see if it is perfect, according to the definition above,
we need to first find out its factors and check whether the sum of all the
factors is equal to the number itself. So there will be two additional steps:
2.1. Find out all the factors, and keep them all in a list.
2.2. Check whether the number is equal to the sum of all its factors
in the list built up in step 2.1.
# use a while loop to keep asking for inputs until success is True
while not success:
# ask the user to enter two numbers
num1 = input("Enter the first number: ")
num2 = input("Enter the second number: ")
a, b = int(num1), int(num2)
The output shows both the perfect numbers and a list of their factors.
In [ ]: try:
except ValueError as e:
Exercises
OceanofPDF.com
Chapter 5
Use Sequences, Sets, Dictionaries, and Text Files
Chapter 5 details how compound data types and files can be used in
programming to solve problems. Data need to be structured and organized
to represent certain kinds of information and to make problem solving,
information processing, and computing possible and more efficient. In
addition to integer, float, and complex numbers, Python provides compound
data types to represent more complicated information. These compound
data types include strings, lists, tuples, sets, and dictionaries, as well as files
that can be used to store a large volume of data in the long term (after the
computer is shut off).
Learning Objectives
After completing this chapter, you should be able to
• explain sequences.
• explain strings and the methods and functions that can be applied
to them.
• construct and format strings with the f prefix and the format
method.
• discuss lists and tuples and the differences between the two.
• properly use the methods and functions of lists and tuples.
• explain sets and dictionaries and discuss the methods and functions
that can be used on them.
• explain files and discuss the differences between text files and
binary files and the methods and functions available for
manipulating files.
• use strings, lists, tuples, sets, dictionaries, and files in problem
solving and system design and development with Python.
5.1 Strings
The string is one of the most important data types for information
representation and processing. Strings are the base of information and data,
and they were used to structure the sequences of characters for the ASCII
table in the early days of modern computers. They are still used the same
way now in UTF-8 (8-bit Unicode Transformation Format Unicode), which
includes characters for all human languages in the world.
Because strings are sequences of characters, the characters are ordered
and indexed. We can access and manipulate individual characters through
these indexes, starting from 0, as shown in the following example:
>>> name = "John Doe"
>>> name[0]
"J"
>>> name[3]
"n"
To construct a string from another data type, you use built-in function
str(), as shown in the following example:
>>> tax_rate = 0.16
>>> tax_string = str(tax_rate)
>>> tax_string
'0.16'
>>> type(tax_string)
<class 'str'>
S.CAPITALIZE()
This converts the first character of the first word of string s to upper case
and returns the converted string. Please note that characters in string s
remain unchanged. This is the same for all string methods: no string method
will alter the content of the original string variable. Rather, the method will
make a copy of the content, manipulate the copy, and return it.
>>> s = "intro to programming with python"
>>> s_capitalized = s.capitalize()
>>> s_capitalized
'Intro to programming with python'
>>> s
'intro to programming with python'
S.CASEFOLD()
Converts all characters of string s into lower case and returns the converted
characters.
>>> s_capitalized
'Intro to programming with python'
>>> s_capitalized.casefold()
'intro to programming with python'
S.CENTER(SPACE)
Returns a string centred within the given space. Note how the empty
whitespace is divided when the number is not even.
>>> s="hello"
>>> s.center(10)
' hello '
S.COUNT(SUB)
Returns the number of times a specified value occurs in a string.
>>> s = "intro to programming with python"
>>> s.count('i')
3
>>> s.count('in')
2
S.ENCODE()
Returns an encoded version of characters if they are not in the standard
ASCII table. In the example below, there are Chinese characters in the
string assigned to variable es.
>>> es = "Python is not a big snake (蟒蛇)"
>>> print(cs.encode())
b'Python is not a big snake \xe8\x9f\x92\xe8\x9b\x87'
S.ENDSWITH(SUB)
Returns true if the string ends with the specified value, such as a question
mark.
>>> cs = "Is Python an animal?"
>>> print(cs.endswith('?'))
True
S.EXPANDTABS(TS)
Sets the size of tabs in the string to ts, which is an integer.
>>> cs = "Is\t Python\t an\t animal?"
>>> cs
'Is\t Python\t an\t animal?'
>>> print(cs)
Is Python an animal?
>>> print(cs.expandtabs(10))
Is Python an animal?
S.FIND(SUB)
Searches the string for a substring and returns the position of where it was
found.
>>> s= 'intro to programming with python'
>>> s.find("ro")
3
S.FORMAT(*ARGS, **KWARGS)
Formats specified values given in the list of position arguments *args,
and/or the list of keyword arguments **kwargs into string s, according to
the formatting specs given in s.
This is very useful in constructing complex strings.
>>> "Hello {0}, you are {1:5.2f} years old.".format("Python", 23.5)
'Hello Python, you are 23.50 years old.'
Please note that ** has converted the dictionary point into a list of
keyword arguments. This formatting can also be done by directly using
keyword arguments:
>>> print('{x} {y}'.format(x=9,y=-10))
9 -10
S.FORMAT_MAP(MAPPING)
Similar to format(**mapping) above. The only difference is that this one
takes a dictionary without operator **.
>>> point = {'x':9,'y':-10}
>>> print('{x} {y}'.format_map(point))
9 -10
S.INDEX(SUB)
Searches the string for a substring and returns the position of the substring.
Generates a return error if there is no such substring.
Note that this may not be a good method to test if one string is a
substring of another.
>>> s= 'intro to programming with python'
'intro to programming with python'
>>> s.index("ing")
17
>>> s.index('w')
21
>>> s.index('z')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: substring not found
S.ISALNUM()
Returns True if all characters in the string are alphanumeric.
>>> "98765".isalnum()
True
>>> "98765abcde".isalnum()
True
>>> "98765<>abcde".isalnum()
False
S.ISALPHA()
Returns True if all characters in the string are in the alphabet, including
Unicode characters.
>>> "abcde".isalpha()
True
>>> "abcTde".isalpha()
True
>>> "abc35Tde".isalpha()
False
>>> "abc他Tde".isalpha()
True
S.ISDECIMAL()
Returns True if all characters in the string are decimals.
>>> "1235".isdecimal()
True
>>> "1235.65".isdecimal()
False
>>> "1235.65e".isdecimal()
False
S.ISDIGIT()
Returns True if all characters in the string are digits.
>>> "123565".isdigit()
True
>>> "1235.65".isdigit()
False
>>> "1235y65".isdigit()
False
S.ISIDENTIFIER()
Returns True if the string is an identifier by Python’s definition.
>>> "w1235y65".isidentifier()
True
>>> "9t1235y65".isidentifier()
False
>>> "w1235_y65".isidentifier()
True
S.ISLOWER()
Returns True if all characters in the string are lower case.
>>> "w1235y65".isidentifier()
True
>>> "9t1235y65".isidentifier()
False
>>> "w1235_y65".isidentifier()
True
S.ISNUMERIC()
Returns True if all characters in the string are numeric.
>>> "123565".isnumeric()
True
>>> "1235.65".isnumeric()
False
>>> "123565nine".isnumeric()
False
S.ISPRINTABLE()
Returns True if all characters in the string are printable.
>>> "123565nine".isprintable()
True
>>> "123565 all printable".isprintable()
True
>>> "123565 all printable<>!@#$%^&**".isprintable()
True
S.ISSPACE()
Returns True if all characters in the string are whitespace.
>>> " ".isspace()
True
>>> " \t ".isspace()
True
>>> " \t \n".isspace()
True
>>> " \t m\n".isspace())
False
S.ISTITLE()
Returns True if the string follows the rules of a title—that is, the first letter
of each word is upper case, while the rest are not.
>>> "Python Is a Great Language".istitle()
False
>>> "Python Is A Great Language".istitle()
True
S.ISUPPER()
Returns True if all characters in the string are upper case.
>>> "THIS IS ALL UPPER".isupper()
True
>>> "THIS IS ALL UPPER with some lower".isupper()
False
SEP.JOIN(ITERABLE)
Joins the elements of an iterable with the separator. The iterable can be a
list, tuple, string, dictionary, or set. Note that each element of the iterable
must be a string. An integer or other number will raise an error.
>>> "-".join([" for", " programming!"])
'for- programming!'
>>> "&".join([" for", " programming!"])
'for& programming!'
>>> "%".join([" for", " programming!"])
'for% programming!'
>>> "%".join(" for programming!")
'%f%o%r% %p%r%o%g%r%a%m%m%i%n%g%!'
>>> "%".join(('a', '2', '3'))
'a%2%3'
>>> "%".join({'a', '2', '3'})
'3%a%2'
>>> "%".join({'a':'mnmn', '2':'987', '3':'43322'})
'a%2%3'
S.LJUST(SL)
Returns a left-justified version of the string within the given size of space.
>>> "Python Is A Great Language".ljust(30)
'Python Is A Great Language '
S.LOWER()
Converts a string into lower case.
>>> "Python Is A Great Language".lower()
'python is a great language'
S.LSTRIP()
Returns a left trim version of the string.
>>> " Python Is A Great Language ".lstrip()
'Python Is A Great Language '
S.MAKETRANS(DICT)
S.MAKETRANS(S1, S2)
Return a translation table to be used in translations.
In s.maketrans(dict), key-value pairs of dict provide mapping for
translation; in the case of s.maketrans(s1, s2), chars in s1 are mapped to
chars in s2 one by one.
>>> "Python Is A Great Language".maketrans({'a':'b', 'c':'d'})
{97: 'b', 99: 'd'}
>>> "Python Is A Great Language".maketrans('ab', 'cd')
{97: 99, 98: 100}
S.PARTITION(SUB)
Returns a tuple where the string is divided into three parts with sub in the
middle.
>>> "Python Is A Great Language".partition('A')
('Python Is ', 'A', ' Great Language')
S.REPLACE(S1, S2)
Returns a string where a specified value is replaced with a specified value.
>>> "Python Is A Great Language".replace('Great', 'Powerful')
'Python Is A Powerful Language'
S.RFIND(SUB)
Searches the string from the right for a substring and returns the position of
where it was first found.
>>> "Python Is A Great Language".rfind('g')
24
S.RINDEX(SUB)
Searches the string from the right for a substring and returns the index of
the substring where it was first found.
>>> "Python Is A Great Language".rindex('g')
24
S.RJUST(SUB)
Returns a right-justified version of the string within the given size of space.
>>> "Python Is A Great Language".rjust(35)
' Python Is A Great Language'
S.RPARTITION(SUB)
Returns a tuple where the string is divided into three parts at the substring
found from the right.
>>> "Python Is A Great Language".rpartition('g')
('Python Is A Great Langua', 'g', 'e')
S.RSPLIT(SEP)
Splits the string at the specified separator and returns a list.
>>> "Python Is A Great Language".rsplit('g')
['Python Is A Great Lan', 'ua', 'e']
S.RSTRIP()
Returns a right-trimmed version of the string.
>>> "Python Is A Great Language ".rstrip()
'Python Is A Great Language'
S.SPLIT(SEP)
Splits the string at the specified separator and returns a list.
>>> "Python Is A Great Language".split('g')
['Python Is A Great Lan', 'ua', 'e']
S.SPLITLINES()
Splits the string at line breaks and returns a list.
>>> "Python Is A Great Language.\n I love it.".splitlines()
['Python Is A Great Language.', ' I love it.']
S.STARTSWITH(SS)
Returns true if the string starts with the specified value.
>>> "Python Is A Great Language".startswith('g')
False
>>> "Python Is A Great Language".startswith('P')
True
S.STRIP()
Returns a trimmed version of the string.
>>> " Python Is A Great Language ".strip()
'Python Is A Great Language'
S.SWAPCASE()
Swaps cases, so lower case becomes upper case, and vice versa.
>>> "Python Is A Great Language".swapcase()
'pYTHON iS a gREAT lANGUAGE'
S.TITLE()
Converts the first character of each word to upper case.
>>> 'pYTHON iS a gREAT lANGUAGE'.title()
'Python Is A Great Language'
S.TRANSLATE()
Returns a string translated from s using a translation table created with the
maketrans() method.
>>> table = "".maketrans("ab", 'cd')
>>> print("Python Is A Great Language".translate(table))
Python Is A Grect Lcngucge
S.UPPER()
Converts a string into upper case.
>>> "Python Is A Great Language".upper()
'PYTHON IS A GREAT LANGUAGE'
S.ZFILL(SL)
Fills the string to a specific length with a specified number of 0s at the
beginning.
>>> "Python Is A Great Language".zfill(39)
'0000000000000Python Is A Great Language'
Table 5-1 summarizes the operators and built-in functions you can use to
manipulate strings.
an integer) Doe"
>>> name[2]
'h'
'hn D'
Doe"
>>> name[:-3]
'John '
"John"
>>> last_name =
"Doe"
>>> first_name
'John Doe'
Operators and Code samples in
built-in functions Python interactive
on string Operation mode
')*3
in name
True
Doe"
>>> print(name)
John Doe
print(s0) # s is evaluated
In the example above, the string before the last percentage sign % is
called a formatting string. %3d is a %-led placeholder for an integer that
will take a 3-digit spot, whereas %9.5 is a %-led placeholder for a float
number, where 9 specifies the total number of digits the float number will
take and 5 specifies the total number of decimal digits. The values in the
tuple behind the last percentage sign are to be converted and placed into
their corresponding placeholders. In the example, the value of n will be
converted to an integer and placed into the first placeholder, whereas the
value of d will be converted into a float number and placed into the second
placeholder.
You can also use named placeholders, as shown in the next example,
where the course and language (in the parentheses) are the names of the
placeholders.
In [ ]: course_number = 'comp218'
language = 'Python'
'%{'course':course_number,
'language':language}
print(s1)
Note that when named placeholders are used, you will need to use
dictionary instead of a tuple behind the last percentage sign.
The general format of a %-led placeholder is as follows:
%[flags][width] [.precision] type
The flags may use one or a combination of the characters in Table 5-2.
formatted value is preceded with 0b, 0o, 0x, or ("COMP 218", 10)
0X, respectively.
>>> '%s has %#X
units.' % data
0XA units.'
218", "number":
10}
>>> '%(course)s
has %
(number)016d
units.' % data
0000000000000010
units.'
Flag Meaning Code sample
{"course": "COMP
218", "number":
10}
>>> '%(course)s
has %(number)-6d
units.' % data
10 units.'
218", "number":
-10}
>>> '%(course)s
has %(number)16d
units.' % data
'COMP 218
has 10 units.'
Flag Meaning Code sample
>>> '%(course)s
has %(number)+6d
units.' % data
'COMP 218
The width is the total width of space held for the corresponding value,
and precision is the number of digits that the decimal portion will take if the
value is a float number. The type can be one of the types shown in Table 5-
3.
>>>
print("%+i"%
(88))
+88
>>>
print("%+u"%
(88))
+88
>>>
print("%+u"%
(-88))
-88
>>>
print("%+i"%
(-88))
-88
>>>
print("%+d"%
(-88 ))
-88
Conversion Meaning Code sample
print("%10o"%
(25))
31
>>>
print("%10.3o"%
(25))
031
>>>
print("%10.5o"%
(25))
00031
Conversion Meaning Code sample
print("%6.5X"%
(88))
00058
>>>
print("%6.5x"%
(88))
00058
>>>
print("%#5X"%
(88))
0X58
>>>
print("%5X"%
(88))
58
Conversion Meaning Code sample
(123456.789))
1.235e+05
>>>
print("%10.3E"%
(123456.789))
1.235E+05
print("%13.5f"%
(123456.789))
123456.78900
>>>
print("%13.5F"%
(123456.789))
123456.78900
Conversion Meaning Code sample
(123456.789))
1.2346e+05
>>>
print("%13.5G"%
(123456.789))
1.2346E+05
character of
string %s is
%c'%(s, s[0])
'The first
character of
string Python
is great! is P'
Conversion Meaning Code sample
number will be
displayed as
(12+35j)'
%s'%(cn)
'The complex
number will be
displayed as
(12+35j)'
Conversion Meaning Code sample
percentage
complex number
is %s'%(cn)
'% will be
displayed as a
single
percentage
complex number
is (12+35j)'
Please note the difference between the two outputs using !s and !a in
particular.
It may also have been noted that with !r, the quotation marks surrounding
the argument remain in the output, whereas with !s, the quotation marks
have disappeared from the output. This is true when the argument for the !r
is a string.
When the argument for !r is not a string, especially when it is a
complicated object, o, the !r will cause the placeholder to be replaced with
the result of o.repr(), which in turn calls the dunder method __repr__()
defined for the object’s class. You will learn how to define and use Python
dunder methods later in Chapter 7.
In string formatting with format method, formatting specification is led
by a colon :, which is followed by formatting instructions, including the
following:
The following example shows how the data type conversions work:
>>> '{:+12.8f}, {:+f}, {:#b}, {:#X}'.format(2.71828182, -3.14, 78,
127)
' +2.71828182, -3.140000, 0b1001110, 0X7F'
If you want the extra space to be filled with a special character, such as #,
you can put the character between the colon and <, >, or ^, as shown below:
>>> '{:#^+22.8f}, {:+f}, {:#b}, {:#X}'.format(2.71828182, -3.14, 78,
127)
'#####+2.71828182######, -3.140000, 0b1001110, 0X7F'
Regular Expressions
Information processing and text manipulation are important uses for
modern computers, and regular expressions, called “REs” or “regexes” for
short, were developed as a powerful way to manipulate text. Many modern
programming languages have special libraries for searching and
manipulating text using regular expressions. In Python, a standard module
called re was developed for that purpose.
To correctly use the re module, we first must understand what regular
expressions are and how to construct a regular expression that genuinely
defines the strings we want to find and/or manipulate within a text because
almost all functions/methods of the re module are based on such defined
regular expressions.
What is a regular expression? A regular expression is a pattern that
describes certain text or literal strings. Examples of some useful patterns
include telephone numbers, email addresses, URLs, and many others.
To be able to correctly define a regular expression precisely describing
the strings we want to find and manipulate, we must first understand and
remember the rules of regular expressions, as well as special characters and
sequences that have special meanings in a re module. Since regular
expressions are strings themselves, they should be quoted with single or
double quotation marks. For simplicity, however, we may omit some
quotation marks in our discussion when we know what we are talking about
in the context.
Plain literals such as a, b, c,…z, A, B, C,…Z, and numeric digits such as
0, 1, 2,…9 can be directly used in a regular expression to construct a
pattern, such as Python, Foo, Canada. Some symbols in the ASCII table
have been given special meanings in re. These symbols, called
metacharacters, are shown in Table 5-4.
Table 5-4: Metacharacters and basic rules for constructing regular expressions
. Match any character except \n, a new line, t..t will match
in a string. test, text,…
? This and the rest in this table are called mpe?g will
quantifiers. When ? is affixed to a preceding match mpg or
regex (character or group) it becomes a mpeg
nongreedy qualifier, meaning it will match
only 0 or 1 occurrence of the preceding
regex.
? can also be affixed to + as +?, or * as *?,
to make + or * nongreedy.
Escape
sequence Special meaning in re Example
The above are the basic rules for constructing regular expressions or
regex patterns. Using these rules, we can write regular expressions to define
most string patterns we are interested in.
The following are some examples of regex patterns:
(?AILMSUX)
Here, ? is followed by one or more letters from set a, i, L, m, s, u, and x,
setting the corresponding flags for the re engine. (?a) sets re.A, meaning
ASCII-only matching; (?i) sets re.I, meaning ignore case when matching; (?
L) sets re.L, meaning local dependent; (?m) sets re.M, meaning multiple
lines; (?s) sets re.S, meaning dot matches all characters including newline;
(?u) sets re.U, meaning Unicode matching; (?x) sets re.X, meaning verbose
matching. These flags are defined in the re module. The details can be
found by running help(re).
The flags can be used at the beginning of a regular expression in place of
passing the optional flag arguments to re functions or methods of pattern
object.
(?AILMSUX-IMSX:…)
Sets or removes the corresponding flags. (?a-u…) will remove Unicode
matching.
(?:…)
Is a noncapturing version of regular parentheses, meaning the match cannot
be retrieved or referenced later.
(?P<NAME>…)
Makes the substring matched by the group accessible by name.
(?P=NAME)
Matches the text matched earlier by given name.
(?#…)
Is a comment; ignored.
(?=…)
Matches if… matches next but does not consume the string being searched,
which means that the current position in string remains unchanged. This is
called a lookahead assertion.
John (?=Doe) will match John only if it is followed by Doe.
(?!…)
Matches if… does not match next.
Jon (?!Doe) will match Jon only if it is not followed by Doe.
(?<=…)
Matches if preceded by… (must be fixed length).
(?<=John) Doe will find a match in John Doe because there is John
before Doe.
(?<!…)
Matches if not preceded by… (must be fixed length).
(?<!John) Doe will find a match in Joe Doe because there is not Joe
before Doe.
Using the dir(re) statement, you can find out what names are defined in
the module, as shown below, but you will need to use help(re) to find out
the core functions and methods you can use from the re module.
The following are functions defined in the re module:
re.compile(pattern, flags=0)
Compile a pattern into a pattern object and return the compiled pattern
object for more effective uses later.
>>> import re
>>> pobj=re.compile('780-?\d{3}-?\d{4}')
>>> pobj.findall('780-9381396, 7804311508, 18663016227') # findall
method of pattern object
['780-9381396', '7804311508']
>>> b = re.compile(r'\d+\.\d*')
>>> b.match('32.23') # match method of pattern object
<re.Match object; span=(0, 5), match='32.23'>
RE.PURGE()
Clear the regular expression cache.
>>> re.purge()
>>>
RE.ESCAPE(PATTERN)
Backslash all nonalphanumerics in a string.
>>> print(re.escape('1800.941.7896'))
1800\.941\.7896
The next step will be to get an input from the user and test it:
name = input('Give me a name and I will tell you if it is a Python
identifier: ')
Trim the whitespace at the beginning and the end of the name just in
case:
name = name.strip() # this will strip the whitespaces
The complete code of the program is shown in the code section of Table
5-6.
The Steps:
analysis Step 1: Import re module before using it
and design Step 2: Define a regex pattern for Python identifiers
Step 3: Get an input from the user, and
Step 4: Test it with an if-else statement
idPatt = '(^[A-Za-z]\w+)$|(^_[A-Za-z]\w+_$)|(^__[A-Za-z]\w+__$)'
Python identifier:')
name = name.strip()
print('Congratulations! It is!')
else:
print('Sorry, it is not.')
The result Give me a name and I will tell you if it is a Python
identifier:A2
Congratulations! It is!
5.2 Lists
The list is an important compound data type in Python and in almost all
programming languages, though not many programming languages have list
as a built-in data type.
In previous sections, you saw a few program examples with a list
involved. In the following, we explain the operators and functions that can
be used on lists.
LIST(ITERABLE)
To construct a list from an iterable such as a sequence or call to range().
>>> l1 = list("test")
>>> l1
['t', 'e', 's', 't']
>>> l2 = list((1,2,3,4))
>>> l2
[1, 2, 3, 4]
>>> l5 = list(range(13, 26))
>>> l5
[13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25]
In addition, you can also create a list by directly putting items in a pair of
square brackets, as shown below:
>>> l6 = ['Jon', 'John', 'Jonathan', 'Jim', 'James']
>>> l6
['Jon', 'John', 'Jonathan', 'Jim', 'James']
L[NTH]
To get the nth element of list l.
>>> students = ['John', 'Mary', 'Terry', 'Smith', 'Chris']
>>> students[3]
'Smith'
L[START:END]
To get a slice/sublist of l, including the members from a start position till
right before the end position.
>>> students = ['John', 'Mary', 'Terry', 'Smith', 'Chris']
>>> students[1:3]
['Mary', 'Terry']
L[START:END:STEP]
To get a slice/sublist of l, including members from a start position to right
before an end position with set step.
>>> l6 = ['Jon', 'John', 'Jonathan', 'Jim', 'James']
>>> l6[:5:3] # start from 0 till 5 with step set as 3.
['Jon', 'Jim']
L[N] = E
To replace element at n with e.
>>> print(students)
['John', 'Mary', 'Terry', 'Smith', 'Chris']
>>> students[2] = 'Cindy'
>>> print(students)
['John', 'Mary', 'Cindy', 'Smith', 'Chris']
L1 + L2
To concatenate list l2 to l1, but without changing l1. As such, if you want to
keep the result of concatenation, you will need to assign the result to a new
variable.
>>> teachers = ['Jeffery', 'Clover', 'David']
>>> students + teachers
['John', 'Mary', 'Terry', 'Smith', 'Chris', 'Jeffery', 'Clover',
'David']
>>> teachers
['Jeffery', 'Clover', 'David']
>>> class_members = students + teachers
>>> class_members
['John', 'Mary', 'Terry', 'Smith', 'Chris', 'Jeffery', 'Clover',
'David']
L*N
N*L
To duplicate list l n times but without changing l.
>>> students[1:3]
['Mary', 'Terry']
>>> students[1:3] * 2
['Mary', 'Terry', 'Mary', 'Terry']
>>> 2*students[1:3]
['Mary', 'Terry', 'Mary', 'Terry']
E IN L
To test if e is in list l. If l has compound data such as lists, tuples, or
instances of a class, e is only part of a compound data or object and is not
considered in the list.
>>> teachers
['David', 'Jeffery', 'Clover']
>>> 'Clover' in teachers
True
>>> l0 = [1, 2, 3, [4, 5], 6] # 4 and 5 are members of a sublist of
l0
>>> 5 in l0 # so that 5 is not considered as part of list l0
False
LEN(L)
To get the number of elements in the list l.
>>> students
['John', 'Mary', 'Terry', 'Smith', 'Chris']
>>> len(students)
5
PRINT(L)
To print list l. Note that the list will be recursively printed, but complex
objects such as instances of a user-defined class may not be printed the way
you expected unless you have defined the __str__() method for the class.
>>> print(teachers)
['Jeffery', 'Clover', 'David']
In addition, there are also built-in methods for list objects, as detailed
below.
L.APPEND(E)
To append element e to list l.
>>> l = ['T', 'h']
>>> l.append('e')
>>> l
['T', 'h', 'e']
L.CLEAR()
To remove all items from list l.
>>> l1 = list("test")
>>> l1
['t', 'e', 's', 't']
>>> l1.clear()
>>> l1 # l1 became an empty list
[]
L.COPY()
To return a shallow copy of list l—that is, it only copies simple objects of
the list such as numbers and strings; for compound data, it does not copy
the actual objects but only makes references to the objects.
>>> l7 = l6.copy() # from above we know that items in l6 are all
simple strings
>>> l7
['Jon', 'John', 'Jonathan', 'Jim', 'James']
>>> l7[3] = 'Joe' # change the value of l7[3]
>>> l7 # it shows l7 has been changed
['Jon', 'John', 'Jonathan', 'Joe', 'James']
>>> l6 # it shows l6 remains the same
['Jon', 'John', 'Jonathan', 'Jim', 'James']
L.POP()
To remove and return an item from the end of list l.
>>> l.pop()
'e'
L.POP(2)
To remove and return an item from the middle of list l. When there are an
even number of elements in the list, there will be two elements in the
middle, but only the first one pops out.
>>> l = [1, 3, 2, 6, 5, 7]
>>> l.pop(2)
2
>>> l
[1, 3, 6, 5, 7]
>>> l.pop(2)
6
L.REVERSE()
To reverse the list.
>>> l.reverse()
>>> l
[7, 5, 3, 1]
L.SORT()
To sort the list in ascending order by default. To sort in descending order,
use l.sort(reverse = True).
>>> l.sort()
>>> l
[1, 3, 5, 7]
L.EXTEND(L0)
To extend list l by appending list l0 to the end of list l. It is different from l
+ l0 but it is same as l += l0.
>>> l = list(range(5))
>>> l
[0, 1, 2, 3, 4]
>>> l0 = list(range(6, 11))
>>> l0
[5, 6, 7, 8, 9, 10]
>>> l.extend(l0)
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
L.INSERT(I, E)
To insert e before index i of existing list l.
>>> l = list(range(10))
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> l.insert(5, 13)
>>> l
[0, 1, 2, 3, 4, 13, 5, 6, 7, 8, 9]
L.REMOVE(E)
To remove first occurrence of e in the list.
>>> l
[0, 1, 2, 3, 4, 13, 5, 6, 7, 8, 9]
>>> l.remove(5)
>>> l # 5 has been removed from l
[0, 1, 2, 3, 4, 13, 6, 7, 8, 9]
L.COUNT(E)
To search the list and return the number of occurrences of e.
>>> l
[0, 1, 2, 3, 4, 13, 6, 7, 8, 9]
>>> l.count(6)
1
As you can see, elements in lists can be changed or mutated. You can
insert, delete, replace, expand, and reorder all the elements in a list.
Lists are a very important data model in programming and problem
solving. First, lists can be used as collections of data. Each member of the
collection can be as simple as a number or a string and as complex as
another list or any other compound data type, or even an object. Many
functions and methods, as discussed above, have been made available for
accessing and manipulating lists and their members.
Suppose we want to develop a management system for a company, for
example. Within the system, we need to represent information on its
employees. We can use a list containing the name, birthdate, department,
start date at the company, and level of employment to represent information
on each employee, then use another list to represent a collection of
employees. This is illustrated as follows:
# this defines an embedded list or two-dimensional array
employees = [['Kevin Smith', 19560323, 'Sale', 20100621, 3],
['Paul Davina', 19860323, 'HR', 20120621, 5],
['Jim Carri', 1969323, 'Design', 20120625, 2],
['John Wong', 19580323, 'Customer Service', 20110323, 3],
['Keri Lam', 19760323, 'Sale', 20130522, 5]]
5.3 Tuples
Unlike a list, a tuple is an immutable object, which means that once created,
the internal structure of a tuple cannot be changed. Hence, most methods
you have seen for lists are not available for tuples, except for the following
two.
T.COUNT(E)
To count and return the number of occurrences of a specified value in a
tuple.
>>> t = (3, 6, 5, 7, 5, 9)
>>> t.count(5)
2
TUPLE(ITERABLE)
To construct a tuple from an iterable such as another sequence or a call to
range(), a built-in function.
>>> l1 = [1, 2, 3]
>>> t0 = tuple(l1)
>>> t0
(1, 2, 3)
This would be the same as the following:
>>> t0 = (1, 2, 3)
>>> t1 = tuple('tuple')
>>> t1
('t', 'u', 'p', 'l', 'e')
>>> tuple(range(7))
(0, 1, 2, 3, 4, 5, 6)
T[N]
To get nth element of a tuple.
>>> teachers = ('Jeffery', 'Clover', 'David')
>>> teachers[2]
'David'
T[I:J]
To get a slice of tuple t including elements from point i to the one right
before point j.
>>> teachers[0:2]
('Jeffery', 'Clover')
>>> print(teachers)
('Jeffery', 'Clover', 'David')
T1 + T2
To concatenate tuple t2 to t1.
>>> students = tuple(students)
>>> print(students)
('John', 'Mary', 'Terry', 'Smith', 'Chris')
>>> students + teachers
('John', 'Mary', 'Terry', 'Smith', 'Chris', 'Jeffery', 'Clover',
'David')
T*N
To duplicate tuple t n times.
>>> teachers * 2
('Jeffery', 'Clover', 'David', 'Jeffery', 'Clover', 'David')
E IN T
To test if e is an element of tuple t.
>>> teachers
('David', 'Jeffery', 'Clover')
>>> 'David' in teachers
True
LEN(T)
To get the number of elements in the tuple t.
>>> len(teachers * 2)
6
PRINT(T)
To print tuple t. Again, print may print the tuple recursively, but the
expected result can only be achieved if __str__() has been defined for every
object at all levels.
>>> print(students)
('John', 'Mary', 'Terry', 'Smith', 'Chris')
5.4 Sets
As in mathematics, a set is a collection of unindexed and unordered
elements. For sets, Python has very few operators and built-in functions that
we can use.
SET(S)
To construct a set from s, which can be a list, tuple, or string.
>>> students = ['Cindy', 'Smith', 'John', 'Chris', 'Mary']
>>> students = set(students)
>>> students
{'Cindy', 'Smith', 'John', 'Chris', 'Mary'}
>>> numbers = set(range(10))
>>> numbers
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
E IN S
To test if e is a member of set s.
>>> students
{'Cindy', 'Smith', 'John', 'Chris', 'Mary'}
>>> 'Chris' in students
True
LEN(S)
To get the total number of elements in the set.
>>> numbers
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> len(numbers)
10
S.ADD(M)
To add an element to the set s.
>>> s = set([3])
>>> s
{3}
>>> s.add(5)
>>> s
{3, 5}
S.CLEAR()
To remove all the elements from the set s.
>>> s.clear()
>>> s
set()
S.COPY()
To make and return a copy of the set s.
>>> s
{3, 5}
>>> s1 = s.copy()
>>> s1
{3, 5}
S.DIFFERENCE(S1,…)
To make and return a set containing only members of s that other sets in the
arguments don’t have—that is, the difference between two or more sets.
>>> s1
{3, 5}
>>> s2 = {5, 7}
>>> s1.difference(s2)
{3}
>>> s3={3,7}
>>> s1.difference(s2,s3) # returns an empty set
set()
S.DIFFERENCE_UPDATE(*SX)
To remove the items in set s that are also included in another, specified set.
>>> s1 = {2 * i for i in range(15)}
>>> s2 = {3 * i for i in range(15)}
>>> s1
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.difference_update(s2)
>>> s1
{2, 4, 8, 10, 14, 16, 20, 22, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
S.DISCARD(M)
To remove the specified item.
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s2.discard(18)
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 21, 24, 27, 30}
S.INTERSECTION(*SX)
To return a set that is the intersection of two other sets.
>>> s1 = {2 * i for i in range(15)}
>>> s2 = {3 * i for i in range(15)}
>>> s1
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.intersection(s2)
{0, 6, 12, 18, 24}
S.INTERSECTION_UPDATE(*SX)
To remove the items in this set that are not present in another, specified set
or sets.
>>> s1
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.intersection_update(s2)
>>> s1
{0, 6, 12, 18, 24}
S.ISDISJOINT(SX)
To check and return whether two sets have an intersection (common
member) or not.
>>> s1
{0, 6, 12, 18, 24}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.isdisjoint(s2)
False
S.ISSUBSET(SX)
To check and return whether another set contains this set or not.
>>> s1 = {2 * i for i in range(15)}
>>> s2 = {3 * i for i in range(15)}
>>> s1
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.issubset(s2)
False
S.ISSUPERSET(SX)
To check and return whether this set contains another set or not.
>>> s1.issuperset(s2)
False
S.POP()
To remove an element from the set.
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s2.pop()
0
>>> s2
{33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
S.REMOVE(M)
To remove the specified element.
>>> s2
{33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s2.remove(18)
>>> s2
{33, 3, 36, 6, 39, 9, 42, 12, 15, 21, 24, 27, 30}
S.SYMMETRIC_DIFFERENCE(SX)
To construct and return a set with elements in either set s or another set but
not both. These are called set symmetric differences (“I have you do not;
you have I do not”).
>>> s1 = {2 * i for i in range(15)}
>>> s2 = {3 * i for i in range(15)}
>>> s1
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28}
>>> s2
{0, 33, 3, 36, 6, 39, 9, 42, 12, 15, 18, 21, 24, 27, 30}
>>> s1.symmetric_difference(s2)
{2, 3, 4, 8, 9, 10, 14, 15, 16, 20, 21, 22, 26, 27, 28, 30, 33, 36,
39, 42}
S.SYMMETRIC_DIFFERENCE_UPDATE(SX)
To insert the symmetric differences from this set and another.
>>> s1.symmetric_difference_update(s2)
>>> s1
{2, 3, 4, 8, 9, 10, 14, 15, 16, 20, 21, 22, 26, 27, 28, 30, 33, 36,
39, 42}
S.UNION(SX)
To return a set containing the union of sets.
>>> s2 = {3 * i for i in range(5)}
>>> s1 = {2 * i for i in range(5)}
>>> s1
{0, 2, 4, 6, 8}
>>> s2
{0, 3, 6, 9, 12}
>>> s1.union(s2)
{0, 2, 3, 4, 6, 8, 9, 12}
S.UPDATE(SX)
To update the set by adding members from other sets.
>>> s1
{0, 2, 4, 6, 8}
>>> s2
{0, 3, 6, 9, 12}
>>> s1.update(s2)
>>> s1
{0, 2, 3, 4, 6, 8, 9, 12}
5.5 Dictionaries
A dictionary is a collection of key and value pairs enclosed in curly
brackets. As with a set, the dictionary is also immutable. There are very few
operators and built-in functions that can be used on dictionaries, as shown
below.
DICT(**KWARG)
To construct a dictionary from a series of keyword arguments.
>>> dt = dict(one = 1, two = 2, three = 3)
>>> dt
{'one': 1, 'two': 2, 'three': 3}
DICT(MAPPING, **KWARG)
To construct a dictionary from mapping. If keyword arguments are present,
they will be added to the dictionary constructed from the mapping.
>>> d1 = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d2 = dict(zip([1, 2, 3], ['one', 'two', 'three']))
>>> d1
{'one': 1, 'two': 2, 'three': 3}
>>> d2
{1:'one', 2:'two', 3:'three'}
DICT(ITERABLE, **KWARG)
To construct a dictionary from an iterable. If keyword arguments are
present, they will be added to the dictionary constructed from the mapping.
>>> d3 = dict([('two', 2), ('one', 1), ('three', 3)])
>>> d3
{'two': 2, 'one': 1, 'three': 3}
LIST(DT)
To return a list of all the keys used in the dictionary dt.
>>> d3
{'two': 2, 'one': 1, 'three': 3}
>>> list(d3)
['two', 'one', 'three']
DT[K]
To get the value of key k from dictionary dt.
>>> dt = {1:'One', 2:'Two', 3:'Three'}
>>> dt[1]
'One'
DT[K] = V
To set d[key] to value V.
>>> d3
{'two': 2, 'one': 1, 'three': 3}
>>> d3['two']
2
>>> d3['two'] = bin(2)
>>> d3['two']
'0b10'
DEL DT[K]
To remove dt[key] from dt.
>>> d3
{'two':'0b10', 'one': 1, 'three': 3}
>>> del d3['two']
>>> d3
{'one': 1, 'three': 3}
K IN DT
To test if dt has a key k.
>>> d3
{'one': 1, 'three': 3}
>>> 'two' in d3
False
K NOT IN DT
Same as not k in dt, or k not in dt.
>>> 'two' not in d3
True
>>> not 'two' in d3
True
ITER(DT)
To return an iterator over the keys of dt. Same as iter(dt.keys()).
>>> iter(d3)
<dict_keyiterator object at 0x00000198FE0EFEF8>
>>> list(iter(d3))
['one', 'three']
LEN(DT)
To get the total number of elements in the dictionary.
>>> dt
{1:'One', 2:'Two', 3:'Three'}
>>> len(dt)
3
REVERSED(DT)
To return a reverse iterator over the keys of the dictionary. Same effect as
reversed(dt.keys()). This is new in Python 3.8.
>>> dt = {1:'One', 2:'Two', 3:'Three'} # keys: 1, 2, 3
>>> rk = reversed(dt) # reversed iterator over the keys in rk
>>> for k in rk:
print(k)
…
3
2
1
D.CLEAR()
To remove all the elements from the dictionary.
>>> dt = {1:'One', 2:'Two', 3:'Three'}
>>> dt
{1:'One', 2:'Two', 3:'Three'}
>>> dt.clear()
>>> dt
D.COPY()
To make and return a copy of the dictionary.
>>> dt = {1:'One', 2:'Two', 3:'Three'}
>>> dx = dt.copy()
>>> dx
{1:'One', 2:'Two', 3:'Three'}
DICT.FROMKEYS()
To make a dictionary from a list of keys.
>>> keys = ['Edmonton','Calgary','Toronto']
>>> weather = dict.fromkeys(keys, 'Sunny')
>>> print(weather)
{'Edmonton': 'Sunny', 'Calgary': 'Sunny', 'Toronto': 'Sunny'}
D.GET(K)
To return the value of the specified key.
>>> d3 =dict([('two', 2), ('one', 1), ('three', 3)])
>>> d3.get('two')
2
D.ITEMS()
To return a list containing a tuple for each key-value pair.
>>> d3.items()
dict_items([('two', 2), ('one', 1), ('three', 3)])
D.KEYS()
To return a list containing the dictionary’s keys.
>>> d3.keys()
dict_keys(['two', 'one', 'three'])
D.VALUES()
To return a list of all the values in the dictionary.
>>> d3.values()
dict_values([2, 1, 3])
D.POP(K)
To remove the element with the specified key. Note that the removed item
will no longer exist in the dictionary.
>>> d3
{'two': 2, 'one': 1, 'three': 3}
>>> d3.pop('two')
2
>>> d3
{'one': 1, 'three': 3}
D.POPITEM()
To remove an item from the end of the dictionary, as a key and value pair.
>>> d3
{'two': 2, 'one': 1, 'three': 3}
>>> d3.popitem()
('three', 3)
D.SETDEFAULT(KEY, VALUE)
To insert a key-value pair into the dictionary if the key is not in the
dictionary; return the value of the key if the key exists in the dictionary.
>>> d3
{'two': 2, 'one': 1}
>>> d3.setdefault('three', 3)
3
>>> d3.setdefault('two', 'II')
2
>>> d3
{'two': 2, 'one': 1, 'three': 3}
D.UPDATE(DX)
To update the dictionary with the specified key-value pairs in dx.
>>> d3
{'two': 2, 'one': 1, 'three': 3}
>>> d2
{1:'one', 2:'two', 3:'three'}
>>> d3.update(d2)
>>> d3
{'two': 2, 'one': 1, 'three': 3, 1:'one', 2:'two', 3:'three'}
List Comprehension
The following is an example that constructs a list of odd numbers from 1 to
100:
In [ ]: l0 = [i * 2 + 1 for i in range(50)]
print(l0)
Out [ ]: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33,
35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93,
95, 97, 99]
In the example, the expression before for represents the items of the list;
the for loop will run through the item expression in each iteration. This list
can also be generated using the for loop with an if clause, as shown below:
In [ ]: l1 = [i for i in range(100) if i % 2 != 0]
print(l1)
Out [ ]: [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33,
35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93,
95, 97, 99]
In the example above, the list item expression will be evaluated in every
iteration of the for loop only if the condition of the if clause is met. In fact,
we can put any condition on the iteration variable i. For example, assume
we have a Boolean function isPrime(N) that can test if number N is prime
or not; then the following statement will produce a list of prime numbers in
the given range:
primes = [i for i in range(1000) if isPrime(i)]
Please note that the list item expression before for can be anything whose
value is a legitimate list item, as shown in the example below:
in range(10)]
print(detailed)
Out [ ]: ['0 is even', '1 is odd', '2 is even', '3 is odd', '4 is even', '5 is
odd', '6 is even', '7 is odd', '8 is even', '9 is odd']
print(combo)
Set Comprehension
A set is a collection of unique unordered items. With that in mind, set
comprehension is similar to list comprehension, except that the items are
enclosed in curly brackets, as shown in the example below:
print(asc)
Out [ ]: {'K', 'M', 'G', 'T', 'C', 'O', 'L', 'D', 'S', 'I', 'B', 'N', 'A', 'F', 'W',
'H', 'P', 'X', 'J', 'Z', 'E', 'R', 'U', 'Y', 'Q', 'V'}
What would happen if items generated from the iteration were duplicated?
No worries! The implementation of set comprehension can take care of that.
If we want to find out all the unique words contained in a web document,
we can simply use set comprehension to get them, as shown below:
web resources
content = requests.get("https://scis.athabascau.ca/").text
separators = [',', '.', '"', "'", '>', '<', '--', '!', '|', ']',
for sp in separators:
for op in operators:
print(len(unique_words), unique_words)
Out [ ]: 969
Dictionary Comprehension
Dictionary comprehension is very similar to set comprehension, except that
we need to add a key and colon before each item to make a dictionary item,
as shown in the following:
print(m_dict)
print(m_dict)
The statement above opened the file mypoem.txt in the current working
directory and returned a stream, which was then assigned to variable f,
often called a file handle.
The general syntax of the open statement is as follows:
open(file, mode = 'r', buffering = -1, encoding = None, errors =
None, newline = None, closefd = True, opener = None)
The statement opens a file and returns a stream or file object; it will raise
OSError upon failure. In the statement, file is a text or byte string referring
to the file to be opened. It may include the path to the actual file if the file is
not in the current working directory.
Apart from the first argument for the name of the file to be opened, all
other arguments have default values, which means that these arguments are
optional. If no value is supplied, the default value will be used.
The second argument is called mode. It is optional with a default value r,
which means “open a text file for reading.” This argument is used to tell the
program what to do with the file after opening. Because reading from a text
file is not always what you want it to do with a file, the argument is not
optional. All available values for the mode argument are shown in Table 5-
7.
r+ Open for both reading and writing; file must already exist.
w Open for writing only; file may or may not exist. If not, a new
file will be created and ready for writing; if file already exists,
content will be overwritten.
w+ Open for writing and reading; file may or may not exist.
x Create a new file for writing. File Exists Error will occur if the
file already exists. This would help prevent accidentally
overwriting an existing file.
print(ln)
When not using the with statement, you will need to use the following
instead:
print(ln)
f.close()
• None
•,
• \n
• \r
• \rn
Once a file is opened, a list of methods can be used to operate on the file
object, as detailed below.
If you could write only this one line of your poem and had to close the
file and shut down the computer, you would be more likely to continue
from where you had stopped the next time you came back to the poem. So
you need to append the new lines to the file. This is done by opening the
file in a mode, as shown below:
>>> f = open("./mypoem.txt", "a") # open file in the current
working directory for writing
>>> f.write("\nWith your bitter, twisted lies") # add \n to write
on a new line
>>> f.flush() # to flush the data out to the actual file
Note that the write method will only write a string to the file. As such,
anything that is not a string must be converted into a string before being
written to the file, as shown in the following example:
>>> f.write(f'\n{3.1415926}')
Also, because of buffering, the data you write to a file will not
immediately show up in the actual file until you close the file or use the
flush() method to flush the data in the buffer out to the file, as shown below:
>>> f.flush()
The write(string) method can only write one string to a file each time. To
write multiple strings to a file, the writelines(sequence) method is used.
However, keep in mind that writelines() does not automatically write one
string on each line. You will still need to add \n at the beginning of the
string if you want it to be on the next line or at the end of the string if you
don’t want anything behind the string on the same line.
Recall the example of printing a 9 × 9 multiplication table. Now we can
write the table to a text file so that you can print it out whenever you want.
This is shown in the two examples below:
"""This first code sample is using the write method."""
f = open('./my9x9table.txt', 'w')
for i in range(1, 10):
for j in range(1, i + 1):
f.write('{:1d} x {:1d} = {:2d} '.format(j, i, i * j))
f.write('\n')
f.close()
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 =
20 5 x 5 = 25
table = []
for i in range(1, 10):
newline = ''
for j in range(1, i + 1):
newline += '{:1d} x {:1d} = {:2d} '.format(j, i, i * j)
newline += '\n'
table.append(newline)
f = open('./my9x9table0.txt', 'w')
f.writelines(table)
f.close()
In [ ]: f = open('./my9x9table0.txt', 'r')
ln = f.read()
print(ln)
f.close()
Out [ ]: 1x1=1
1x2=22x2=4
1x3=32x3=63x3=9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6
= 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7
= 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8
= 48 7 x 8 = 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9
= 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
If size is given, only that number of bytes will be read, as shown in the
next example:
In [ ]: f = open('./my9x9table0.txt', 'r')
print(ln)
f.close()
Out [ ]: 1x1=1
1x2=22x2=4
1x3=32x3=63x3=9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1
In [ ]: f = open('./my9x9table0.txt', 'r')
ln = f.readline(3)
print(ln, end='')
f.close()
Out [ ]: 1x
Using this method to read all the lines of the 9 × 9 multiplication table in
the file shown in the previous examples, we will need to put it in a loop and
read line by line until the end of the file. In Python, however, there is no
effective way to test if it has reached the end of the file. For this particular
file, since we know there is no blank line before the end of the file, we will
use an empty string to signify the end of the file. The revised code is shown
below:
In [ ]: f = open('./my9x9table0.txt', 'r')
while True:
ln = f.readline()
print(ln, end='')
break
f.close()
Out [ ]: 1x1=1
1x2=22x2=4
1x3=32x3=63x3=9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6
= 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7
= 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8
= 48 7 x 8 = 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9
= 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
The code above does not look so neat. In fact, since the text file is treated
as an iterator in Python, with one item for each line, the above code can be
simply written as follows:
f = open('./my9x9table0.txt', 'r')
for ln in f:
print(ln, end = '')
f.close()
Considering the fact that a text file is an iterator, the built-in function
next(iterator) can be used to iterate the file line by line. However, it would
raise a StopIteration error if it reached the end of the file. The following
example shows how to use next(iterator) to read and print the entire
multiplication table:
In [ ]: f = open('./my9x9table0.txt', 'r')
try:
while True:
print(line, end='')
except (StopIteration):
Out [ ]: 1x1=1
1x2=22x2=4
1x3=32x3=63x3=9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30 6 x 6
= 36
1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7
= 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x 8
= 48 7 x 8 = 56 8 x 8 = 64
1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45 6 x 9
= 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
In [ ]: f = open('./my9x9table0.txt', 'r')
while True:
pt = f.tell()
line = f.readline()
break
f.close()
Out [ ]: 0: 1 x 1 = 1
15: 1 x 2 = 2 2 x 2 = 4
43: 1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
84: 1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
138: 1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
205: 1 x 6 = 6 2 x 6 = 12 3 x 6 = 18 4 x 6 = 24 5 x 6 = 30
6 x 6 = 36
285: 1 x 7 = 7 2 x 7 = 14 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35
6 x 7 = 42 7 x 7 = 49
378: 1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40
6 x 8 = 48 7 x 8 = 56 8 x 8 = 64
484: 1 x 9 = 9 2 x 9 = 18 3 x 9 = 27 4 x 9 = 36 5 x 9 = 45
6 x 9 = 54 7 x 9 = 63 8 x 9 = 72 9 x 9 = 81
603:
The output above shows where each line starts. For example, the end of
the file is at 603. So with this information, the code using the
readline([size]) method to read the multiplication table previously given can
be easily revised to the following:
f = open('./my9x9table0.txt', 'r')
while f.tell() != 603: # we use the read location to identify if it
has reached the end of the file
line = f.readline()
print(line, end = '')
f.close()
In [ ]: f = open('./my9x9table0.txt', 'r')
f.seek(138)
pt = f.tell()
line = f.readline()
Out [ ]: 138: 1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
In [ ]: f = open('./my9x9table0.txt', 'r+')
f.seek(138)
pt = f.tell()
line = f.readline()
f.seek(138, 0)
f.close()
Out [ ]: 138: 1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
The updated content of the file is shown below:
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 1update this line
= 20 5 x 5 = 25
Note that if there is less new content than the original, only part of the
original is replaced.
We can also replace a single original line with multiple lines, as shown
below:
In [ ]: f = open('./my9x9table0.txt', 'r+')
f.seek(138)
pt = f.tell()
line = f.readline()
f.seek(138, 0)
written\n")
f.close()
Out [ ]: 138: 1 x 5 = 5 2 x 5 = 10 3 x 5 = 15 4 x 5 = 20 5 x 5 = 25
However, if the total size of the new written data is longer than the line
being replaced, part of the line or lines under will be overwritten. Therefore,
if you want to replace a specific line of the text file exactly, you will need to
write just enough to cover the existing data—no more, no less.
f.close()
1 x 1 = 1
1 x 2 = 2 2 x 2 = 4
1 x 3 = 3 2 x 3 = 6 3 x 3 = 9
1 x 4 = 4 2 x 4 = 8 3 x 4 = 12 4 x 4 = 16
1 x 5 = 5 2 x 5 = 1we write a line at the current position
we write another line below
we add third line below the two lines already written
4 3 x 7 = 21 4 x 7 = 28 5 x 7 = 35 6 x 7 = 42 7 x 7 = 49
1 x 8 = 8 2 x 8 = 16 3 x 8 = 24 4 x 8 = 32 5 x 8 = 40 6 x
8 = 48 7 x 8 = 56
Please note that only part of the content in the file is left.
If the file is opened in w or w+ mode, the file will be truncated to a size
of 0 regardless.
With all we have learned so far, we are ready to design and code a
program to analyze an article stored in a text file. The program is shown in
Table 5-8.
The To analyze the article, we need to read the file into memory,
analysis build a list of words used in the article, then count how many
and times each word appears in the article. Because the file needs
design to be read line by line, we will read, analyze, and count the
words in each line. How can we store the result containing the
unique words and the number of times each word appeared in
the article? Recall what we learned about dictionaries: each
unique word can be used as a key, and the number of times
the word appears can be the value. We then just need to
determine the words used most often in the article. The best
way to do that would be to sort the items of the dictionary
based on the values (instead of keys), then take the first 10
items as the result. The algorithm is as follows:
1. Prepare by creating a list of punctuation marks and a list of
nonessential words that can be ignored.
2. Initialize by setting the counter to 0, w_dict = {}.
3. Read the first line from the article into the memory.
4. Build a list of all words within the line:
a. replace all the punctuation marks with whitespace
b. split the entire article at whitespace to build a list of
words
c. remove all nonessential words from the list
5. Add the length of the list to the word counter:
a. get a word from the list
b. if the word is already in w_dict, increase the value by 1;
otherwise, add dictionary item (word:1) to w_dict
c. repeat step 5
6. Repeat steps 3–5 on the next line until there are no
remaining lines in the file.
7. Sort w_dict based on the values.
8. Print out the first 10 items to show the words used most
often by the article’s author.
Please note that this is just an example of programming with
text files and Python dictionaries. The underlying theory
about writing style may not be sound. The words that appear
most often in an article may also be relevant to the topics
covered by the article.
The """
code This program finds out the frequencies of all words used in a news
"""
def news_analysis(article="WritingProposal.txt"):
f = open(article, 'r')
punctuations = ['//', '-', ',', '.', ':', '"', '[', ']', '(', ')',
for m in f: # this will lead the PVM to read the file line by
line
for c in punctuations:
words = m.split(f"{space}")
for w in words:
if w == '':
continue
else:
for w in less_meaningful:
words = m.split(f"{space}")
for w in words:
if w == '':
continue
else:
if w not in w_dict.keys():
unique_count += 1
w_dict.update({w: 1})
else:
w_dict[w] += 1
f.close()
result = news_analysis()
for i in range(20):
Exercises
Projects
1. Write a program that reads a text from a user, then counts and
displays how many words and how many alphanumeric letters are
in the text.
2. Write a program that
a. reads a series of numbers that are separated by whitespace
and uses a new line to end the input, then converts the
numbers in the input string and puts them into a list.
b. sorts the numbers in the list in descending order, using the
sort() list object method.
c. sorts the numbers in the list in descending order, using the
Python built-in function sorted().
Write your own code to sort the numbers in the list in ascending
order without using the sort() method or sorted() function.
3. Sorting is a very important operation in computing and
information processing because it is much easier to find a
particular item (a number or a word) from a large collection of
items if the items have been sorted in some manner. In computer
science, many algorithms have been developed, among which
selection sort, bubble sort, insertion sort, merge sort, quick sort,
and heap sort are the fundamental ones. For this project, search
the internet for articles about these sorting algorithms. Choose
one to sort a list of integers.
4. Every course offered at universities has a course number and a
title. For this project, write an application that uses a dictionary to
save course information, allows users to add a course into the
dictionary, and allows a user to get the title of a course for a given
course number. The application should perform the following
functions:
a. Get a course number and name from a user and add an
item, with the course number as key and the name as
value, to the dictionary if the course doesn’t already exist
in the dictionary.
b. Get a course number from a user, then find out the name
of the course.
c. Display a list of all the courses in the dictionary showing
the course numbers as well as names.
d. Quit the application.
Hint: You will need a top-level while loop, which displays a
menu showing the four options then acts accordingly.
5. This project is about text analysis. Find a news article on the
internet, analyze the content, and generate and display some
statistical data from the article. The detailed requirements are as
follows:
a. Find a news article on the internet and save it as a text file
on your computer.
b. Have your program build a list of words in the article
while reading the news content from the file.
c. Generate and display the following statistics of the article:
i. the total number of words in the article
ii. a list of unique words
iii. the frequency of each unique word in the article
iv. a short list of words that represent the essence
of the article
v. a table with the above data nicely presented
6. Cryptography is the study of theory and technology for the
protection of confidential documents in transmission or storage. It
involves both encryption and decryption. In any cryptographic
scheme, encryption is the process of converting plaintext to
ciphertext according to a given algorithm using an encryption
key, whereas decryption is the process of converting encrypted
text (ciphertext) back to plaintext according to a given algorithm
using a decryption key. If the encryption key and decryption key
are the same in a cryptographic scheme, the scheme is a
symmetric cryptographic scheme; if the two keys are different,
the scheme is an asymmetrical cryptographic scheme.
Among the many cryptographic schemes, substitution is a classic
one, though the scheme is prone to frequency analysis attack.
Write a program that can
a. automatically generate a substitution key and add it to a
key list stored in a file.
b. display the substitution keys in the file.
c. allow the user to choose a key in the list and encrypt some
text taken from the user.
d. allow the user to choose a key to decrypt an encrypted text
taken from the user.
e. allow the user to choose a key, encrypt the content of a
text file, and save the encrypted content into a different
file.
f. allow a user to choose a key, decrypt the encrypted content
in a file, and display the plaintext decrypted content.
OceanofPDF.com
Chapter 6
Define and Use Functions
Learning Objectives
After completing this chapter, you should be able to
As you will see, many Python modules, available via either Python
distribution or a third party, have also defined functions ready for you to use
in your programs.
For functions defined in a standard or third-party module, you must
import the module before you can call the function by using the dot notation
or operator, such as m.f(…), where m is a name referring to the module, and
f is the name of the function to be used. Within the pair of parentheses are
data as arguments of the function call, to be passed to the function for
processing. The following is an example calling the pow() function from
the math module:
>>> import math
>>> math.pow(35,12)
3.3792205080566405e+18
In [ ]: def factorial(n):
return None
r = 1
for i in range(n):
r *= (i + 1)
return r
In [ ]: N = 16
fn = factorial(N)
Sometimes you need to return more than one value from a function. To
do that, you can either put the values in a compound data type such as a list,
tuple, set, or dictionary, or just put the value all behind return. In the latter
case, the values will be automatically packed in a tuple by the return
statement.
The following example calculates and returns both the quotient and
remainder of two integers at the same time.
== 0):
return None
return n // m, n % m
n, m = 23, 5
m)}.')
The In this case study, we are going to write a program to ask for a
problem big integer from the user, then find all the perfect numbers
smaller than the big integer.
The Step 1. Take an input from user, and convert it into an integer
analysis Step 2. Loop from 2 to the big integer
and a. Test each integer to see if it is a perfect number
design b. If yes, print the number and all its factors
Step 3. Finish
Steps to check if a number is a perfect number:
Step 4. Find all its factors, including 1 but excluding the
number itself, and put them into a list
Step 5. Sum up the factors with sum(factors)
Step 6. If the number == sum(factors), then return True.
The """
code This program is used to find all the perfect numbers that are less
"""
def perfect(n):
if n % j == 0: # if j is a factor
else:
test = perfect(i)
if test[0]:
print(f"{i} = {test[1]}")
func_demo1(1, 2, 3)
Out [ ]: a = 1, b = 2, c = 3
This shows that the first argument was passed to the first parameter a, the
second argument was passed to the second parameter b, and the third
argument was passed to the third parameter c.
When calling a function, its parameter name, such as x, can be used as a
keyword to explicitly indicate that a specific value, such as v, will be passed
to x. This is done using x = v syntax, called a keyword argument in a
function call. The following example shows how keyword arguments are
used.
func_demo1(b =1, a = 2, c = 3)
Out [ ]: a = 2, b = 1, c = 3
In this case, the order of the arguments does not matter because the code
explicitly indicates which argument is given to which parameter. Please
note that in a function call when keyword argument is used, no more
positional arguments, except variable-length nonkeyword arguments, may
follow. An error will occur otherwise, as shown below:
func_demo1(3, 1, a = 2)
Out [ ]: ----------------------------------
TypeError Traceback (most recent call last)
<ipython-input-185-f540d2127799> in <module>
2 print(f'a = {a}, b = {b}, c = {c}')
3 ---->
4 func_demo1(3, 1, a = 2)
TypeError : func_demo1() got multiple values for
argument 'a'
print(powerof(12))
print(powerof(23, 5))
print(powerof(13, y = 6))
In [ ]: def product(*n):
s = 1
for i in n:
s *= i
print(product(1,2,5,32,67))
print(product(11,32,25,3,7))
print(product(19,12,15,322,6))
Out [ ]: Product of all numbers in (1, 2, 5, 32, 67) is 21440
Product of all numbers in (11, 32, 25, 3, 7) is 184800
Product of all numbers in (19, 12, 15, 322, 6) is 6607440
In [ ]: def reporting(**kwargs):
for k, v in kwargs.items():
print(f'{k}:{v}')
reporting()
Out [ ]: First_name:John
Last_name:Doe
Sex:Male
for k, v in ps.items():
print(f'{k}:{v}')
dict_reporting(pdict)
Out [ ]: First_name:John
Last_name:Doe
Sex:Male
In [ ]: def product_tuple(nt):
s = 1
for i in nt:
s *= i
print(product_tuple((1,2,5,32,67)))
print(product_tuple((11,32,25,3,7)))
print(product_tuple((19,12,15,322,6)))
Coding Practice
because the dots (…) do not make sense to computers in this context. With
what you have learned so far, the function can be defined as
def fac(n):
if n == 0:
return 1
product = 1
for i in range(n): # using loop
product *= (i + 1)
return product
Table 6-2: Case study: How to use a recursive function for calculating factorial n
code if n == 0:
return 1
else:
return n * fac(n - 1)
n = 9
print(f"{n}! = {fac(n)}")
The 9! = 362880
result
As you can see, the function has become shorter and neater, although it
often takes more memory and more time to run.
The next case study, in Table 6-3, shows how a recursive function can be
used to find the greatest common divisor of two integers.
Coding Alert
The This simple problem aims to find the greatest common divisor
problem (GCD) for two given integers. A common divisor of two
integers is an integer that can divide both integers, and the
GCD is the biggest one among the common divisors. For
example, 1 and 2 are common divisors of 4 and 6, and 2 is the
GCD of 4 and 6.
code Ask for two integers and find the GCD of the two using the improved
Euclidean algorithm.
"""
global depth
if b == 0: # condition to finish
return b
else:
return my_gcd(a, b)
if i < j:
i, j = j, i
depth = 0
As noted, the program took 30 recursions to find the GCD of 3238 and
326. Can we make it more efficient? The answer is yes, and it is fun to
design and code a better and faster program to solve a problem, as shown in
the case study of this same problem in Table 6-4.
The This simple problem aims to find the greatest common divisor
problem (GCD) for two given integers. A common divisor of two
integers is an integer that can divide both integers, and the
GCD is the biggest one among the common divisors. For
example, 1 and 2 are common divisors of 4 and 6, and 2 is the
GCD of 4 and 6.
The """
code Ask for two integers and find the GCD of the two using the improved
Euclidean algorithm.
"""
def my_gcd(a, b):
global depth
return a
else:
return my_gcd(a, b)
if i < j:
i, j = j, i
depth = 0
As you can see, for the same numbers, the improved algorithm took only
six recursions, whereas the original took 30. Another benefit of using the
improved algorithm is that because Python Virtual Machine (PVM) has a
limit on the maximum depth of recursions due to the limitations of
computer memory, the improved algorithm will be able to handle much
bigger numbers than the original algorithm. You may run the two programs
on 24230336504090 and 356879542 to see the difference between the two
algorithms.
We can then call the function with the name, as shown below:
>>> double(23)
46
Our next anonymous function takes two arguments and checks if one is a
multiple of the other:
>>> is_multiple = lambda m, n: m % n == 0
>>> is_multiple(32, 4)
True
>>> is_multiple(32, 5)
False
The next section will show how lambda expressions can be used to
program more effectively.
Mapping
It is easier to explain what mapping does with a code example:
>>> integers = [-12, 32, -67, -78, -90, 88] # this list has
negative numbers
>>> list(map(abs, integers)) # this maps the function abs to each
integer in the list
[12, 32, 67, 78, 90, 88]
Note that abs() has been applied to every member of the list.
Basically, the map function can apply any function to as many lists as
required for its arguments. The following is an example:
>>> def sum(a, b): # this function requires two arguments
… return a + b
…
>>> list(map(sum, [1, 2, 3], [5,8,9])) # this maps the sum function
to two lists for the two arguments
[6, 10, 12]
Given what you have already learned about anonymous functions, you
can generate a list of odd numbers neatly, as follows:
>>> list(map(lambda n: 2 * n + 1, range(10)))
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
Filtering
The filtering function takes the same form as the mapping function but is
used to extract items from the iterable that satisfy the Boolean filtering
condition at hand. The following sample code keeps only even numbers in
the generated list:
>>> def even(n):
… return n % 2 == 0 # if it can be divided by 2, then return true;
return false otherwise
…
>>> list(filter(even, range(10))) # filter applies to each even
number and keeps only some
[0, 2, 4, 6, 8]
Note that only the words that include the letter o are selected.
Reducing
The reduce function is not a built-in function but defined in the functools
module. It takes the same form as the mapping and filtering functions but
applies the function to items in the iterable progressively until the list is
exhausted and reduced to a single value or object, as shown in the following
example in JupyterLab:
return m ** n
Out [ ]: 1152921504606846976
Out [ ]: 1152921504606846976
As seen from the examples above, a lambda expression becomes handy
when you use a function only once and the function is simple enough to be
written with an expression.
In [ ]: def isPerfect(n):
factor = [1]
if n % j == 0:
factor.append(j)
if n == sum(factor):
else:
for i in range(m):
testResult = isPerfect(i)
if testResult[0]:
myPerfects = perfectGenerator(10000)
print(myPerfects)
As we can see, instead of returning a list of all the perfect numbers and
factors within the given range, the function actually returned a generator.
To get the next perfect number in the generator, we use the built-in
function next, as shown below:
In [ ]: print(next(myPerfects))
print(next(myPerfects))
print(next(myPerfects))
print(next(myPerfects))
print(next(myPerfects))
In [ ]: myPerfects = perfectGenerator(10000)
for p in myPerfects:
print(p)
In [ ]: import time # time module for time and timing related functions
memory usage
def isPerfect(n):
factor = [1]
for j in range(2, (n // 2) + 1):
if n % j == 0:
factor.append(j)
if n == sum(factor):
else:
perfects=[]
testResult = isPerfect(i)
if testResult[0]:
perfects.append((i, testResult[1]))
return perfects
t0 = time.process_time()
perfectNumbers = getAllPerfects(10000)
t1 = time.process_time()
In [ ]: import time # time module for time and timing related functions
memory usage
def isPerfect(n):
factor = [1]
if n % j == 0:
factor.append(j)
if n == sum(factor):
else:
for i in range(m):
testResult = isPerfect(i)
if testResult[0]:
t0 = time.process_time()
myPerfects = perfectGenerator(10000)
t1 = time.process_time()
numbers")
The first code sample is to find a list of perfect numbers within a given
range using a normal function to return a list of perfect numbers, whereas
the second code sample uses a generator instead. As you can see, to get a
generator of perfect numbers took no time (0.0 seconds), whereas using a
function to return a list of perfect numbers took 1.1875 seconds.
The gain from returning a generator instead of a complete list from a
function is even more obvious in terms of memory usage, because a list
would usually take a bigger chunk of computer memory, which increases
drastically along with the growth of the list, whereas for a list generator, the
memory usage is determined by the coding of the function and will not
change. In our examples above, the generator that generates perfect
numbers from 1 to 100000 has almost the same number of lines of code as
the function that produces a list of perfect numbers in the same range, but
the function consumes much more memory than the generator because of
the use of list. To get a sense of how much memory would be consumed by
a bigger list, see the following example:
In [ ]: import sys
{sys.getsizeof(list(range(100)))}Bytes")
{sys.getsizeof(list(range(1000)))}Bytes")
{sys.getsizeof(list(range(10000)))}Bytes")
As you can see, a simple list containing integer numbers from 0 to 10000
takes up almost 90KB of memory.
6.7 Closures: Turning a Function into a Closure
In Python and some other programming languages such as JavaScript,
closures are the result of a nested function—that is, one function that is
defined inside another—as shown in the following example:
In [ ]: def outer(greeting):
print('Good morning!')
def inner(msg):
print(msg)
inner(greeting)
outer('Good day!')
In the example above, the outer function can also return the inner
function with the parameter list as a first-order object, as shown below:
In [ ]: def outer():
def greet(who):
print(greeting, who)
return greet
The output was produced when you input Joe for the name.
What has been returned from call of outer() is a function object.
However, because of the way the function is defined and returned, the value
of the variable greeting, defined locally within the outer function, has been
attached to the inner function object. This is called closure—the binding of
certain data to a function without actually executing the function.
t0 = time.asctime()
number
number
call_args = ''
if args:
call_args += str(args)
if kwargs:
call_args += str(kwargs)
{call_args}\n"
logs.write(log_str)
{log_str}")
return func_handle
return wrapper_function
factors
if n%f == 0: # f is a factor of n
if not f in factor_list:
factor_list.append(f)
return factor_list
# function to find all perfect numbers in a given range
c = a; a = b; b = c
perfect numbers
factor_list = factors(n)
if n == sum(factor_list):
return perfect_list
def do_perfect():
success = False
True
try:
a, b = int(num1), int(num2)
perfect_list = perfect_numbers(a, b)
for n in perfect_list:
except ValueError:
except ZeroDivisionError:
number.")
except Exception as e:
# end of do_perfect
do_perfect()
[8128, [1, 2, 4, 8, 16, 32, 64, 127, 254, 508, 1016, 2032, 4064]]
Call to do_perfect
was made at Mon Mar 13 13:18:15 2023, taking
5.2627036571502686
Call to do_perfect
was made at Mon Mar 13 13:18:15 2023, taking
5.2627036571502686
As you can see, although a decorated function is called in the same way
as other functions, a lot of other things can be done through a decorator
during the call.
It is also worth noting that perfect numbers are very rare. Between 3 and
10000, there are only four perfect numbers, and it took a little over
5 seconds to find them. Tested on the same machine, it took more than
100 second to look for all the perfect numbers between 3 and 100000, and
there are no perfect numbers between 10000 and 100000.
__DOC__
This holds the function’s docstring, written by the programmer, or None if
no docstring is written by the coder. The docstring will show up when the
help() function is called on a function, though help() will also show some
standard information even if no docstring is available.
__NAME__
This contains the name of the function.
__QUALNAME__
This contains the qualified name of the function and is new to Python 3.3
and later versions. By qualified name, we mean the name that includes the
path leading to the location where the function is defined. For example, a
function F can be a method defined in a class C, which is defined in a
module M, in which case the qualified name will be M.C.F.
__MODULE__
This stores the name of the module in which the function was defined. It
contains None if module info is unavailable.
__DEFAULTS__
This stores a tuple containing default argument values for those arguments
that have defaults or stores None if no arguments have a default value.
__CODE__
This contains the actual code object representing the compiled function
body.
__GLOBALS__
This contains a reference to the dictionary that holds the function’s global
variables, the global namespace of the module in which the function was
defined. It is a read-only function automatically generated by Python
Virtual Machine (PVM).
__DICT__
This stores a dictionary describing names of attributes and their values in
the namespace of the function. In Python, a namespace is a mapping from
names to objects and is implemented as a Python dictionary.
__CLOSURE__
This stores a tuple of cells that contain bindings for the function’s free
variables. Each cell has an attribute called cell_contents from which a cell’s
value can be retrieved. It is automatically generated by PVM.
__ANNOTATIONS__
This stores a dictionary containing annotations of parameters. The keys of
the dictionary are the parameter names, and return as key for the return
annotation, if provided, and the values of the dictionary are the expected
data type of the parameters as well as the expected data type of the object to
be returned by the function.
__KWDEFAULTS__
This stores a dictionary containing default values for keyword-only
parameters.
Chapter Summary
• Functions are important building blocks of programs in almost all
programming languages.
• Different languages use different keywords to signify the
definition of a function. Python uses def to start the definition of a
function (and method within a class definition).
• In Python, the definition of one function can contain the definition
of other function or functions.
• A function can have positional arguments, variable-length lists of
arguments, and keyword arguments.
• When calling a function, the parameters for positional arguments
must come first, followed by variable-length lists of arguments.
Keyword arguments come last.
• A recursive function is a function that calls itself within its
definition.
• Anonymous functions are functions without a name. They begin
with the keyword lambda. Anonymous functions are useful when
the function is only used once.
• Mapping, filtering, and reducing are special functions that can
used to apply a function, including an anonymous function, to a
list of parameters.
• Mapping applies a function to each item of a list.
• Filtering applies some criteria specified in a Boolean function to a
list to filter out the items that do not meet the criteria.
• Reducing sequentially applies a function to the members of a list
and reduces the list to a single member.
• Functions are often used to process and return the results of
information processing using the return statement.
• In a function definition, the return statement can be replaced with
the yield statement to turn the function into a generator of a
sequence.
Note that a function cannot be turned into a generator by simply
replacing the return statement with a yield statement.
Exercises
F0 = 1, F1 = 1, Fn = Fn−1 + Fn−2
Projects
1. Study the federal personal income tax rates for the current tax
year and define a function that takes one argument as net taxable
income and calculates and returns the total federal income tax
due.
2. Study both the federal personal income tax rates and the
provincial tax rates for your province for the current tax year.
Define a function that takes one argument as net taxable income
and calculate and return both total federal income tax due and
total provincial tax due.
3. Modify the function defined for 6.6 by adding a keyword
argument with the default value f or F to tell the function to
calculate and return the federal tax due. If the argument passed to
the keyword parameter is p or P, then provincial tax due should be
calculated and returned. Test the modified function with different
values passed to the keyword argument to make sure it works as
expected.
4. The Tower of Hanoi is a mental game. It consists of three rods
and N disks of different sizes that can move onto any rod one by
one, but at no time is a bigger disk allowed to be on top of a
smaller disk. The three rods are labelled A, B, and C. The game
begins with all disks stack on rod A, and the goal is to move all
the disks onto rod C. Write a recursive function that takes one
argument as the number of disks initially on rod A and print out
the moves to be taken in order to move all the disks from A to C.
Each move can be represented as i: Rs Rd, where i is 0, 1, 2…, Rs
and Rd is A, B or C, but Rs and Rd cannot be the same. It means
that at step i, take one disk from source rod Rs and slide it onto
destination rod Rd. For example, if there are three disks on rod A,
the moves will be as follows:
1: A C, 2 : A B, 3 : C B, 4 : A C, 5 : B A, 6 : B C, 7 :
A C
OceanofPDF.com
Chapter 7
Object-Oriented Programming with Python
Learning Objectives
After completing this chapter, you should be able to
Abstraction
Abstraction is a very fundamental concept of object-oriented programming.
The concept is rather simple. Because an object in the real word can be very
complicated, containing many parts and with many attributes, it would be
practical to consider only those parts and attributes that are relevant to the
programming tasks at hand. This simplified model of a real-world object is
an abstraction of it.
Inheritance
Inheritance is a very important concept of object-oriented programming,
and inheriting is an important mechanism in problem solving and system
development with the object-oriented approach. The underlying philosophy
of inheritance is how programmers describe and understand the world. Most
often, things are categorized and put in a tree-like hierarchy with the root on
the top, as shown in Figure 7-1 below. In such a tree-like hierarchy, the root
of the tree is the most generic class or concept, and the leaves are the most
specific and often refer to specific objects. From the root down to the
leaves, nodes on a lower level will inherit the properties of all the connected
nodes at higher levels.
class Computer(builtins.object)
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
We can check the result using the help statement, as shown below:
>>> help(PC)
Help on class PC in module __main__:
class PC(Computer)
| Method resolution order:
| PC
| Computer
| builtins.object
|
| Data descriptors inherited from Computer:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
This shows that the class PC has been created, which is a subclass of
Computer.
Although the Computer class contains nothing in its original definition,
we can create an instance of the class, add attributes to the instance, and
manipulate the attributes using some built-in functions. For example, we
can use the setattr function to add an attribute called CPU to an instance of
the Computer class, as shown below:
>>> c = Computer() # to create an instance of the Computer class
>>> setattr(c, 'CPU', 'Intel i6800')
>>> c.CPU
'Intel i6800'
As you can see, the c object has an attribute called CPU and its value
intel i6800.
In addition to setattr, Python has a number of built-in functions available
for class and object manipulation. These built-in functions are summarized
in Table 7-1.
Built-in
function Operation Coding example
<built-in function
sqrt>
>>> getattr(math,
'e')
2.718281828459045
Built-in
function Operation Coding example
True
>>> hasattr(math,
'sqrt')
True
>>> s1 = student()
>>> setattr(s1,
'name', 'John')
>>> s1.name
'John'
'name')
>>> hasattr(s1,
'name')
False
Built-in
function Operation Coding example
>>> s1 = student()
>>> isinstance(s1,
student)
True
C graduate(student):
… pass
>>>
issubclass(graduate,
student)
True
object o "<class
'__main__.graduate'>"
The rest of this section describes in detail how to define classes in Python
—in particular, how to define attributes and methods in a class definition.
Your journey to learn OOP begins with modelling a small world, shapes,
which include the circle, rectangle, and triangle.
First, define an abstract class called shape, as shown in Table 7-2.
1 """
3 """
5 class Shape:
7 def circumference(self):
8 """Method to be overridden."""
9 pass
10
11 def area(self):
Code sample in Python interactive mode
12 """Method to be overridden."""
13 pass
14
15 class Circle(Shape):
17 self.radius = radius
18
Shape
21
24
25 c1 = Circle(35)
{c1.area()},")
1 """
3 """
5 class Shape:
7 def circumference(self):
8 """Method to be overridden"""
9 pass
10
11 def area(self):
Code sample in Python interactive mode
12 """Method to be overridden"""
13 pass
14
15 class Rectangular(Shape):
17 self._length = length
18 self._width = width
19
20 def circumference(self):
22
23 def area(self):
25
26 def is_square(self):
28
30
{rt1.circumference()}, and")
Note that class Rectangular not only has overridden two methods of
Shape but has also defined a new method named is_square() to test if the
rectangular is a square.
Inheritance: Subclass and Superclass
If you want to inherit from other base classes when defining a new class in
Python, you need to add all the base classes to the list of inheritances
enclosed in a pair of parentheses, as shown below:
class myClass(base_1, base_2, base_3):
pass
The new class will inherit all the attributes and methods from base_1,
base_2, and base_3 and override the methods defined in the base classes.
In Python, all classes are a subclass of the built-in base object class and
inherit all the properties and methods of object, even if object is not
explicitly included in the inheritance list. So the following two statements
will have the same effects:
In [ ]: class myClassA:
pass
dir(myClassA)
In [ ]: class myClassB(object):
pass
dir(myClassB)
As you can see, myClassA and myClassB both inherit from the base class
object. However, in the list, some of the dunder names such as __le__ and
__ge__ inherited from base class object are merely wrapper descriptors. If
you want to make real use of these wrapper descriptors in your class, you
will need to override them. Some inherited dunder methods can be used, but
the values returned are not so useful. In particular, you will need to override
the dunder methods __init__ __str__, and __repr__. The method __init__ is
a dunder method used as constructor called internally by PVM whenever a
new instance of a class needs to be created. The method __str__ is a dunder
method called internally whenever an object of a class needs to be
converted to a string, such as for printout. Finally, __repr__ is a dunder
method called internally when an object needs to be converted to a
representation for serialization—a process that converts a Python object
into a byte stream that can be stored or transmitted.
In [ ]: class Student:
self._firstname = firstname
self._lastname = lastname
s0 = Student('Jim', 'Carte')
print(s0._firstname, s0._lastname)
In our example about shapes, _width and _length are protected attributes
of the class, which should only be accessible within the class or its
subclasses and should be hidden from the outside.
In contrast, the rule on private members, those with names prefixed with
a double underscore __, is strictly enforced in Python. So if we change
firstname and lastname to private members, it will raise exceptions, as
shown in the following example:
In [ ]: class Student:
self.__lastname = lastname
s0 = Student('Jim', 'Carte')
print(s0.__firstname, s0.__lastname)
If you want to access the private members of a class from outside, the
built-in functions setattr and getattr can be used to access both private and
protected members of a class or its instance, as shown below:
In [ ]: class Student:
self.__firstname = firstname
self.__lastname = lastname
s0 = Student('Jim', 'Carte')
Class Methods
As we have seen, in Python, special method __init__ is used as a
constructor of the class. People familiar with C++ or Java might be
wondering if __init__ can be overloaded or defined multiple times in
Python to make multiple constructors, because a class in C++ and Java can
have two or more constructors with different signature. In Python, however,
a class cannot have more than one __init__ effectively defined. If you
define two or more __init__ within a class definition, only the last one will
take effect.
So how can you create an instance of a class differently in Python if there
can be only one constructor, the special __init__ method, in a class
definition? The solution is to use the class method, as shown in the next
example:
In [ ]: class Graduate:
self.firstname = firstname
self.lastname = lastname
g1 = Graduate.newGraduate('John', 'Doe')
Static Methods
Similar to the class method of a class, a static method can be called directly
through the class. The difference is that in the definition of a static method,
no parameter refers to the class nor to the instance itself. Its usefulness may
be demonstrated by the example below, where we define a class called
Convertor, and within the class definition, we define a number of static
methods, each of which convert values from one unit to another:
In [ ]: class Convertor:
@staticmethod
def kg2lb(w):
return w * 2.20462
@staticmethod
def lb2kb(w):
return w/2.20462
@staticmethod
def metre2feet(l):
return l * 3.28084
@staticmethod
def feet2metre(l):
return l / 3.28084
@staticmethod
def C2F(d):
return (d * 9 / 5) + 32
@staticmethod
def F2C(d):
return (d - 32) * 5 / 9
@staticmethod
def acr2hec(a):
return a * 0.404686
@staticmethod
def hec2arc(a):
return a / 0.404686
print(Convertor.kg2lb(123))
print(Convertor.C2F(21))
Out [ ]: 271.16826
69.8
As you can see from the above example, the static methods can be called
directly through the class Convertor, without an instance. Defining a static
method within a class is a way to add utility functions to the class so that it
can be used without instantiating an object.
Class Attributes
As previously mentioned, in Python, you can define a class without
explicitly declaring attributes of the class. However, Python does allow the
explicit declaration of attributes within a class definition. These attributes
are called class attributes. Explicit declaration of an attribute within a class
definition means that the attribute is declared outside of the __init__
method. In the following example, student_id is declared as a class
attribute.
In [ ]: class Graduate:
self.f_name = firstname
self.l_name = lastname
self.__class__.student_id += 1
@classmethod # decorator
def __str__(self):
g0 = Graduate('James Gord')
print(g0)
g1 = Graduate.newGraduate('John', 'Doodle')
print(g1)
From this example, you can see how a class attribute is used and shared
among all the instances of the class. You can create student_id as a class
attribute to dynamically track the student IDs allocated to new students—a
new instance of the class Graduate. It starts from 20201195 and increases
by one every time a new student is enrolled.
Note the dunder name __class__ used in the example. In Python,
__class__ refers to the class of an object. So in the example above,
self.__class__ refers to the class of object self—that is, Graduate. If you do
not have __class__ between self and student_id but simply use
self.student_id, student_id would become an attribute of each instance of
the class, different from the class attribute, as demonstrated in the following
example:
In [ ]: class Graduate:
student_id = 20201195
self.f_name = firstname
self.l_name = lastname
self.student_id += 1
g0 = Graduate('James Gord')
print(g0)
g1 = Graduate('John Doodle')
print(g1)
__CALL__
Dunder method __call__ can be used to make an object, an instance of
class, callable, like a function. In the following example, a class is defined
as Home, which has two attributes: size and value. In addition to __init__ as
a constructor, a dunder function __call__ is defined, which turns object h1,
an instance of class Home, into a callable function.
In [ ]: class Home():
self.size = size
self.value = value
if check == 'size':
return self.size
return self.value
else:
return self.value/self.size
h1 = Home(3270, 986500)
Out [ ]: 301.68195718654437
3270
986500
What can be done through dunder method __call__ can also be done
through a normal method, say checking. The obvious benefit of using the
dunder method __call__ is cleaner and neater code.
__NEW__
Dunder method __new__ is a method already defined in the object base
class. It can be overridden to do something extra before the creation of a
new instance of a class. Dunder method __ new__ itself doesn’t create or
initialize an object for a class. Instead, it can check, for example, if a new
object can be created. If the answer is yes, then it will call __init__ to do the
actual work of creation and initialization, as shown in the following
example:
In [ ]: class TravelPlan():
_places = dict()
_step = 0
if newPlace in TravelPlan._places.values():
return newPlace
else:
TravelPlan._places[TravelPlan._step] = newPlace
print(f'{TravelPlan._places[TravelPlan._step]} is added.')
TravelPlan._step += 1
@staticmethod
def printPlan():
for pl in TravelPlan._places:
TravelPlan('Calgary')
TravelPlan('Toronto')
TravelPlan('Calgary')
TravelPlan.printPlan()
__STR__
Dunder method __str__can be used to implement the string representation
of objects for a class so that it can be printed out by using the print
statement. The method will be invoked when str() function is called to
convert an object of the class to a string. In our definition of class Graduate
in our earlier example, the __str__ has been implemented to just return the
full name of a student. You may, of course, choose to return whatever string
you think would better represent the object for a given purpose.
__LEN__
Dunder method __len__ can be used to return the length of an object for a
class. It is invoked when function len(o) is called on object o of the class. It
is up to the programmer to decide how to measure the length, though. In our
definition of class Graduate, we simply use the sum of the first name, last
name, and id length.
__REPR__
Dunder method __repr__ can be used to return the object representation of
a class instance so that, for example, the object can be saved to and
retrieved from a file or database. An object representation can be in the
form of a list, tuple, or dictionary, but it has to be returned as a string in
order to be written to and read from a file or database. The __repr__ method
will be invoked when function repr() is called on an object of the class. The
following example extended from the definition of class Graduate shows
how dunder methods __str__, __len__, and __repr__ can be defined and
used.
In [ ]: class Graduate:
student_id = 20201195
self.firstname = firstname
self.lastname = lastname
self.__class__.student_id += 1
@classmethod
def __str__(self):
def __len__(self):
len(str(self.student_id))
def __repr__(self):
__DELITEM__
This is called to implement the deletion of self[key].
__MISSING__
This is called by dict.__getitem__() to implement self[key] for dict
subclasses when the key is not in the dictionary.
__ITER__
This is called when an iterator is required for a container.
__REVERSED__
This can be implemented and called by the reversed() built-in function to
implement a reverse iteration.
__CONTAIN__
This is called to implement membership test operators. It should return True
if the item is in self and False if it is not.
__DELETE__
This is called to delete the attribute on an instance of the owner class.
Tables 7-4, 7-5, 7-6, and 7-7 show a comprehensive list of dunder
methods and their respective operators that can be overridden by
programmers when defining new classes.
+ object.__add__(self, other)
- object.__sub__(self, other)
* object.__mul__(self, other)
// object.__floordiv__(self, other)
/ object.__truediv__(self, other)
% object.__mod__(self, other)
^ object.__xor__(self, other)
| object.__or__(self, other)
+= object.__iadd__(self, other)
-= object.__isub__(self, other)
*= object.__imul__(self, other)
/= object.__idiv__(self, other)
%= object.__imod__(self, other)
^= object.__ixor__(self, other)
|= object.__ior__(self, other)
- object.__neg__(self)
+ object.__pos__(self)
abs() object.__abs__(self)
~ object.__invert__(self)
complex() object.__complex__(self)
int() object.__int__(self)
long() object.__long__(self)
float() object.__float__(self)
oct() object.__oct__(self)
hex() object.__hex__(self)
== object.__eq__(self, other)
!= object.__ne__(self, other)
In [ ]: class MyClass:
self.func = decorated
function")
function")
@MyClass
class ProgramTimer:
self.function = func
program_end_time = time()
return result
def i_list(max_l_int):
return l0
@ProgramTimer
def primesBySieving(upper_bound):
nl = i_list(upper_bound)
flag = True
while flag:
d = sl[0]
nl = sieving(d, nl)
sl = sl[1:]
return nl
ub = 2**19
pl = primesBySieving(ub)
{ub}")
In [ ]: class Employee:
self.firstname = firstname
self.lastname = lastname
names = fullname.split()
self.firstname = names[0]
self.lastname = names[1]
def getFullname(self):
e1 = Employee('Jack', 'Smith')
print(e1.fullname)
print(f'{e1.lastname}, {e1.firstname}')
In [ ]: class Student:
self.firstname = firstname
self.lastname = lastname
@property
def fullname(self):
def emailaddress(self):
return f"{self.firstname}.{self.lastname}@globalemail.com"
s0 = Student('John', 'Doe')
s0.lastname = 'Smith'
In [ ]: class Student:
self.firstname = firstname
self.lastname = lastname
@property
def fullname(self):
@fullname.setter
"""
"""
names = fullname.split()
self.firstname = names[0]
self.lastname = names[1]
s0 = Student('John', 'Doe')
print(s0.fullname)
s0.fullname = 'Kevin Smith'
print(s0.fullname)
Note that using a property decorator can make a method to be used like
an attribute/property without the need to allocate memory space to keep the
value of the attribute. As such, you cannot assign a value directly to such an
attribute.
s0=Shape()
s1=Shape()
print(f's0.points = {s0.points}')
print(f's1.points = {s1.points}')
print(f's0.points = {s0.points}')
print(f's1.points = {s1.points}')
print(f's1.points = {s1.points}')
In [ ]:
s0.shape_type = 'line'
Out [ ]: The shape is a line, with points [(1, 1), (12, 23)]
The second statement has proved that a new attribute shape_type has
been added to object s0, and now this particular instance of Shape is called
line.
A new attribute can also be added by using the built-in function setattr().
To add the shape_type attribute to s0 with setattr(), run the following
statement:
s0.shape_type
Out [ ]: 'rectangle'
An attribute can also be deleted from an object using the built-in function
delattr(). When you want to add or delete an attribute, but you are not sure
if the attribute exits, you can use built-in function hasattr() to check, as
shown below:
In [ ]: print(hasattr(s0, 'shape_type'))
delattr(s0, 'shape_type')
print(hasattr(s0, 'shape_type'))
Out [ ]: True
False
From now on, all instances of the Shape class will have an attribute
called shape_type, as shown in the examples below:
In [ ]: Shape.shape_type = 'point'
print(f's0.shape_type = {s0.shape_type}')
print(f's1.shape_type = {s1.shape_type}')
As you may have noted, the attribute shape_type and its value, added to
the Shape class, have been propagated to both s0 and s1 because the
shape_type attribute was added as a class attribute. By comparison, the
attribute later added to an individual instance of the class is the attribute of
that instance only. This is shown in the following code sample:
In [ ]: print(s0.points, s1.points)
s0.weight = 1
print(s0.weight)
hasattr(s1, 'weight')
Out [ ]: [(1, 1), (12, 23), (2, 3), (2, 3)] [(1, 1), (12, 23), (2, 3), (2,
3)]
1
False
The example shows that the new attribute weight was only added to
object s0, and s1 does not have the attribute. Again, if you want the weight
attribute and its value to be shared by all instances of the class, you have to
add the attribute to the class directly, as shown below:
In [ ]: Shape.weight = 1
Out [ ]: s0 weight = 1
s1 weight = 1
How can you add a new method to an already defined class? You can do
this in almost the same way as you would add new attributes to a class or
instance of a class, as shown in the following example:
for i, p in enumerate(self.points):
This provides programmers with so much power, as they can create new
classes and modify all aspects of classes dynamically. For example, we
know we can only define one __init__() in a class definition, so we only
have one constructor to use when creating new instances of the class. By
attaching a different properly defined method to the __init__ attribute, we
are now able to construct a new instance of a class in whatever way we
want, as shown in the following example:
In [ ]: def print_shape(self):
Shape.print_shape = print_shape
self.points = list(points)
self.shape_type = 'point'
self.points = list(points)
self.shape_type = 'line'
self.points = list(points)
self.shape_type = 'triangle'
Shape.__init__= c1 # constructor for one point
p1 = Shape((3,5))
print(p1.print_shape())
print(l1.print_shape())
print(t1.print_shape())
In [ ]: class Employee:
age : int = 20
self.firstname = firstname
self.lastname = lastname
def __str__(self):
return f'{self.firstname} {self.lastname}, {self.age},
{self.salary}'
def __repr__(self):
rdict = {'firstname':self.firstname,'lastname':self.lastname,
'age':self.age, 'salary':self.salary}
return f"{rdict}"
e1 = Employee('Jack', 'Smith')
e1.age =37
e1.salary = 56900
e2 = Employee('Jone', 'Doe')
With the __repr__() method for a class, you can save the representation
of these objects into a file. To use the object representations stored in a file,
you will need to write another function/method to pick up the information
from each object representation and add it to its respective object. The two
processes must work together to ensure that objects can be correctly
restored from files. Neither process is easy. Fortunately, there is a Python
module called pickle already developed just for this purpose.
In formal terms, saving data, especially complex data such as objects in
OOP, in permanent storage is called serialization, whereas restoring data
from permanent storage back to its original form in programs is called
deserialization. The pickle module is a library implemented for serializing
and deserializing objects in Python. The pickling/serializing process
converts objects with hierarchical structure into a byte stream ready to save
on a binary file, send across a network such as the internet, or store in a
database, whereas the unpickling/deserializing process does the reverse: it
converts a byte stream from a binary file or database, or received from a
network, back into the object hierarchy.
There are some good sections and documents on the internet that explain
how to use the pickle module for your Python programming needs. When
you do need to use it, be aware of the following:
Exercises
print(myClassB.__dict__)
dir(myClassB)
def getFullname(self):
return f'{self.firstname} {self.lastname}'
e1 = Employee('Jack', 'Smith')
print(e1.fullname)
e2 = e1
e2.fullname = 'John Doe'
print(e2.fullname)
Project
1. Using the Quiz_question and Quiz classes you developed in
Exercises 7 and 8 above, develop a terminal-based quiz system
that will allow the user to do the following:
• Create a quiz.
• Select a quiz and add new quiz questions.
• Select a quiz and preview all the quiz questions.
• Select a quiz and execute the quiz by presenting the quiz
questions one by one.
• At the end of the quiz, calculate the user’s score as a
percentage and show the correct answers to incorrectly
answered questions. The quiz questions should be
displayed to the user one by one during the quiz.
OceanofPDF.com
Chapter 8
Modules and Packages
Divide-and-conquer is a fundamental but effective strategy in problem solving as well as system design
and development. This is because big problems can often be divided into smaller problems that can be
easily solved or have already been solved, and large systems can often be made of smaller ones that can
be easily created or are already readily available. Not only that, but the divide-and-conquer method also
results in easier system maintenance, better quality insurance, quicker error detection and correction, and
better reusability.
In Chapter 6, we learned how functions can be used in problem solving, and in Chapter 7, we studied
object-oriented programming and learned how classes and objects can be used in system development
and to solve problems. In computing, both functions and objects are common programming technologies
that implement divide-and-conquer strategies.
In this chapter, we will study modules and packages that can also be used to implement the divide-
and-conquer strategy in programming. In this way, we will learn how to create and use modules in
programming and software development. We will also study some Python modules and packages that are
readily available and often needed to solve problems and develop computer applications.
Learning Objectives
After completing this chapter, you should be able to
• describe modules.
• explain what packages are, what files are required, and how they are structured in a file system.
• import and use modules already in the Python programming/development environment.
• import and use specific parts from a module or specific modules from a package.
• explain the functionalities of some standard and widely used modules, and use them
comfortably in programming.
• write and use your own modules and packages.
1 """
2 The module in this file defines some functions often used in calculations related to circles
Code sample in VS Code IDE
6 Version: 1.0
7 """
10 PAI = 3.1415926
11
12
13 def area(r):
16
17
18 def circumference(r):
20 return 2 * PAI * r
21
22
The file can then be imported into a Python program and used as a module, as shown below:
In [ ]: import circle
How do you create a module or package and publish it at https://pypi.org/ for the Python community
at large so that it can be found and installed with the pip command?
Suppose you want to create a package for developing e-learning applications. You would need to take
the following steps to develop the package to make it available for the others in the Python community:
1. First, create a directory called mypackages, which will contain all the packages and modules
that you will develop for yourself or the Python community at large.
2. Suppose you would like the package to be called elearn. You first need to check to see if the
name has been used by others to name any top-level module or package published at
http://pypi.python.org.
3. Under the mypackages directory, create a directory named elearn, which will contain
everything for your elearn package or module.
4. Under this elearn directory, you can create Python script files (.py) and other subdirectories
under which you may have other packages or modules.
5. To distinguish this elearn directory from other ordinary directories of the file system so that it
can be searchable through a Python interpreter, create a special file called __init__.py right
under the elearn directory. The __init__.py file should contain all the names and objects
defined in the package or module, either directly or indirectly (by importing individual names
and objects from each of the other files). The must-have __init__.py file is the entry point of
each package or module.
6. Under the mypackages directory, write a special Python script file called setup.py, which
imports a special module called setuptools and calls the setup function to prepare the package
to be sent to the repository. The following is an example of the setup.py file.
import setuptools
setup(name = 'elearn',
version = '1.0beta',
description = 'A package for developing elearn applications',
url = 'http://github.com/AU.CA/elearn',
author = 'SCIS Athabasca',
author_email = '[email protected]',
license = 'FSF free software foundation',
packages = ['elearn'],
zip_safe = False)
7. If you are not really ready to submit the package to the repository but would rather test it or
just want to use it by yourself, you can install the package locally so that it can be found with
the import statement. The following is the command to be used to install the package when
your current working directory is mypackages:
$ pip install .
Upon completing the above steps, anyone on the internet will be able to install and use your elearn
library to develop elearn applications using the following command:
$ pip install elearn
Please note that for your package to be available in a GitHub repository so that the link used in your
entry at PYPI is valid, you will need to create or sign into an account with GitHub and do the following:
VS Code IDE can work with Git and GitHub through respective GitHub extensions that can be
downloaded and installed in VS Code so that your project in VS can be easily synchronized with
GitHub.
2
import circle
4
radius = float(input("Tell me the radius:"))
6
print(f"The area of a circle with the radius {radius} is {circle.area(radius)}")
When importing a module, you can also give the module an alias to use, especially if the original
name is too long or hard to remember. In the above code sample, the import statement import circle can
be changed to ci, as in the following:
>>> import circle as ci
Then in the program file, you can use ci in place of circle, as shown below:
>>> print(f"The area of a circle with the radius {radius} is {ci.area(radius)}")
When designing and coding a system, you may create and use as many modules as needed, but do so
wisely and do not make a simple system too complicated. Managing too many unnecessary modules and
files will consume time and resources as well, especially since many Python modules have already been
developed by the great Python community for almost every application domain you can think of. In most
cases, all you need is to know is what modules are available out there and what each module does, even
if you do not want to learn about the details now.
In general, the import statement may take one of the following forms.
IMPORT <THE NAME OF THE MODULE> AS <SIMPLER ALIAS FOR THE MODULE
NAME>
Sometimes, the name of a module can be long and hard to remember, and giving the module an alias
would make programming more efficient. For example, there is a module for mathematical plotting
called matplotlib if you give an alias to the module when importing it as follows:
import matplotlib as mpl
A name such as o defined in the module can then be referred to using mpl.o, which is much simpler
than matplotlib.o.
This dot notation can also be used to import a module from a package without using from, as shown in
the following example:
which imports the pyplot module from the matplotlib package and assigns an alias to the module.
To find out what a particular installed module or package does, you can import the package or module
into a Python interactive shell or a Jupyter Notebook cell, then run the dir command/statement to find
out the names defined in the module or package and use the help command/statement to see more
detailed information for a particular name.
PS C:\> python
Python 3.9.0 (tags/v3.9.0:9cf6752, Oct 5 2020, 15:34:40) [MSC v.1927 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import math
>>> dir(math)
['__doc__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin , asinh ,
atan', 'atan2', 'ata
nh', 'ceil', 'comb', 'copysign', 'cos', 'cosh', 'degrees', 'dist', 'e', 'erf', 'erfc', 'exp', 'expmr,
'fabs', 'factoria
l', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf',
'isnan', 'isqrt',
'1cm', 'Idexp', 'lgamma', 'log', 'log10', 'Ioglp', 'log2', 'modf', 'nan', 'nextafter', 'perm', 'pi',
'pow', 'prod', 'rad
ians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc', 'ulp']
>>> help(math)
Help on built-in module math:
NAME
math
DESCRIPTION
This module provides access to the mathematical functions
defined by the C standard.
FUNCTIONS
acos(x, /)
Return the arc cosine (measured in radians) of x.
acosh(x, /)
Return the inverse hyperbolic cosine of x.
asin(x, /)
Return the arc sine (measured in radians) of x.
asinh(x, /)
Return the inverse hyperbolic sine of x.
atan(x, /)
Return the arc tangent (measured in radians) of x.
atan2(y, x, /)
Return the arc tangent (measured in radians) of y/x.
atanh(x, /)
Return the inverse hyperbolic tangent of x.
Another way to learn about and navigate through the available modules and packages is to use a
module called pydoc. However, this module is usually run from a command shell or PowerShell terminal
as shown below:
(base) PS C:\Users\james> python pydoc
pydoc - the Python documentation tool
pydoc <name> …
Show text documentation on something. <name> may be the name of a
Python keyword, topic, function, module, or package, or a dotted
reference to a class or function within a module or module in a
package. If <name> contains a '\', it is used as the path to a
Python source file to document. If name is 'keywords', 'topics',
or 'modules', a listing of these things is displayed.
pydoc -k <keyword>
Search for a keyword in the synopsis lines of all available modules.
pydoc -n <hostname>
Start an HTTP server with the given hostname (default: localhost).
pydoc -p <port>
Start an HTTP server on the given port on the local machine. Port
number 0 can be used to get an arbitrary unused port.
pydoc -b
Start an HTTP server on an arbitrary unused port and open a Web browser
to interactively browse documentation. This option can be used in
combination with -n and/or -p.
pydoc -w <name> …
Write out the HTML documentation for a module to a file in the current
directory. If <name> contains a '\', it is treated as a filename; if
it names a directory, documentation is written for all the contents.
(base) PS C:\Users\james>
Note that when you want to run a Python module as a normal script, run Python with the -m switch
before the module name.
As shown above, if you want to get documentation on something, just add the something behind
pydoc. For example, if you want to see the documentation on the math module, run the following
command in the command shell:
python -m pydoc math
NAME
math
DESCRIPTION
This module provides access to the mathematical functions
defined by the C standard.
FUNCTIONS
acos(x, /)
Return the arc cosine (measured in radians) of x.
acosh(x, /)
Return the inverse hyperbolic cosine of x.
asin(x, /)
Return the arc sine (measured in radians) of x.
asinh(x, /)
Return the inverse hyperbolic sine of x.
atan(x, /)
Return the arc tangent (measured in radians) of x.
atan2(y, x, /)
Return the arc tangent (measured in radians) of y/x.
atanh(x, /)
Return the inverse hyperbolic tangent of x.
With some installations of Python, such as those installed with Anaconda, pydoc has been made
available as executable directly from command shell, as shown here:
(base) PS C:\Users\james> pydoc math
Help on built-in module math:
NAME
math
DESCRIPTION
This module provides access to the mathematical functions
defined by the C standard.
FUNCTIONS
acos(x, /)
Return the arc cosine (measured in radians) of x.
acosh(x, /)
Return the inverse hyperbolic cosine of x.
asin(x, /)
Return the arc sine (measured in radians) of x.
asinh(x, /)
Return the inverse hyperbolic sine of x.
atan(x, /)
Return the arc tangent (measured in radians) of x.
atan2(y, x, /)
Return the arc tangent (measured in radians) of y/x.
atanh(x, /)
Return the inverse hyperbolic tangent of x.
pydoc has some switches that can be used when running it as a Python module or an executable
directly from the command shell. These switches include the following.
-K <KEYWORD>
Used to search for a keyword in the synopsis lines of all available modules installed. The following
example searches for all modules that has the word “hash” in the synopsis.
PS C:\Users\james> python -m pydoc -k hash
-N <HOSTNAME>
Used to start an HTTP server with the given <hostname>. When no hostname is given, localhost is
default.
-P <PORT>
Used to start an HTTP server on the given <port> on the local machine. Port number 0 can be used to get
an arbitrary unused port.
-B
Used to start an HTTP server on an arbitrary unused port and open a web browser to interactively
browse documentation. This option can be used in combination with -n and/or -p.
The following example starts a server on the local machine at an available port and launches a web
browser to browse all available modules and packages.
(base) PS S:\Dev\learn-python> pydoc -b
Server ready at http://localhost:30128/
Server commands: [b]rowser, [q]uit
server>
Please note that if you type q to quit from the program, the server will be down and no longer
available.
The browser opened by the example above will look like this:
Index of Modules
Built-In Modules
Please note that the above only shows the built-in modules. There is more about nonbuilt-in modules
if you scroll down to read further.
-W <NAME>…
Used to write out the HTML documentation for a module to a file in the current directory. If the name
contains a backslash \, it is treated as a filename; if it names a directory, documentation is written for all
the contents. The following example generates documentation in HTML for a module called timeit:
(base) PS S:\Dev\learn-python > pydoc -w timeit
wrote timeit.html
As can be seen, using the pydoc -b in command shell can easily access a server and start to browse
documentation for all the available modules and packages installed on your computer. For example, if
we want to learn more about the timeit module, we can browse or search for timeit within the first page
of the browser window launched by the pydoc -b command, then click the link to see the details of the
documentation.
The remainder of this chapter introduces some Python modules that you may need to use in the
development of different computer applications.
In the list, names with leading underscores are often intended to be hidden. It’s important to know
only what those without leading underscores are and what they do. You can use the help statement to
find out what randint is, for example:
>>> help(random.randint)
Running help on method randint in the random module outputs the following:
This returns a random integer within the range [a, b], including both end points.
As you can see with the help statement, all these names defined in the random module are functions
and methods. These functions and methods can be categorized as bookkeeping methods, random integer
generating methods, random real/float number generating methods, random item generating methods, or
items from a sequence. The module also provides alternate random number generators such as the one
provided by the operating system.
In the following, you will run through the functions provided in the random module. These functions
are categorized into four groups: bookkeeping functions, functions randomly generating integers,
functions randomly generating float/real numbers, and functions randomly selecting items from a
sequence.
GETSTATE()
This gets and returns the current internal state of the random number generator.
>>> s1 = random.getstate()
SETSTATE(STATE)
This sets the internal state of the random number generator to state.
>>> random.setstate(s1)
GETRANDBITS(K)
This generates and returns an integer with k random bits.
>>> bin(random.getrandbits(9))
'0b100101111'
>>> bin(random.getrandbits(9)) # will get a different number
'0b10111101'
RANDINT(A, B)
This generates and returns a random integer within the given range.
>>> random.randint(1, 100)
42
>>> random.randint(1, 100)
85
RANDOM()
This randomly generates and returns a random float number between 0 and 1, including 0 but excluding
1.
>>> random.random()
0.4084252811341471
UNIFORM(A, B)
This randomly generates and returns a float number between a and b.
>>> random.uniform(2, 99)
73.1658416986511
>>> random.uniform(2, 99)
92.92610150048253
BETAVARIATE(ALPHA, BETA)
This randomly generates and returns a random float number between 0 and 1 based on the beta
distribution of statistics. Parameters alpha and beta (both > 0) are used to set the conditions of the
distribution, as used in the beta distribution function.
>>> random.betavariate(2, 99)
0.011368344795580798
>>> random.betavariate(2, 99)
0.019428131869773747
EXPOVARIATE(LAMBDA)
This randomly generates and returns a random float number between 0 and 1, or between 0 and −1 if
lambda is negative, based on the exponential distribution of statistics.
>>> random.expovariate(2)
0.379317249922913
GAMMAVARIATE(ALPHA, BETA)
This randomly generates and returns a random float number between 0 and 1 based on the gamma
distribution of statistics. Parameters alpha and beta (both > 0) are used to set the conditions of the
distribution, as used in the gamma distribution function.
>>> random.gammavariate(2,99)
43.06391063895096
GAUSS(MU, SIGMA)
This randomly generates and returns a random float number between 0 and 1 based on the Gaussian
distribution of probability theories. Parameter mu is the mean, and sigma is the standard deviation, as
used in the distribution function.
>>> random.gauss(2, 99)
38.05513497609059
LOGNORMVARIATE(MU, SIGMA)
This generates and returns a random float number between 0 and 1 based on a log-normal distribution of
probability theories. Parameter mu is the mean, and sigma is the standard deviation, as used in the log
normal distribution function.
>>> random.lognormvariate(2, 99)
9.252497191266324e-41
NORMALVARIATE(MU, SIGMA)
This generates and returns a random float number between 0 and 1 based on the normal distribution of
probability theories. Parameter mu is the mean, and sigma is the standard deviation, as used in the
normal distribution function.
>>> random.normalvariate(2, 99)
155.45854862650918
VONMISESVARIATE(MU, KAPPA)
This generates and returns a random float number between 0 and 1 based on the von Mises distribution
of directional statistics. Parameter mu is the mean angle, expressed in radians between 0 and 2 * pi,
whereas kappa is the concentration.
>>> random.vonmisesvariate(2, 99)
1.9289474404869416
PARETOVARIATE(ALPHA)
This generates and returns a random float number between 0 and 1 based on the Pareto distribution of
probability theories. Parameter alpha is used to indicate the shape.
>>> random.paretovariate(2)
1.7794461337233882
WEIBULLVARIATE(ALPHA,BETA)
This generates and returns a random float number between 0 and 1 based on the Weibull distribution of
statistics. Parameter alpha is the scale, and beta is the shape, as in its mathematical function.
>>> random.weibullvariate(2, 99)
2.0164248554211417
CHOICE(POPULATION)
This generates and returns a random element from the given population (in the form of a Python
sequence).
>>> random.choice(range(1, 1000))
536
>>> random.choice(list("The message will look like this but"))
'l'
>>> random.choice(list("The message will look like this but"))
't'
This function can be very useful when you want to generate a quiz by randomly selecting questions
from a question bank. Assume the question bank is called q_bank, and each quiz will have 10 questions.
The random choices can be easily made by calling the function as follows:
>>> random.choices(q_bank, k = 10)
SAMPLE(POPULATION, K)
This generates and returns a sample for a given population. It seems similar to choices(), but internally
the algorithm should check whether the choices would make a sample of the population according to
some sampling criteria in statistics.
>>> random.sample(range(1, 1000), k = 5)
[251, 337, 822, 499, 853]
In the following programming problem in Table 8-1, you will study how well the random generator
works. You will randomly generate 1000 integer numbers within the range of 0 to 999 and visualize the
randomness of these numbers.
The This case study will find out how good the random number generator is.
problem
The Random numbers generated by computers are not completely random. Rather, they are
analysis pseudorandom sequences. To study how good a generator is, you need to see if the
and numbers generated by the generator look random. We will show that in a two-dimensional
design chart to visualize it.
pyp.xlabel('Run #')
pyp.ylabel('Random Integer')
pyp.title('Visualization of Randomness')
pyp.show()
The Figure 8-1 below is plotted by the program. It seems the random generator works very
result well.
Then run help on a particular name to find out what that name, such as ceil, does:
>>> help(math.ceil)
Running help on the built-in function ceil in the math module outputs the following:
ceil(x, /)
Return the ceiling of x as an Integral.
ACOS(X)
This calculates and returns the arc cosine (measured in radians) of x, where 0 <= x < = 1.
>>> import math
>>> math.acos(0.5)
1.0471975511965979
ACOSH(X)
This calculates and returns the inverse hyperbolic cosine of x. (Google “hyperbolic functions” to learn
more.)
>>> math.acosh(1000)
7.600902209541989
ASIN(X)
This calculates and returns the arc sine (measured in radians) of x.
>>> math.asin(0.5)
0.5235987755982989
MATH.ASINH(X)
This calculates and returns the inverse hyperbolic sine of x.
>>> math.asinh(5)
2.3124383412727525
MATH.ATAN(X)
This calculates and returns the arc tangent (measured in radians) of x.
>>> math.atan(0.5)
0.4636476090008061
MATH.ATAN2(Y, X)
This calculates and returns the arc tangent (measured in radians) of y/x. Unlike atan(y/x), the signs of
both x and y are considered.
>>> math.atan2(3, -5)
2.601173153319209
MATH.ATANH(X)
This calculates and returns the inverse hyperbolic tangent of x.
>>> math.atanh(0.5)
0.5493061443340549
MATH.CEIL(X)
This calculates and returns the ceiling of x as an Integral—the smallest integer >= x.
>>> math.ceil(0.5)
1
MATH.COPYSIGN(X, Y)
This calculates and returns a float with the magnitude (absolute value) of x but the sign of y. On
platforms that support signed zeros, copysign(1.0, −0.0) returns −1.0.
>>> math.copysign(0.5, -1.2)
-0.5
MATH.COS(X)
This calculates and returns the cosine of x (measured in radians).
>>> math.cos(0.5)
0.8775825618903728
MATH.COSH(X)
This calculates and returns the hyperbolic cosine of x.
>>> math.cosh(50)
2.592352764293536e+21
MATH.DEGREES(X)
This converts angle x from radians to degrees and returns the result.
>>> math.degrees(0.5)
28.64788975654116
MATH.ERF(X)
This is the error function at x, as defined in statistics.
>>> math.erf(0.5)
0.5204998778130465
MATH.ERFC(X)
This is the complementary error function at x, so that erf(x) + erfc(x) = 1.
>>> math.erfc(0.5)
0.4795001221869534
MATH.EXP(X)
This calculates and returns e raised to the power of x. This is the same as math.e**x, or
math.pow(math.e, x).
>>> math.exp(5)
148.4131591025766
MATH.EXPM1(X)
This calculates and returns exp(x)−1. This function avoids the loss of precision involved in the direct
evaluation of exp(x)−1 for small x.
>>> math.expm1(5)
147.4131591025766
MATH.FABS(X)
This calculates and returns the absolute value of the float x.
>>> math.fabs(-23.6)
23.6
MATH.FACTORIAL(X)
This calculates and returns x!. It will raise a ValueError if x is negative or nonintegral.
>>> math.factorial(23)
25852016738884976640000
MATH.FLOOR(X)
This calculates and returns the floor of x as an integer—that is, the return value is the largest integer < =
x.
>>> math.floor(2.3)
2
MATH.FMOD(X, Y)
This calculates and returns fmod(x, y), according to platform C. x % y may differ.
>>> math.fmod(2.3, 1.5)
0.7999999999999998
MATH.FREXP(X)
This calculates the mantissa and exponent of x and returns a pair (m, e). m is a float, and e is an integer,
such that x = m * 2** e. If x is 0, m and e are both 0. Otherwise, 0.5 <= abs(m) < 1.0.
>>> math.frexp(2.3)
(0.575, 2)
MATH.FSUM(SEQ)
This calculates and returns an accurate floating-point sum of values in the iterable seq. It assumes IEEE-
754 floating-point arithmetic. It is a lossless sum.
>>> math.fsum([2.3, 2, 53454, 6.71232])
53465.01232
MATH.GAMMA(X)
This returns the value of the gamma function at x.
>>> math.gamma(2.3)
1.16671190519816
MATH.GCD(X, Y)
This calculates and returns the greatest common divisor of x and y.
>>> math.gcd(222, 780)
6
MATH.HYPOT(X, Y)
This calculates and returns the Euclidean distance—that is, the value of sqrt(x * x + y * y).
>>> math.hypot(3, 4)
5.0
MATH.ISFINITE(X)
This returns True if x is neither an infinity nor a NaN, and False otherwise.
>>> math.isfinite(3.5)
True
MATH.ISINF(X)
This returns True if x is a positive or negative infinity, and False otherwise.
>>> math.isinf(3.5)
False
MATH.ISNAN(X)
This returns True if x is a NaN (not a number), and False otherwise.
>>> math.isnan(3.5)
False
MATH.ISQRT(N)
This returns the integer square root of the nonnegative integer n, which is the floor of the exact square
root of n, or equivalently the greatest integer is such that a2 ≤ n. This function is only available in Python
3.8.0 or later.
>>> math.isqrt(43)
6
MATH.LDEXP(X, I)
This calculates and returns x* (2 ** i). The function is essentially the inverse of frexp().
>>> math.ldexp(3, 12)
12288.0
MATH.LGAMMA(X)
This calculates and returns the natural logarithm of the absolute value of the gamma function at x.
>>> math.lgamma(3)
0.693147180559945
MATH.LOG10(X)
This calculates and returns the base-10 logarithm of x.
>>> math.log10(3)
0.47712125471966244
MATH.LOG1P(X)
This calculates and returns the natural logarithm of 1 + x (base-e). The result is computed in a way that is
accurate for x near 0.
>>> math.log1p(3)
1.3862943611198906
MATH.LOG2(X)
This calculates and returns the base-2 logarithm of x.
>>> math.log2(3)
1.584962500721156
MATH.MODF(X)
This calculates and returns the fractional and integer parts of x. Both results carry the sign of x and are
floats.
>>> math.modf(32.6)
(0.6000000000000014, 32.0)
MATH.POW(X, Y)
This calculates and returns x ** y (x to the power of y).
>>> math.pow(32,6)
1073741824.0
MATH.RADIANS(X)
This converts angle x from degrees to radians and returns the result.
>>> math.radians(32)
0.5585053606381855
MATH.REMAINDER(X, Y)
This calculates and returns the difference between x and the closest integer multiple of y, which is x − n
* y, where n * y is the closest integer multiple of y. In the case where x is exactly halfway between two
multiples of y, the nearest even value of n is used. The result is always exact.
>>> math.remainder(32,7)
-3.0
>>> math.remainder(30,7)
2.0
>>> math.remainder(31,7)
3.0
MATH.SIN(X)
This calculates and returns the sine of x (measured in radians).
>>> math.sin(0.31)
0.3050586364434435
MATH.SINH(X)
This calculates and returns the hyperbolic sine of x.
>>> math.sinh(31)
14524424832623.713
MATH.SQRT(X)
This calculates and returns the square root of x.
>>> math.sqrt(31)
5.5677643628300215
MATH.TAN(X)
This calculates and returns the tangent of x (measured in radians).
>>> math.tan(31)
-0.441695568020698
MATH.TANH(X)
This calculates and returns the hyperbolic tangent of x.
>>> math.tanh(31)
1.0
MATH.TRUNC(X)
This truncates the float number x to the nearest Integral toward 0. It uses the __trunc__ magic method.
>>> math.trunc(3.561)
3
In addition, the module also defines the following constants used in math:
math.e = 2.718281828459045
math.inf = inf
math.nan = nan
math.pi = 3.141592653589793
math.tau = 6.283185307179586
Note that to use these functions and constants, you will have to use the dot notation shown in the sample
code above to indicate that it is from the math module.
If you only need to use one or some functions from the math module, you may import the particular
functions from it to save computer memory and use the functions without using the dot notation. The
following is an example, generating a table of square roots for numbers from 1 to 100, in which only the
sqrt function has been imported from the math module:
In [ ]: from math import sqrt
for i in range(100):
if (i + 1) % 10 == 0:
print('\n')
Out [ ]: 1.0 1.41 1.73 2.0 2.24 2.45 2.65 2.83 3.0 3.16
3.32 3.46 3.61 3.74 3.87 4.0 4.12 4.24 4.36 4.47
4.58 4.69 4.8 4.9 5.0 5.1 5.2 5.29 5.39 5.48
5.57 5.66 5.74 5.83 5.92 6.0 6.08 6.16 6.24 6.32
6.4 6.48 6.56 6.63 6.71 6.78 6.86 6.93 7.0 7.07
7.14 7.21 7.28 7.35 7.42 7.48 7.55 7.62 7.68 7.75
7.81 7.87 7.94 8.0 8.06 8.12 8.19 8.25 8.31 8.37
8.43 8.49 8.54 8.6 8.66 8.72 8.77 8.83 8.89 8.94
9.0 9.06 9.11 9.17 9.22 9.27 9.33 9.38 9.43 9.49
9.54 9.59 9.64 9.7 9.75 9.8 9.85 9.9 9.95 10.0
To find out what is defined and available in the module, run the following dir statement:
>>> dir(datetime)
To further find out what each name is defined for, use the help statement on each. As usual, we will go
through some of the important names defined in the module, with examples.
DATETIME.DATE.CTIME()
This returns a ctime()-style string.
>>> d1.ctime()
'Wed Jul 1 00:00:00 2020'
DATETIME.DATE.ISOCALENDAR()
This returns a three-tuple containing an ISO year, week number of the year, and day number of the week.
In the datetime module, Monday is 1, Tuesday is 2,…, Sunday is 7.
>>> d1.isocalendar()
(2020, 27, 3)
DATETIME.DATE.ISOFORMAT()
This returns a date string in ISO 8601 format, YYYY-MM-DD.
>>> d1.isoformat()
'2020-07-01'
DATETIME.DATE.ISOWEEKDAY()
This returns an integer from 1 to 7 as the day of the week represented by the date.
>>> d1.isoweekday()
3
DATETIME.DATE.REPLACE(…)
This returns the date with new specified fields.
DATETIME.DATE.STRFTIME(…)
This changes the date format and returns a strftime()-style string.
DATETIME.DATE.TIMETUPLE(…)
This returns a time-tuple that is compatible with time.localtime().
DATETIME.DATE.TOORDINAL(…)
This returns a proleptic Gregorian ordinal. January 1 of year 1 is day 1.
DATETIME.DATE.WEEKDAY(…)
This returns the day of the week represented by the date: Monday is 0…Sunday is 6.
The following are all class methods of the date class defined in the datetime module, which means they
can be called from the class name date.
DATETIME.DATE.FROMISOFORMAT(<ISO_DATE_FORMAT STRING>)
This will construct a date object from an ISO date format string, which is YYYY-MM-DD.
>>> d2 = datetime.date.fromisoformat('2020-07-01')
>>> d2.ctime()
'Wed Jul 1 00:00:00 2020'
DATETIME.DATE.FROMTIMESTAMP(<TIMESTAMP>)
This constructs a local date object from a POSIX timestamp (a big positive float number), such as
returned time.time(), which will be explained shortly.
>>> import time
>>> time.time() # it returns a timestamp for now
1593745988.6121984
>>> date.fromtimestamp(1593745988.6121984)
datetime.date(2020, 7, 2)
DATETIME.DATE.TODAY()
This returns a date object of for the current date.
>>> from datetime import date
>>> print(date.today())
2020-07-05
The datetime module also has a class called time. The following is the constructor of the time class.
The following is the only class method of the date class in the datetime module.
TIME.FROMISOFORMAT(…)
This class method will construct a date object from a string passed in the parameter.
>> import datetime
>> canada_day_str = "2022-07-01"
>> canada_day_object = datetime.date.fromisoformat(canada_day_str)
>> print(f"{canada_day_object} as {type(canada_day_object)}")
2022-07-01 as <class 'datetime.date'>
The datetime module also has a class called datetime, which is a combination of date and time. The
following is the constructor of the datetime objects.
DATETIME.CTIME(…)
This returns a ctime()-style time string.
>>> from datetime import datetime
>>> dt1 = datetime.now()
>>> print(f'now it is {dt1.ctime()}')
now it is Mon Jul 6 14:07:01 2020
DATETIME.ASTIMEZONE(TZ)
This converts to the local time with the time zone set to <tz> or local.
>>> from datetime import datetime
>>> dt1 = datetime.now()
>>> print(dt1)
2020-07-06 14:07:01.046202
>>> print(dt1.astimezone())
2020-07-06 14:07:01.046202-06:00
>>> import pytz
>>> asiachina=pytz.timezone('Asia/Chongqing')
>>> print(dt1)
2020-07-06 14:07:01.046202
>>> print(dt1.astimezone(asiachina)) # print time in China
2020-07-07 04:07:01.046202+08:00
DATETIME.DATE()
This returns a date object of the date portion of the datetime object with the same year, month, and day.
>>> from datetime import datetime
>>> tm1 = datetime.now()
>>> print(f'now is {dtm1.ctime()}')
now is Tue Jul 7 08:50:25 2020
>>> dt1 = dtm1.date()
>>> print(f'the date is {dt1}')
the date is 2020-07-07
DATETIME.DST()
This returns the DST (daylight saving time) status of a given tzinfo.
>>> print(f'the date is {dt1}')
the date is 2020-07-07
>>> print(f'the dst status is {dtm1.dst()}')
None
DATETIME.ISOFORMAT(SEP = 'T')
This returns a date and time string in ISO 8601 format, YYYY-MM-DDT[HH[:MM[:SS[.mmm[uuu]]]]]
[+HH:MM]. sep is a single character used to separate the year from the time, and defaults to T. timespec
specifies what components of the time to include. The allowed values include the following: auto, hours,
minutes, seconds, milliseconds, and microseconds.
>>> from datetime import datetime
>>> dt1 = datetime.now()
>>> print(dt1.isoformat(sep='@'))
2023-03-13@18:51:29.324588
DATETIME.REPLACE(<FIELD>=<VALUE>)
This returns a datetime object with the named field(s) replaced.
>>> dt2 = dt1.replace(year=2025)
>>> print(f'new datetime becomes {dt}')
new datetime becomes 2021-07-07 09:00:37.138388
DATETIME.TIME()
This returns a time object for the time portion of the datetime object but with tzinfo = None.
>>> dt1 = dtm1.date()
>>> tm1=dtm1.time()
>>> print(f'the date is {dt1}')
the date is 2020-07-07
>>> print(f'the time is {tm1}')
the time is 09:17:06.055195
DATETIME.TIMESTAMP()
This returns POSIX timestamp as a float number.
>>> tmstamp = dtm1.timestamp()
>>> print(f'The timestamp of {dtm1} is {tmstamp}')
DATETIME.TIMETUPLE()
This returns a time-tuple compatible with time.localtime().
>>> tmtuple = dtm1.timetuple()
>>> print(f'The time-tuple of {dtm1} is {tmtuple}')
DATETIME.TIMETZ()
This returns a time object with the same time and tzinfo. Note the difference between timetz() and
time().
>>> tminfo = dtm1.timetz()
>>> print(f'The time of {dtm1} is {tminfo}')
The timezone info of 2020-07-07 09:24:39.517213 is 09:24:39.517213
DATETIME.TZNAME(…)
This returns the tzname of tzinfo.
>>> import pytz
>>> tz = pytz.timezone('Canada/Mountain')
>>> dtm = datetime.fromisoformat('2020-07-05T21:05:33')
>>> ndtm = dtm.replace(tzinfo = tz)
>>> tmzname = ndtm.tzname()
>>> print(f'The timezone for {ndtm} is {tmzname}')
The timezone for 2020-07-05 21:05:33-07:34 is LMT
DATETIME.UTCOFFSET(…)
This returns utcoffset of tzinfo.
>>> tmzutcoffset = ndtm.utcoffset()
>>> print(f'The timezone utc offset of {ndtm} is {tmzutcoffset}')
The timezone utc offset of 2020-07-05 21:05:33-07:34 is -1 day, 16:26:00
The following are some class methods defined in the datetime class.
DATETIME.COMBINE(DT, TM)
This combines the date dt and time tm into a datetime object and returns the datetime object.
>>> dt = datetime.date.today()
>>> tm = datetime.time(20,59,12)
>>> dtm = datetime.datetime.combine(dt, tm)
>>> print(f'date is {dt}, time is {tm}, datetime is {dtm}')
date is 2020-07-05, time is 20:59:12, datetime is 2020-07-05 20:59:12
DATETIME.FROMISOFORMAT(DTMSTR)
This constructs the datetime object from a date and time string in ISO format and returns the converted
datetimeobject. Remember that the ISO time string format is YYYY-MM-DDTHH:MM:SS:mmm:uuu.
>>> dtm = datetime.datetime.fromisoformat('2020-07-05T21:05:33')
>>> print(dtm)
2020-07-05 21:05:33
DATETIME.FROMTIMESTAMP(…)
This constructs a datetime object from a POSIX timestamp.
>>> tmstamp1 = ndtm.timestamp()
>>> print(f'The time stamp of {ndtm} is {tmstamp1}')
The time stamp of 2020-07-05 21:05:33-07:34 is 1594010373.0
>>> redtmobj = datetime.fromtimestamp(tmstamp1)
>>> print(f'It is a different object and the time value has changed to {redtmobj}')
It is a different object, and the time value has changed to 2020-07-05 22:39:33.
DATETIME.NOW(TZ = NONE)
This returns a datetime object representing the current time local to tz, which should be a Timezone
object if given. If no tz is specified, the local timezone is used.
>>> from datetime import datetime # import the datetime class from the datetime module
>>> dt1 = datetime.now()
>>> print(f'it is {dt1}')
it is 2020-07-05 11:22:48.876825
DATETIME.STRPTIME(<DATE_STRING, FORMAT>)
This returns a datetime object by parsing a date_string, based on a given format.
>>> dtstring = "7 July, 2020"
>>> dtobj = datetime.strptime(dtstring, "%d %B, %Y") # note the date formatting string
>>> print("date object = ", dtobj)
DATETIME.TODAY()
This returns a datetime object for today.
>>> dt2 = datetime.today()
>>> print(f'Today is {dt2}')
Today is 11:34:09.228618
DATETIME.UTCFROMTIMESTAMP()
This constructs a naive UTC datetime from a POSIX timestamp.
>>> redtmobj = datetime.utcfromtimestamp(tmstamp1)
>>> print(f'{redtmobj} is a UTC datetime from a POSIX timestamp {redtmobj}')
2020-07-06 04:39:33 is a UTC datetime from a POSIX timestamp 1594010373.0
DATETIME.UTCNOW()
This returns a new datetime representing the UTC day and time.
>>> dt2 = datetime.today()
>>> dt3 = datetime.utcnow()
>>> print(f'Today is {dt2}, and the UTC time is {dt3}')
Today is 2020-07-07 11:37:02.862356, and the UTC time is 2020-07-07 17:37:02.862356
Sometimes, you need to deal with time intervals such as how long has passed since the last time you saw
your best friend. That is what the timedelta class is defined for in the datetime module. The following is
the constructor of the class.
TIMEDELTA.TOTAL_SECONDS(…)
This returns the total number of seconds in the duration.
>>> print(f'the total number of seconds in 31 days is {ndlt.total_seconds()}')
the total number of seconds in 31 days is 2678400.0
>>> ndlt = timedelta(31, 25, hours = -3)
>>> print(f'the total number of seconds in 31 days is {ndlt.total_seconds()}')
the total number of seconds in 31 days and 25 seconds minus 3 hours is 2667625.0
In the following, we explain the names, including attributes and functions, available in the time
module on a Windows platform. The code samples are all shown as they would appear in a Python
interactive shell. If you wish to see all functions defined in the time module, please read the
documentation at https://docs.python.org/3/library/time.html.
TIME.ALTZONE
This is an attribute that contains the offset of the local DST timezone in seconds west of UTC, if one is
defined. The value is negative if the local DST timezone is east of UTC (as in Western Europe, including
the UK). Only use this if daylight is nonzero.
>>> import time
>>> print("local time zone is %d " % (time.altzone/3600))
local time zone is 6
TIME.ASCTIME(TUPLETIME)
This accepts a time-tuple and returns a readable 24-character string such as Tue Dec 11 18:07:14 2008. A
time-tuple has nine elements, as returned by gmtime() or localtime().
>>> import time # you only need to import a module once, so this is just in case
>>> print("local time is %s " % (time.asctime()))
local time is Tue Nov 12 15:10:50 2019
>>> time.asctime(tuple(time.localtime()))
'Tue Nov 12 15:24:05 2019'
TIME.CLOCK()
This returns a floating-point number for the CPU time or real time since the start of the process or since
the first call to clock(). It is very useful, especially when measuring the computational cost of a code
block.
>>> time.clock()
428446.1717301
TIME.CTIME([SECS])
This returns a time in seconds since the epoch to a string in the local time. Remember that the argument
in [] is optional.
This has the same result as asctime(localtime(secs)), and simply a call of asctime(), which will use the
current local time in seconds.
>>> time.asctime()
'Tue Nov 12 15:24:49 2019'
>>> time.ctime()
'Tue Nov 12 15:24:55 2019'
TIME.GET_CLOCK_INFO(NAME)
This returns information on the specified clock as a namespace object. Supported clock names and the
corresponding functions to read their value are the following: monotonic, perf_counter, process_time,
thread_time, and time.
>>> time.get_clock_info('monotonic')
namespace(adjustable = False, implementation='GetTickCount64()', monotonic=True, resolution =
0.015625)
>>> time.get_clock_info('time')
namespace(adjustable = True, implementation = 'GetSystemTimeAsFileTime()', monotonic=False,
resolution=0.015625)
TIME.GMTIME([SECS])
This accepts an instant expressed in seconds since the epoch and returns a time-tuple t with the UTC
time. Note: t.tm_isdst is always 0.
>>> time.gmtime()
time.struct_time(tm_year = 2019, tm_mon = 11, tm_mday = 12, tm_hour = 22, tm_min = 21, tm_sec = 31,
tm_wday = 1, tm_yday = 316, tm_isdst = 0)
>>> tuple(time.gmtime())
(2019, 11, 12, 22, 22, 2, 1, 316, 0)
TIME.LOCALTIME([SECS])
This accepts an instant expressed in seconds since the epoch and returns a time-tuple t with the local
time (t.tm_isdst is 0 or 1, depending on whether DST applies to instant secs by local rules).
>>> time.localtime()
time.struct_time(tm_year = 2019, tm_mon = 11, tm_mday = 12, tm_hour = 15, tm_min = 19, tm_sec = 0,
tm_wday = 1, tm_yday = 316, tm_isdst = 0)
>>> tuple(time.localtime())
(2019, 11, 12, 15, 22, 32, 1, 316, 0)
TIME.MKTIME(TUPLETIME)
This accepts a time instant expressed as a time-tuple in the local time and returns a floating-point value,
with the instant expressed in seconds since the epoch.
>>> time.mktime((2019, 11, 12, 22, 22, 2, 1, 316, 0))
1573622522.0
TIME.MONOTONIC()
This returns the value of a monotonic clock as a float number, the number of seconds since the previous
call. The clock is not affected by system clock updates. The reference point of the returned value is
undefined, so that only the difference between the results of consecutive calls is valid.
>>> time.monotonic()
1557979.093
TIME.MONOTONIC_NS()
This is similar to monotonic() but returns time as nanoseconds.
>>> time.monotonic_ns()
1557954406000000
TIME.PERF_COUNTER()
This returns the value of a performance counter as a float number since the previous call. A performance
counter is a clock with the highest available resolution to measure a short duration. It includes time
elapsed during sleep and is system-wide. The reference point of the returned value is undefined, so that
only the difference between the results of consecutive calls is valid.
>>> time.perf_counter()
429437.6389873
TIME.PERF_COUNTER_NS()
This is similar to perf_counter() but returns time as nanoseconds.
>>> time.perf_counter_ns()
429556266018100
TIME.PROCESS_TIME()
This returns the value (in fractional seconds) of the sum of the system and the user CPU time of the
current process. It does not include time elapsed during sleep. It is process-wide by definition. The
reference point of the returned value is undefined so that only the difference between the results of
consecutive calls is valid.
>>> time.process_time()
6.71875
TIME.PROCESS_TIME_NS()
This is similar to process_time() but returns time as nanoseconds.
>>> time.process_time_ns()
6687500000
TIME.SLEEP(SECS)
This suspends the calling thread for secs (seconds). It can be used to delay programs.
>>> time.sleep(6) # sleep 6 seconds
TIME.STRFTIME(FMT[,TUPLETIME])
This accepts an instant expressed as a time-tuple in the local time and returns a string representing the
instant as specified by string fmt.
>>> t = (2019, 11, 17, 17, 3, 38, 1, 48, 0)
>>> t = time.mktime(t)
>>> print(time.strftime("%b %d %Y %H:%M:%S", time.gmtime(t)))
Nov 18 2019 00:03:38
TIME.STRPTIME(STRINGTIME[, FMT])
This parses str according to format string fmt and returns the instant in time-tuple format.
>>> time.strptime('Tue Nov 12 15:24:05 2019','%a %b %d %H:%M:%S %Y')
time.struct_time(tm_year = 2019, tm_mon = 11, tm_mday = 12, tm_hour = 15, tm_min = 24, tm_sec = 5,
tm_wday = 1, tm_yday = 316, tm_isdst = -1)
>>> tuple(time.strptime('Tue Nov 12 15:24:05 2019','%a %b %d %H:%M:%S %Y'))
(2019, 11, 12, 15, 24, 5, 1, 316, -1)
TIME.TIME()
This returns the current time instant, a floating-point number of seconds since the epoch.
>>> time.time()
1573607220.4043384
>>> time.asctime(time.localtime(time.time())) # it is the same as time.asctime()
'Mon Jun 8 13:59:35 2020'
>>> time.asctime()
'Mon Jun 8 13:59:45 2020'
CALENDAR.FIRSTWEEKDAY()
This returns an integer that is the current setting for the weekday that starts each week. By default, when
the calendar module is first imported, it is 0 for Monday.
>>> import calendar as cl
>>> cl.firstweekday()
0
CALENDAR.ISLEAP(YEAR)
This tests if a year is a leap year. It returns True if it is; it returns False otherwise.
>>> cl.isleap(2022)
False
CALENDAR.LEAPDAYS(Y1, Y2)
This returns the total number of leap days in the years within range(y1, y2).
>>> cl.leapdays(2020, 2030)
3
CALENDAR.MONTH(YEAR, MONTH, W = 2, L = 1)
This returns a multiline string with a calendar for month of year, one line per week plus two header lines.
w is the width in characters of each date; each line has length 7 * w + 6. l is the number of lines for each
week.
>>> print(cl.month(2021, 3))
March 2021
Mo Tu We Th Fr Sa Su
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 28
29 30 31
CALENDAR.MONTHCALENDAR(YEAR, MONTH)
This returns a list of sublists of integers. Each sublist denotes a week starting from Monday. Days
outside month of year are set to 0; days within the month are set to their day-of-month, 1 and up. The
result as a list of sublists can be conveniently used in applications. For example, you can easily tell what
date it is for Monday of the third week of a month.
>>> print(cl.monthcalendar(2020, 6))
[[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, 28], [29, 30, 0, 0, 0, 0, 0]]
CALENDAR.MONTHRANGE(YEAR, MONTH)
This returns two integers. The first one is the code of the weekday for the first day of the month in year;
the second one is the number of days in the month. Weekday codes are 0 (Monday) to 6 (Sunday); month
numbers are 1 (January) to 12 (December). This is useful if you want to print a calendar that begins on a
specific day of the week.
>>> print(cl.monthrange(2020, 6))
(0, 30)
CALENDAR.PRCAL(YEAR, W = 2, L = 1, C = 6)
This prints a well-formatted calendar of a given year. It is the same as calendar.calendar(year, w, l, c).
Remember that w is the width of each date in number of characters and l is the number of lines for each
week.
>>> cl.prcal(2020, w = 2, l = 1, c = 6)
2020
CALENDAR.PRMONTH(YEAR, MONTH, W = 2, L = 1)
This prints a well-formatted calendar month, the same as the one created by calendar.month(year, month,
w, l).
>>> cl.prmonth(2020, 6, w = 2, l = 1)
June 2020
Mo Tu We Th Fr Sa Su
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 28
29 30
CALENDAR.SETFIRSTWEEKDAY(WEEKDAY)
This sets the first day of each week. Weekday codes are 0 (Monday by default) to 6 (Sunday by default),
so if you change this, you will see the days in the calendar shift.
>>> cl.setfirstweekday(6) # set to start from Sunday
>>> cl.prmonth(2020, 6, w = 2, l = 1)
June 2020
Su Mo Tu We Th Fr Sa
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
28 29 30
CALENDAR.TIMEGM(TUPLETIME)
This is the inverse of time.gmtime. It accepts a time instant in time-tuple form and returns the same
instant as a floating-point number of seconds since the epoch.
>>> cl.timegm((2020, 6, 19, 11, 35, 56))
1592566556
Our last example in Jupyter Lab is to display a calendar for March of 1961.
import calendar
cld = calendar.month(1961, 3)
print(cld)
March 1961
Mo Tu We Th Fr Sa Su
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 28 29 30 31
With the calendar module, you will be able to produce a calendar of any year you want.
In the following, we explain two pairs of important functions provided in the json module. The first
pair of functions is used to convert JSON data to Python data, which is called deserialization or
decoding. The other is used to convert Python data to JSON data, which is called serialization.
The next pair of functions are used to convert Python objects into JSON data. This process is called
serialization or encoding.
Conversions can be made between JSON and Python on different types of data. Table 8-2 shows those
conversions.
dict {'firstname': 'Jone', 'lastname': 'Doe'} Object {"firstname": "Jone", "lastname": "Doe"}
list ['James', 'Jone', 'Smith', 'Doe'] Array ["James", "Jone", "Smith", "Doe"]
tuple ('James', 'Jone', 'Smith', 'Doe') Array ["James", "Jone", "Smith", "Doe"]
str "James, Jone, Smith, Doe" String "James, Jone, Smith, Doe"
As you can see, all basic Python data can be converted/serialized into JSON data, and vice versa.
However, trying to serialize multiple Python objects by repeatedly calling dump() using the same file
handle will result in an invalid JSON file because when doing deserialization with load() from the file,
load has no way to find out the boundary between different JSON data. As such, there will be only one
serialized Python object per file.
If you use the dir(os) statement, you can get a rather big list of names defined in the module. Note that
because the os module is operating-system dependent, you may get a different list of names available
depending on your platform (e.g., Windows or Linux).
The following are some functions provided in the os module. You are encouraged to test these
functions with your own examples on your own machine.
OS.ACCESS(PATH, MODE)
This tests if access to path is in mode, which is an integer such as 777 (111111111) representing the
global, group, and user’s executable, write, and read rights.
>>> import os
>>> p = os.path.abspath(".")
>>> p
'd:\\workshop'
>>> os.access(p,763)
True
OS.CHDIR(PATH)
This changes the current working directory to path.
>>> os.chdir('c:\\workbench')
>>> os.getcwd()
' c:\\workbench'
>>> os.listdir()
['myprimes.txt', ' news_01.txt', ' personal']
OS.CHMOD(PATH, MODE)
This changes the mode of path to the numeric mode.
>>> os.chmod('c:\\workbench', 477)
OS.CPU_COUNT()
This returns the number of CPUs in the system; it will return None if the number is indeterminable.
>>> os.cpu_count()
8
OS.GET_EXEC_PATH(ENV=NONE)
This returns the sequence of directories that will be searched for by the named executable.
>>> import os
>>> print(os.get_exec_path())
['/opt/tljh/user/bin', '/usr/local/sbin', '/usr/local/bin', '/usr/sbin', '/usr/bin', '/sbin', '/bin',
'/snap/bin']
OS.GETCWD()
This returns a Unicode string representing the current working directory.
>>> import os
>>> print(os.getcwd())
/home/jupyter-kevin
OS.GETCWDB()
This returns a byte string representing the current working directory.
>>> import os
>>> print(os.getcwdb())
b'/home/jupyter-kevin'
OS.GETENV(KEY, DEFAULT=NONE)
This returns an environment variable and returns None if it does not exist. The optional second argument
can specify an alternate default.
OS.GETLOGIN()
This returns the actual login name.
>>> os.getlogin()
kevin
OS.LINK(SRC, DST)
This creates a hard link pointing to src named dst.
OS.LISTDIR(PATH)
This returns a list containing the names of the entries in the directory given by path.
>>> os.listdir('.')
['backups', 'Pipfile', 'snap']
OS.PUTENV(NAME, VALUE)
This changes or adds an environment variable if name doesn’t exist yet.
>>> os.times()
nt.times_result(user = 4.125, system = 1.890625, children_user = 0.0, children_system = 0.0, elapsed
= 0.0)
OS.READ(FD, N)
This reads at most n bytes from file descriptor fd and returns a string containing the bytes read. If the end
of the file referred to by fd has been reached, an empty string is returned.
OS.UMASK(MASK)
This sets the current numeric umask to mask and returns the previous umask. umask is used by operating
systems to determine the default permission for newly created files.
>>> import os
>>> os.umask(666) # from now on all new files created will have umask 666 till next change
256
OS.URANDOM(SIZE)
This returns a bytes object containing random bytes suitable for cryptographic use.
>>> os.urandom(5)
b'-\x8e\xeb\xf1\x7f'
In [ ]: import os
print('\t%s' % fname)
OS.WRITE(FD, STR)
This writes the string str to the file descriptor fd and returns the number of bytes actually written.
The path module provides functions for joining and splitting paths, getting information about a path or
file such as its size and timestamp, and testing whether a path is a file, a directory, a real path, or just a
link.
PATH.ABSPATH(P)
This returns the absolute version of p.
>>> path.abspath('.')
'd:\\workshop\\comp218'
PATH.BASENAME(P)
This returns the final component of a pathname.
>>> os.path.basename(p)
'comp218'
PATH.COMMONPATH(PATHS)
This returns the longest common subpath for a given sequence of pathnames.
>>> os.path.commonpath(['d:/workshop/comp218','d:/workshop/comp369'])
'd:\\workshop'
PATH.COMMONPREFIX(PATHS)
This returns the longest common leading component of a given list of pathnames.
>>> os.path.commonprefix(['d:/workshop/comp218','d:/workshop/comp369'])
'd:/workshop/comp'
PATH.DIRNAME(P)
This returns the directory component of a pathname.
>>> os.path.dirname('d:/workshop/comp218/test.py')
'd:/workshop/comp218'
PATH.EXISTS(P)
This tests whether a path exists. It returns False for broken symbolic links.
>>> os.path.exists('d:/workshop/comp218/test.py')
False
PATH.EXPANDUSER(P)
This expands ~ and ~user constructs, mostly for Unix/Linux systems. If user or $HOME is unknown, it
does nothing.
>>> os.path.expanduser('~/workshop/comp218/test.py')
'C:\\Users\\kevin/workshop/comp218/test.py'
PATH.EXPANDVARS(P)
This expands shell variables of the forms $var, ${var}, and %var%. Unknown variables will be left
unchanged.
PATH.GETATIME(FILENAME)
This returns the time a file was last accessed, as reported by os.stat().
PATH.GETCTIME(FILENAME)
This returns the time a file’s metadata was last changed, as reported by os.stat().
PATH.GETMTIME(FILENAME)
This returns the time a file was last modified, as reported by os.stat().
PATH.GETSIZE(FILENAME)
This returns the size of a file, as reported by os.stat().
PATH.ISABS(S)
This tests whether a path is absolute.
PATH.ISDIR(P)
PATH._ISDIR(P)
These return True if the pathname refers to an existing directory.
>>> from os import path
>>> path.isdir('.')
True
PATH.ISFILE(P)
This tests whether a path is a regular file.
>>> from os import path
>>> path.isfile('.')
False
PATH.ISLINK(P)
This tests whether a path is a symbolic link. It will always return False for Windows prior to 6.0.
PATH.ISMOUNT(P)
This tests whether a path is a mount point (a drive root, the root of a share, or a mounted volume).
PATH.JOIN(P1, P2)
This is used to join two paths or a path with a file.
>>> from os import path
>>> fullpath = path.join('/comp218/', 'testfile')
>>> print(fullpath)
/comp218/testfile
PATH.LEXISTS(P)
This tests whether a path exists. It will return True for broken symbolic links.
PATH.NORMCASE(S)
This normalizes the case of a pathname. That is, it makes all characters lower case and all slashes
backslashes.
PATH.NORMPATH(P)
This normalizes the path, eliminating double slashes, etc.
PATH.ABSPATH(P)
This returns the absolute version of a path.
PATH.RELPATH(P, START=NONE)
This returns a relative version of a path.
PATH.SAMEFILE(F1, F2)
This tests whether two pathnames reference the same actual file or directory.
PATH.SAMEOPENFILE(FP1, FP2)
This tests whether two open file objects reference the same file.
PATH.SAMESTAT(S1, S2)
This tests whether two stat buffers reference the same file.
PATH.SPLIT(P)
This splits a pathname and returns tuple (head, tail), where tail is everything after the final slash.
PATH.SPLITDRIVE(P)
This splits a pathname into a drive/UNC sharepoint and relative path specifiers and returns a two-tuple
(drive_or_unc, path); either part may be empty.
PATH.SPLITEXT(P)
This splits the extension from a pathname. An extension is everything from the last dot to the end,
ignoring leading dots. For some paths without a dot, the extension part will be empty.
The sys Module for Interaction Between the Python and Python Interpreter or Python Virtual
Machine (PVM)
The os and path modules we studied above provide programmers with ways to interact with the
operating system and to access the underlying interface of the operating system. The sys module we are
going to study below allows programs to interact with Python interpreter.
The following are the objects defined in the sys module and maintained by Python interpreter. These
objects are put into two groups: dynamic objects and static objects.
The following are the dynamic objects defined in the sys module. Dynamic means the values can be
changed.
SYS.ARGV
This holds command-line arguments; argv[0] is the script pathname if known. The following example
shows what happens when we test it in Jupyter Lab:
# factorial.py
def fac(n):
if n == 0:
return 1
else:
return n * fac(n-1)
n = 9
print(f"{n}! = {fac(n)}")
import sys
print(f'argv = {sys.argv}')
python -u "d:\workshop\research\books\COMP218\samples\factorial.py"
9! = 362880
argv = ['d:\\workshop\\research\\books\\COMP218\\samples\\factorial.py']
SYS.PATH
This holds the module search path; path[0] is the script directory. The sys.path for the above Python
program/script will be
sys.path = ['d:\\workshop\\research\\books\\COMP218\\samples',
's:\\python\\python311\\python311.zip', 's:\\python\\python311\\Lib', 's:\\python\\python311\\DLLs',
'C:\\Users\\james\\AppData\\Roaming\\Python\\Python311\\site-packages',
'C:\\Users\\james\\AppData\\Roaming\\Python\\Python311\\site-packages\\win32',
'C:\\Users\\james\\AppData\\Roaming\\Python\\Python311\\site-packages\\win32\\lib',
'C:\\Users\\james\\AppData\\Roaming\\Python\\Python311\\site-packages\\Pythonwin',
's:\\python\\python311', 's:\\python\\python311\\Lib\\site-packages']
SYS.MODULES
This is a dictionary of all loaded modules. It will provide a long list of modules it is using.
SYS.DISPLAYHOOK
This contains an executable object and can be called to show the results in an interactive session.
>>> sys.displayhook
<ipykernel.displayhook.ZMQShellDisplayHook at 0x15a70b56b48>
SYS.EXCEPTHOOK
This contains an executable object and can be called to handle any uncaught exception other than
SystemExit.
SYS.STDIN
This contains the standard input file object; it is used by input().
SYS.STDOUT
It contains the standard output file object; it is used by print().
SYS.STDERR
This contains the standard error object; it is used for error messages.
SYS.LAST_TYPE
This contains the type of the last uncaught exception.
>>> sys.last_type
AttributeError
SYS.LAST_VALUE
This contains the value of the last uncaught exception.
>>> sys.last_value
AttributeError("module 'os' has no attribute 'chroot'")
SYS.LAST_TRACEBACK
This contains the traceback of the last uncaught exception.
>>> sys.last_traceback
<traceback at 0x15a70ca9388>
The above three objects are only available in an interactive session after a traceback has been printed.
The next group of objects available from the sys module are called static objects, which means the
values do not change for the given Python interpreter being used.
SYS.BUILTIN_MODULE_NAMES
This contains a tuple of built-in module names.
SYS.COPYRIGHT
This contains the copyright notice pertaining to the interpreter in use. sys.copyright in our case will
produce the following, as an example:
Copyright (c) 2001–2022 Python Software Foundation.
All Rights Reserved.
SYS.EXEC_PREFIX
This contains the prefix used to find the machine-specific Python library.
SYS.EXECUTABLE
This contains the absolute path of the executable binary of the Python interpreter.
SYS.FLOAT_INFO
This contains a named tuple with information about the float implementation.
SYS.FLOAT_REPR_STYLE
This contains a string indicating the style of repr() output for floats.
SYS.HASH_INFO
This contains a named tuple with information about the hash algorithm.
>>> print(sys.hash_info)
sys.hash_info(width = 64, modulus = 2305843009213693951, inf = 314159, nan = 0, imag = 1000003,
algorithm = 'siphash24', hash_bits = 64, seed_bits = 128, cutoff = 0)
SYS.HEXVERSION
This contains version information encoded as a single integer.
SYS.IMPLEMENTATION
This contains Python implementation information.
>>> print(sys.implementation)
namespace(cache_tag = 'cpython-37', hexversion = 50792432, name = 'cpython', version =s
ys.version_info(major = 3, minor = 7, micro = 7, releaselevel = 'final', serial = 0))
SYS.INT_INFO
This contains a named tuple with information about the int implementation.
>>> print(sys.int_info)
sys.int_info(bits_per_digit = 30, sizeof_digit = 4)
SYS.MAXSIZE
This contains the largest supported length of containers.
>>> print(sys.maxsize)
9223372036854775807
SYS.MAXUNICODE
This contains the value of the largest Unicode code point.
>>> print(sys.maxunicode)
1114111
>>> print(chr(1114111))
�
>>> print(chr(1114112)) # this is out of range and will cause an error
----------------------------------
ValueError Traceback (most recent call last)
<ipython-input-81-1965bd6642f9> in <module>
----> 1< print(chr<(1114112))
ValueError: chr() arg not in range(0x110000)
SYS.PLATFORM
This contains the platform identifier.
>>> print(sys.platform)
win32
SYS.PREFIX
This contains the prefix used to find the Python library.
>>> print(sys.prefix)
C:\ProgramData\Anaconda3
SYS.THREAD_INFO
This contains a named tuple with information about the thread implementation.
>>> print(sys.thread_info)
sys.thread_info(name = 'nt', lock = None, version = None)
SYS.VERSION
This contains the version of this interpreter as a string.
SYS.VERSION_INFO
This contains the version information as a named tuple.
SYS.DLLHANDLE
This is the integer handle of the Python DLL (Windows only).
SYS.WINVER
This contains the version number of the Python DLL (Windows only).
SYS.__STDIN__
This is the original stdin.
SYS.__STDOUT__
This is the original stdout.
SYS.__STDERR__
This is the original stderr.
SYS.__DISPLAYHOOK__
This is the original displayhook.
SYS.__EXCEPTHOOK__
This is the original excepthook.
SYS.DISPLAYHOOK()
This function prints an object to the screen and saves it in builtins.
SYS.EXCEPTHOOK()
This function prints an exception and its traceback to sys.stderr.
SYS.EXC_INFO()
This function returns thread-safe information about the current exception.
SYS.EXIT()
This function exits the interpreter by raising SystemExit.
SYS.GETDLOPENFLAGS()
This function returns flags to be used for dlopen() calls.
SYS.GETPROFILE()
This function returns the global profiling function.
SYS.GETREFCOUNT()
This function returns the reference count for an object.
SYS.GETRECURSIONLIMIT()
This function returns the max recursion depth for the interpreter.
SYS.GETSIZEOF()
This function returns the size of an object in bytes.
>>> from datetime import datetime
>>> import sys
>>> dt1 = datetime.now()
>>> print(sys.getsizeof(dt1))
48
SYS.GETTRACE()
This function gets the global debug tracing function.
SYS.SETCHECKINTERVAL()
This function controls how often the interpreter checks for events.
SYS.SETDLOPENFLAGS()
This function sets the flags to be used for dlopen() calls.
SYS.SETPROFILE()
This function sets the global profiling function.
SYS.SETRECURSIONLIMIT()
This function sets the max recursion depth for the interpreter.
SYS.SETTRACE()
This function sets the global debug tracing function.
As can be seen, the sys module gives programmers a way to find out information about the Python
interpreter and the runtime environment in particular.
Numeric
Category of value of the
logs Description level
Numeric
Category of value of the
logs Description level
NOTSET
DEBUG Events are useful for error debugging. This is the lowest level of severity. 10
CRITICAL The event is critical for the program to perform correctly and should be 50
checked and resolved. This is highest level of severity.
The logging library defines several classes and module-level functions, and it is the latter that you
would be using directly in your programs and applications. The basicConfig() function is used to set up
the logging file and other parameters for the logger. The logging() function is for logging messages
describing events in each category, as shown in the following code sample:
In [ ]: import logging
1 import logging
3 logging.basicConfig(level=logging.DEBUG,
4 filename='c:\\users\\james\\myapp.log',
5 filemode='w', format='%(name)s - %(levelname)s - %(message)s') # this line belongs to the basicConfig call
as well
Instead of directly printing out to the terminal, this code writes the logs to a file named myapp.log, and
the content of the generated logging file myapp.log is as follows:
Now as can be seen, DEBUG and INFO are recorded in the logging file because we changed the
logging level to DEBUG.
Please note that for logging configuration to take full effect, all should be configured in a single
basicConfig() method call. If the statement becomes too long to fit in a single line, the statement can take
two or more lines, as long as newline is not within the string or word, as shown above.
In the basicConfig() function call shown above, keyword arguments are used to set the level of
logging to DEBUG, the logging file name to c:\users\james\myapp.log, and the log file mode to w for
write, which means that everything in the log file will be overwritten by new logging messages. If you
want to keep the old logs and add the new logs to the end of the old logs, you need to set the file mode to
a for append, which is the default set by the logging mode.
It has been noted that the basicConfig() function for logging is not fully functional within Jupyter
Notebook. To change the logging level within Jupyter Notebook, you can use the
logging.getLogger().setLevel() method. However, you cannot set the logging file name and logging file
mode within Jupyter Notebook.
8.10 Modules for Playing and Manipulating Audio and Video Files
This section covers how to develop sound- and music-related applications with Python.
winsound
To play WAV files in your Windows applications, you can use the winsound module included in the
standard Python distribution. You can import the module and use the functions defined in it without
installing the module. Using the following statements, you can get a list of names defined in the module:
>>> import winsound
>>> dir(winsound)
['Beep', 'MB_ICONASTERISK', 'MB_ICONEXCLAMATION', 'MB_ICONHAND', 'MB_ICONQUESTION', 'MB_OK',
'MessageBeep', 'PlaySound', 'SND_ALIAS', 'SND_APPLICATION', 'SND_ASYNC', 'SND_FILENAME', 'SND_LOOP',
'SND_MEMORY', 'SND_NODEFAULT', 'SND_NOSTOP', 'SND_NOWAIT', 'SND_PURGE', '__doc__', '__file__',
'__loader__', '__name__', '__package__', '__spec__']
For more details about the module and functionalities provided, run help(winsound) in Python
interactive mode, as shown below:
>>> import winsound
>>> help(winsound)
Help on module winsound:
NAME
winsound
DESCRIPTION
PlaySound(sound, flags)—play a sound
SND_FILENAME—sound is a wav file name
SND_ALIAS—sound is a registry sound association name
SND_LOOP—play the sound repeatedly; must also specify SND_ASYNC
SND_MEMORY—sound is a memory image of a wav file
SND_PURGE—stop all instances of the specified sound
SND_ASYNC—PlaySound returns immediately
SND_NODEFAULT—Do not play a default beep if the sound cannot be found
SND_NOSTOP—Do not interrupt any sounds currently playing
SND_NOWAIT—Return immediately if the sound driver is busy
Beep(frequency, duration)—Make a beep through the PC speaker.
MessageBeep(type)—Call Windows MessageBeep.
FUNCTIONS
eep(frequency, duration)
A wrapper around the Windows Beep API.
frequency
Frequency of the sound in hertz.
Must be in the range 37 through 32,767.
duration
How long the sound should play, in milliseconds.
MessageBeep(type = 0)
Call Windows MessageBeep(x).
x defaults to MB_OK.
PlaySound(sound, flags)
A wrapper around the Windows PlaySound API.
sound
The sound to play; a filename, data, or None.
flags
Flag values, ORed together. See module documentation.
DATA
MB_ICONASTERISK = 64
MB_ICONEXCLAMATION = 48
MB_ICONHAND = 16
MB_ICONQUESTION = 32
MB_OK = 0
SND_ALIAS = 65536
SND_APPLICATION = 128
SND_ASYNC = 1
SND_FILENAME = 131072
SND_LOOP = 8
SND_MEMORY = 4
SND_NODEFAULT = 2
SND_NOSTOP = 16
SND_NOWAIT = 8192
SND_PURGE = 64
FILE
s:\python\python311\dlls\winsound.pyd
Among the functions defined in the module, PlaySound is an important one for playing sound or
music files. The following statement will play a WAV file named dj.wav.
>>> import winsound
>>> winsound.PlaySound("c:/users/comp218/dj.wav",winsound.SND_FILENAME)
When using the PlaySound function to a play sound file, you must make sure the WAV file exists in
the default or specified path. In the example above, an absolute path has been given. You can also use a
relative path that makes use of two special notations, a single dot (.) representing the current directory
and a double dot (..) representing the parent directory; or you don’t need to specify the path at all if the
WAV file is in the current directory. In any case, the rule is that you must be clearly aware of where the
file is located. This rule is applicable whenever the file is used.
PyGame
The PlaySound function in the standard winsound module can play only WAV files. To play the popular
MP3 music files in your Python applications, use the module called mixer in the PyGame package.
Because the package is usually included in the standard Python distribution, you can install the package
into your Python programming environment using the pip command, as shown below:
pip install pygame
Then you can import and use the mixer module to load and play MP3 files, as shown below:
>>> from pygame import mixer # load the required library
Hello from the pygame community. https://www.pygame.org/contribute.html
>>> mixer.init()
>>> mixer.music.load("../I_Will_Remember_You.mp3")
>>> mixer.music.play()
To learn more about how to use the mixer and mixer.music module, you can run the following
commands in Python interactive mode as shown below, after the module has been imported:
>>> help(mixer)
You can then see the functions defined within the module, as further detailed below.
CHANNEL(ID)
This is used to create and return a Channel object for controlling playback.
FADEOUT(TIME)
This sets the time to fade out the volume on all sounds before stopping.
FIND_CHANNEL(FORCE = FALSE)
This finds and returns an unused channel.
GET_BUSY()
This tests if any sound is being mixed and returns a Boolean value.
GET_INIT()
This tests if the mixer is initialized and returns a tuple (frequency, format, channels) representing the
channel.
GET_NUM_CHANNELS()
This can be used to check and return the total number of playback channels.
INIT(FREQUENCY = 22050, SIZE = −16, CHANNELS = 2, BUFFER = 4096, DEVICENAME =
NONE, ALLOWEDCHANGES = AUDIO_ALLOW_FREQUENCY_CHANGE |
AUDIO_ALLOW_CHANNELS_CHANGE)
This can be used to initialize the mixer module.
QUIT()
This can be used to uninitialize the mixer.
SET_NUM_CHANNELS(COUNT)
This can be used to set the total number of playback channels.
SET_RESERVED(COUNT)
This can be used to keep channels from being automatically used.
STOP()
This can be used to stop playback on all sound channels.
UNPAUSE()
This can be used to resume playback on sound channels after it has been paused.
The mixer module has a submodule named music. To learn what functions are available in the
mixer.music submodule module, run the following statement:
>>> help(mixer.music)
You will then see the following information about the related functions.
FADEOUT(TIME)
This can be used to stop music playback after fading out.
GET_BUSY()
This can be used to check if the music stream is playing. It will return True or False.
GET_ENDEVENT()
This can be used to get the event a channel sends when playback stops.
GET_POS()
This can be used to get the music playtime.
These functions in mixer.music are the ones used directly to handle music files. These functions are
sufficient for you to develop a high-quality music player with what you will learn in Chapter 9 on
developing GUI-based applications in Python.
Please note that the mixer module from the PyGame package can also play other types of music files
including WAV, as shown below:
>>> from pygame import mixer # import mixer module from PyGame
>>> mixer.init() # initialize the mixer
>>> mixer.music.load("../I_will_Remember_you.mp3") # load the mp3 file
>>> mixer.music.play(loops = 2) # play the most recent loaded file twice
The functions listed above are needed if you are developing a music player with PyGame. For details
on these functions, please refer to the official documentation on the PyGame mixer at
https://www.pygame.org/docs/ref/mixer.html.
**options) 2
**options) "Hello!")
window create_window(position,
**options)
Every method listed in Table 8-4 returns a unique ID for the created graphic object, which can be used
later to manipulate the object.
Note that graphic objects created by the above methods will be stacked on the Canvas and will remain
until being moved, lifted, lowered, or deleted, with the methods in Table 8-5.
dchars(item, Deletes text from an editable graphic item such as text: from is >>>
from, to = where to start deleting text, to is where to stop deleting text. If d_board.create_text(130,
None) to is omitted, only a single character is deleted. 150, text = "Hello
Python!")
>>>
d_board.dchars('text',
1,2)
Method Operation Code sample
d_board.create_text(230,
150, text="Hello!")
>>> d_board.delete(h3)
>>> d_board.delete(3)
>>> d_board.delete(10)
>>> d_board.delete(11)
>>> d_board.delete(9)
Canvas has many other methods for accessing and manipulating graphic objects. Running the
following statements in Python interactive mode will give you a list of names defined within the Canvas
class.
>>> from tkinter import *
>>> dir(Canvas)
['_Misc__winfo_getint', '_Misc__winfo_parseitem', '__class__', '__delattr__', '__dict__', '__dir__',
'__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__',
'__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', '_bind', '_configure', '_create', '_displayof', '_do',
'_getboolean', '_getconfigure', '_getconfigure1', '_getdoubles', '_getints', '_grid_configure',
'_gridconvvalue', '_last_child_ids', '_nametowidget', '_noarg_', '_options', '_register',
'_report_exception', '_root', '_setup', '_subst_format', '_subst_format_str', '_substitute',
'_tclCommands', '_windowingsystem', 'addtag', 'addtag_above', 'addtag_all', 'addtag_below',
'addtag_closest', 'addtag_enclosed', 'addtag_overlapping', 'addtag_withtag', 'after', 'after_cancel',
'after_idle', 'anchor', 'bbox', 'bell', 'bind', 'bind_all', 'bind_class', 'bindtags', 'canvasx',
'canvasy', 'cget', 'clipboard_append', 'clipboard_clear', 'clipboard_get', 'columnconfigure',
'config', 'configure', 'coords', 'create_arc', 'create_bitmap', 'create_image', 'create_line',
'create_oval', 'create_polygon', 'create_rectangle', 'create_text', 'create_window', 'dchars',
'delete', 'deletecommand', 'destroy', 'dtag', 'event_add', 'event_delete', 'event_generate',
'event_info', 'find', 'find_above', 'find_all', 'find_below', 'find_closest', 'find_enclosed',
'find_overlapping', 'find_withtag', 'focus', 'focus_displayof', 'focus_force', 'focus_get',
'focus_lastfor', 'focus_set', 'forget', 'getboolean', 'getdouble', 'getint', 'gettags', 'getvar',
'grab_current', 'grab_release', 'grab_set', 'grab_set_global', 'grab_status', 'grid', 'grid_anchor',
'grid_bbox', 'grid_columnconfigure', 'grid_configure', 'grid_forget', 'grid_info', 'grid_location',
'grid_propagate', 'grid_remove', 'grid_rowconfigure', 'grid_size', 'grid_slaves', 'icursor',
'image_names', 'image_types', 'index', 'info', 'insert', 'itemcget', 'itemconfig', 'itemconfigure',
'keys', 'lift', 'location', 'lower', 'mainloop', 'move', 'nametowidget', 'option_add',
'option_clear', 'option_get', 'option_readfile', 'pack', 'pack_configure', 'pack_forget',
'pack_info', 'pack_propagate', 'pack_slaves', 'place', 'place_configure', 'place_forget',
'place_info', 'place_slaves', 'postscript', 'propagate', 'quit', 'register', 'rowconfigure', 'scale',
'scan_dragto', 'scan_mark', 'select_adjust', 'select_clear', 'select_from', 'select_item',
'select_to', 'selection_clear', 'selection_get', 'selection_handle', 'selection_own',
'selection_own_get', 'send', 'setvar', 'size', 'slaves', 'tag_bind', 'tag_lower', 'tag_raise',
'tag_unbind', 'tk_bisque', 'tk_focusFollowsMouse', 'tk_focusNext', 'tk_focusPrev', 'tk_setPalette',
'tk_strictMotif', 'tkraise', 'type', 'unbind', 'unbind_all', 'unbind_class', 'update',
'update_idletasks', 'wait_variable', 'wait_visibility', 'wait_window', 'waitvar', 'winfo_atom',
'winfo_atomname', 'winfo_cells', 'winfo_children', 'winfo_class', 'winfo_colormapfull',
'winfo_containing', 'winfo_depth', 'winfo_exists', 'winfo_fpixels', 'winfo_geometry', 'winfo_height',
'winfo_id', 'winfo_interps', 'winfo_ismapped', 'winfo_manager', 'winfo_name', 'winfo_parent',
'winfo_pathname', 'winfo_pixels', 'winfo_pointerx', 'winfo_pointerxy', 'winfo_pointery',
'winfo_reqheight', 'winfo_reqwidth', 'winfo_rgb', 'winfo_rootx', 'winfo_rooty', 'winfo_screen',
'winfo_screencells', 'winfo_screendepth', 'winfo_screenheight', 'winfo_screenmmheight',
'winfo_screenmmwidth', 'winfo_screenvisual', 'winfo_screenwidth', 'winfo_server', 'winfo_toplevel',
'winfo_viewable', 'winfo_visual', 'winfo_visualid', 'winfo_visualsavailable', 'winfo_vrootheight',
'winfo_vrootwidth', 'winfo_vrootx', 'winfo_vrooty', 'winfo_width', 'winfo_x', 'winfo_y', 'xview',
'xview_moveto', 'xview_scroll', 'yview', 'yview_moveto', 'yview_scroll']
You can then call help on each of the names in the list to learn more about the name defined. The
following are just two examples:
>>> help(Canvas.addtag)
Running help on the function addtag in module tkinter outputs the following:
addtag(self, *args)
Internal function.
>>> help(Canvas.after)
Running help on the function after in module tkinter outputs the following:
>>> help(Canvas.create_image)
Running help on the function create_image in module tkinter outputs the following:
create_image(self, *args, **kw)
Create image item with coordinates x1, y1.
The following coding example will draw a line on a Canvas:
import tkinter
from tkinter.constants import *
tk = tkinter.Tk()
canvas = tkinter.Canvas(tk, relief = RIDGE, borderwidth = 2)
canvas.pack(fill = BOTH, expand=1)
ln1 = canvas.create_line(100, 100, 300, 300, width = 6)
tk.mainloop()
How can all these manipulations be done within your computer? First, an image is made of pixels, which
can be stored in an m × n matrix, or two-dimensional array, mapped to a rectangular area of the computer
screen. The value of each cell of the matrix represents a pixel and contains all the information about it.
All manipulations to the image can be done by manipulating the matrix or its values.
To manipulate an image with Python, you can use a package called Pillow (available from
https://pypi.org/project/Pillow/2.2.1/ or https://github.com/python-pillow/Pillow). Because it is not a
standard part of the Python library, you will need to install it with the following statement:
• Image.convert(self, mode = None, matrix = None, dither = None, palette = 0, colors = 256)
makes various conversions to the image object.
Figure 8-4: Picture sharpened with Pillow (©Harris Wang, Athabasca University)
There are other methods defined within the Image class for other purposes. You can find out more info
about the Image class by running the following statement in Python interactive mode:
>>> from PIL import Image, ImageFilter
>>> help(Image.Image)
As we have seen from the above list, the Image class has provided a good set of methods to
manipulate an image.
The ImageFilter module provides some filtering operations on images, as the name implies. These
filtering operations include blurring, box blurring, contouring, colour transformation, detailing, edge
enhancing, embossing, sharpening, smoothing, and more.
Our next example is to visualize the world population changes in some regions as well as world total
since 1960. The program code is as follows:
import pandas as pd
import matplotlib.pyplot as mplt
content = pd.read_excel("world-population.xls")
years = [1960, 1970, 1980, 1990, 2000, 2010, 2017]
mplt.plot(years, content.iloc[0, 1:])
mplt.plot(years, content.iloc[1, 1:])
mplt.plot(years, content.iloc[7, 1:])
mplt.plot(years, content.iloc[11, 1:])
mplt.plot(years, content.iloc[12, 1:])
mplt.plot(years, content.iloc[17, 1:])
mplt.plot(years, content.iloc[22, 1:])
mplt.title("Population - World Total and Region Total")
mplt.xlabel("years")
mplt.ylabel("Populations (in millions)")
mplt.legend(["World Total", "Africa", "Latin America", "North America", "Asia", "Europe", "Oceana"])
mplt.show()
In the program, the pandas module is used to read and prepare the data. For details on how it works,
please read the complete documentation at https://pandas.pydata.org/docs/—the user guide at
https://pandas.pydata.org/docs/user_guide/index.html#user-guide in particular.
The rendered result of the program is shown in Figure 8-6.
NumPy allows you to do math manipulations on a data set, most often manipulations on a matrix.
Here is an example:
import numpy as np # import numpy
Exercises
1. Open VS Code, create or open a Jupyter Notebook file (.ipynb), and select a Python
virtual environment for the notebook file. Open a terminal and run the pip list
command to see what library modules have been installed in the virtual environment.
In the output of your VS Code shell terminal, identify some interesting packages
and modules, and write a summary of those packages and modules in a Word
document, including what each is developed for, where it may be used, and so on.
2. In VS Code, open the Jupyter Notebook file named chapter-8.ipynb. Create a new
cell and import the math module, run the help command to study each of the
functions defined in the math module, and do some hands-on coding with the
function.
3. Search the internet for tutorials or other web documents related to web scraping with
Python and choose some to watch or read. Take some coding samples to run in your
Jupyter Notebook within VS Code, then develop your own application based on the
code samples.
Projects
1. Rational numbers are those real numbers that can be represented as a quotient of two integers
such as a/b, which can then be represented by the pair of integers a and b. For this project,
define a module that contains the definition of a class named Rational, within which dunder
methods for print, addition, subtraction, division, multiplication, and various comparisons are
defined.
2. Develop an application using the math module to calculate and display a table of squares for
integers from 0 to 99. The layout is illustrated in Table 8-6.
0 1 2 3 4 5 6 7 8 9
0 0 1 4 9 26 25 36 49 8 9
1 100 121 144 169 196 225 256 289 324 361
2 … … …
3. Develop an application to calculate and display a table showing the square roots of integers
from 0 to 99 (similar to what you did for Project 2).
OceanofPDF.com
Chapter 9
Develop GUI-Based Applications
Learning Objectives
After completing this chapter, you should be able to
Please note that although the frame size is measured in pixels, the
coordinate of each grid above is only a relative location within the grid and
has nothing to do with pixels. The size of each grid is dynamically
determined by the object or widget placed in it.
Tkinter Module
The following code running from Python interactive mode renders a
window/frame (as shown in Figure 9-1):
>>> from tkinter import *
>>> f = Tk()
The following statements can be used to set the title and the size of the
window:
>>> f.title("My First GUI App")
>>> f.geometry("300 x 200")
Figure 9-1: A window rendered by Python with Tkinter
In the above, the first statement creates a label object with the text “This
is my first label” on it, whereas the second statement places the object in a
specific grid of the window. If no arguments are specified for the grid, the
default value is used, which is the next available grid in the window in
order from top to bottom, left to right.
Figure 9-2: A GUI example with more details
Similarly, we can add an Entry widget to the window using the following
statements:
In [ ]: f = Tk()
f.geometry("300x200")
lb.grid(row = 0, column = 0)
ent = tkinter.Entry()
ent.grid(row = 0, column = 1)
f.mainloop()
By now the window should look like the one shown in Figure 9-3.
Figure 9-3: A GUI example with added entry widget
In addition to the Entry widget for taking single-line text input, the
Button and Text widgets take mouse click and multiple-line text input,
respectively, from users. We can add buttons and text boxes to the window
with the following statements:
In [ ]: f = Tk()
f.geometry("300 x 200")
lb.grid(row = 0, column = 0)
ent = tkinter.Entry()
ent.grid(row = 0, column = 1)
btn.grid(column = 0, row = 1)
f.mainloop()
How can we make the app respond to the user’s input and do what we
want it to do? We need to attach an even handler to the intended object,
such as a button, as shown below:
In [ ]: f = Tk()
f.geometry("300 x 200")
lb.grid(row = 0, column = 0)
ent = tkinter.Entry()
ent.grid(row = 0, column = 1)
btn.grid(column = 0, row = 1)
def hdl():
f.mainloop()
help(Frame)
As always, you can also search the internet for any widget in the tkinter
module to get help, including very detailed discussions on its use.
With what we have learned so far, we should be ready to develop a real
GUI-based application, which is the GUI version of a grade conversion
program. The conversion is based on the data in Table 9-1, and the case
study is in Table 9-2.
A+ 90–100 C+ 67–69
A 85–89 C 64–66
A- 80-84 C- 60-63
B+ 76–79 D+ 55–59
B 73–75 D 50–54
B− 70–72 F 0–49
The """
"""
def n_to_l(n_g):
n_g = round(float(n_g))
else:
lg = "invalid mark!"
return lg
def hdl():
n = int(ent1.get())
lb2.config(text = f"{n_to_l(n)}")
return -1
w = Tk()
w.geometry("500 x 200")
ent1 = Entry()
btn.config(command = hdl)
btn_quit.config(command=quit)
mainloop()
In the coding example, the .grid() method positions a widget in the parent
widget in a grid or cell. The options that can be used with the .grid() method
are as follows:
def n_to_l(n_g):
n_g = round(float(n_g))
if n_g in range(90, 101):
lg = f"Letter grade of {n_g} is A+"
elif n_g in range(85, 90):
lg = f"Letter grade of {n_g} is A"
elif n_g in range(80, 85):
lg = f"Letter grade of {n_g} is A-"
elif n_g in range(76, 80):
lg = f"Letter grade of {n_g} is B+"
elif n_g in range(73, 76):
lg = f"Letter grade of {n_g} is B"
elif n_g in range(70, 73):
lg = f"Letter grade of {n_g} is B-"
elif n_g in range(67, 70):
lg = f"Letter grade of {n_g} is C+"
elif n_g in range(64, 67):
lg = f"Letter grade of {n_g} is C"
elif n_g in range(60, 64):
lg = f"Letter grade of {n_g} is C-"
elif n_g in range(55, 60):
lg = f"Letter grade of {n_g} is D+"
elif n_g in range(50, 54):
lg = f"Letter grade of {n_g} is D"
elif n_g in range(0, 50):
lg = f"Letter grade of {n_g} is F"
else:
lg = "invalid mark!"
return lg
def hdl():
n = int(ent1.get())
lb2.config(text = f"{n_to_l(n)}")
return -1
w = Frame()
# to add frame widget
If you don’t like placing widgets with the .geometry() method, you may
use the .pack() method to let the PVM automatically place the widgets for
you. The new GUI-based app and the revised Python code are shown in
Figure 9-8 and below.
def n_to_l(n_g):
n_g = round(float(n_g))
if n_g in range(90, 101):
lg = f"Letter grade of {n_g} is A+"
elif n_g in range(85, 90):
lg = f"Letter grade of {n_g} is A"
elif n_g in range(80, 85):
lg = f"Letter grade of {n_g} is A-"
elif n_g in range(76, 80):
lg = f"Letter grade of {n_g} is B+"
elif n_g in range(73, 76):
lg = f"Letter grade of {n_g} is B"
elif n_g in range(70, 73):
lg = f"Letter grade of {n_g} is B-"
elif n_g in range(67, 70):
lg = f"Letter grade of {n_g} is C+"
elif n_g in range(64, 67):
lg = f"Letter grade of {n_g} is C"
elif n_g in range(60, 64):
lg = f"Letter grade of {n_g} is C-"
elif n_g in range(55, 60):
lg = f"Letter grade of {n_g} is D+"
elif n_g in range(50, 54):
lg = f"Letter grade of {n_g} is D"
elif n_g in range(0, 50):
lg = f"Letter grade of {n_g} is F"
else:
lg = "invalid mark!"
return lg
def hdl():
n = int(ent1.get())
lb2.config(text = f"{n_to_l(n)}")
return -1
w = Tk()
w.title("My GUI-based grade converter")
w.geometry("500 x 200")
lb1 = Label(text = "Please input percentage grade:")
lb1.pack(fill = Y, expand = 1)
ent1 = Entry()
ent1.pack(expand = 0)
btn_convert = Button(text = "Convert", background = "#33FF88")
btn_convert.pack(padx = 10, side = LEFT, expand = 0)
btn_convert.config(command = hdl)
btn_quit = Button(text = "Quit", background = "#FF0000")
btn_quit.pack(padx = 10, side = RIGHT, expand = 0)
btn_quit.config(command = quit)
lb2 = Label(text = "Letter grade will be displayed here")
lb2.pack(fill = Y, expand = 1)
mainloop()
# this statement must be placed at the end to keep the window alive
As you can see, the GUI-based app is rendered much more nicely with
the .pack() method. The .pack() method is used to pack a widget in the
parent widget. The options of the .pack() method and their meaning are as
follows:
Because all the widgets inherit behaviours from the Widget class, it is
worth learning about the general methods available in the Widget class for
manipulating widgets.
tkinter.ttk—Tk-Themed Widgets
In the past, people have complained about the look of GUI and the widgets
of tkinter, which led to the development of themed widgets of tkinter, or Ttk
for short. Now the Ttk module is part of the standard Python distribution.
To use it, all you need to do is to import the modules in the sequence shown
below to make sure Ttk overrides definitions of classes as intended.
>>> from tkinter import *
>>> import tkinter.ttk
BUTTON(WIDGET)
Ttk Button displays a textual label and/or image and evaluates a command
when pressed. In addition to the methods inherited from Widget, it has
method specific for its purpose, invoke(self), which invokes the command
associated with the button.
CHECKBUTTON
Ttk Checkbutton will be either in an on or off state. It has a specific method
called invoke(self) in addition to those inherited from Widget. The
invoke(self) will switch the Checkbutton between on and off states, further
invoke the associated command, and return the result of executing the
command associated with Checkbutton.
ENTRY(WIDGET, TKINTER.ENTRY)
Ttk Entry displays a one-line text string that allows that string to be edited
by the user. It inherits from Widget and tkinter.Entry.
COMBOBOX(ENTRY)
Ttk Combobox widget combines a text field with a pop-down list of values.
It inherits from Ttk Entry, described above. It has two methods of its own:
1. current(self, newindex = None)—if newindex is supplied, it sets
the combobox value to the element at position newindex in the
list of values. Otherwise, it returns the index of the current value
in the list of values or −1 if the current value does not appear in
the list.
2. set(self, value)—sets the value of the combobox to “value.”
SPINBOX(ENTRY)
Ttk Spinbox is an Entry with increment and decrement arrows. It is
commonly used for number entry or to select from a list of string values.
FRAME(WIDGET)
Ttk Frame is a container used to group other widgets together.
LABELEDSCALE(FRAME)
Ttk Scale is used with Ttk Label, indicating its current value. Ttk Scale can
be accessed through instance.scale, and Ttk Label can be accessed through
instance.label.
LABEL(WIDGET)
Ttk Label displays a textual label and/or image.
LABELFRAME(WIDGET)
Ttk Labelframe is a container used to group other widgets together. It has
an optional label, which may be a plaintext string or another widget.
MENUBUTTON(WIDGET)
Ttk Menubutton displays a textual label and/or image. It will display a
menu when pressed.
OPTIONMENU(MENUBUTTON)
Ttk OptionMenu allows the user to select a value from a menu.
NOTEBOOK(WIDGET)
Ttk Notebook manages a collection of windows and displays a single one at
a time. Each child window is associated with a tab that the user may select
to make the associated window show up. This gives us a way to implement
tabs like those in web browsers.
PANEDWINDOW(WIDGET, TKINTER.PANEDWINDOW)
Ttk Panedwindow displays a number of subwindows stacked either
vertically or horizontally. It has the following specific methods:
1. remove(self, child)
2. insert(self, pos, child, **kw)—inserts a pane at the specified
positions.
3. pane(self, pane, option = None, **kw)—queries or modifies the
options of the specified pane.
4. sashpos(self, index, newpos = None)—if newpos is specified, sets
the position of sash number index and returns the new position of
sash number index.
PROGRESSBAR(WIDGET)
Ttk Progressbar shows the status of a long-running operation. It can operate
in two modes. Determinate mode shows the amount completed relative to
the total amount of work to be done, and indeterminate mode provides an
animated display to let the user know that something is happening.
RADIOBUTTON
Ttk Radiobuttons are used in groups to show or change a set of mutually
exclusive options. The specific method invoke(self) sets the option variable
to the option value, selects the widget, and invokes the associated
command. It returns the result of the command or an empty string if no
command is specified.
SCALE(WIDGET, TKINTER.SCALE)
Ttk Scale is typically used to control the numeric value of a linked variable
that varies uniformly over some range.
SCROLLBAR(WIDGET, TKINTER.SCROLLBAR)
Ttk Scrollbar controls the viewport of a scrollable widget.
SEPARATOR(WIDGET)
Ttk Separator displays a horizontal or vertical separator bar.
SIZEGRIP(WIDGET)
Ttk Sizegrip allows the user to resize the containing top-level window by
pressing and dragging the grip.
class FileManager:
def __init__(self):
self.root = tk.Tk()
self.tree = ttk.Treeview(self.root)
self.tree.pack()
self.tree["columns"] = ("one", "two", "three", "four")
self.tree.heading("one", text="Path")
self.tree.heading("two", text="File name")
self.tree.heading("three", text="File size")
self.tree.heading("four", text="Last modified")
self.tree.insert("", "end", text="1", values=("/home/james/",
"a.txt","213","June 3, 2023" ))
self.tree.insert("", "end", text="2", values=("/home/james/",
"b.txt","215","June 5, 2023" ))
self.tree.insert("", "end", text="3", values=("/home/james/",
"c.txt","217","June 7, 2023" ))
self.root.mainloop()
FileManager()
Chapter Summary
• Terminal-based applications are those started and rendered within
a terminal.
• A terminal is a system command-line-based application in which
you can interact with a computer.
• On the Windows platform, Windows terminal, Windows
PowerShell, and command prompt are examples of terminals.
• Within a terminal-based application, pointing devices such as a
mouse cannot be used to interact with the application.
• A graphical user interface is a two-dimensional graphic area in
which graphic objects or widgets can be created, placed, located,
and accessed with mouse and keyboard.
• GUI-based applications look nicer and are much more user-
friendly.
• Python has some very well-developed library modules for the
development of applications with graphical user interface.
• The Tk and Themed Tk (Ttk) are the modules covered in this text;
both come with the Tkinter package.
• The Tk module provides the fundamental widgets and operations
needed for a graphic interface.
• To use the Tk module, use import tkinter, import tkinter as tk, or
from tkinter import. *.
• The Themed Tk (Ttk) module provides programmers with more
styled widgets to develop applications with a nicer graphical user
interface.
• To ensure you are using the Ttk module instead of Tk module,
override Tk by running statements from tkinter import * and
from tkinter.ttk import * in order.
• To build a graphical user interface, create a main frame or window
first.
• Other widgets can be created and added to the main frame/window
as needed.
• Each widget has certain properties/attributes such as size, colour,
and more.
• The properties of a widget can be set when created and changed
later.
• A widget can be placed at particular location within the main
frame or subframe.
• A function/method can be bound to widgets, such as a button, to
help users interact with the graphical user interface.
• A graphical user interface needs to be rendered by calling the
mainloop() method of main frame object.
Exercises
Projects
1. For this project, develop a GUI-based music player with the
module mixer.music as well as the os and os.path modules for file
navigation. The player should have a panel for the navigation and
selection of music files, as well as buttons to control play, stop,
and pause.
2. For this project, develop a course management system with a
graphical user interface that meets the following requirements:
a. Define a student class modelling a student, including their
name, student id, and start date in the class, as well as the
name of the tutor assigned to them and a list of their
assessment records. Each assessment record will be a
tuple containing a number to identify the assessment, the
weight of the assessment, and the mark, which should be 0
for a newly added instance to a course.
b. Define a course class modelling a course, including its
course number (such as comp218), title, and revision
number, as well as the date of its initial offering and a list
of its students, professor(s). Additionally, include an
assessment schedule as a list of assessment items where
each assessment item is represented as a tuple of (id,
name, weight) in which the id is the assessment item id,
the name is the assessment name such as assignment 1 or
final exam, and the weight is the percentage of the
assessment that will go toward the final grade.
c. The GUI program should include and do all of the
following:
• There should be a button for adding a new course
to the system, which will open a form for input
and save the basic course info (previously
mentioned), with the list of students as empty.
Note that when saving the basic course info, the
system should be able to check whether the
weight of all the assessment items makes up
100%.
• When a new course is added to the system, a
unique binary file will be created as permanent
storage of the course data.
• At the start of the system, it should automatically
load all courses from their respective binary
files to restore their internal object
representation.
• There should be a button to get a list of courses
being offered to students.
• A user should be able to select a course from the
list.
• A user should be able to add students to the
selected course.
• A user should be able to see a list of students in
the course.
• A user should be able to select a student from the
list.
• A user should be able to record an assessment for
the selected student.
• The system should be able to automatically
calculate and display the final grade of the
student for the course.
• A user should be able to see a list of assessments,
including the calculated final grade for the
selected student.
• There should be a button to shut down the
system, but before shutting down the
application, the system must save/pickle each
piece of course data back to its binary file.
d. Your analysis and design of the system should be well
documented in your assignment report.
e. Within each of your program files, there should be a
docstring at the beginning stating the name and purpose of
the file, as well as its ownership and revision history. One
docstring is required for each class and function/method
class. An end-of-line comment is desired when deemed
necessary.
3. In Project 1 of Chapter 7, you developed a terminal-based quiz
system. For this project, you are required to develop a GUI-based
quiz system also using the Quiz_item and Quiz classes you wrote
in Chapter 7’s Exercises 7 and 8. The system should have
controls/widgets on the GUI that will allow a user to do the
following:
a. Create a quiz.
b. Select a quiz and add new quiz items.
c. Select a quiz and preview all the quiz items.
d. Select a quiz and execute the quiz by presenting the quiz
items one by one.
4. Modify the quiz system developed for Project 3 so that after the
quiz, it will present to the user the score as a percentage and the
correct answers to incorrectly answered questions. The quiz items
should be displayed to the user one by one during the quiz. Add a
timer to the quiz so that the entire quiz must be done within a
given time. To make sense of the timer function, you will need to
show the total number of quiz items, the number of items left to
be answered, the total amount of time allocated for the entire
quiz, and the amount of time left for the remaining quiz items.
5. Further modify the quiz system developed for Projects 3 and 4, so
that not only is the quiz timed, but each quiz item is also timed
too, meaning that the user must answer each quiz question within
a given time. For simplicity, we can assume that the time
allocated to each quiz item is the same and equal to the total time
allocated to the quiz divided by the total number of questions in
the quiz. To make better sense of both timers now, the time
(number of seconds) left for a quiz question also needs to be
displayed, and the quiz will move to the next question as soon as
the question is answered or the timer for the question has run out.
OceanofPDF.com