Thinkcspy
Thinkcspy
Scientist
The PreTeXt Interactive Edition
How to Think Like a Computer
Scientist
The PreTeXt Interactive Edition
Preface to the First and Second
Editions
by Jeffrey Elkner. This book owes its existence to the collaboration made
possible by the Internet and the free software movement. Its three authors—a
college professor, a high school teacher, and a professional programmer—never
met face to face to work on it, but we have been able to collaborate closely,
aided by many other folks who have taken the time and energy to send us their
feedback.
We think this book is a testament to the benefits and future possibilities of
this kind of collaboration, the framework for which has been put in place by
Richard Stallman and the Free Software Foundation.
How and why I came to use Python. In 1999, the College Board’s Ad-
vanced Placement (AP) Computer Science exam was given in C++ for the
first time. As in many high schools throughout the country, the decision to
change languages had a direct impact on the computer science curriculum at
Yorktown High School in Arlington, Virginia, where I teach. Up to this point,
Pascal was the language of instruction in both our first-year and AP courses.
In keeping with past practice of giving students two years of exposure to the
same language, we made the decision to switch to C++ in the first year course
for the 1997-98 school year so that we would be in step with the College Board’s
change for the AP course the following year.
Two years later, I was convinced that C++ was a poor choice to use for
introducing students to computer science. While it is certainly a very powerful
programming language, it is also an extremely difficult language to learn and
teach. I found myself constantly fighting with C++’s difficult syntax and
multiple ways of doing things, and I was losing many students unnecessarily as
a result. Convinced there had to be a better language choice for our first-year
class, I went looking for an alternative to C++.
I needed a language that would run on the machines in our GNU/Linux
lab as well as on the Windows and Macintosh platforms most students have at
home. I wanted it to be free software, so that students could use it at home
regardless of their income. I wanted a language that was used by professional
programmers, and one that had an active developer community around it. It
had to support both procedural and object-oriented programming. And most
importantly, it had to be easy to learn and teach. When I investigated the
choices with these goals in mind, Python stood out as the best candidate for
the job.
I asked one of Yorktown’s talented students, Matt Ahrens, to give Python a
try. In two months he not only learned the language but wrote an application
called pyTicket that enabled our staff to report technology problems via the
iv
v
Web. I knew that Matt could not have finished an application of that scale
in so short a time in C++, and this accomplishment, combined with Matt’s
positive assessment of Python, suggested that Python was the solution I was
looking for.
Building a community. I have received email from all over the globe from
people using this book to learn or to teach programming. A user community
has begun to emerge, and many people have been contributing to the project by
sending in materials for the companion Website at http://openbookproject.net/
pybiblio3 .
With the continued growth of Python, I expect the growth in the user
community to continue and accelerate. The emergence of this user community
and the possibility it suggests for similar collaboration among educators have
been the most exciting parts of working on this project for me. By working
together, we can increase the quality of materials available for our use and save
valuable time. I invite you to join our community and look forward to hearing
from you. Please write to me at [email protected] .Jeffrey Elkner
Governor’s Career and Technical Academy in Arlington
Arlington, Virginia
3 http://openbookproject.net/pybiblio
4 mailto:[email protected]
Preface to the Interactive Edition
viii
Contents
1 General Introduction 1
1.1 The Way of the Program . . . . . . . . . . . . . . . 1
1.2 Algorithms . . . . . . . . . . . . . . . . . . . . 1
1.3 The Python Programming Language . . . . . . . . . . . 2
1.4 Executing Python in this Book . . . . . . . . . . . . . 4
1.5 More About Programs . . . . . . . . . . . . . . . . 6
1.6 What is Debugging? . . . . . . . . . . . . . . . . . 7
1.7 Syntax errors . . . . . . . . . . . . . . . . . . . 7
1.8 Runtime Errors . . . . . . . . . . . . . . . . . . 8
1.9 Semantic Errors . . . . . . . . . . . . . . . . . . 8
1.10 Experimental Debugging . . . . . . . . . . . . . . . 9
1.11 Formal and Natural Languages . . . . . . . . . . . . . 9
1.12 A Typical First Program . . . . . . . . . . . . . . . 11
1.13 Comments . . . . . . . . . . . . . . . . . . . . 12
1.14 Glossary . . . . . . . . . . . . . . . . . . . . . 12
1.15 Exercises . . . . . . . . . . . . . . . . . . . . . 14
ix
CONTENTS x
3 Debugging Interlude 1 35
3.1 How to be a Successful Programmer . . . . . . . . . . . 35
3.2 How to Avoid Debugging . . . . . . . . . . . . . . . 35
3.3 Beginning tips for Debugging . . . . . . . . . . . . . 38
3.4 Know Your Error Messages . . . . . . . . . . . . . . 38
3.5 Summary . . . . . . . . . . . . . . . . . . . . . 44
3.6 Exercises . . . . . . . . . . . . . . . . . . . . . 44
5 Python Modules 75
5.1 Modules and Getting Help . . . . . . . . . . . . . . 75
5.2 More About Using Modules . . . . . . . . . . . . . . 78
5.3 The math module. . . . . . . . . . . . . . . . . . 78
5.4 The random module . . . . . . . . . . . . . . . . . 79
5.5 Creating Modules . . . . . . . . . . . . . . . . . . 81
5.6 Glossary . . . . . . . . . . . . . . . . . . . . . 87
5.7 Exercises . . . . . . . . . . . . . . . . . . . . . 87
6 Functions 88
6.1 Functions. . . . . . . . . . . . . . . . . . . . . 88
6.2 Functions that Return Values . . . . . . . . . . . . . 93
6.3 Unit Testing. . . . . . . . . . . . . . . . . . . . 96
6.4 Variables and Parameters are Local . . . . . . . . . . . 98
6.5 The Accumulator Pattern . . . . . . . . . . . . . . . 100
6.6 Functions can Call Other Functions . . . . . . . . . . . 103
6.7 Flow of Execution Summary . . . . . . . . . . . . . . 106
6.8 Using a Main Function . . . . . . . . . . . . . . . . 107
6.9 Program Development . . . . . . . . . . . . . . . . 109
6.10 Composition . . . . . . . . . . . . . . . . . . . 112
6.11 A Turtle Bar Chart . . . . . . . . . . . . . . . . . 112
6.12 Glossary . . . . . . . . . . . . . . . . . . . . . 115
6.13 Exercises . . . . . . . . . . . . . . . . . . . . . 115
7 Selection 122
7.1 Boolean Values and Boolean Expressions . . . . . . . . . 122
7.2 Logical operators . . . . . . . . . . . . . . . . . . 123
7.3 Precedence of Operators . . . . . . . . . . . . . . . 126
7.4 Conditional Execution: Binary Selection . . . . . . . . . 127
CONTENTS xi
9 Strings 170
9.1 Strings Revisited . . . . . . . . . . . . . . . . . . 170
9.2 A Collection Data Type . . . . . . . . . . . . . . . 170
9.3 Operations on Strings . . . . . . . . . . . . . . . . 170
9.4 Index Operator: Working with the Characters of a String . . . 172
9.5 String Methods . . . . . . . . . . . . . . . . . . 173
9.6 Length. . . . . . . . . . . . . . . . . . . . . . 176
9.7 The Slice Operator . . . . . . . . . . . . . . . . . 177
9.8 String Comparison . . . . . . . . . . . . . . . . . 178
9.9 Strings are Immutable . . . . . . . . . . . . . . . . 180
9.10 Traversal and the for Loop: By Item . . . . . . . . . . 181
9.11 Traversal and the for Loop: By Index . . . . . . . . . . 182
9.12 Traversal and the while Loop . . . . . . . . . . . . . 183
9.13 The in and not in operators . . . . . . . . . . . . . 183
9.14 The Accumulator Pattern with Strings . . . . . . . . . . 184
9.15 Turtles and Strings and L-Systems . . . . . . . . . . . 185
9.16 Looping and Counting . . . . . . . . . . . . . . . . 189
9.17 A find function . . . . . . . . . . . . . . . . . . 189
9.18 Optional parameters . . . . . . . . . . . . . . . . . 190
9.19 Character classification . . . . . . . . . . . . . . . . 192
9.20 Summary . . . . . . . . . . . . . . . . . . . . . 192
9.21 Glossary . . . . . . . . . . . . . . . . . . . . . 193
9.22 Exercises . . . . . . . . . . . . . . . . . . . . . 194
10 Lists 202
10.1 Lists . . . . . . . . . . . . . . . . . . . . . . 202
10.2 List Values . . . . . . . . . . . . . . . . . . . . 202
10.3 List Length . . . . . . . . . . . . . . . . . . . . 203
CONTENTS xii
11 Files 235
11.1 Working with Data Files . . . . . . . . . . . . . . . 235
11.2 Finding a File on your Disk . . . . . . . . . . . . . . 235
11.3 Reading a File . . . . . . . . . . . . . . . . . . . 237
11.4 Iterating over lines in a file . . . . . . . . . . . . . . 237
11.5 Alternative File Reading Methods . . . . . . . . . . . . 238
11.6 Writing Text Files . . . . . . . . . . . . . . . . . 240
11.7 With Statements . . . . . . . . . . . . . . . . . . 241
11.8 Fetching Something From The Web . . . . . . . . . . . 242
11.9 Glossary . . . . . . . . . . . . . . . . . . . . . 242
11.10Exercises . . . . . . . . . . . . . . . . . . . . . 243
12 Dictionaries 244
12.1 Dictionaries . . . . . . . . . . . . . . . . . . . . 244
12.2 Dictionary Operations . . . . . . . . . . . . . . . . 245
12.3 Dictionary Methods . . . . . . . . . . . . . . . . . 246
12.4 Aliasing and Copying . . . . . . . . . . . . . . . . 249
12.5 Sparse Matrices . . . . . . . . . . . . . . . . . . 249
12.6 Glossary . . . . . . . . . . . . . . . . . . . . . 251
12.7 Exercises . . . . . . . . . . . . . . . . . . . . . 251
CONTENTS xiii
13 Exceptions 255
13.1 What is an exception? . . . . . . . . . . . . . . . . 255
13.2 Runetime Stack and raise command. . . . . . . . . . . 255
13.3 Standard Exceptions. . . . . . . . . . . . . . . . . 257
13.4 Principles for using Exceptions . . . . . . . . . . . . . 259
13.5 Exceptions Syntax . . . . . . . . . . . . . . . . . 260
13.6 The finally clause of the try statement . . . . . . . . . 262
13.7 Glossary . . . . . . . . . . . . . . . . . . . . . 263
13.8 Exercises . . . . . . . . . . . . . . . . . . . . . 263
16 Recursion 302
16.1 What Is Recursion? . . . . . . . . . . . . . . . . . 302
16.2 Calculating the Sum of a List of Numbers . . . . . . . . . 302
16.3 The Three Laws of Recursion . . . . . . . . . . . . . 304
16.4 Converting an Integer to a String in Any Base . . . . . . . 305
16.5 Visualizing Recursion . . . . . . . . . . . . . . . . 308
16.6 Sierpinski Triangle . . . . . . . . . . . . . . . . . 311
16.7 Glossary . . . . . . . . . . . . . . . . . . . . . 313
16.8 Programming Exercises. . . . . . . . . . . . . . . . 314
16.9 Exercises . . . . . . . . . . . . . . . . . . . . . 316
CONTENTS xiv
19 Inheritance 337
19.1 Pillars of OOP . . . . . . . . . . . . . . . . . . . 337
19.2 Introduction to Inheritance . . . . . . . . . . . . . . 337
19.3 Extending . . . . . . . . . . . . . . . . . . . . 338
19.4 Reuse Through Composition . . . . . . . . . . . . . . 339
19.5 Class Diagrams . . . . . . . . . . . . . . . . . . 340
19.6 Composition vs. Inheritance . . . . . . . . . . . . . . 341
19.7 Case Study: Structured Postal Addresses . . . . . . . . . 342
Back Matter
20.10Operator precedence table . . . . . . . . . . . . . . 372
Chapter 1
General Introduction
1.2 Algorithms
If problem solving is a central part of computer science, then the solutions
that you create through the problem solving process are also important. In
computer science, we refer to these solutions as algorithms. An algorithm is
a step by step list of instructions that if followed exactly will solve the problem
under consideration.
Our goal in computer science is to take a problem and develop an algorithm
that can serve as a general solution. Once we have such a solution, we can use
our computer to automate the execution. As noted above, programming is a
skill that allows a computer scientist to take an algorithm and represent it in
a notation (a program) that can be followed by a computer. These programs
are written in programming languages.
Check your understanding
Checkpoint 1.2.1 What is the most important skill for a computer scientist?
A. To think like a computer.
B. To be able to write code really well.
C. To be able to solve problems.
1
CHAPTER 1. GENERAL INTRODUCTION 2
A compiler reads the program and translates it completely before the pro-
gram starts running. In this case, the high-level program is called the source
code, and the translated program is called the object code or the executable.
Once a program is compiled, you can execute it repeatedly without further
translation.
CHAPTER 1. GENERAL INTRODUCTION 3
Many modern languages use both processes. They are first compiled into
a lower level language, called byte code, and then interpreted by a program
called a virtual machine. Python uses both processes, but because of the way
programmers interact with it, it is usually considered an interpreted language.
There are two ways to use the Python interpreter: shell mode and program
mode. In shell mode, you type Python expressions into the Python shell, and
the interpreter immediately shows the result. The example below shows the
Python shell at work.
$ python3
Python 3.2 (r32:88445, Mar 25 2011, 19:28:28)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 + 3
5
>>>
The >>> is called the Python prompt. The interpreter uses the prompt to
indicate that it is ready for instructions. We typed 2 + 3. The interpreter
evaluated our expression and replied 5. On the next line it gave a new prompt
indicating that it is ready for more input.
Working directly in the interpreter is convenient for testing short bits of
code because you get immediate feedback. Think of it as scratch paper used
to help you work out problems.
Alternatively, you can write an entire program by placing lines of Python
instructions in a file and then use the interpreter to execute the contents of the
file as a whole. Such a file is often referred to as source code. For example,
we used a text editor to create a source code file named firstprogram.py with
the following contents:
print ( " My ␣ first ␣ program ␣ adds ␣ two ␣ numbers ,␣2␣ and ␣ 3: " )
print (2 + 3)
By convention, files that contain Python programs have names that end
with .py . Following this convention will help your operating system and other
programs identify a file as containing python code.
$ python firstprogram.py
My first program adds two numbers, 2 and 3:
5
These examples show Python being run from a Unix command line. In other
development environments, the details of executing programs may differ. Also,
most programs are more interesting than this one.
Note 1.3.1 Want to learn more about Python? If you would like to learn
more about installing and using Python, here are some video links. Installing
Python for Windows1 shows you how to install the Python environment under
Windows Vista, Installing Python for Mac2 shows you how to install under
Mac OS/X, and Installing Python for Linux3 shows you how to install from
the Linux command line. Using Python4 shows you some details about the
Python shell and source code.
Check your understanding
1 http://youtu.be/9EfGpN1Pnsg
2 http://youtu.be/MEmEJCLLI2k
3 http://youtu.be/RLPYBxfAud4
4 http://youtu.be/kXbpB5_ywDw
CHAPTER 1. GENERAL INTRODUCTION 4
A. 1 = a process, 2 = a function
B. 1 = translating an entire book, 2 = translating a line at a time
C. 1 = software, 2 = hardware
D. 1 = object code, 2 = byte code
Interactive1
This book provides two special ways to execute Python programs. Both
techniques are designed to assist you as you learn the Python programming
language. They will help you increase your understanding of how Python
programs work.
First, you can write, modify, and execute programs using a unique active-
code interpreter that allows you to execute Python code right in the text
1 www.youtube.com/watch?v=LZ7H1X8ar9E
CHAPTER 1. GENERAL INTRODUCTION 5
itself (right from the web browser). Although this is certainly not the way real
programs are written, it provides an excellent environment for learning a pro-
gramming language like Python since you can experiment with the language
as you are reading.
print ( " My ␣ first ␣ program ␣ adds ␣ two ␣ numbers ,␣2␣ and ␣ 3: " )
print (2 + 3)
Take a look at the activecode interpreter in action.
What you see depends on whether you are logged in or not! Code that you
write and run is saved for all future sessions only if you are logged in! If you
are logged in, you should see a green Save & Run button. If you are not logged
in you see only Run. In the next discussion we will refer to both variants as
the Run button.
If we use the Python code from the previous example and make it active,
you will see that it can be executed directly by pressing the Run button. Try
pressing the Run (or Save & Run) button above.
Now try modifying the activecode program shown above. First, modify
the string in the first print statement by changing the word adds to the word
multiplies. Now press Run. You can see that the result of the program has
changed. However, it still prints “5” as the answer. Modify the second print
statement by changing the addition symbol, the “+”, to the multiplication
symbol, “∗”. Press Run to see the new results.
As the name suggests, Save & Run also saves your latest version of the code,
and you can recover it even in later sessions when logged in. If not logged in,
Run saves versions only until your browser leaves the current web page, and
then you lose all modifications.
After you have run your code the first time, a Load History button that was
beside the Run button turns into a slider. If you click on the slider location
box, you can use your left and right arrow buttons to switch to other versions
you ran. Alternately you can drag the box on the slider. Now move the slider
to see a previously saved state. You can just run it by pressing Run, or edit
and then save and run it as the latest version.
In addition to activecode, you can also execute Python code with the as-
sistance of a unique visualization tool. This tool, known as codelens, allows
you to control the step by step execution of a program. It also lets you see
the values of all variables (introduced in Section 2.4 ) as they are created and
modified. The following example shows codelens in action on the same pro-
gram as we saw above. Note that in activecode, the source code executes from
beginning to end and you can see the final result. In codelens you can see and
control the step by step progress. Note that the red arrow always points to the
next line of code that is going to be executed. The light green arrow points to
the line that was just executed.
print ( " My ␣ first ␣ program ␣ adds ␣ two ␣ numbers ,␣2␣ and ␣ 3: " )
print (2 + 3)
The examples in this book use a mixture of the standard Python interpreter,
source code, activecode, and codelens. You will be able to tell which is which by
looking for either the Python prompt in the case of a shell mode program, the
run button for the activecode, or the forward/backward buttons for codelens.
Check your understanding
Checkpoint 1.4.1 The activecode interpreter allows you to (select all that
apply):
input Get data from the keyboard, a file, or some other device.
output Display data on the screen or send data to a file or other
device.
math and logic Perform basic mathematical operations like addition and
multiplication and logical operations like and, or, and
not.
conditional Check for certain conditions and execute the appropriate
execution sequence of statements.
repetition Perform some action repeatedly, usually with some vari-
ation.
Believe it or not, that’s pretty much all there is to it. Every program
you’ve ever used, no matter how complicated, is made up of instructions that
look more or less like these. Thus, we can describe programming as the process
of breaking a large, complex task into smaller and smaller subtasks until the
subtasks are simple enough to be performed with sequences of these basic
instructions.
Check your understanding
Checkpoint 1.5.1 A program is:
A. Attempting to divide by 0.
B. Forgetting a colon at the end of a statement where one is required.
A. The programmer.
B. The compiler / interpreter.
1 http://en.wikipedia.org/wiki/File:H96566k.jpg
2 http://en.wikipedia.org/wiki/Syntax_error
3 http://en.wikipedia.org/wiki/Runtime_error
4 http://en.wikipedia.org/wiki/Logic_error
CHAPTER 1. GENERAL INTRODUCTION 8
C. The computer.
D. The teacher / instructor.
A. Attempting to divide by 0.
B. Forgetting a colon at the end of a statement where one is required.
C. Forgetting to divide by 100 when printing a percentage amount.
Checkpoint 1.8.2 Who or what typically finds runtime errors?
A. The programmer.
B. The interpreter.
C. The computer.
D. The teacher / instructor.
A. Attempting to divide by 0.
B. Forgetting a colon at the end of a statement where one is required.
C. Forgetting to divide by 100 when printing a percentage amount.
Checkpoint 1.9.2 Who or what typically finds semantic errors?
A. The programmer.
Glossary
ambiguity.Natural languages are full of ambiguity, which people deal with by
using contextual clues and other information. Formal languages are designed
to be nearly or completely unambiguous, which means that any statement has
exactly one meaning, regardless of context.
redundancy.In order to make up for ambiguity and reduce misunderstand-
ings, natural languages employ lots of redundancy. As a result, they are often
verbose. Formal languages are less redundant and more concise.
literalness.Formal languages mean exactly what they say. On the other hand,
natural languages are full of idiom and metaphor. If someone says, “The other
shoe fell”, there is probably no shoe and nothing falling.
Note 1.11.1 You’ll need to find the original joke to understand the idiomatic
meaning of the other shoe falling. Yahoo! Answers thinks it knows!
People who grow up speaking a natural language—everyone—often have a
hard time adjusting to formal languages. In some ways, the difference between
formal and natural language is like the difference between poetry and prose,
but more so:
Glossary
poetry.Words are used for their sounds as well as for their meaning, and the
whole poem together creates an effect or emotional response. Ambiguity is not
only common but often deliberate.
prose.The literal meaning of words is more important, and the structure con-
tributes more meaning. Prose is more amenable to analysis than poetry but
CHAPTER 1. GENERAL INTRODUCTION 11
A. True
B. False
C. tells the computer to put the information in print, rather than cursive,
format.
D. tells the computer to speak the information.
1.13 Comments
As programs get bigger and more complicated, they get more difficult to read.
Formal languages are dense, and it is often difficult to look at a piece of code
and figure out what it is doing, or why. For this reason, it is a good idea to
add notes to your programs to explain in natural language what the program
is doing. These notes are called comments.
A comment in a computer program is text that is intended only for the
human reader - it is completely ignored by the interpreter. In Python, the #
token starts a comment. The rest of the line is ignored. Here is a new version
of Hello, World!.
# ---------------------------- -----------------------
# This demo program shows off how elegant Python is !
# Written by Joe Soap , December 2010.
# Anyone may freely copy or modify this program .
# ---------------------------- -----------------------
1.14 Glossary
Glossary
activecode.A unique interpreter environment that allows Python to be exe-
cuted from within a web browser.
algorithm.A general step by step process for solving a problem.
bug.An error in a program.
CHAPTER 1. GENERAL INTRODUCTION 13
byte code.An intermediate language between source code and object code.
Many modern languages first compile source code into byte code and then
interpret the byte code with a program called a virtual machine.
codelens.An interactive environment that allows the user to control the step
by step execution of a Python program
comment.Information in a program that is meant for other programmers (or
anyone reading the source code) and has no effect on the execution of the
program.
compile.To translate a program written in a high-level language into a low-
level language all at once, in preparation for later execution.
debugging.The process of finding and removing any of the three kinds of
programming errors.
exception.Another name for a runtime error.
executable.Another name for object code that is ready to be executed.
formal language.Any one of the languages that people have designed for spe-
cific purposes, such as representing mathematical ideas or computer programs;
all programming languages are formal languages.
high-level language.A programming language like Python that is designed
to be easy for humans to read and write.
interpret.To execute a program in a high-level language by translating it one
line at a time.
low-level language.A programming language that is designed to be easy for
a computer to execute; also called machine language or assembly language.
natural language.Any one of the languages that people speak that evolved
naturally.
object code.The output of the compiler after it translates the program.
parse.To examine a program and analyze the syntactic structure.
portability.A property of a program that can run on more than one kind of
computer.
print function.A function used in a program or script that causes the Python
interpreter to display a value on its output device.
problem solving.The process of formulating a problem, finding a solution,
and expressing the solution.
program.A sequence of instructions that specifies to a computer actions and
computations to be performed.
programming language.A formal notation for representing solutions.
Python shell.An interactive user interface to the Python interpreter. The
user of a Python shell types commands at the prompt (>>>), and presses
the return key to send these commands immediately to the interpreter for
processing.
runtime error.An error that does not occur until the program has started to
execute but that prevents the program from continuing.
semantic error.An error in a program that makes it do something other than
what the programmer intended.
semantics.The meaning of a program.
shell mode.A style of using Python where we type expressions at the command
prompt, and the results are shown immediately. Contrast with source code,
and see the entry under Python shell.
CHAPTER 1. GENERAL INTRODUCTION 14
1.15 Exercises
1. This exercise will let you practice displaying information. Write a program
that prints following:
• Your name.
• The author of the poem. The name should be indented four spaces
and preceded by a hyphen and a space. If you don’t know who wrote
the poem, use “Anonymous” as the author.
Use complete sentences and blank lines for readability. To print a blank
line, use:
print ()
The parentheses are required, even though there is nothing between
them. If you don’t believe me, leave them out and see what the output
looks like!
Here is what the output of a possible solution looks like:
My name is Juana Fulano .
My favorite color is purple .
My favorite word is " giraffe ".
My favorite poem :
Interactive1
15
CHAPTER 2. SIMPLE PYTHON DATA 16
Not surprisingly, strings belong to the class str and integers belong to the
class int.
Note 2.2.2 When we show the value of a string using the print function, such
as in the third example above, the quotes are not present in the output. The
value of the string is the sequence of characters inside the quotes. The quotes
are only necessary to help Python know what the value is.
You may have used function notation in a math class, like y = f(x), likely
only for functions that act on a single numeric value, and produce a single
numeric value. Python has no such restrictions: Inputs and outputs may be
of any type.
In the Python shell, it is not necessary to use the print function to see the
values shown above. The shell evaluates the Python function and automati-
cally prints the result. For example, consider the shell session shown below.
When we ask the shell to evaluate type("Hello, World!"), it responds with
the appropriate answer and then goes on to display the prompt for the next
use.
Python 3.1.2 (r312:79360M, Mar 24 2010, 01:33:18)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> type("Hello, World!")
<class 'str'>
>>> type(17)
<class 'int'>
>>> "Hello, World"
'Hello, World'
>>>
Note that in the last example, we simply ask the shell to evaluate the string
“Hello, World”. The result is as you might expect, the string itself.
Continuing with our discussion of data types, numbers with a decimal point
belong to a class called float, because these numbers are represented in a
format called floating-point. At this stage, you can treat the words class and
type interchangeably. We’ll come back to a deeper understanding of what a
class is in later chapters.
print ( type (17) )
print ( type (3.2) )
What about values like "17" and "3.2"? They look like numbers, but they
are in quotation marks like strings.
print ( type ( " 17 " ))
print ( type ( " 3.2 " ))
They’re strings!
Strings in Python can be enclosed in either single quotes (') or double
quotes (" - the double quote character), or three of the same separate quote
characters (''' or """).
print ( type ( ' This ␣ is ␣a␣ string . ' ) )
print ( type ( " And ␣ so ␣ is ␣ this . " ) )
print ( type ( """ and this . """ ) )
print ( type ( ' ' ' and even this ... ' ' ' ) )
Double quoted strings can contain single quotes inside them, as in "Bruce's
beard", and single quoted strings can have double quotes inside them, as in 'The
knights who say "Ni!"'. Strings enclosed with three occurrences of either
CHAPTER 2. SIMPLE PYTHON DATA 17
quote symbol are called triple quoted strings. They can contain either single
or double quotes:
print ( ' ' ' " Oh no ", she exclaimed , " Ben ' s bike is broken !" ' ' ' )
Triple quoted strings can even span multiple lines:
print ( """ This message will span
several lines
of the text . """ )
Python doesn’t care whether you use single or double quotes or the three-
of-a-kind quotes to surround your strings. Once it has parsed the text of your
program or command, the way it stores the value is identical in all cases, and
the surrounding quotes are not part of the value.
print ( ' This ␣ is ␣a␣ string . ' )
print ( """ And so is this . """ )
So the Python language designers usually chose to surround their strings by
single quotes. What do you think would happen if the string already contained
single quotes?
When you type a large integer, you might be tempted to use commas be-
tween groups of three digits, as in 42,000. This is not a legal integer in Python,
but it does mean something else, which is legal:
print (42000)
print (42 ,000)
Well, that’s not what we expected at all! Because of the comma, Python
chose to treat this as a pair of values. In fact, the print function can print any
number of values as long as you separate them by commas. Notice that the
values are separated by spaces when they are displayed.
print (42 , 17 , 56 , 34 , 11 , 4.35 , 32)
print (3.4 , " hello " , 45)
Remember not to put commas or spaces in your integers, no matter how big
they are. Also revisit what we said in the previous chapter: formal languages
are strict, the notation is concise, and even the smallest change might mean
something quite different from what you intended.
Check your understanding
Checkpoint 2.2.3 How can you determine the type of a variable?
A. Print out the value and determine the data type based on the value
printed.
B. Use the type function.
C. Use it in a known equation and print the result.
A. Character
B. Integer
C. Float
D. String
CHAPTER 2. SIMPLE PYTHON DATA 18
print ( " 2345 " , int ( " 2345 " )) # parse a string to
produce an int
print (17 , int (17) ) # int even works on
integers
print ( int ( " 23 bottles " ))
The last case shows that a string has to be a syntactically legal number,
otherwise you’ll get one of those pesky runtime errors. Modify the example by
deleting the bottles and rerun the program. You should see the integer 23.
The type converter float can turn an integer, a float, or a syntactically
legal string into a float.
print ( float ( " 123.45 " ))
print ( type ( float (" 123.45 ")) )
The type converter str turns its argument into a string. Remember that
when we print a string, the quotes are removed. However, if we print the type,
we can see that it is definitely str.
print ( str (17) )
print ( str (123.45) )
print ( type ( str (123.45) ) )
Check your understanding
Checkpoint 2.3.1 What value is printed when the following statement exe-
cutes?
print ( int (53.785) )
D. 53.785
CHAPTER 2. SIMPLE PYTHON DATA 19
2.4 Variables
Interactive1
Note 2.4.1 When reading or writing code, say to yourself “n is assigned 17”
or “n gets the value 17” or “n is a reference to the object 17” or “n refers to
the object 17”. Don’t say “n equals 17”.
A common way to represent variables on paper is to write the name with
an arrow pointing to the variable’s value. This kind of figure, known as a
reference diagram, is often called a state snapshot because it shows what
state each of the variables is in at a particular instant in time. (Think of it as
the variable’s state of mind). This diagram shows the result of executing the
assignment statements shown above.
1 www.youtube.com/watch?v=1uQM-TVlaMo
CHAPTER 2. SIMPLE PYTHON DATA 20
If you ask Python to evaluate a variable, it will produce the value that is
currently linked to the variable. In other words, evaluating a variable will give
you the value that is referred to by the variable.
message = " What ' s␣up ,␣ Doc ? "
n = 17
pi = 3.14159
print ( message )
print ( n )
print ( pi )
In each case the result is the value of the variable. To see this in even more
detail, we can run the program using codelens.
message = " What ' s␣up ,␣ Doc ? "
n = 17
pi = 3.14159
print ( message )
print ( n )
print ( pi )
Now, as you step through the statements, you can see the variables and the
values they reference as those references are created.
Variables also have types; again, we can ask the interpreter what they are.
message = " What ' s␣up ,␣ Doc ? "
n = 17
pi = 3.14159
B. Thursday
C. 32.5
D. 19
they’ve called some variable average or pi, it will somehow automagically cal-
culate an average, or automagically associate the variable pi with the value
3.14159. No! The computer doesn’t attach semantic meaning to your variable
names.
So you’ll find some instructors who deliberately don’t choose meaningful
names when they teach beginners — not because they don’t think it is a good
habit, but because they’re trying to reinforce the message that you, the pro-
grammer, have to write some program code to calculate the average, or you
must write an assignment statement to give a variable the value you want it
to have.
Check your understanding
Checkpoint 2.5.4 True or False: the following is a legal variable name in
Python: A_good_grade_is_A+
A. True
B. False
Interactive1
If we take a look at this same example in the Python shell, we will see one
of the distinct differences between statements and expressions.
>>> y = 3.14
>>> x = len ( " hello " )
>>> print ( x )
5
>>> print ( y )
3.14
>>> y
3.14
>>>
Note that when we enter the assignment statement, y = 3.14, only the
prompt is returned. There is no value. This is due to the fact that statements,
such as the assignment statement, do not return a value. They are simply
executed.
On the other hand, the result of executing the assignment statement is the
creation of a reference from a variable, y, to a value, 3.14. When we execute
the print function working on y, we see the value that y is referring to. In fact,
evaluating y by itself results in the same response.
gives us a second flavor of the division operator. This version, called integer
division, uses the token //. It always truncates its result down to the next
smallest integer (to the left on the number line).
print (7 / 4)
print (7 // 4)
minutes = 645
hours = minutes // 60
print ( hours )
print (6//4)
print ( -6//4)
Pay particular attention to the first two examples above. Notice that the
result of floating point division is 1.75 but the result of the integer division is
simply 1. Take care that you choose the correct flavor of the division operator.
If you’re working with expressions where you need floating point values, use
the division operator /. If you want an integer result, use //.
The modulus operator, sometimes also called the remainder operator
or integer remainder operator works on integers (and integer expressions)
and yields the remainder when the first operand is divided by the second. In
Python, the modulus operator is a percent sign (%). The syntax is the same as
for other operators.
quotient = 7 // 3 # This is the integer division
operator
print ( quotient )
remainder = 7 % 3
print ( remainder )
In the above example, 7 divided by 3 is 2 when we use integer division and
there is a remainder of 1 when we use the modulus operator.
The modulus operator turns out to be surprisingly useful. For example,
you can check whether one number is divisible by another—if x % y is zero,
then x is divisible by y. Also, you can extract the right-most digit or digits
from a number. For example, x % 10 yields the right-most digit of x (in base
10). Similarly x % 100 yields the last two digits.
Finally, returning to our time example, the remainder operator is extremely
useful for doing conversions, say from seconds, to hours, minutes and seconds.
If we start with a number of seconds, say 7684, the following program uses
integer division and remainder to convert to an easier form. Step through it
to be sure you understand how the division and remainder operators are being
used to compute the correct values.
total_secs = 7684
hours = total_secs // 3600
secs_still_remaining = total_secs % 3600
minutes = secs_still_remaining // 60
secs_finally_remaining = secs_still_remaining % 60
Check your understanding
Checkpoint 2.7.1 What value is printed when the following statement exe-
cutes?
print (18 / 4)
A. 4.5
B. 5
CHAPTER 2. SIMPLE PYTHON DATA 25
C. 4
D. 2
Checkpoint 2.7.2 What value is printed when the following statement exe-
cutes?
print (18 // 4)
A. 4.25
B. 5
C. 4
D. 2
Checkpoint 2.7.3 What value is printed when the following statement exe-
cutes?
print (18 % 4)
A. 4.25
B. 5
C. 4
D. 2
2.8 Input
Interactive1
The program in the previous section works fine but is very limited in that
it only works with one value for total_secs. What if we wanted to rewrite the
program so that it was more general. One thing we could do is allow the user
to enter any value they wish for the number of seconds. The program could
then print the proper result for that starting value.
In order to do this, we need a way to get input from the user. Luckily,
in Python there is a built-in function to accomplish this task. As you might
expect, it is called input.
n = input ( " Please ␣ enter ␣ your ␣ name :␣" )
The input function allows the user to provide a prompt string. When
the function is evaluated, the prompt is shown. The user of the program can
enter the name and press return. When this happens the text that has been
entered is returned from the input function, and in this case assigned to the
1 www.youtube.com/watch?v=2KYixkCBXSQ
CHAPTER 2. SIMPLE PYTHON DATA 26
variable n. Make sure you run this example a number of times and try some
different names in the input box that appears.
n = input ( " Please ␣ enter ␣ your ␣ name :␣" )
print ( " Hello " , n )
It is very important to note that the input function returns a string value.
Even if you asked the user to enter their age, you would get back a string like
"17". It would be your job, as the programmer, to convert that string into an
int or a float, using the int or float converter functions we saw earlier.
To modify our previous program, we will add an input statement to allow
the user to enter the number of seconds. Then we will convert that string to
an integer. From there the process is the same as before. To complete the
example, we will print some appropriate output.
str_seconds = input ( " Please ␣ enter ␣ the ␣ number ␣ of ␣ seconds ␣ you ␣
wish ␣ to ␣ convert " )
total_secs = int ( str_seconds )
print ( " Hrs = " , hours , " mins = " , minutes , " secs = " ,
secs_finally_remaining )
The variable str_seconds will refer to the string that is entered by the user.
As we said above, even though this string may be 7684, it is still a string and
not a number. To convert it to an integer, we use the int function. The result
is referred to by total_secs. Now, each time you run the program, you can
enter a new value for the number of seconds to be converted.
Check your understanding
Checkpoint 2.8.1 What is printed when the following statements execute?
n = input ( " Please ␣ enter ␣ your ␣ age :␣" )
# user types in 18
print ( type ( n ) )
A. <class ’str’>
B. <class ’int’>
C. <class 18>
D. 18
Checkpoint 2.8.2 Click on all of the variables of type `int` in the code below
seconds = input (" Please enter the number of seconds
you wish to convert ")
Checkpoint 2.8.3 Click on all of the variables of type `str` in the code below
seconds = input (" Please enter the number of seconds
you wish to convert ")
Interactive1
When more than one operator appears in an expression, the order of evalua-
tion depends on the rules of precedence. Python follows the same precedence
rules for its mathematical operators that mathematics does.
See Section 20.10 for all the operators introduced in this book. You will also
see many upcoming non-mathematical Python operators.
Check your understanding
Checkpoint 2.9.2 What is the value of the following expression:
16 - 2 * 5 // 3 + 1
A. 14
B. 24
C. 3
D. 13.667
Checkpoint 2.9.3 What is the value of the following expression:
2 ** 2 ** 3 * 3
A. 768
B. 128
C. 12
D. 256
Here are animations for the above expressions:
Checkpoint 2.9.4 An interactive Runestone problem goes here, but there is
not yet a static representation.
Checkpoint 2.9.5 An interactive Runestone problem goes here, but there is
not yet a static representation.
2.10 Reassignment
2.10.1 Introduction
Interactive1
The first time bruce is printed, its value is 5, and the second time, its value
is 7. The assignment statement changes the value (the object) that bruce refers
to.
Here is what reassignment looks like in a reference diagram:
Checkpoint 2.10.3 After the following statements, what are the values of x
and y?
x = 15
y = x
x = 22
A. x is 15 and y is 15
B. x is 22 and y is 22
C. x is 15 and y is 22
D. x is 22 and y is 15
Interactive1
A. 12
B. -1
C. 11
A. 12
B. 9
C. 15
• mybankbalance␣=␣100
mybankbalance␣=␣mybankbalance␣+␣34
print(mybankbalance)
Note 2.11.6 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
2 at_1_1.html
3 http://www.diveintopython3.net/
CHAPTER 2. SIMPLE PYTHON DATA 32
2.12 Glossary
Glossary
assignment statement.A statement that assigns a value to a name (variable).
To the left of the assignment operator, =, is a name. To the right of the assign-
ment token is an expression which is evaluated by the Python interpreter and
then assigned to the name. The difference between the left and right hand sides
of the assignment statement is often confusing to new programmers. In the fol-
lowing assignment: n = n + 1
n plays a very different role on each side of the =. On the right it is a value
and makes up part of the expression which will be evaluated by the Python
interpreter before assigning it to the name on the left.
assignment token.= is Python’s assignment token, which should not be con-
fused with the mathematical comparison operator using the same symbol.
class.see data type below
comment.Information in a program that is meant for other programmers (or
anyone reading the source code) and has no effect on the execution of the
program.
data type.A set of values. The type of a value determines how it can be used
in expressions. So far, the types you have seen are integers (int), floating-point
numbers (float), and strings (str).
decrement.Decrease by 1.
evaluate.To simplify an expression by performing the operations in order to
yield a single value.
expression.A combination of operators and operands (variables and values)
that represents a single result value. Expressions are evaluated to give that
result.
float.A Python data type which stores floating-point numbers. Floating-point
numbers are stored internally in two parts: a base and an exponent. When
printed in the standard format, they look like decimal numbers. Beware of
rounding errors when you use floats, and remember that they are only ap-
proximate values.
increment.Both as a noun and as a verb, increment means to increase by 1.
initialization (of a variable).To initialize a variable is to give it an initial
value. Since in Python variables don’t exist until they are assigned values, they
are initialized when they are created. In other programming languages this is
not the case, and variables can be created without being initialized, in which
case they have either default or garbage values.
int.A Python data type that holds positive and negative whole numbers.
integer division.An operation that divides one integer by another and yields
an integer. Integer division yields only the whole number of times that the
numerator is divisible by the denominator and discards any remainder.
keyword.A reserved word that is used by the compiler to parse program; you
cannot use keywords like if, def, and while as variable names.
modulus operator.Also called remainder operator or integer remainder oper-
ator. Gives the remainder after performing integer division.
object.Also known as a data object (or data value). The fundamental things
that programs are designed to manipulate (or that programmers ask to do
things for them).
CHAPTER 2. SIMPLE PYTHON DATA 33
2.13 Exercises
1. Evaluate the following numerical expressions in your head, then use the
active code window to check your results:
1 5 ** 2
2 9 * 5
3 15 / 12
4 12 / 15
5 15 // 12
6 12 // 15
7 5 % 2
8 9 % 5
9 15 % 12
10 12 % 15
11 6 % 6
12 0 % 7
print (5 ** 2)
CHAPTER 2. SIMPLE PYTHON DATA 34
Debugging Interlude 1
35
CHAPTER 3. DEBUGGING INTERLUDE 1 36
print ( current_time )
print ( wait_time )
So far so good. Now let’s take the next step. We need to figure out what the
time will be after waiting wait_time number of hours. A reasonable solution
is to simply add wait_time to current_time and print out the result. So lets
try that.
current_time = input ( " What ␣ is ␣ the ␣ current ␣ time ␣( in ␣ hours ␣0␣
-␣ 23) ? " )
wait_time = input ( " How ␣ many ␣ hours ␣ do ␣ you ␣ want ␣ to ␣ wait " )
print ( current_time )
print ( wait_time )
print ( final_time )
Hmm, when you run this example you see that something unexpected has
happened. You would not realize this was an error unless you first knew what
the program was supposed to do.
Checkpoint 3.2.2 Which of the following best describes what is wrong with
the previous example?
final_answer = final_time_int % 24
CHAPTER 3. DEBUGGING INTERLUDE 1 38
• Error Messages
• Print Statements
Aha! Now we have an error message that might be useful. The name error
tells us that wait_time_int is not defined. It also tells us that the error is on
line 5. That’s really useful information. Now look at line five and you will
see that wait_time_int is used on both the left and the right hand side of the
assignment statement.
Note 3.4.1 The error descriptions you see in activecode may be different (and
more understandable!) than in a regular Python interpreter. The interpreter in
activecode is limited in many ways, but it is intended for beginners, including
the wording chosen to describe errors.
Checkpoint 3.4.2 Which of the following explains why wait_time_int =
int(wait_time_int) is an error?
A. You cannot use a variable on both the left and right hand sides of an
assignment statement.
B. wait_time_int does not have a value so it cannot be used on the right
hand side.
C. This is not really an error, Python is broken.
In writing and using this book over the last few years we have collected
a lot of statistics about the programs in this book. Here are some statistics
about error messages for the exercise we have been looking at.
Table 3.4.3
Message Number Percent
ParseError: 4999 54.74%
TypeError: 1305 14.29%
NameError: 1009 11.05%
ValueError: 893 9.78%
URIError: 334 3.66%
TokenError: 244 2.67%
SyntaxError: 227 2.49%
TimeLimitError: 44 0.48%
IndentationError: 28 0.31%
AttributeError: 27 0.30%
ImportError: 16 0.18%
IndexError: 6 0.07%
Nearly 90% of the error messages encountered for this problem are ParseEr-
ror, TypeError, NameError, or ValueError. We will look at these errors in three
stages:
3.4.2 ParseError
Parse errors happen when you make an error in the syntax of your program.
Syntax errors are like making grammatical errors in writing. If you don’t use
periods and commas in your writing then you are making it hard for other
readers to figure out what you are trying to say. Similarly Python has certain
CHAPTER 3. DEBUGGING INTERLUDE 1 40
grammatical rules that must be followed or else Python can’t figure out what
you are trying to say.
Usually ParseErrors can be traced back to missing punctuation characters,
such as parentheses, quotation marks, or commas. Remember that in Python
commas are used to separate parameters to functions. Parentheses must be
balanced, or else Python thinks that you are trying to include everything that
follows as a parameter to some function.
Here are a couple examples of Parse errors in the example program we have
been using. See if you can figure out what caused them.
Checkpoint 3.4.4
Finding Clues How can you help yourself find these problems? One trick
that can be very valuable in this situation is to simply start by commenting out
the line number that is flagged as having the error. If you comment out line
four, the error message now changes to point to line 5. Now you ask yourself,
am I really that bad that I have two lines in a row that have errors on them?
Maybe, so taken to the extreme, you could comment out all of the remaining
lines in the program. Now the error message changes to TokenError: EOF in
multi-line statement This is a very technical way of saying that Python got
to the end of file (EOF) while it was still looking for something. In this case a
right parenthesis.
Checkpoint 3.4.5
Finding Clues If you follow the same advice as for the last problem, com-
ment out line one, you will immediately get a different error message. Here’s
where you need to be very careful and not panic. The error message you
get now is: NameError: name 'current_time_str' is not defined on line .
You might be very tempted to think that this is somehow related to the earlier
problem and immediately conclude that there is something wrong with the
variable name current_time_str but if you reflect for a minute you will see
that by commenting out line one you have caused a new and unrelated error.
That is you have commented out the creation of the name current_time_str.
So of course when you want to convert it to an int you will get the NameError.
Yes, this can be confusing, but it will become much easier with experience. It’s
also important to keep calm, and evaluate each new clue carefully so you don’t
waste time chasing problems that are not really there.
Uncomment line 1 and you are back to the ParseError. Another track is to
eliminate a possible source of error. Rather than commenting out the entire
line you might just try to assign current_time_str to a constant value. For
example you might make line one look like this: current_time_str = "10"
#input("What is the "current time" (in hours 0-23)?"). Now you have
assigned current_time_str to the string 10, and commented out the input
statement. And now the program works! So you conclude that the problem
must have something to do with the input function.
3.4.3 TypeError
TypeErrors occur when you you try to combine two objects that are not com-
patible. For example you try to add together an integer and a string. Usually
type errors can be isolated to lines that are using mathematical operators, and
usually the line number given by the error message is an accurate indication
of the line.
Here’s an example of a type error created by a Polish learner. See if you
can find and fix the error.
CHAPTER 3. DEBUGGING INTERLUDE 1 41
So, the solution to this problem is to change lines 3 and 4 so they are
assignment statements.
Finding Clues One thing that can help you in this situation is to print
out the values and the types of the variables involved in the statement that is
causing the error. You might try adding a print statement after line 4 print(x,
type(x)) You will see that at least we have confirmed that x is of type string.
Now you need to start to work backward through the program. You need to
ask yourself, where is x used in the program? x is used on lines 2, 3, and of
course 5 and 6 (where we are getting an error). So maybe you move the print
statement to be after line 2 and again after 3. Line 3 is where you expect the
value of x to be changed to an integer. Could line 4 be mysteriously changing
x back to a string? Not very likely. So the value and type of x is just what you
would expect it to be after line 2, but not after line 3. This helps you isolate
the problem to line 3. In fact if you employ one of our earlier techniques of
commenting out line 3 you will see that this has no impact on the error, and
CHAPTER 3. DEBUGGING INTERLUDE 1 42
3.4.4 NameError
Name errors almost always mean that you have used a variable before it has a
value. Often NameErrors are simply caused by typos in your code. They can
be hard to spot if you don’t have a good eye for catching spelling mistakes.
Other times you may simply mis-remember the name of a variable or even a
function you want to call. You have seen one example of a NameError at the
beginning of this section. Here is another one. See if you can get this program
to run successfully:
str_time = input (" What ␣ time ␣ is ␣ it ␣ now ? " )
str_wait_time = input ( " What ␣ is ␣ the ␣ number ␣ of ␣ nours ␣ to ␣
wait ? " )
time = int ( str_time )
wai_time = int ( str_wait_time )
help you with this one easily, but there is another clue for you as well. The
editor in the textbook, as well as almost all Python editors in the world provide
you with color clues. Notice that on line 2 the function imt is not highlighted
blue like the word int on line 4.
And one last bit of code to fix.
present_time = input ( " Enter ␣ the ␣ present ␣ timein ␣ hours : " )
set_alarm = input ( " Set ␣ the ␣ hours ␣ for ␣ alarm : " )
int ( present_time , set_time , alarm_time )
alarm_time = present_time + set_alarm
print ( alarm_time )
3.
Note 3.4.9 Solution. In this example the error message is about set_time
not defined on line 3. In this case the undefined name is not used in an as-
signment statement, but is used as a parameter (incorrectly) to a function
call. A search on set_time reveals that in fact it is only used once in the
program. Did the author mean set_alarm? If we make that assumption we im-
mediately get another error NameError: name 'alarm_time' is not defined
on line: 3. The variable alarm_time is defined on line 4, but that does not
help us on line 3. Furthermore we now have to ask the question is this function
call int(present_time, set_alarm, alarm_time) even the correct use of the
int function? The answer to that is a resounding no. Let’s list all of the things
wrong with line 3:
1 set_time is not defined and never used, the author probably meant
set_alarm.
2 alarm_time cannot be used as a parameter before it is defined, even on
the next line!
3.4.5 ValueError
Value errors occur when you pass a parameter to a function and the function
is expecting a certain limitations on the values, and the value passed is not
compatible. We can illustrate that with this particular program in two different
ways.
current_time_str = input (" What ␣ is ␣ the ␣ current ␣ time ␣( in ␣
hours ␣ 0 -23) ? " )
current_time_int = int ( current_time_str )
wait_time_str = input ( " How ␣ many ␣ hours ␣ do ␣ you ␣ want ␣ to ␣ wait " )
wait_time_int = int ( wait_time_int )
need for that yet. The error happens because the user did not give us something
we can convert to an integer, instead we gave it an empty string. Try running
the program again. Now this time enter “ten” instead of the number 10. You
will get a similar error message.
Run the program but instead of typing in anything to the dialog box just
click OK. You should see the following error message: ValueError: invalid
literal for int() with base 10: '' on line: This error is not because
you have made a mistake in your program. Although sometimes we do want
to check the user input to make sure its valid, but we don’t have all the tools
we need for that yet. The error happens because the user did not give us some-
thing we can convert to an integer, instead we gave it an empty string. Try
running the program again. Now this time enter “ten” instead of the number
10. You will get a similar error message.
ValueErrors are not always caused by user input error, but in this program
that is the case. We’ll look again at ValueErrors again when we get to more
complicated programs. For now it is worth repeating that you need to keep
track of the restrictions needed for your variables, and understand what your
function is expecting. You can do this by writing comments in your code, or
by naming your variables in a way that reminds you of their proper form.
3.5 Summary
• Make sure you take the time to understand error messages. They can
help you a lot.
• print statements are your friends. Use them to help you uncover what
is really happening in your code.
• Work backward from the error. Many times an error message is caused by
something that has happened before it in the program. Always remember
that python evaluates a program top to bottom.
3.6 Exercises
This page is intentionally blank (for now)
Chapter 4
Interactive1
There are many modules in Python that provide very powerful features that
we can use in our own programs. Some of these can send email or fetch web
pages. Others allow us to perform complex mathematical calculations. In this
chapter we will introduce a module that allows us to create a data object called
a turtle that can be used to draw pictures.
Turtle graphics, as it is known, is based on a very simple metaphor. Imagine
that you have a turtle that understands English. You can tell your turtle to
do simple commands such as go forward and turn right. As the turtle moves
around, if its tail is down touching the ground, it will draw a line (leave a trail
behind) as it moves. If you tell your turtle to lift up its tail it can still move
around but will not leave a trail. As you will see, you can make some pretty
amazing drawings with this simple capability.
Note 4.1.1 The turtles are fun, but the real purpose of the chapter is to teach
ourselves a little more Python and to develop our theme of computational
thinking, or thinking like a computer scientist. Most of the Python covered
here will be explored in more depth later.
45
CHAPTER 4. PYTHON TURTLE GRAPHICS 46
The program as shown will only draw the first two sides of the rectangle.
After line 4 you will have a straight line going from the center of the drawing
canvas towards the right. After line 6, you will have a canvas with a turtle and
a half drawn rectangle. Press the run button to try it and see.
import turtle # allows us to use the turtles library
wn = turtle . Screen () # creates a graphics window
alex = turtle . Turtle () # create a turtle named alex
alex . forward (150) # tell alex to move forward by 150 units
alex . left (90) # turn by 90 degrees
alex . forward (75) # complete the second side of a rectangle
Here are a couple of things you’ll need to understand about this program.
The first line tells Python to load a module named turtle. That module
brings us two new types that we can use: the Turtle type, and the Screen
type. The dot notation turtle.Turtle means “The Turtle type that is defined
within the turtle module”. (Remember that Python is case sensitive, so the
module name, turtle, with a lowercase t, is different from the type Turtle
because of the uppercase T.)
We then create and open what the turtle module calls a screen (we would
prefer to call it a window, or in the case of this web version of Python simply
a canvas), which we assign to variable wn. Every window contains a canvas,
which is the area inside the window on which we can draw.
In line 3 we create a turtle. The variable alex is made to refer to this turtle.
These first three lines set us up so that we are ready to do some drawing.
In lines 4-6, we instruct the object alex to move and to turn. We do this
by invoking or activating alex’s methods — these are the instructions that
all turtles know how to respond to. Here the dot indicates that the methods
invoked belong to and refer to the object alex.
Note 4.2.1 Complete the rectangle …. Modify the program by adding
the commands necessary to have alex complete the rectangle.
Check your understanding
Checkpoint 4.2.2 Which direction does the Turtle face when it is created?
A. North
B. South
C. East
D. West
Mixed up programs
Checkpoint 4.2.3 The following program uses a turtle to draw a capital L as
shown in the picture to the left of this text,
CHAPTER 4. PYTHON TURTLE GRAPHICS 47
But the lines are mixed up. The program should do all necessary set-up:
import the turtle module, get the window to draw on, and create the turtle.
Remember that the turtle starts off facing east when it is created. The turtle
should turn to face south and draw a line that is 150 pixels long and then turn
to face east and draw a line that is 75 pixels long. We have added a compass
to the picture to indicate the directions north, south, west, and east.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• ella.left(90)
ella.forward(75)
• import␣turtle
window␣=␣turtle.Screen()
ella␣=␣turtle.Turtle()
• ella.right(90)
ella.forward(150)
Checkpoint 4.2.4 The following program uses a turtle to draw a checkmark
as shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 48
But the lines are mixed up. The program should do all necessary set-up:
import the turtle module, get the window to draw on, and create the turtle.
The turtle should turn to face southeast, draw a line that is 75 pixels long,
then turn to face northeast, and draw a line that is 150 pixels long. We have
added a compass to the picture to indicate the directions north, south, west,
and east. Northeast is between north and east. Southeast is between south
and east.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• import␣turtle
• maria.right(45)
maria.forward(75)
• maria.left(90)
maria.forward(150)
• maria␣=␣turtle.Turtle()
• window␣=␣turtle.Screen()
Checkpoint 4.2.5 The following program uses a turtle to draw a single line
to the west as shown to the left,
CHAPTER 4. PYTHON TURTLE GRAPHICS 49
But the program lines are mixed up. The program should do all necessary
set-up: import the turtle module, get the window to draw on, and create the
turtle. The turtle should then turn to face west and draw a line that is 75
pixels long.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• import␣turtle
window␣=␣turtle.Screen()
jamal␣=␣turtle.Turtle()
jamal.left(180)
jamal.forward(75)
An object can have various methods — things it can do — and it can also
have attributes — (sometimes called properties). For example, each turtle
has a color attribute. The method invocation alex.color(“red”) will make alex
red and the line that it draws will be red too.
The color of the turtle, the width of its pen(tail), the position of the turtle
within the window, which way it is facing, and so on are all part of its current
state. Similarly, the window object has a background color which is part of
its state.
Quite a number of attributes and methods exist that allow us to modify
the turtle and window objects. In the example below, we show just show a
couple and have only commented those lines that are different from the previous
example. Note also that we have decided to call our turtle object tess.
import turtle
wn = turtle . Screen ()
wn . bgcolor ( " lightgreen " ) # set the window background color
A. This is simply for clarity. It would also work to just type ”Turtle()”
instead of ”turtle.Turtle()”.
B. The period (.) is what tells Python that we want to invoke a new object.
1 https://www.w3schools.com/colors/colors_names.asp
CHAPTER 4. PYTHON TURTLE GRAPHICS 51
C. The first ”turtle” (before the period) tells Python that we are referring
to the turtle module, which is where the object ”Turtle” is found.
Checkpoint 4.2.9 True or False: A Turtle object can have any name that
follows the naming rules from Chapter 2.
A. True
B. False
Checkpoint 4.2.10 Which of the following code would produce the following
image?
A.
CHAPTER 4. PYTHON TURTLE GRAPHICS 52
B.
C.
D.
CHAPTER 4. PYTHON TURTLE GRAPHICS 53
E.
Mixed up programs
Checkpoint 4.2.11 The following program uses a turtle to draw a capital L
in white on a blue background as shown to the left,
But the lines are mixed up. The program should do all necessary set-up
and create the turtle and set the pen size to 10. The turtle should then turn
to face south, draw a line that is 150 pixels long, turn to face east, and draw a
line that is 75 pixels long. Finally, set the window to close when the user clicks
in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• import␣turtle
wn␣=␣turtle.Screen()
• jamal.color("white")
jamal.pensize(10)
CHAPTER 4. PYTHON TURTLE GRAPHICS 54
• jamal.left(90)
jamal.forward(75)
wn.exitonclick()
• wn.bgcolor("blue")
jamal␣=␣turtle.Turtle()
• jamal.right(90)
jamal.forward(150)
Checkpoint 4.2.12 The following program uses a turtle to draw a capital T
in white on a green background as shown to the left,
But the lines are mixed up. The program should do all necessary set-up,
create the turtle, and set the pen size to 10. After that the turtle should turn
to face north, draw a line that is 150 pixels long, turn to face west, and draw a
line that is 50 pixels long. Next, the turtle should turn 180 degrees and draw
a line that is 100 pixels long. Finally, set the window to close when the user
clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• jamal.left(90)
jamal.forward(150)
• wn.exitonclick()
• import␣turtle
wn␣=␣turtle.Screen()
wn.bgcolor("green")
jamal␣=␣turtle.Turtle()
jamal.color("white")
jamal.pensize(10)
CHAPTER 4. PYTHON TURTLE GRAPHICS 55
• jamal.left(90)
jamal.forward(50)
• jamal.right(180)
jamal.forward(100)
wn . exitonclick ()
Here are some How to think like a computer scientist observations:
• There are 360 degrees in a full circle. If you add up all the turns that a
turtle makes, no matter what steps occurred between the turns, you can
easily figure out if they add up to some multiple of 360. This should
convince you that alex is facing in exactly the same direction as he was
CHAPTER 4. PYTHON TURTLE GRAPHICS 56
• And, uh-huh, two turtles may not be enough for a herd, but you get the
idea!
A. True
B. False
Mixed up programs
Checkpoint 4.3.2 The following program has one turtle, “jamal”, draw a
capital L in blue and then another, “tina”, draw a line to the west in orange
as shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 57
The program should do all set-up, have “jamal” draw the L, and then have
“tina” draw the line. Finally, it should set the window to close when the user
clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• import␣turtle
wn␣=␣turtle.Screen()
• wn.exitonclick()
• jamal␣=␣turtle.Turtle()
jamal.pensize(10)
jamal.color("blue")
jamal.right(90)
jamal.forward(150)
• jamal.left(90)
jamal.forward(75)
• tina␣=␣turtle.Turtle()
tina.pensize(10)
tina.color("orange")
tina.left(180)
tina.forward(75)
Checkpoint 4.3.3 The following program has one turtle, “jamal”, draw a line
to the north in blue and then another, “tina”, draw a line to the east in orange
as shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 58
The program should import the turtle module, get the window to draw on,
create the turtle “jamal”, have it draw a line to the north, then create the
turtle “tina”, and have it draw a line to the east. Finally, it should set the
window to close when the user clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order. Then click on Check Me to see if you are right.
You will be told if any of the lines are in the wrong order.
• wn␣=␣turtle.Screen()
• tina␣=␣turtle.Turtle()
tina.pensize(10)
tina.color("orange")
tina.forward(150)
• import␣turtle
• wn.exitonclick()
• jamal␣=␣turtle.Turtle()
jamal.color("blue")
jamal.pensize(10)
• jamal.left(90)
jamal.forward(150)
CHAPTER 4. PYTHON TURTLE GRAPHICS 59
Interactive1
When we drew the square, it was quite tedious. We had to move then
turn, move then turn, etc. etc. four times. If we were drawing a hexagon,
or an octogon, or a polygon with 42 sides, it would have been a nightmare to
duplicate all that code.
A basic building block of all programs is to be able to repeat some code
over and over again. In computer science, we refer to this repetitive idea as
iteration. In this section, we will explore some mechanisms for basic iteration.
In Python, the for statement allows us to write programs that implement
iteration. As a simple example, let’s say we have some friends, and we’d like
to send them each an email inviting them to our party. We don’t quite know
how to send email yet, so for the moment we’ll just print a message for each
friend.
for name in [ " Joe " , " Amy " , " Brad " , " Angelina " , " Zuki " ,
" Thandi " , " Paris " ]:
print ( " Hi " , name , " Please ␣ come ␣ to ␣ my ␣ party ␣ on ␣
Saturday ! " )
Take a look at the output produced when you press the run button. There
is one line printed for each friend. Here’s how it works:
• The list of names in the square brackets is called a Python list. Lists are
very useful. We will have much more to say about them later.
• Line 2 is the loop body. The loop body is always indented. The inden-
tation determines exactly what statements are “in the loop”. The loop
body is performed one time for each name in the list.
• On each iteration or pass of the loop, a check is done to see if there are
still more items to be processed. If there are none left (this is called the
terminating condition of the loop), the loop has finished. Program
execution continues at the next statement after the loop body.
three lines (not including the setup code). Remember that the for statement
will repeat the forward and left four times, one time for each value in the list.
import turtle # set up alex
wn = turtle . Screen ()
alex = turtle . Turtle ()
wn . exitonclick ()
While “saving some lines of code” might be convenient, it is not the big deal
here. What is much more important is that we’ve found a “repeating pattern”
of statements, and we reorganized our program to repeat the pattern. Finding
the chunks and somehow getting our programs arranged around those chunks
is a vital skill when learning How to think like a computer scientist.
The values [0,1,2,3] were provided to make the loop body execute 4 times.
We could have used any four values. For example, consider the following pro-
gram.
import turtle # set up alex
wn = turtle . Screen ()
alex = turtle . Turtle ()
for aColor in [ " yellow " , " red " , " purple " , " blue " ]: #
repeat four times
alex . forward (50)
alex . left (90)
wn . exitonclick ()
In the previous example, there were four integers in the list. This time there
are four strings. Since there are four items in the list, the iteration will still
occur four times. aColor will take on each color in the list. We can even take
this one step further and use the value of aColor as part of the computation.
import turtle # set up alex
wn = turtle . Screen ()
alex = turtle . Turtle ()
for aColor in [ " yellow " , " red " , " purple " , " blue " ]:
alex . color ( aColor )
alex . forward (50)
alex . left (90)
wn . exitonclick ()
In this case, the value of aColor is used to change the color attribute of
alex. Each iteration causes aColor to change to the next value in the list.
The for-loop is our first example of a compound statement. Syntactically
a compound statement is a statement. The level of indentation of a (whole)
compound statement is the indentation of its heading. In the example above
there are five statements with the same indentation, executed sequentially:
the import, 2 assignments, the whole for-loop, and wn.exitonclick(). The
for-loop compound statement is executed completely before going on to the
next sequential statement, wn.exitonclick().
Mixed up program
CHAPTER 4. PYTHON TURTLE GRAPHICS 62
But the lines are mixed up. The program should do all necessary set-up
and create the turtle. After that, iterate (loop) 3 times, and each time through
the loop the turtle should go forward 175 pixels, and then turn left 120 degrees.
After the loop, set the window to close when the user clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order with the correct indention. Click on <i>Check
Me</i> to see if you are right. You will be told if any of the lines are in the
wrong order or are incorrectly indented.
• #␣repeat␣3␣times
for␣i␣in␣[0,1,2]:
• ␣␣marie.forward(175)
• ␣␣marie.left(120)
• import␣turtle
• wn␣=␣turtle.Screen()
marie␣=␣turtle.Turtle()
• wn.exitonclick()
Mixed up program
Checkpoint 4.6.2 The following program uses a turtle to draw a rectangle as
shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 63
But the lines are mixed up. The program should do all necessary set-up and
create the turtle. After that, iterate (loop) 2 times, and each time through the
loop the turtle should go forward 175 pixels, turn right 90 degrees, go forward
150 pixels, and turn right 90 degrees. After the loop, set the window to close
when the user clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order with the correct indention. Click on <i>Check
Me</i> to see if you are right. You will be told if any of the lines are in the
wrong order or are incorrectly indented.
• wn.exitonclick()
• ␣␣carlos.forward(175)
• import␣turtle
wn␣=␣turtle.Screen()
carlos␣=␣turtle.Turtle()
• ␣␣carlos.forward(150)
␣␣carlos.right(90)
• #␣repeat␣2␣times
for␣i␣in␣[1,2]:
• ␣␣carlos.right(90)
Check your understanding
Checkpoint 4.6.3 In the following code, how many lines does this code print?
for number in [5 , 4, 3 , 2, 1 , 0]:
print ( " I␣ have " , number , " cookies .␣␣I ' m␣ going ␣ to ␣ eat ␣
one . " )
A. 1
B. 5
CHAPTER 4. PYTHON TURTLE GRAPHICS 64
C. 6
D. 10
Checkpoint 4.6.4 How does python know what statements are contained in
the loop body?
A. They are indented to the same degree from the loop header.
B. There is always exactly one line in the loop body.
C. The loop body ends with a semi-colon (;) which is not shown in the code
above.
Checkpoint 4.6.5 In the following code, what is the value of number the
second time Python executes the loop?
for number in [5 , 4, 3 , 2, 1 , 0]:
print ( " I␣ have " , number , " cookies .␣␣I ' m␣ going ␣ to ␣ eat ␣
one . " )
A. 2
B. 4
C. 5
D. 1
Checkpoint 4.6.6 Consider the following code:
for aColor in [ " yellow " , " red " , " green " , " blue " ]:
alex . forward (50)
alex . left (90)
What does each iteration through the loop do?
Interactive1
In our simple example from the last section (shown again below), we used
a list of four integers to cause the iteration to happen four times. We said that
we could have used any four values. In fact, we even used four colors.
1 www.youtube.com/watch?v=YK8QlIT3__M
CHAPTER 4. PYTHON TURTLE GRAPHICS 65
wn . exitonclick ()
It turns out that generating lists with a specific number of integers is a
very common thing to do, especially when you want to write simple for loop
controlled iteration. Even though you can use any four items, or any four
integers for that matter, the conventional thing to do is to use a list of integers
starting with 0. In fact, these lists are so popular that Python gives us special
built-in range objects that can deliver a sequence of values to the for loop.
When called with one parameter, the sequence provided by range always starts
with 0. If you ask for range(4), then you will get 4 values starting with 0. In
other words, 0, 1, 2, and finally 3. Notice that 4 is not included since we
started with 0. Likewise, range(10) provides 10 values, 0 through 9.
for i in range (4) :
# Executes the body with i = 0, then 1, then 2, then 3
for x in range (10) :
# sets x to each of ... [0 , 1, 2, 3, 4, 5, 6, 7, 8, 9]
work on very long sequences, and it may allow you to be sloppy, avoiding the
list function, and see the elements in the range with print(range(4)).
Here are two examples for you to run. Try them and then add another line
below to create a sequence starting at 10 and going up to 20 (including 20).
print ( list ( range (4) ))
print ( list ( range (1 , 5) ))
Codelens will help us to further understand the way range works. In this
case, the variable i will take on values produced by the range function.
for i in range (10) :
print (i )
Finally, suppose we want to have a sequence of even numbers. How would
we do that? Easy, we add another parameter, a step, that tells range what
to count by. For even numbers we want to start at 0 and count by 2’s. So
if we wanted the first 10 even numbers we would use range(0,19,2). The
most general form of the range is range(start, beyondLast, step). You can
also create a sequence of numbers that starts big and gets smaller by using a
negative value for the step parameter.
print ( list ( range (0 , 19 , 2) ))
print ( list ( range (0 , 20 , 2) ))
print ( list ( range (10 , 0, -1) ))
Try it in codelens. Do you see why the first two statements produce the
same result?
for i in range (0 , 20 , 2) :
print (i )
Check your understanding
Checkpoint 4.7.4 In the command range(3, 10, 2), what does the second
argument (10) specify?
D. Range should generate a sequence using every 10th number between the
start and the stopping number.
Checkpoint 4.7.5 What command correctly generates the sequence 2, 5, 8?
A. range(2, 5, 8)
B. range(2, 8, 3)
C. range(2, 10, 3)
D. range(8, 1, -3)
Checkpoint 4.7.6 What happens if you give range only one argument? For
example: range(4)
A. It will generate a sequence starting at 0, with every number included up
to but not including the argument it was passed.
B. It will generate a sequence starting at 1, with every number up to but
CHAPTER 4. PYTHON TURTLE GRAPHICS 67
A. range(5, 25, 5)
B. range(20, 3, -5)
C. range(20, 5, 4)
D. range(20, 5, -5)
Checkpoint 4.7.8 What could the second parameter (12) in range(2, 12, 4)
be replaced with and generate exactly the same sequence?
C. 11, 13, or 14
• Every turtle can have its own shape. The ones available “out of the box”
are arrow, blank, circle, classic, square, triangle, turtle.
...
alex . shape ( " turtle " )
...
• You can speed up or slow down the turtle’s animation speed. (Animation
controls how quickly the turtle turns and moves forward). Speed settings
can be set between 1 (slowest) to 10 (fastest). But if you set the speed
to 0, it has a special meaning — turn off animation and go as fast as
possible.
alex . speed (10)
• A turtle can “stamp” its footprint onto the canvas, and this will remain
after the turtle has moved somewhere else. Stamping works even when
the pen is up.
wn . exitonclick ()
The list of integers printed above for list(range(5,60,2)) is only displayed
to show you the distances being used to move the turtle forward. The actual
use appears as part of the for loop.
One more thing to be careful about. All except one of the shapes you see
on the screen here are footprints created by stamp. But the program still only
has one turtle instance — can you figure out which one is the real tess? (Hint:
if you’re not sure, write a new line of code after the for loop to change tess’
color, or to put her pen down and draw a line, or to change her shape, etc.)
Mixed up program
Checkpoint 4.8.1 The following program uses the stamp method to create a
circle of turtle shapes as shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 69
But the lines are mixed up. The program should do all necessary set-up,
create the turtle, set the shape to “turtle”, and pick up the pen. Then the
turtle should repeat the following ten times: go forward 50 pixels, leave a copy
of the turtle at the current position, reverse for 50 pixels, and then turn right
36 degrees. After the loop, set the window to close when the user clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order with the correct indention. Click on <i>Check
Me</i> to see if you are right. You will be told if any of the lines are in the
wrong order or are incorrectly indented.
• wn.exitonclick()
• ␣␣jose.forward(-50)
• import␣turtle
wn␣=␣turtle.Screen()
jose␣=␣turtle.Turtle()
jose.shape("turtle")
jose.penup()
• ␣␣jose.forward(50)
• for␣size␣in␣range(10):
• ␣␣jose.stamp()
• ␣␣jose.right(36)
Mixed up program
Checkpoint 4.8.2 The following program uses the stamp method to create a
line of turtle shapes as shown to the left:
CHAPTER 4. PYTHON TURTLE GRAPHICS 70
But the lines are mixed up. The program should do all necessary set-up,
create the turtle, set the shape to “turtle”, and pick up the pen. Then the
turtle should repeat the following three times: go forward 50 pixels and leave
a copy of the turtle at the current position. After the loop, set the window to
close when the user clicks in it.
Drag the blocks of statements from the left column to the right column and
put them in the right order with the correct indention. Click on <i>Check
Me</i> to see if you are right. You will be told if any of the lines are in the
wrong order or are incorrectly indented.
• ␣␣nikea.stamp()
• nikea.shape("turtle")
• wn.exitonclick()
• ␣␣nikea.forward(50)
• nikea␣=␣turtle.Turtle()
• import␣turtle
wn␣=␣turtle.Screen()
• nikea.penup()
• for␣size␣in␣range(3):
Note 4.8.3 Lab.
• Turtle Race1 In this guided lab exercise we will work through a simple
problem solving exercise related to having some turtles race.
1 ../Labs/lab03_01.html
CHAPTER 4. PYTHON TURTLE GRAPHICS 71
4.10 Glossary
Glossary
attribute.Some state or value that belongs to a particular object. For example,
tess has a color.
canvas.A surface within a window where drawing takes place.
control flow.See flow of execution in the next chapter.
for loop.A statement in Python for convenient repetition of statements in the
body of the loop.
instance.An object that belongs to a class. tess and alex are different instances
of the class Turtle
invoke.An object has methods. We use the verb invoke to mean activate the
method. Invoking a method is done by putting parentheses after the method
name, with some possible arguments. So wn.exitonclick() is an invocation
of the exitonclick method.
iteration.A basic building block for algorithms (programs). It allows steps to
be repeated. Sometimes called looping.
loop body.Any number of statements nested inside a loop. The nesting is
indicated by the fact that the statements are indented under the for loop state-
ment.
1 http://docs.python.org/dev/py3k/library/turtle.html
CHAPTER 4. PYTHON TURTLE GRAPHICS 72
4.11 Exercises
1. Write a program that prints We like Python's turtles! 100 times.
2. Turtle objects have methods and attributes. For example, a turtle has
a position and when you move the turtle forward, the position changes.
Think about the other methods shown in the summary above. Which
attibutes, if any, does each method relate to? Does the method change
the attribute?
3.
4. Assume you have a list of numbers 12, 10, 32, 3, 66, 17, 42, 99, 20
• An equilateral triangle
• A square
• A hexagon (six sides)
• An octagon (eight sides)
CHAPTER 4. PYTHON TURTLE GRAPHICS 73
6. Write a program that asks the user for the number of sides, the length of
the side, the color, and the fill color of a regular polygon. The program
should draw the polygon and then fill it in.
7. A drunk pirate makes a random turn and then takes 100 steps forward,
makes another random turn, takes another 100 steps, turns another ran-
dom amount, etc. A social science student records the angle of each
turn before the next 100 steps are taken. Her experimental data is 160,
-43, 270, -97, -43, 200, -940, 17, -86. (Positive angles are counter-
clockwise.) Use a turtle to draw the path taken by our drunk friend. After
the pirate is done walking, print the current heading.
8. On a piece of scratch paper, trace the following program and show the
drawing. When you are done, press run and check your answer.
import turtle
wn = turtle . Screen ()
tess = turtle . Turtle ()
tess . right (90)
tess . left (3600)
tess . right ( -90)
tess . left (3600)
tess . left (3645)
tess . forward ( -100)
9. Write a program to draw a shape like this:
10. Write a program to draw a face of a clock that looks something like this:
11. Write a program to draw some kind of picture. Be creative and experiment
with the turtle methods provided in Section 4.9.
CHAPTER 4. PYTHON TURTLE GRAPHICS 74
12. Create a turtle and assign it to a variable. When you print its type, what
do you get?
13. A sprite is a simple spider shaped thing with n legs coming out from a
center point. The angle between each leg is 360 / n degrees.
Write a program to draw a sprite where the number of legs is provided
by the user.
Chapter 5
Python Modules
Interactive1
75
CHAPTER 5. PYTHON MODULES 76
If you have not done so already, take a look at the Global Module Index.
Here you will see an alphabetical listing of all the modules that are available
as part of the standard library. Find the turtle module.
3 http://docs.python.org/py3k/py-modindex.html
4 http://docs.python.org/py3k/reference/index.html
5 http://docs.python.org/py3k/tutorial/index.html
CHAPTER 5. PYTHON MODULES 77
You can see that all the turtle functionality that we have talked about is
there. However, there is so much more. Take some time to read through and
familiarize yourself with some of the other things that turtles can do.
Note 5.1.1 Note: Python modules and limitations with activecode.
Throughout the chapters of this book, activecode windows allow you to practice
the Python that you are learning. We mentioned in the first chapter that
programming is normally done using some type of development environment
and that the activecode used here was strictly to help us learn. It is not the
way we write production programs.
To that end, it is necessary to mention that many of the modules available
in standard Python will not work in the activecode environment. In fact, only
turtle, math, and random have been completely ported at this point. If you
wish to explore any additional modules, you will need to also explore using a
more robust development environment.
Check your understanding
Checkpoint 5.1.2 In Python a module is:
B. Look at the import statements of the program you are working with or
writing.
C. Ask the professor
D. Look in this textbook.
Checkpoint 5.1.4 True / False: All standard Python modules will work in
activecode.
A. True
CHAPTER 5. PYTHON MODULES 78
B. False
Interactive1
Here are some items from the math module in action. If you want more
information, you can check out the Math Module1 Python Documentation.
import math
print ( math . pi )
print ( math . e )
A. import math
B. include math
C. use math
D. You don’t need a statement. You can always use the math module
• To play a game of chance where the computer needs to throw some dice,
pick a number, or flip a coin,
• To shuffle a deck of playing cards randomly,
• To randomly allow a new enemy spaceship to appear and shoot at you,
Python provides a module random that helps with tasks like this. You can
take a look at it in the documentation. Here are the key things we can do with
it.
import random
A. math.pi
B. math(pi)
C. pi.math
D. math->pi
Checkpoint 5.4.3 Which module would you most likely use if you were writing
a function to simulate rolling dice?
D. The computer can’t tell what values were already selected, so it might
generate all 5’s instead of 5 unique numbers.
Note 5.4.6 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
roast )
5.6 Glossary
Glossary
deterministic.A process that is repeatable and predictable.
documentation.A place where you can go to get detailed information about
aspects of your programming language.
module.A file containing Python definitions and statements intended for use
in other Python programs. The contents of a module are made available to the
other program by using the import statement.
pseudo-random number.A number that is not genuinely random but is
instead created algorithmically.
random number.A number that is generated in such a way as to exhibit
statistical randomness.
random number generator.A function that will provide you with random
numbers, usually between 0 and 1.
standard library.A collection of modules that are part of the normal instal-
lation of Python.
5.7 Exercises
1. Use a for statement to print 10 random numbers.
2. Repeat the above exercise but this time print 10 random numbers between
25 and 35, inclusive.
3. The Pythagorean Theorem tells us that the length of the hypotenuse
of a right triangle is related to the lengths of the other two sides. Look
through the math module and see if you can find a function that will
compute this relationship for you. Once you find it, write a short program
to try it out.
4. Search on the internet for a way to calculate an approximation for pi.
There are many that use simple arithmetic. Write a program to compute
the approximation and then print that value as well as the value of math.pi
from the math module.
Chapter 6
Functions
6.1 Functions
Interactive1
1 A header line which begins with a keyword and ends with a colon.
2 A body consisting of one or more Python statements, each indented the
same amount – 4 spaces is the Python standard – from the header line.
We’ve already seen the for loop which follows this pattern.
In a function definition, the keyword in the header is def, which is followed
by the name of the function and some parameters enclosed in parentheses.
1 www.youtube.com/watch?v=4wKtB57J5J4
88
CHAPTER 6. FUNCTIONS 89
The parameter list may be empty, or it may contain any number of parameters
separated from one another by commas. In either case, the parentheses are
required.
We need to say a bit more about the parameters. In the definition, the
parameter list is more specifically known as the formal parameters. This
list of names describes those things that the function will need to receive from
the user of the function. When you use a function, you provide values to the
formal parameters.
The figure below shows this relationship. A function needs certain infor-
mation to do its work. These values, often called arguments or actual pa-
rameters, are passed to the function by the user.
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
wn . exitonclick ()
This function is named drawSquare. It has two parameters — one to tell
the function which turtle to move around and the other to tell it the size of
the square we want drawn. In the function definition they are called t and sz
respectively. Make sure you know where the body of the function ends — it
depends on the indentation and the blank lines don’t count for this purpose!
Note 6.1.1 docstrings. If the first thing after the function header is a string
(some tools insist that it must be a triple-quoted string), it is called a docstring
and gets special treatment in Python and in some of the programming tools.
Another way to retrieve this information is to use the interactive interpreter,
and enter the expression <function_name>.__doc__, which will retrieve the
docstring for the function. So the string you write as documentation at the start
of a function is retrievable by python tools at runtime. This is different from
comments in your code, which are completely eliminated when the program is
parsed.
By convention, Python programmers use docstrings for the key documen-
tation of their functions.
Defining a new function does not make the function run. To do that we
need a function call. This is also known as a function invocation. We’ve
already seen how to call some built-in functions like print, range and int.
Function calls contain the name of the function to be executed followed by
a list of values in parentheses, called arguments, which are assigned to the
parameters in the function definition. So in the second to the last line of the
program, we call the function, and pass alex as the turtle to be manipulated,
and 50 as the size of the square we want.
Once we’ve defined a function, we can call it as often as we like and its
statements will be executed each time we call it. In this case, we could use it
to get one of our turtles to draw a square and then we can move the turtle and
have it draw a different square in a different location. Note that we lift the tail
so that when alex moves there is no trace. We put the tail back down before
drawing the next square. Make sure you can identify both invocations of the
drawSquare function.
import turtle
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
alex . penup ()
alex . goto (100 ,100)
alex . pendown ()
CHAPTER 6. FUNCTIONS 91
wn . exitonclick ()
In the next example, we’ve changed the drawSquare function a little and
we get tess to draw 15 squares with some variations. Once the function has
been defined, we can call it as many times as we like with whatever actual
parameters we like.
import turtle
def drawMulticolorSquare (t , sz ):
""" Make turtle t draw a multi - colour square of sz . """
for i in [ ' red ' , ' purple ' , ' hotpink ' , ' blue ' ]:
t. color ( i)
t. forward ( sz )
t. left (90)
wn . exitonclick ()
B. To help the programmer organize programs into chunks that match how
they think about the solution to the problem.
C. All Python programs must be written using functions
D. To calculate values.
Checkpoint 6.1.6 Which of the following is a valid function header (first line
of a function definition)?
A. def drawCircle(t):
B. def drawCircle:
C. drawCircle(t, sz):
D. def drawCircle(t, sz)
Checkpoint 6.1.7 What is the name of the following function?
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
for i in range (4) :
t. forward ( sz )
t. left (90)
A. i
B. t
C. t, sz
D. t, sz, i
Checkpoint 6.1.9 Considering the function below, which of the following
statements correctly invokes, or calls, this function (i.e., causes it to run)?
Assume we already have a turtle named alex.
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
for i in range (4) :
t. forward ( sz )
t. left (90)
D. drawSquare(alex, 10):
E. drawSquare(alex, 10)
Checkpoint 6.1.10 True or false: A function can be called several times by
placing a function call in the body of a loop.
A. True
B. False
Note 6.2.1 Of course, we have already seen that raising a base to an exponent
can be done with the ∗∗ operator.
Another built-in function that takes more than one argument is max.
print ( max (7 , 11) )
print ( max (4 , 1, 17 , 2 , 12) )
print ( max (3 * 11 , 5 ** 3, 512 - 9, 1024 ** 0) )
max can be sent any number of arguments, separated by commas, and will
return the maximum value sent. The arguments can be either simple values
or expressions. In the last example, 503 is returned, since it is larger than 33,
125, and 1. Note that max also works on lists of values.
Furthermore, functions like range, int, abs all return values that can be
used to build more complex expressions.
So an important difference between these functions and one like drawSquare
is that drawSquare was not executed because we wanted it to compute a value
— on the contrary, we wrote drawSquare because we wanted it to execute a
sequence of steps that caused the turtle to draw a specific shape.
Functions that return values are sometimes called fruitful functions. In
many other languages, a chunk that doesn’t return a value is called a proce-
dure, but we will stick here with the Python way of also calling it a function,
or if we want to stress it, a non-fruitful function.
Fruitful functions still allow the user to provide information (arguments).
However there is now an additional piece of data that is returned from the
function.
CHAPTER 6. FUNCTIONS 94
How do we write our own fruitful function? Let’s start by creating a very
simple mathematical function that we will call square. The square function
will take one number as a parameter and return the result of squaring that
number. Here is the black-box diagram with the Python code following.
def square ( x ):
y = x * x
return y
toSquare = 10
result = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , result )
The return statement is followed by an expression which is evaluated. Its
result is returned to the caller as the “fruit” of calling this function. Because
the return statement can contain any Python expression we could have avoided
creating the temporary variable y and simply used return x*x. Try modi-
fying the square function above to see that this works just the same. On the
other hand, using temporary variables like y in the program above makes
debugging easier. These temporary variables are examples of local variables,
pursued further in the next section.
Notice something important here. The name of the variable we pass as
an argument — toSquare — has nothing to do with the name of the formal
parameter — x. It is as if x = toSquare is executed when square is called. It
doesn’t matter what the value was named in the caller. In square, it’s name
is x. You can see this very clearly in codelens, where the global variables
(variables defined outside of any function) and the local variables for the square
function are in separate boxes.
As you step through the example in codelens notice that the return state-
ment not only causes the function to return a value, but it also returns the
flow of control back to the place in the program where the function call was
made. this is true in general:
Note 6.2.2 The call to a function terminates after the execution of a return
statement. This is fairly obvious if the return statement is the last statement
in the function, but we will see later where it makes sense to have a return
statement even when other statements follow, and the further statements are
not executed.
def square ( x ):
y = x * x
return y
toSquare = 10
squareResult = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , squareResult )
Another important thing to notice as you step through this codelens demon-
CHAPTER 6. FUNCTIONS 95
stration is the movement of the red and green arrows. Codelens uses these
arrows to show you where it is currently executing. Recall that the red arrow
always points to the next line of code that will be executed. The light green
arrow points to the line that was just executed in the last step.
When you first start running this codelens demonstration you will notice
that there is only a red arrow and it points to line 1. This is because line 1 is
the next line to be executed and since it is the first line, there is no previously
executed line of code.
When you click on the forward button, notice that the red arrow moves to
line 5, skipping lines 2 and 3 of the function (and the light green arrow has
now appeared on line 1). Why is this? The answer is that function definition
is not the same as function execution. Lines 2 and 3 will not be executed
until the function is called on line 6. Line 1 defines the function and the name
square is added to the global variables, but that is all the def does at that
point. The body of the function will be executed later. Continue to click the
forward button to see how the flow of control moves from the call, back up to
the body of the function, and then finally back to line 7, after the function has
returned its value and the value has been assigned to squareResult.
Finally, there is one more aspect of function return values that should be
noted. All Python functions return the value None unless there is an explicit
return statement with a value other than None. Consider the following common
mistake made by beginning Python programmers. As you step through this
example, pay very close attention to the return value in the local variables
listing. Then look at what is printed when the function returns.
def square ( x ):
y = x * x
print ( y ) # Bad ! should use return instead !
toSquare = 10
squareResult = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , squareResult )
The problem with this function is that even though it prints the value
of the square, that value will not be returned to the place where the call
was made. Since line 6 uses the return value as the right hand side of an
assignment statement, the evaluation of the function will be None. In this
case, squareResult will refer to that value after the assignment statement and
therefore the result printed in line 7 is incorrect. Typically, functions will
return values that can be printed or processed in some other way by the caller.
Check your understanding
Checkpoint 6.2.3 What is wrong with the following function definition:
def addEm (x , y , z):
return x + y + z
print ( ' the ␣ answer ␣ is ' , x + y + z )
C. You must calculate the value of x+y+z before you return it.
D. A function cannot return a number.
CHAPTER 6. FUNCTIONS 96
A. None
B. The value of x + y + z
C. The string ’x + y + z’
The python interpreter does not enforce restrictions about the data types
of objects that can be bound to particular variables; however, type checking
could alert us that something has gone wrong in our program execution. If we
are assuming at that x is a list, but it’s actually an integer, then at some point
later in the program execution, there will probably be an error. We can add
assert statements that will cause an error to be flagged sooner rather than
later, which might make it a lot easier to debug.
Check your understanding
Checkpoint 6.3.1 When assert x==y is executed and x and y have the same
values, what will happen?
particular input produces the particular output that you expect. Take a look
at the following code.
def square ( x ):
# raise x to the second power
return x * x
print ( ' testing ␣ square ␣ function ' )
assert square (3) == 9
Because each test checks whether a function works properly on specific
inputs, the test cases will never be complete: in principle, a function might
work properly on all the inputs that are tested in the test cases, but still not
work properly on some other inputs. That’s where the art of defining test
cases comes in: you try to find specific inputs that are representative of all the
important kinds of inputs that might ever be passed to the function.
Checkpoint 6.3.2 For the hangman game, this ‘blanked’ function takes a word
and some letters that have been guessed, and returns a version of the word with
_ for all the letters that haven’t been guessed. Which of the following is the
correct way to write a test to check that ‘under’ will be blanked as 'u_d__'
when the user has guessed letters d and u so far?
z = square (10)
print ( y )
If you press the ‘last >>’ button you will see an error message. When we
try to use y on line 6 (outside the function) Python looks for a global variable
named y but does not find one. This results in the error: Name Error: 'y' is
not defined.
The variable y only exists while the function is being executed — we call
this its lifetime. When the execution of the function terminates (returns),
the local variables are destroyed. Codelens helps you visualize this because the
local variables disappear after the function returns. Go back and step through
the statements paying particular attention to the variables that are created
when the function is called. Note when they are subsequently destroyed as the
function returns.
Formal parameters are also local and act like local variables. For example,
the lifetime of x begins when square is called, and its lifetime ends when the
function completes its execution.
CHAPTER 6. FUNCTIONS 99
power = 2
result = badsquare (10)
print ( result )
Although the badsquare function works, it is silly and poorly written. We
have done it here to illustrate an important rule about how variables are looked
up in Python. First, Python looks at the variables that are defined as local
variables in the function. We call this the local scope. If the variable name
is not found in the local scope, then Python looks at the global variables, or
global scope. This is exactly the case illustrated in the code above. power is
not found locally in badsquare but it does exist globally. The appropriate way
to write this function would be to pass power as a parameter. For practice,
you should rewrite the badsquare example to have a second parameter called
power.
There is another variation on this theme of local versus global variables.
Assignment statements in the local function cannot change variables defined
outside the function, without further (discouraged) special syntax. Consider
the following codelens example:
def powerof (x , p ):
power = p # Another dumb mistake
y = x ** power
return y
power = 3
result = powerof (10 , 2)
print ( result )
Now step through the code. What do you notice about the values of variable
power in the local scope compared to the variable power in the global scope?
The value of power in the local scope was different than the global scope.
That is because in this example power was used on the left hand side of the
assignment statement power = p. When a variable name is used on the left
hand side of an assignment statement Python creates a local variable. When
a local variable has the same name as a global variable we say that the local
shadows the global. A shadow means that the global variable cannot be
accessed by Python because the local variable will be found first. This is
another good reason not to use global variables. As you can see, it makes your
code confusing and difficult to understand.
To cement all of these ideas even further lets look at one final example. In-
side the square function we are going to make an assignment to the parameter
x There’s no good reason to do this other than to emphasize the fact that the
parameter x is a local variable. If you step through the example in codelens you
will see that although x is 0 in the local variables for square, the x in the global
scope remains 2. This is confusing to many beginning programmers who think
CHAPTER 6. FUNCTIONS 100
x = 2
z = square ( x )
print ( z )
Check your understanding
Checkpoint 6.4.1 What is a variable’s scope?
A. Its value
B. The range of statements in the code where a variable can be accessed.
C. Its name
Checkpoint 6.4.2 What is a local variable?
Interactive1
number by itself. In this section we will reimplement the square function and
use a different algorithm, one that relies on addition instead of multiplication.
If you want to multiply two numbers together, the most basic approach is to
think of it as repeating the process of adding one number to itself. The number
of repetitions is where the second number comes into play. For example, if we
wanted to multiply three and five, we could think about it as adding three to
itself five times. Three plus three is six, plus three is nine, plus three is 12, and
finally plus three is 15. Generalizing this, if we want to implement the idea of
squaring a number, call it n, we would add n to itself n times.
Do this by hand first and try to isolate exactly what steps you take. You’ll
find you need to keep some “running total” of the sum so far, either on a piece
of paper, or in your head. Remembering things from one step to the next is
precisely why we have variables in a program. This means that we will need
some variable to remember the “running total”. It should be initialized with
a value of zero. Then, we need to update the “running total” the correct
number of times. For each repetition, we’ll want to update the running total
by adding the number to it.
In words we could say it this way. To square the value of n, we will repeat
the process of updating a running total n times. To update the running total,
we take the old value of the “running total” and add n. That sum becomes the
new value of the “running total”.
Here is the program in activecode. Note that the heading of the function
definition is the same as it was before. All that has changed is the details of
how the squaring is done. This is a great example of “black box” design. We
can change out the details inside of the box and still use the function exactly
as we did before.
def square ( x ):
runningtotal = 0
for counter in range (x ):
runningtotal = runningtotal + x
return runningtotal
toSquare = 10
squareResult = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , squareResult )
In the program above, notice that the variable runningtotal starts out
with a value of 0. Next, the iteration is performed x times. Inside the for loop,
the update occurs. runningtotal is reassigned a new value which is the old
value plus the value of x.
This pattern of iterating the updating of a variable is commonly referred to
as the accumulator pattern. We refer to the variable as the accumulator.
This pattern will come up over and over again. Remember that the key to
making it work successfully is to be sure to initialize the variable before you
start the iteration. Once inside the iteration, it is required that you update
the accumulator.
Note 6.5.1 What would happen if we put the assignment runningTotal = 0
inside the for statement? Not sure? Try it and find out.
Here is the same program in codelens. Step through the function and watch
the “running total” accumulate the result.
def square ( x ):
runningtotal = 0
for counter in range (x ):
CHAPTER 6. FUNCTIONS 102
runningtotal = runningtotal + x
return runningtotal
toSquare = 10
squareResult = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , squareResult )
Note 6.5.2 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
Check your understanding
Checkpoint 6.5.3 Consider the following code:
def square ( x ):
for counter in range (x ):
runningtotal = 0
runningtotal = runningtotal + x
return runningtotal
What happens if you put the initialization of runningtotal (the line run-
ningtotal = 0) inside the for loop as the first instruction in the loop?
• ␣␣␣thesum␣=␣thesum␣+␣oddnumber
␣␣␣oddnumber␣=␣oddnumber␣+␣2
• for␣counter␣in␣range(n):
• print(thesum)
• n␣=␣int(input('How␣many␣odd␣numbers␣would
you␣like␣to␣add␣together?'))
thesum␣=␣0
oddnumber␣=␣1
CHAPTER 6. FUNCTIONS 103
return runningtotal
toSquare = 10
squareResult = square ( toSquare )
print ( " The ␣ result ␣ of " , toSquare , " squared ␣ is " , squareResult )
Note 6.5.5 Modify the program …. Change the value of toSquare in line
9 to -10 and run.
We now see that our function has a semantic error. Remember when we
first introduced the square function, unit testing and equivalence classes?
Change the value of toSquare in line 9 back to 10 and run.
What would happen if we change runningtotal = runningtotal + x to
use multiplication instead of addition? Make this change to the program
and look at the output.
It is very important to properly initialize the accumulator variable. Do a
web search on additive identity and multiplicative identity. Properly
initialize the accumulator variable and run the program.
Now we get an answer other than 0. However, the answer is not the square
of of x. It is also important that the loop repeat the proper number of times.
How many times do we need to execute line 5 to get the square of x? Change
line 4 to repeat the correct number of times. Now the program should
produce the correct result.
Change the value of toSquare in line 9 to -10 and run. Now negative inputs
also work!
Remember that the boundary between our equivalence classes is 0. Try
that value for toSquare also.
def sum_of_squares (x , y , z ):
a = square ( x )
b = square ( y )
c = square ( z )
CHAPTER 6. FUNCTIONS 104
return a + b + c
a = -5
b = 2
c = 10
result = sum_of_squares (a , b , c )
print ( result )
Even though this is a pretty simple idea, in practice this example illustrates
many very important Python concepts, including local and global variables
along with parameter passing. Note that when you step through this example,
codelens bolds line 1 and line 5 as the functions are defined. The body of
square is not executed until it is called from the sum_of_squares function for
the first time on line 6. Also notice that when square is called there are two
groups of local variables, one for square and one for sum_of_squares. As you
step through you will notice that x, and y are local variables in both functions
and may even have different values. This illustrates that even though they are
named the same, they are in fact, very different.
Now we will look at another example that uses two functions. This example
illustrates an important computer science problem solving technique called
generalization. Assume we want to write a function to draw a square. The
generalization step is to realize that a square is just a special kind of rectangle.
To draw a rectangle we need to be able to call a function with different
arguments for width and height. Unlike the case of the square, we cannot
repeat the same thing 4 times, because the four sides are not equal. However,
it is the case that drawing the bottom and right sides are the same sequence
as drawing the top and left sides. So we eventually come up with this rather
nice code that can draw a rectangle.
def drawRectangle (t , w , h):
""" Get turtle t to draw a rectangle of width w and
height h . """
for i in range (2) :
t. forward ( w )
t. left (90)
t. forward ( h )
t. left (90)
The parameter names are chosen as single letters for conciseness. In real
programs, we will insist on better variable names than this. The point is that
the program doesn’t “understand” that you’re drawing a rectangle or that the
parameters represent the width and the height. Concepts like rectangle, width,
and height are meaningful for humans. They are not concepts that the program
or the computer understands.
Thinking like a computer scientist involves looking for patterns and rela-
tionships. In the code above, we’ve done that to some extent. We did not just
draw four sides. Instead, we spotted that we could draw the rectangle as two
halves and used a loop to repeat that pattern twice.
But now we might spot that a square is a special kind of rectangle. A
square simply uses the same value for both the height and the width. We
already have a function that draws a rectangle, so we can use that to draw our
square.
def drawSquare ( tx , sz ): # a new version of drawSquare
drawRectangle ( tx , sz , sz )
Here is the entire example with the necessary set up code.
CHAPTER 6. FUNCTIONS 105
import turtle
wn . exitonclick ()
There are some points worth noting here:
• Functions can call other functions.
• Rewriting drawSquare like this captures the relationship that we’ve spot-
ted.
• A caller of this function might say drawSquare(tess, 50). The parameters
of this function, tx and sz, are assigned the values of the tess object, and
the integer 50 respectively.
• In the body of the function, tz and sz are just like any other variable.
• When the call is made to drawRectangle, the values in variables tx and
sz are fetched first, then the call happens. So as we enter the top of
function drawRectangle, its variable t is assigned the tess object, and w
and h in that function are both given the value 50.
So far, it may not be clear why it is worth the trouble to create all of
these new functions. Actually, there are a lot of reasons, but this example
demonstrates two:
1 Creating a new function gives you an opportunity to name a group of
statements. Functions can simplify a program by hiding a complex com-
putation behind a single command. The function (including its name)
can capture your mental chunking, or abstraction, of the problem.
2 Creating a new function can make a program smaller by eliminating
repetitive code.
3 Sometimes you can write functions that allow you to solve a specific
problem using a more general solution.
Note 6.6.1 Lab.
• Drawing a Circle1 In this guided lab exercise we will work through a
simple problem solving exercise related to drawing a circle with the turtle.
1 ../Labs/lab04_01.html
CHAPTER 6. FUNCTIONS 106
def square ( x ):
a = pow (x , 2)
return a
n = 5
result = square ( n)
print ( result )
Which of the following best reflects the order in which these lines of code
are processed in Python?
A. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
B. 1, 2, 3, 5, 6, 7, 9, 10, 11
C. 9, 10, 11, 1, 2, 3, 5, 6, 7
D. 9, 10, 5, 6, 1, 2, 3, 6, 7, 10, 11
E. 1, 5, 9, 10, 5, 6, 1, 2, 3, 6, 7, 10, 11
Checkpoint 6.7.2 Consider the following Python code. Note that line num-
bers are included on the left.
CHAPTER 6. FUNCTIONS 107
def pow (b , p ):
y = b ** p
return y
def square ( x ):
a = pow (x , 2)
return a
n = 5
result = square ( n)
print ( result )
What does this function print?
A. 25
B. 5
C. 125
D. 32
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
wn . exitonclick ()
If you look closely at the structure of this program, you will notice that we
first perform all of our necessary import statements, in this case to be able to
use the turtle module. Next, we define the function drawSquare. At this point,
we could have defined as many functions as were needed. Finally, there are
five statements that set up the window, create the turtle, perform the function
invocation, and wait for a user click to terminate the program.
These final five statements perform the main processing that the program
will do. Notice that much of the detail has been pushed inside the drawSquare
CHAPTER 6. FUNCTIONS 108
function. However, there are still these five lines of code that are needed to get
things done.
In many programming languages (e.g. Java and C++), it is not possible
to simply have statements sitting alone like this at the bottom of the program.
They are required to be part of a special function that is automatically invoked
by the operating system when the program is executed. This special function
is called main. Although this is not required by the Python programming
language, it is actually a good idea that we can incorporate into the logical
structure of our program. In other words, these five lines are logically related
to one another in that they provide the main tasks that the program will
perform. Since functions are designed to allow us to break up a program into
logical pieces, it makes sense to call this piece main.
The following activecode shows this idea. In line 11 we have defined a new
function called main that doesn’t need any parameters. The five lines of main
processing are now placed inside this function. Finally, in order to execute that
main processing code, we need to invoke the main function (line 20). When
you push run, you will see that the program works the same as it did before.
import turtle
def drawSquare (t , sz ):
""" Make turtle t draw a square of with side sz . """
wn . exitonclick ()
we may or may not choose to execute some of the code that we have written.
For example, assume that we have written a collection of functions to do
some simple math. We can include a main function to invoke these math
functions. It is much more likely, however, that these functions will be imported
by another program for some other purpose. In that case, we would not want
to execute our main function.
The activecode below defines two simple functions and a main.
def squareit ( n ):
return n * n
def cubeit ( n ):
return n * n * n
def main () :
anum = int ( input ( " Please ␣ enter ␣a␣ number " ))
print ( squareit ( anum ))
print ( cubeit ( anum ))
The first step is to consider what a distance function should look like in
Python. In other words, what are the inputs (parameters) and what is the
output (return value)?
CHAPTER 6. FUNCTIONS 110
In this case, the two points are the inputs, which we can represent using
four parameters. The return value is the distance, which is a floating-point
value.
Already we can write an outline of the function that captures our thinking
so far.
def distance ( x1 , y1 , x2 , y2 ):
return 0.0
Obviously, this version of the function doesn’t compute distances; it always
returns zero. But it is syntactically correct, and it will run, which means that
we can test it before we make it more complicated.
We import the test module to enable us to write a unit test for the function.
import test
def distance ( x1 , y1 , x2 , y2 ):
return 0.0
Again, we could run the program at this stage and check the value of
dsquared (which should be 25).
Finally, using the fractional exponent 0.5 to find the square root, we com-
pute and return the result.
import test
def distance ( x1 , y1 , x2 , y2 ):
dx = x2 - x1
dy = y2 - y1
dsquared = dx **2 + dy **2
result = dsquared **0.5
return result
Note 6.9.2 Fix the error …. Two of the tests pass but the last one fails.
Is there still an error in the function?
Frequently we discover errors in the functions that we are writing. However,
it is possible that there is an error in a test. Here the error is in the precision
of the correct answer.
The third test fails because by default testEqual checks 5 digits to the right
of the decimal point.
There are circumstances where 2 digits to the right of the decimal point is
sufficiently precise.
• Copy line 11 on to line 12. On line 12, change 1.41421 to 1.41. Run.
The test fails.
• Type , 2 after 1.41. (The 2 represents the precision of the test – how
many digits to the right of the decimal that must be correct.) Run.
Now all four the tests pass! Wonderful! However, you may still need to
perform additional tests.
When you start out, you might add only a line or two of code at a time.
As you gain more experience, you might find yourself writing and debugging
bigger conceptual chunks. As you improve your programming skills you should
find yourself managing bigger and bigger chunks: this is very similar to the
way we learned to read letters, syllables, words, phrases, sentences, paragraphs,
etc., or the way we learn to chunk music — from indvidual notes to chords,
bars, phrases, and so on.
The key aspects of the process are:
1 Make sure you know what you are trying to accomplish. Then you can
write appropriate unit tests.
2 Start with a working skeleton program and make small incremental changes.
At any point, if there is an error, you will know exactly where it is.
3 Use temporary variables to hold intermediate values so that you can
easily inspect and check them.
4 Once the program is working, you might want to consolidate multiple
statements into compound expressions, but only do this if it does not
make the program more difficult to read.
CHAPTER 6. FUNCTIONS 112
6.10 Composition
As we have already seen, you can call one function from within another. This
ability to build functions by using other functions is called composition.
As an example, we’ll write a function that takes two points, the center of
the circle and a point on the perimeter, and computes the area of the circle.
Assume that the center point is stored in the variables xc and yc, and the
perimeter point is in xp and yp. The first step is to find the radius of the circle,
which is the distance between the two points. Fortunately, we’ve just written
a function, distance, that does just that, so now all we have to do is use it:
radius = distance ( xc , yc , xp , yp )
The second step is to find the area of a circle with that radius and return
it. Again we will use one of our earlier functions:
result = area ( radius )
return result
Wrapping that up in a function, we get:
def distance ( x1 , y1 , x2 , y2 ):
dx = x2 - x1
dy = y2 - y1
dsquared = dx **2 + dy **2
result = dsquared **0.5
return result
def area2 ( xc , yc , xp , yp ):
radius = distance ( xc , yc , xp , yp )
result = area ( radius )
return result
• We can get a turtle to display text on the canvas at the turtle’s current po-
sition. The method is called write. For example, alex.write("Hello")
would write the string hello at the current position.
CHAPTER 6. FUNCTIONS 113
• One can fill a shape (circle, semicircle, triangle, etc.) with a fill color.
It is a two-step process. First you call the method begin_fill, for ex-
ample alex.begin_fill(). Then you draw the shape. Finally, you call
end_fill ( alex.end_fill()).
• We’ve previously set the color of our turtle - we can now also set it’s fill
color, which need not be the same as the turtle and the pen color. To do
this, we use a method called fillcolor, for example, alex.fillcolor("red").
Ok, so can we get tess to draw a bar chart? Let us start with some data
to be charted,
xs = [48, 117, 200, 240, 160, 260, 220]
Corresponding to each data measurement, we’ll draw a simple rectangle of
that height, with a fixed width. Here is a simplified version of what we would
like to create.
We can quickly see that drawing a bar will be similar to drawing a rectangle
or a square. Since we will need to do it a number of times, it makes sense to
create a function, drawBar, that will need a turtle and the height of the bar.
We will assume that the width of the bar will be 40 units. Once we have the
function, we can use a basic for loop to process the list of data values.
def drawBar (t , height ):
""" Get turtle t to draw one bar , of height . """
t . left (90) # Point up
t . forward ( height ) # Draw up the left side
t . right (90)
t . forward (40) # width of bar , along the top
t . right (90)
t . forward ( height ) # And down again !
t . left (90) # put the turtle facing the
way we found it .
...
for v in xs : # assume xs and tess are ready
drawBar ( tess , v )
It is a nice start! The important thing here was the mental chunking. To
solve the problem we first broke it into smaller pieces. In particular, our chunk
is to draw one bar. We then implemented that chunk with a function. Then,
for the whole chart, we repeatedly called our function.
Next, at the top of each bar, we’ll print the value of the data. We will
do this in the body of drawBar by adding t.write(str(height)) as the new
fourth line of the body. Note that we had to turn the number into a string.
Finally, we’ll add the two methods needed to fill each bar.
CHAPTER 6. FUNCTIONS 114
The one remaining problem is related the fact that our turtle lives in a world
where position (0,0) is at the center of the drawing canvas. In this problem, it
would help if (0,0) were in the lower left hand corner. To solve this we can use
our setworldcoordinates method to rescale the window. While we are at it,
we should make the window fit the data. The tallest bar will correspond to the
maximum data value. The width of the window will need to be proportional
to the number of bars (the number of data values) where each has a width of
40. Using this information, we can compute the coordinate system that makes
sense for the data set. To make it look nice, we’ll add a 10 unit border around
the bars.
Here is the complete program. Try it and then change the data to see that
it can adapt to the new values. Note also that we have stored the data values
in a list and used a few list functions. We will have much more to say about
lists in a later chapter.
import turtle
xs = [48 , 117 , 200 , 240 , 160 , 260 , 220] # here is the data
maxheight = max ( xs )
numbars = len ( xs )
border = 10
for a in xs :
drawBar ( tess , a )
wn . exitonclick ()
This code is quite concise, but each height label is partly covered by the
top segment of its bar. Can you modifiy the drawBar code, moving the label
CHAPTER 6. FUNCTIONS 115
up slightly but not changing the bar? Hint: The label cannot be drawn during
the polygon fill sequence.
Note 6.11.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
6.12 Glossary
Glossary
chatterbox function.A function which interacts with the user (using input
or print) when it should not. Silent functions that just convert their input
arguments into their output results are usually the most useful ones.
composition (of functions).Calling one function from within the body of
another, or using the return value of one function as an argument to the call
of another.
dead code.Part of a program that can never be executed, often because it
appears after a return statement.
fruitful function.A function that yields a return value instead of None.
incremental development.A program development plan intended to simplify
debugging by adding and testing only a small amount of code at a time.
None.A special Python value. One use in Python is that it is returned by
functions that do not execute a return statement with a return argument.
return value.The value provided as the result of a function call.
scaffolding.Code that is used during program development to assist with de-
velopment and debugging. The unit test code that we added in this chapter
are examples of scaffolding.
temporary variable.A variable used to store an intermediate value in a com-
plex calculation.
6.13 Exercises
1. Use the drawsquare function we wrote in this chapter in a program to draw
the image shown below. Assume each side is 20 units. (Hint: notice that
the turtle has already moved away from the ending point of the last square
import turtle
def drawSquare (t , sz ) :
""" Get turtle t to draw a square of sz side """
wn = turtle . Screen ()
wn . bgcolor ( " lightgreen " )
wn . exitonclick ()
2. Write a program to draw this. Assume the innermost square is 20 units
per side, and each successive square is 20 units bigger, per side, than the
one inside it.
5. The two spirals in this picture differ only by the turn angle. Draw both.
myTests () . main ()
8. Write a function areaOfCircle(r) which returns the area of a circle of radius
r. Make sure you use the math module in your solution.
CHAPTER 6. FUNCTIONS 118
def areaOfCircle (r ) :
# your code here ====
from unittest . gui import TestCaseGui
myTests () . main ()
9. Write a non-fruitful function to draw a five pointed star, where the length
of each side is 100 units.
10. Extend your program above. Draw five stars, but between each, pick up
the pen, move forward by 350 units, turn right by 144, put the pen down,
and draw the next star. You’ll get something like this (note that you
will need to move to the left before drawing your first star in order to fit
everything in the window):
12. Write a function called drawSprite that will draw a sprite. The function
will need parameters for the turtle, the number of legs, and the length of
the legs. Invoke the function to create a sprite with 15 legs of length 120.
13. Rewrite the function sumTo(n) that returns the sum of all integer numbers
up to and including n. This time use the accumulator pattern.
def sumTo ( n ):
# your code here ====
from unittest . gui import TestCaseGui
class myTests ( TestCaseGui ) :
myTests () . main ()
14. Write a function called mySqrt that will approximate the square root of
a number, call it n, by using Newton’s algorithm. Newton’s approach is
an iterative guessing algorithm where the initial guess is n/2 and each
subsequent guess is computed using the formula: newguess = (1/2) ∗
(oldguess + (n/oldguess)).
def mySqrt ( n ):
# your code here ====
from unittest . gui import TestCaseGui
myTests () . main ()
15. Write a function called myPi that will return an approximation of PI
(3.14159…). Use the Leibniz1 approximation.
def myPi ( iters ):
# Calculate an approximation of PI using the Leibniz
# approximation with iters number of iterations
import turtle
for a in xs :
drawBar ( tess , a )
wn . exitonclick ()
Chapter 7
Selection
Interactive1
The Python type for storing true and false values is called bool, named
after the British mathematician, George Boole. George Boole created Boolean
Algebra, which is the basis of all modern computer arithmetic.
There are only two boolean values. They are True and False. Capital-
ization is important, since true and false are not boolean values (remember
Python is case sensitive).
print ( True )
print ( type ( True ))
print ( type ( False ))
print (5 == 6)
1 www.youtube.com/watch?v=LD-F4RODy-I
122
CHAPTER 7. SELECTION 123
A. True
B. 3 == 4
C. 3 + 4
D. 3 + 4 == 7
E. ”False”
n = 25
print ( n % 2 == 0 or n % 3 == 0)
CHAPTER 7. SELECTION 124
When trying to show how logical operators work, computer scientists and
mathematicians alike will use truth tables. A truth table is a small table that
lists all possible inputs on its left columns and then will display the output of
its particular logical operator in the right column. Take the logical operator
and for example:
Table 7.2.1
a b a and b
T T T
T F F
F T F
F F F
The T in the table stands for True while the F stands for False. Notice
that when a and b are both True, the logcial operator and outputs True. This
is exactly how we normally use “and” in everyday conversation. Here are the
rest of the operators:
Table 7.2.2
Interactive1
B. x > 0 or x < 5
C. x > 0 and x < 5
Checkpoint 7.2.5 Say you are registering for next semester’s classes. You
have choice A, which is your art class, and choice B, which is your math class.
You need both of them, but it’s a race between time and luck. If you end up
registering on time for choice A, but you don’t get your choice B, which logical
operators would be true?
A. A and B
B. A or B
C. not A
D. not B
For example, suppose you want to update your phone; however, your phone
will only update if it has at least 50% battery life and 15% of its storage
available. As we look at the Python code for this, we see:
if not (( phone_charge >= 0.50) and ( phone_storage >= .15) ):
print (" You ␣ cannot ␣ restart ␣ your ␣ phone .␣ Battery ␣ too ␣ low ␣ or ␣
not ␣ enough ␣ free ␣ space . " )
else :
print (" Updating ␣ now ... Several ␣ restarts ␣ may ␣ be ␣ required . ")
Applying rules of logical opposites would let us rework the condition in a
(perhaps) easier to understand way like this:
if ( phone_charge < 0.50) or ( phone_storage < .15) :
print (" You ␣ cannot ␣ restart ␣ your ␣ phone .␣ Battery ␣ too ␣ low ␣ or ␣
not ␣ enough ␣ free ␣ space . " )
else :
print (" Updating ␣ now ... Several ␣ restarts ␣ may ␣ be ␣ required . ")
We could also get rid of the not by swapping around the then and else
parts of the conditional. So here is a third version, also equivalent:
if ( phone_charge >= 0.50) and ( phone_storage >= .15) :
print (" Updating ␣ now ... Several ␣ restarts ␣ may ␣ be ␣ required . ")
else :
print (" You ␣ cannot ␣ restart ␣ your ␣ phone .␣ Battery ␣ too ␣ low ␣ or ␣
not ␣ enough ␣ free ␣ space . " )
This version is probably the best of the three, because it very closely
matches the initial English statement. Clarity of our code (for other humans),
and making it easy to see that the code does what was expected should always
be a high priority.
As our programming skills develop we’ll find we have more than one way
to solve any problem. So good programs are designed. We make choices that
favour clarity, simplicity, and elegance. The job title software architect says a
lot about what we do — we are architects who engineer our products to balance
beauty, functionality, simplicity and clarity in our creations.
Table 7.3.1
Level Category Operators
7(high) exponent ∗∗
6 multiplication ∗,/,//,%
5 addition +,-
4 relational ==,!=,<=,>=,>,<
3 logical not
2 logical and
1(low) logical or
Note 7.3.2 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
Check your understanding
Checkpoint 7.3.3 Which of the following properly expresses the precedence
of operators (using parentheses) in the following expression: 5∗3 > 10 and
4+6==11
Interactive1
In order to write useful programs, we almost always need the ability to check
conditions and change the behavior of the program accordingly. Selection
statements, sometimes also referred to as conditional statements, give
us this ability. The simplest form of selection is the if statement. This is
sometimes referred to as binary selection since there are two possible paths
of execution.
x = 15
if x % 2 == 0:
print (x , " is ␣ even " )
else :
1 www.youtube.com/watch?v=HriDtn-0Dcw
CHAPTER 7. SELECTION 128
As with the function definition from the last chapter and other compound
statements like for, the if statement consists of a header line and a body. The
header line begins with the keyword if followed by a boolean expression and
ends with a colon (:).
The more indented statements that follow are called a block.
Each of the statements inside the first block of statements is executed in
order if the boolean expression evaluates to True. The entire first block of
statements is skipped if the boolean expression evaluates to False, and instead
all the statements under the else clause are executed.
There is no limit on the number of statements that can appear under the
two clauses of an if statement, but there has to be at least one statement in
each block.
Each compound statement includes a heading and all the following further-
indented statements in the block after the heading. The if - else statement
is an unusual compound statement because it has more than one part at the
same level of indentation as the if heading, (the else clause, with its own
indented block).
Note 7.4.1 Lab.
Checkpoint 7.4.2 How many statements can appear in each block (the if and
the else) in a conditional statement?
A. Just one.
B. Zero or more.
C. One or more.
D. One or more, and each must contain the same number.
Checkpoint 7.4.3 What does the following code print (choose from output a,
b, c or nothing)?
if 4 + 5 == 10:
print ( " TRUE " )
else :
print ( " FALSE ")
A. TRUE
B. FALSE
C. TRUE on one line and FALSE on the next
D. Nothing will be printed
Checkpoint 7.4.4 What does the following code print?
if 4 + 5 == 10:
print ( " TRUE " )
else :
print ( " FALSE ")
print ( " TRUE " )
a. TRUE
b.
TRUE
FALSE
c.
FALSE
TRUE
d.
TRUE
FALSE
TRUE
A. Output a
B. Output b
C. Output c
D. Output d
CHAPTER 7. SELECTION 130
Interactive1
Another form of the if statement is one in which the else clause is omitted
entirely. This creates what is sometimes called unary selection. In this case,
when the condition evaluates to True, the statements are executed. Otherwise
the flow of execution continues to the statement after the body of the if.
x = 10
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
print ( " This ␣ is ␣ always ␣ printed " )
What would be printed if the value of x is negative? Try it.
Check your understanding
Checkpoint 7.5.1 What does the following code print?
x = -10
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
print ( " This ␣ is ␣ always ␣ printed " )
a.
1 www.youtube.com/watch?v=Fd4a8ktQURc
CHAPTER 7. SELECTION 131
b.
The negative number -10 is not valid here
This is always printed
c.
The negative number -10 is not valid here
A. Output a
B. Output b
C. Output c
A. No
B. Yes
Here is a complete program that defines values for x and y. Run the program
and see the result. Then change the values of the variables to change the flow
of control.
x = 10
y = 10
if x < y :
print ( " x␣ is ␣ less ␣ than ␣y " )
else :
if x > y :
print ( " x␣ is ␣ greater ␣ than ␣y" )
else :
print ( " x␣ and ␣y␣ must ␣ be ␣ equal " )
Note 7.6.1 In some programming languages, matching the if and the else is
a problem. However, in Python this is not the case. The indentation pattern
tells us exactly which else belongs to which if.
If you are still a bit unsure, here is the same selection as part of a codelens
example. Step through it to see how the correct print is chosen.
x = 10
y = 10
if x < y :
print ( " x␣ is ␣ less ␣ than ␣y " )
else :
if x > y :
print ( " x␣ is ␣ greater ␣ than ␣y" )
else :
print ( " x␣ and ␣y␣ must ␣ be ␣ equal " )
Check your understanding
Checkpoint 7.6.2 Will the following code cause an error?
CHAPTER 7. SELECTION 133
x = -10
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
else :
if x > 0:
print (x , "␣ is ␣a␣ positive ␣ number " )
else :
print (x , "␣ is ␣0 " )
A. No
B. Yes
if x < y :
CHAPTER 7. SELECTION 134
Note 7.7.1 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
Check your understanding
Checkpoint 7.7.2 Which of I, II, and III below gives the same result as the
following nested if?
# nested if - else statement
x = -10
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
else :
if x > 0:
print (x , "␣ is ␣a␣ positive ␣ number " )
else :
print (x , "␣ is ␣0 " )
I.
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
else x > 0:
print (x , "␣ is ␣a␣ positive ␣ number " )
else :
print (x , "␣ is ␣0 " )
II .
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
elif x > 0:
print (x , "␣ is ␣a␣ positive ␣ number " )
else :
print (x , "␣ is ␣0 " )
III .
if x < 0:
print ( " The ␣ negative ␣ number ␣" , x , "␣ is ␣ not ␣ valid ␣ here . ")
if x > 0:
print (x , "␣ is ␣a␣ positive ␣ number " )
else :
print (x , "␣ is ␣0 " )
A. I only
B. II only
C. III only
D. II and III
E. I, II, and III
Checkpoint 7.7.3 What will the following code print if x = 3, y = 5, and z
= 2?
CHAPTER 7. SELECTION 135
A. a
B. b
C. c
return result
if isDivisible (10 , 5) :
print ( " That ␣ works " )
else :
print ( " Those ␣ values ␣ are ␣ no ␣ good " )
Here is the same program in codelens. When we evaluate the if statement
in the main part of the program, the evaluation of the boolean expression
causes a call to the isDivisible function. This is very easy to see in codelens.
def isDivisible (x , y ):
return x % y == 0
if isDivisible (10 , 5) :
print ( " That ␣ works " )
else :
print ( " Those ␣ values ␣ are ␣ no ␣ good " )
Check your understanding
Checkpoint 7.8.1 What is a Boolean function?
A. Yes
B. No
Note 7.8.3 Extend the program …. Starting on line 7, write two unit
tests (that should pass), one for each output equivalence class.
Note 7.8.4 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
CHAPTER 7. SELECTION 137
7.9 Glossary
Glossary
block.A group of consecutive statements with the same indentation.
body.The block of statements in a compound statement that follows the
header.
boolean expression.An expression that is either true or false.
boolean function.A function that returns a boolean value. The only possible
values of the bool type are False and True.
boolean value.There are exactly two boolean values: True and False. Boolean
values result when a boolean expression is evaluated by the Python interepreter.
They have type bool.
branch.One of the possible paths of the flow of execution determined by con-
ditional execution.
chained conditional.A conditional branch with more than two possible flows
of execution. In Python chained conditionals are written with if ... elif ...
else statements.
comparison operator.One of the operators that compares two values: ==, !=,
>, <, >=, and <=.
condition.The boolean expression in a conditional statement that determines
which branch is executed.
conditional statement.A statement that controls the flow of execution de-
pending on some condition. In Python the keywords if, elif, and else are
used for conditional statements.
logical operator.One of the operators that combines boolean expressions:
and, or, and not.
modulus operator.An operator, denoted with a percent sign ( %), that works
on integers and yields the remainder when one number is divided by another.
nesting.One program structure within another, such as a conditional state-
ment inside a branch of another conditional statement.
7.10 Exercises
1. What do these expressions evaluate to?
1 3 == 3
2 3 != 3
3 3 >= 4
4 not (3 < 4)
2. Give the logical opposites of these conditions. You are not allowed to
use the not operator.
1 a > b
2 a >= b
====
myTests () . main ()
4. Modify the turtle bar chart program from the previous chapter so that
the bar for any value of 200 or more is filled with red, values between [100
and 200) are filled yellow, and bars representing values less than 100 are
filled green.
5. In the turtle bar chart program, what do you expect to happen if one or
more of the data values in the list is negative? Go back and try it out.
Change the program so that when it prints the text value for the negative
bars, it puts the text above the base of the bar (on the 0 axis).
6. Write a function findHypot. The function will be given the length of
two sides of a right-angled triangle and it should return the length of the
hypotenuse. (Hint: x ** 0.5 will return the square root, or use sqrt from
the math module)
CHAPTER 7. SELECTION 139
====
myTests () . main ()
7. Write a function called is_even(n) that takes an integer as an argument
and returns True if the argument is an even number and False if it is
odd.
def is_even ( n ):
# your code here
====
myTests () . main ()
8. Now write the function is_odd(n) that returns True when n is odd and
False otherwise.
CHAPTER 7. SELECTION 140
def is_odd ( n ):
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
9. Modify is_odd so that it uses a call to is_even to determine if its argument
is an odd integer.
def is_odd ( n ):
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
10. Write a function is_rightangled which, given the length of three sides
of a triangle, will determine whether the triangle is right-angled. Assume
that the third argument to the function is always the longest side. It will
return True if the triangle is right-angled, or False otherwise.
Hint: floating point arithmetic is not always exactly accurate, so it is
not safe to test floating point numbers for equality. If a good programmer
wants to know whether x is equal or close enough to y, they would probably
code it up as
if abs ( x - y ) < 0.001: # if x is approximately
equal to y
...
CHAPTER 7. SELECTION 141
def is_rightangled (a , b , c ) :
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
11. Extend the above program so that the sides can be given to the function
in any order.
CHAPTER 7. SELECTION 142
def is_rightangled (a , b , c ) :
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
12. 3 criteria must be taken into account to identify leap years:
The year is evenly divisible by 4;
If the year can be evenly divided by 100, it is NOT a leap year, unless;
The year is also evenly divisible by 400. Then it is a leap year.
Write a function that takes a year as a parameter and returns True if
the year is a leap year, False otherwise.
CHAPTER 7. SELECTION 143
====
from unittest . gui import TestCaseGui
myTests () . main ()
13. Implement the calculator for the date of Easter.
The following algorithm computes the date for Easter Sunday for any
year between 1900 to 2099.
Ask the user to enter a year. Compute the following:
1 a = year % 19
2 b = year % 4
3 c = year % 7
4 d = (19 ∗ a + 24) % 30
5 e = (2 ∗ b + 4 ∗ c + 6 ∗ d + 5) % 7
6 dateofeaster = 22 + d + e
Special note: The algorithm can give a date in April. Also, if the year is
one of four special years (1954, 1981, 2049, or 2076) then subtract 7 from
the date.
Your program should print an error message if the user provides a date
that is out of range.
Chapter 8
return theSum
144
CHAPTER 8. MORE ABOUT ITERATION 145
printnums (5 , 3)
A. 5
B. 8
C. 15
D. 18
E. 20
Interactive1
There is another Python statement that can also be used to build an itera-
tion. It is called the while statement. The while statement provides a much
more general mechanism for iterating. Similar to the if statement, it uses a
boolean expression to control the flow of execution. The body of while will be
repeated as long as the controlling boolean expression evaluates to True.
The following figure shows the flow of control.
1 www.youtube.com/watch?v=blTBEqybQmQ
CHAPTER 8. MORE ABOUT ITERATION 146
We can use the while loop to create any type of iteration we wish, including
anything that we have previously done with a for loop. For example, the
program in the previous section could be rewritten using while. Instead of
relying on the range function to produce the numbers for our summation, we
will need to produce them ourselves. To to this, we will create a variable
called aNumber and initialize it to 1, the first number in the summation. Every
iteration will add aNumber to the running total until all the values have been
used. In order to control the iteration, we must create a boolean expression
that evaluates to True as long as we want to keep adding values to our running
total. In this case, as long as aNumber is less than or equal to the bound, we
should keep going.
Here is a new version of the summation program that uses a while state-
ment.
def sumTo ( aBound ):
""" Return the sum of 1+2+3 ... n """
theSum = 0
aNumber = 1
while aNumber <= aBound :
theSum = theSum + aNumber
aNumber = aNumber + 1
return theSum
theSum = 0
aNumber = 1
while aNumber <= aBound :
theSum = theSum + aNumber
aNumber = aNumber + 1
return theSum
The body consists of all of the statements below the header with the same
indentation.
This type of flow is called a loop because the third step loops back around
to the top. Notice that if the condition is False the first time through the loop,
the statements inside the loop are never executed.
Warning 8.3.1 Though Python’s while is very close to the English “while”,
there is an important difference: In English “while X, do Y”, we usually assume
that immediately after X becomes false, we stop with Y. In Python there is
not an immediate stop: After the initial test, any following tests come only
after the execution of the whole body, even if the condition becomes false in
the middle of the loop body.
The body of the loop should change the value of one or more variables so
that eventually the condition becomes False and the loop terminates. Other-
wise the loop will repeat forever. This is called an infinite loop. An endless
source of amusement for computer scientists is the observation that the direc-
tions written on the back of the shampoo bottle (lather, rinse, repeat) create
an infinite loop.
In the case shown above, we can prove that the loop terminates because
we know that the value of aBound is finite, and we can see that the value of
aNumber increments each time through the loop, so eventually it will have to
exceed aBound. In other cases, it is not so easy to tell.
Note 8.3.2 Introduction of the while statement causes us to think about the
types of iteration we have seen. The for statement will always iterate through
a sequence of values like the list of names for the party or the list of numbers
created by range. Since we know that it will iterate once for each value in the
collection, it is often said that a for loop creates a definite iteration because
we definitely know how many times we are going to iterate. On the other
hand, the while statement is dependent on a condition that needs to evaluate
to False in order for the loop to terminate. Since we do not necessarily know
when this will happen, it creates what we call indefinite iteration. Indefinite
iteration simply means that we don’t know how many times we will repeat but
eventually the condition controlling the iteration will fail and the iteration will
stop. (Unless we have an infinite loop which is of course a problem.)
CHAPTER 8. MORE ABOUT ITERATION 148
What you will notice here is that the while loop is more work for you —
the programmer — than the equivalent for loop. When using a while loop
you have to control the loop variable yourself. You give it an initial value, test
for completion, and then make sure you change something in the body so that
the loop terminates.
So why have two kinds of loop if for looks easier? The next section, Sec-
tion 8.4 , shows an indefinite iteration where we need the extra power that we
get from the while loop.
Note 8.3.3 This workspace is provided for your convenience. You can use this
activecode window to try out anything you like.
Check your understanding
Checkpoint 8.3.4 True or False: You can rewrite any for-loop as a while-loop.
A. True
B. False
Checkpoint 8.3.5 The following code contains an infinite loop. Which is the
best explanation for why the loop does not terminate?
n = 10
answer = 1
while n > 0:
answer = answer + n
n = n + 1
print ( answer )
A. 4 7
B. 5 7
C. 7 15
CHAPTER 8. MORE ABOUT ITERATION 149
Notice that we cannot predict how many times the turtle will need to flip
the coin before it wanders out of the screen, so we can’t use a for loop in this
case. In fact, although very unlikely, this program might never end, that is
why we call this indefinite iteration.
So based on the problem description above, we can outline a program as
follows:
create a window and a turtle
def isInScreen (w , t ):
if random . random () > 0.1:
return True
else :
return False
t = turtle . Turtle ()
wn = turtle . Screen ()
CHAPTER 8. MORE ABOUT ITERATION 150
t . forward (50)
wn . exitonclick ()
Now we have a working program that draws a random walk of our turtle
that has a 90% chance of staying on the screen. We are in a good position,
because a large part of our program is working and we can focus on the next
bit of work – deciding whether the turtle is inside the screen boundaries or not.
We can find out the width and the height of the screen using the window_width
and window_height methods of the screen object. However, remember that the
turtle starts at position 0,0 in the middle of the screen. So we never want the
turtle to go farther right than width/2 or farther left than negative width/2.
We never want the turtle to go further up than height/2 or further down than
negative height/2. Once we know what the boundaries are we can use some
conditionals to check the turtle position against the boundaries and return
False if the turtle is outside or True if the turtle is inside.
Once we have computed our boundaries we can get the current position of
the turtle and then use conditionals to decide. Here is one implementation:
def isInScreen ( wn , t ):
leftBound = -( wn . window_width () / 2)
rightBound = wn . window_width () / 2
topBound = wn . window_height () / 2
bottomBound = -( wn . window_height () / 2)
turtleX = t . xcor ()
turtleY = t . ycor ()
stillIn = True
if turtleX > rightBound or turtleX < leftBound :
stillIn = False
if turtleY > topBound or turtleY < bottomBound :
stillIn = False
return stillIn
There are lots of ways that the conditional could be written. In this case we
have given stillIn the default value of True and use two if statements to pos-
sibly set the value to False. You could rewrite this to use nested conditionals
or elif statements and set stillIn to True in an else clause.
Here is the full version of our random walk program.
import random
import turtle
def isInScreen (w ,t ):
leftBound = - w . window_width () / 2
rightBound = w . window_width () / 2
topBound = w . window_height () / 2
bottomBound = -w . window_height () / 2
CHAPTER 8. MORE ABOUT ITERATION 151
turtleX = t . xcor ()
turtleY = t . ycor ()
stillIn = True
if turtleX > rightBound or turtleX < leftBound :
stillIn = False
if turtleY > topBound or turtleY < bottomBound :
stillIn = False
return stillIn
t = turtle . Turtle ()
wn = turtle . Screen ()
t . forward (50)
wn . exitonclick ()
We could have written this program without using a boolean function. You
might want to try to rewrite it using a complex condition on the while state-
ment. However, using a boolean function makes the program much more read-
able and easier to understand. It also gives us another tool to use if this was
a larger program and we needed to have a check for whether the turtle was
still in the screen in another part of the program. Another advantage is that
if you ever need to write a similar program, you can reuse this function with
confidence the next time you need it. Breaking up this program into a couple
of parts is another example of functional decomposition.
Check your understanding
Checkpoint 8.4.1 Which type of loop can be used to perform the following
iteration: You choose a positive integer at random and then print the numbers
from 1 up to and including the selected integer.
A. a for-loop or a while-loop
B. only a for-loop
C. only a while-loop
Checkpoint 8.4.2 In the random walk program in this section, what does the
isInScreen function do?
A. Returns True if the turtle is still on the screen and False if the turtle is
no longer on the screen.
B. Uses a while loop to move the turtle randomly until it goes off the screen.
C. Turns the turtle right or left at random and moves the turtle forward 50.
D. Calculates and returns the position of the turtle in the window.
CHAPTER 8. MORE ABOUT ITERATION 152
seq3np1 (3)
The condition for this loop is n != 1. The loop will continue running until
n == 1 (which will make the condition false).
Each time through the loop, the program prints the value of n and then
checks whether it is even or odd using the remainder operator. If it is even,
the value of n is divided by 2 using integer division. If it is odd, the value is
replaced by n * 3 + 1. Try some other examples.
Since n sometimes increases and sometimes decreases, there is no obvious
proof that n will ever reach 1, or that the program terminates. For some
particular values of n, we can prove termination. For example, if the starting
value is a power of two, then the value of n will be even each time through the
loop until it reaches 1.
You might like to have some fun and see if you can find a small starting
number that needs more than a hundred steps before it terminates.
Note 8.5.1 Lab.
• Experimenting with the 3n+1 Sequence1 In this guided lab exercise we
will try to learn more about this sequence.
Particular values aside, the interesting question is whether we can prove
that this sequence terminates for all positive values of n. So far, no one has
been able to prove it or disprove it!
Think carefully about what would be needed for a proof or disproof of
the hypothesis “All positive integers will eventually converge to 1”. With fast
computers we have been able to test every integer up to very large values, and
so far, they all eventually end up at 1. But this doesn’t mean that there might
not be some as-yet untested number which does not reduce to 1.
You’ll notice that if you don’t stop when you reach one, the sequence gets
into its own loop: 1, 4, 2, 1, 4, 2, 1, 4, and so on. One possibility is that there
might be other cycles that we just haven’t found.
1 ../Labs/sequencelab.html
CHAPTER 8. MORE ABOUT ITERATION 153
Note 8.5.2 Choosing between for and while. Use a for loop if you
know the maximum number of times that you’ll need to execute the body. For
example, if you’re traversing a list of elements, or can formulate a suitable call
to range, then choose the for loop.
So any problem like “iterate this weather model run for 1000 cycles”, or
“search this list of words”, “check all integers up to 10000 to see which are
prime” suggest that a for loop is best.
By contrast, if you are required to repeat some computation until some
condition is met, as we did in this 3n + 1 problem, you’ll need a while loop.
As we noted before, the first case is called definite iteration — we have
some definite bounds for what is needed. The latter case is called indefinite
iteration — we are not sure how many iterations we’ll need — we cannot even
establish an upper bound!
Check your understanding
Checkpoint 8.5.3 Consider the code that prints the 3n+1 sequence in Active-
Code box 6. Will the while loop in this code always terminate for any positive
integer value of n?
A. Yes.
B. No.
C. No one knows.
Note 8.6.1 Modify the program …. All three of the calls to newtonSqrt
in the previous example produce the correct square root for the first parameter.
However, were 10 iterations required to get the correct answer? Experiment
CHAPTER 8. MORE ABOUT ITERATION 154
with different values for the number of repetitions (the 10 on lines 8, 9, and 10).
For each of these calls, find the smallest value for the number of repetitions
that will produce the correct result.
Repeating more than the required number of times is a waste of computing
resources. So definite iteration is not a good solution to this problem.
In general, Newton’s algorithm will eventually reach a point where the new
approximation is no better than the previous. At that point, we could simply
stop. In other words, by repeatedly applying this formula until the better
approximation gets close enough to the previous one, we can write a function
for computing the square root that uses the number of iterations necessary and
no more.
This implementation, shown in codelens, uses a while condition to execute
until the approximation is no longer changing. Each time through the loop
we compute a “better” approximation using the formula described earlier. As
long as the “better” is different, we try again. Step through the program and
watch the approximations get closer and closer.
def newtonSqrt ( n ):
approx = 0.5 * n
better = 0.5 * ( approx + n / approx )
while better != approx :
approx = better
better = 0.5 * ( approx + n/ approx )
return approx
Note 8.6.2 The while statement shown above uses comparison of two floating
point numbers in the condition. Since floating point numbers are themselves
approximation of real numbers in mathematics, it is often better to compare
for a result that is within some small threshold of the value you are looking
for.
You may have studied this sequence in a math class and learned that the
sum approaches but never reaches 2.0. That is true in theory. However, when
we implement this summation in a program, we see something different.
def sumTo () :
""" Return the sum of reciprocals of powers of 2 """
theSum = 0
aNumber = 0
CHAPTER 8. MORE ABOUT ITERATION 155
return theSum
print ( sumTo () )
Note 8.7.1 Modify the program …. If the sum never reaches 2.0, the loop
would never terminate. But the loop does stop! How many repetitions did it
make before it stopped?
On line 9 (not indented), print the value of aNumber and you will see.
But why did it reach 2.0? Are those math teachers wrong?
• If you are selling tickets to an event, you don’t know in advance how
many tickets you will sell. You keep selling tickets as long as people
come to the door and there’s room in the hall.
• When the baggage crew unloads a plane, they don’t know in advance
how many suitcases there are. They just keep unloading while there are
bags left in the cargo hold. (Why your suitcase is always the last one is
an entirely different problem.)
• When you go through the checkout line at the grocery, the clerks don’t
know in advance how many items there are. They just keep ringing up
items as long as there are more on the conveyor belt.
Let’s implement the last of these in Python, by asking the user for prices
and keeping a running total and count of items. When the last item is entered,
the program gives the grand total, number of items, and average price. We’ll
need these variables:
The pseudocode (code written half in English, half in Python) for the body
of the loop looks something like this:
while moreItems
ask for price
add price to total
add one to count
This pseudocode has no option to set moreItems to False, so it would run
forever. In a grocery store, there’s a little plastic bar that you put after your
last item to separate your groceries from those of the person behind you; that’s
how the clerk knows you have no more items. We don’t have a “little plastic
bar” data type in Python, so we’ll do the next best thing: we will use a price
CHAPTER 8. MORE ABOUT ITERATION 156
checkout ()
There are still a few problems with this program.
• If you enter a negative number, it will be added to the total and count.
Modify the code so that negative numbers give an error message instead
(but don’t end the loop) Hint: elif is your friend.
• If you enter zero the first time you are asked for a price, the loop will end,
and the program will try to divide by zero. Use an if/else statement
outside the loop to avoid the division by zero and tell the user that you
can’t compute an average without data.
• This program doesn’t display the amounts to two decimal places. In the
next chapter you will see the Section 9.5 that will do the trick.
A. True
B. False
D. You must use tabs for creating tables. You cannot use spaces.
CHAPTER 8. MORE ABOUT ITERATION 159
Table 8.11.1
Color Red Green Blue
Red 255 0 0
Green 0 255 0
Blue 0 0 255
White 255 255 255
Black 0 0 0
Yellow 255 255 0
Magenta 255 0 255
In order to manipulate an image, we need to be able to access individual pixels.
This capability is provided by a module called image, provided in ActiveCode.
See Section 8.12 for ways to deal with images in standard Python. The image
module defines two classes: Image and Pixel.
Each Pixel object has three attributes: the red intensity, the green intensity,
and the blue intensity. A pixel provides three methods that allow us to ask
for the intensity values. They are called getRed, getGreen, and getBlue. In
addition, we can ask a pixel to change an intensity value using its setRed,
setGreen, and setBlue methods.
Table 8.11.2
Method Name Example Explanation
Pixel(r,g,b) Pixel(20,100,50) Create a new pixel with 20 red, 100 green, and 50 blue.
getRed() r = p.getRed() Return the red component intensity.
getGreen() r = p.getGreen() Return the green component intensity.
getBlue() r = p.getBlue() Return the blue component intensity.
setRed() p.setRed(100) Set the red component intensity to 100.
setGreen() p.setGreen(45) Set the green component intensity to 45.
setBlue() p.setBlue(156) Set the blue component intensity to 156.
In the example below, we first create a pixel with 45 units of red, 76 units of
green, and 200 units of blue. We then print the current amount of red, change
the amount of red, and finally, set the amount of blue to be the same as the
current amount of green.
import image
A. Dark red
B. Light red
C. Dark green
D. Light green
CHAPTER 8. MORE ABOUT ITERATION 161
import image
img = image . Image ( " luther . jpg " )
When you run the program you can see that the image has a width of 400
pixels and a height of 244 pixels. Also, the pixel at column 45, row 55, has
RGB values of 165, 161, and 158. Try a few other pixel locations by changing
the getPixel arguments and rerunning the program.
Check your understanding
Checkpoint 8.11.5 Using the previous ActiveCode example, select the answer
that is closest to the RGB values of the pixel at row 100, column 30? The values
may be off by one or two due to differences in browsers.
a.
0 0
0 1
1 0
1 1
1 http://en.wikipedia.org/wiki/Sepia_tone#Sepia_toning
CHAPTER 8. MORE ABOUT ITERATION 165
2 0
2 1
b.
0 0
1 0
2 0
0 1
1 1
2 1
c.
0 0
0 1
0 2
1 0
1 1
1 2
d.
0 1
0 1
0 1
A. Output a
B. Output b
C. Output c
D. Output d
Checkpoint 8.11.8 What would the image produced from ActiveCode box
16 look like if you replaced the lines:
newred = 255 - p . getRed ()
newgreen = 255 - p . getGreen ()
newblue = 255 - p. getBlue ()
with the lines:
newred = p . getRed ()
newgreen = 0
newblue = 0
D. It would look the same as the negative image in the example code
CHAPTER 8. MORE ABOUT ITERATION 166
Note 8.12.1 Note. One important caveat about using cImage.py is that it
will only work with GIF files unless you also install the Python Image Library.
Don’t worry if you pip install cImage it will automatically take care of this
for you. Otherwise, the easiest version to install is called Pillow. If you have
the pip command installed on your computer this is really easy to install, with
pip install pillow otherwise you will need to follow the instructions on the
Python Package Index2 page. With Pillow installed you will be able to use
almost any kind of image that you download.
Note 8.12.2 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
8.13 Glossary
Glossary
algorithm.A step-by-step process for solving a category of problems.
body.The indented statements after a heading ending in a colon, for instance
after a for-loop heading.
counter.A variable used to count something, usually initialized to zero and
incremented in the body of a loop.
cursor.An invisible marker that keeps track of where the next character will
be printed.
definite iteration.A loop where we have an upper bound on the number of
times the body will be executed. Definite iteration is usually best coded as a
for loop.
escape sequence.An escape character, \, followed by one or more printable
characters used to designate a nonprintable character.
generalize.To replace something unnecessarily specific (like a constant value)
with something appropriately general (like a variable or parameter). Gener-
alization makes code more versatile, more likely to be reused, and sometimes
even easier to write.
infinite loop.A loop in which the terminating condition is never satisfied.
indefinite iteration.A loop where we just need to keep going until some
condition is met. A while statement is used for this case.
iteration.Repeated execution of a set of programming statements.
loop.A statement or group of statements that execute repeatedly until a ter-
minating condition is satisfied.
1 https://github.com/bnmnetp/cImage
2 https://pypi.python.org/pypi/Pillow/
CHAPTER 8. MORE ABOUT ITERATION 167
8.14 Exercises
1. Add a print statement to Newton’s sqrt function that prints out better
each time it is calculated. Call your modified function with 25 as an argu-
ment and record the results. def newtonSqrt ( n ):
2. Write a function print_triangular_numbers(n) that prints out the first
n triangular numbers. A call to print_triangular_numbers(5) would
produce the following output:
1 1
2 3
3 6
4 10
5 15
(hint: use a web search to find out what a triangular number is.)
Write a function `` print_triangular_numbers ( n ) `` that
prints out the first
n triangular numbers . A call to
`` print_triangular_numbers (5) `` would
produce the following output ::
1 1
2 3
3 6
4 10
5 15
def is_prime ( n ):
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
4. Modify the walking turtle program so that rather than a 90 degree left or
right turn the angle of the turn is determined randomly at each step.
5. Modify the turtle walk program so that you have two turtles each with
a random starting location. Keep the turtles moving until one of them
leaves the screen.
6. Modify the previous turtle walk program so that the turtle turns around
when it hits the wall or when one turtle collides with another turtle (when
the positions of the two turtles are closer than some small number).
7. Write a function to remove all the red from an image.<img src=”../_static/
LutherBellPic.jpg” id=”luther.jpg”> <h4 style=”text-align: left;”>For
this and the following exercises, use the luther.jpg photo.</h4>
8. Write a function to convert the image to grayscale.
9. Write a function to convert an image to black and white.
10. Sepia Tone images are those brownish colored images that may remind
you of times past. The formula for creating a sepia tone is as follows:
14. When you scan in images using a scanner they may have lots of noise due
to dust particles on the image itself or the scanner itself, or the images
may even be damaged. One way of eliminating this noise is to replace
each pixel by the median value of the pixels surrounding it.
15. Research the Sobel edge detection algorithm and implement it.
Chapter 9
Strings
170
CHAPTER 9. STRINGS 171
Interestingly, the + operator does work with strings, but for strings, the
+ operator represents concatenation, not addition. Concatenation means
joining the two operands by linking them end-to-end. For example:
fruit = " banana "
bakedGood = "␣ nut ␣ bread "
print ( fruit + bakedGood )
The output of this program is banana nut bread. The space before the
word nut is part of the string and is necessary to produce the space between
the concatenated strings. Take out the space and run it again.
The * operator also works on strings. It performs repetition. For example,
'Fun'*3 is 'FunFunFun'. One of the operands has to be a string and the other
has to be an integer.
print ( " Go " * 6)
A. python rocks
B. python
C. pythonrocks
A. python!!!
B. python!python!python!
C. pythonpythonpython!
D. Error, you cannot perform concatenation and repetition at the same time.
CHAPTER 9. STRINGS 172
It is also the case that the positions are named from right to left using
negative numbers where -1 is the rightmost index and so on. Note that the
character at index 6 (or -8) is the blank character.
school = " Luther ␣ College "
m = school [2]
print ( m )
A. t
B. h
C. c
D. Error, you cannot use the [ ] operator with a string.
Checkpoint 9.4.2 What is printed by the following statements?
s = " python ␣ rocks "
print ( s [2] + s [ -5])
A. tr
B. ps
CHAPTER 9. STRINGS 173
C. nn
D. Error, you cannot use the [ ] operator with the + operator.
tt = ss . lower ()
print ( tt )
In this example, upper is a method that can be invoked on any string object
to create a new string in which all the characters are in uppercase. lower works
in a similar fashion changing all characters in the string to lowercase. (The
original string ss remains unchanged. A new string tt is created.)
In addition to upper and lower, the following table provides a summary of
some other useful string methods. There are a few activecode examples that
follow so that you can try them out.
Table 9.5.1
Method Parameters Description
upper none Returns a string in all uppercase
lower none Returns a string in all lowercase
capitalize none Returns a string with first character capitalized, the rest lower
strip none Returns a string with the leading and trailing whitespace removed
lstrip none Returns a string with the leading whitespace removed
rstrip none Returns a string with the trailing whitespace removed
count item Returns the number of occurrences of item
replace old, new Replaces all occurrences of old substring with new
center width Returns a string centered in a field of width spaces
ljust width Returns a string left justified in a field of width spaces
rjust width Returns a string right justified in a field of width spaces
find item Returns the leftmost index where the substring item is found, or -1 if not found
rfind item Returns the rightmost index where the substring item is found, or -1 if not foun
index item Like find except causes a runtime error if item is not found
rindex item Like rfind except causes a runtime error if item is not found
format substitutions Involved! See Subsection 9.5.2, below
You should experiment with these methods so that you understand what
they do. Note once again that the methods that return strings do not change
the original. You can also consult the Python documentation for strings1 .
1 https://docs.python.org/3/library/stdtypes.html#string-methods
CHAPTER 9. STRINGS 174
A. 0
B. 2
C. 3
Checkpoint 9.5.3 What is printed by the following statements?
s = " python ␣ rocks "
print ( s [1] * s . index ( " n " ))
A. yyyyy
B. 55555
C. n
D. Error, you cannot combine all those things together.
and you can fill in the name of the person greeted, and combine given text
with a chosen insertion. We use this as an analogy: Python has a similar
construction, better called fill-in-the-braces. The string method format, makes
substitutions into places in a string enclosed in braces. Run this code:
person = input ( ' Your ␣ name :␣ ' )
greeting = ' Hello ␣ {}! ' . format ( person )
print ( greeting )
There are several new ideas here!
The string for the format method has a special form, with braces embedded.
Such a string is called a format string. Places where braces are embedded are
replaced by the value of an expression taken from the parameter list for the
format method. There are many variations on the syntax between the braces.
In this case we use the syntax where the first (and only) location in the string
with braces has a substitution made from the first (and only) parameter.
In the code above, this new string is assigned to the identifier greeting,
and then the string is printed.
The identifier greeting was introduced to break the operations into a
clearer sequence of steps. However, since the value of greeting is only ref-
erenced once, it can be eliminated with the more concise version:
person = input ( ' Enter ␣ your ␣ name :␣ ' )
print ( ' Hello ␣ {}! ' . format ( person ))
There can be multiple substitutions, with data of any type. Next we use
floats. Try original price $2.50 with a 7% discount:
origPrice = float ( input ( ' Enter ␣ the ␣ original ␣ price :␣$ ' ))
discount = float ( input ( ' Enter ␣ discount ␣ percentage :␣ ' ))
newPrice = (1 - discount /100) * origPrice
calculation = ' $ {} ␣ discounted ␣ by ␣ {}% ␣ is ␣
$ {}. ' . format ( origPrice , discount , newPrice )
print ( calculation )
The parameters are inserted into the braces in order.
If you used the data suggested, this result is not satisfying. Prices should
appear with exactly two places beyond the decimal point, but that is not the
default way to display floats.
Format strings can give further information inside the braces showing how
to specially format data. In particular floats can be shown with a specific
number of decimal places. For two decimal places, put :.2f inside the braces
for the monetary values:
origPrice = float ( input ( ' Enter ␣ the ␣ original ␣ price :␣$ ' ))
discount = float ( input ( ' Enter ␣ discount ␣ percentage :␣ ' ))
newPrice = (1 - discount /100) * origPrice
calculation = ' $ {:.2 f }␣ discounted ␣ by ␣ {}% ␣ is ␣
$ {:.2 f }. ' . format ( origPrice , discount , newPrice )
print ( calculation )
The 2 in the format modifier can be replaced by another integer to round
to that specified number of digits.
This kind of format string depends directly on the order of the parameters
to the format method. There are other approaches that we will skip here,
explicitly numbering substitutions and taking substitutions from a dictionary.
A technical point: Since braces have special meaning in a format string,
there must be a special rule if you want braces to actually be included in the
final formatted string. The rule is to double the braces: { { and }}. For
CHAPTER 9. STRINGS 176
example mathematical set notation uses braces. The initial and final doubled
braces in the format string below generate literal braces in the formatted string:
a = 5
b = 9
setStr = 'The set is {{ {},{} }}.'.format(a, b)
print(setStr)
Unfortunately, at the time of this writing, the ActiveCode format implemen-
tation has a bug, printing doubled braces, but standard Python prints {5,
9}.
You can have multiple placeholders indexing the same argument, or perhaps
even have extra arguments that are not referenced at all:
letter = """
Dear {0} {2}.
{0} , I have an interesting money - making proposition for
you !
If you deposit $10 million into my bank account , I can
double your money ...
"""
print ( letter . format ( " Paris " , " Whitney " , " Hilton " ))
print ( letter . format ( " Bill " , " Henry " , " Gates " ))
9.6 Length
The len function, when applied to a string, returns the number of characters
in a string.
fruit = " Banana "
print ( len ( fruit ))
To get the last letter of a string, you might be tempted to try something
like this:
CHAPTER 9. STRINGS 177
A. 11
B. 12
Checkpoint 9.6.2 What is printed by the following statements?
s = " python ␣ rocks "
print ( s [ len ( s ) -5])
A. o
B. r
C. s
D. Error, len(s) is 12 and there is no index 12.
Checkpoint 9.6.3 What is printed by the following statements?
s = " python ␣ rocks "
print ( s [ -3])
A. c
B. k
C. s
D. Error, negative indices are illegal.
A. python
B. rocks
C. hon r
D. Error, you cannot have two numbers inside the [ ].
Checkpoint 9.7.2 What is printed by the following statements?
s = " python ␣ rocks "
print ( s [7:11] * 3)
A. rockrockrock
else :
print ( " Yes ,␣ we ␣ have ␣ NO ␣ bananas ! " )
Other comparison operations are useful for putting words in lexicographical
order1 . This is similar to the alphabetical order you would use with a dictionary,
except that all the uppercase letters come before all the lowercase letters.
word = " zebra "
print ( " The ␣ character ␣ for ␣ 32 ␣ is " , chr (32) , " !!! " )
print ( ord ( "␣" ))
1 http://en.wikipedia.org/wiki/Lexicographic_order
CHAPTER 9. STRINGS 180
One thing to note in the last two examples is the fact that the space char-
acter has an ordinal value (32). Even though you don’t see it, it is an actual
character. We sometimes call it a nonprinting character.
Check your understanding
Checkpoint 9.8.1 Evaluate the following comparison:
" Dog " < " Doghouse "
A. True
B. False
Checkpoint 9.8.2 Evaluate the following comparison:
" dog " < " Dog "
A. True
B. False
C. They are the same word
Checkpoint 9.8.3 Evaluate the following comparison:
" dog " < " Doghouse "
A. True
B. False
A. Ball
B. Call
C. Error
A. 10
B. 11
C. 12
D. Error, the for statement needs to use the range function.
Checkpoint 9.10.2 How many times is the word HELLO printed by the
following statements?
s = " python ␣ rocks "
for ch in s [3:8]:
print ( " HELLO ")
A. 4
CHAPTER 9. STRINGS 182
B. 5
C. 6
D. Error, the for statement cannot use slice.
A. 0
B. 1
C. 2
CHAPTER 9. STRINGS 183
position = 0
while position < len ( fruit ):
print ( fruit [ position ])
position = position + 1
The loop condition is position < len(fruit), so when position is equal
to the length of the string, the condition is false, and the body of the loop is not
executed. The last character accessed is the one with the index len(fruit)-1,
which is the last character in the string.
Here is the same example in codelens so that you can trace the values of
the variables.
fruit = " apple "
position = 0
while position < len ( fruit ):
print ( fruit [ position ])
position = position + 1
Check your understanding
Checkpoint 9.12.1 How many times is the letter o printed by the following
statements?
s = " python ␣ rocks "
idx = 1
while idx < len ( s):
print ( s [ idx ])
idx = idx + 2
A. 0
B. 1
C. 2
Note 9.12.2 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
Note that a string is a substring of itself, and the empty string is a substring
of any other string. (Also note that computer scientists like to think about
these edge cases quite carefully!)
print ( ' a ' in ' a ' )
print ( ' apple ' in ' apple ' )
print ( ' ' in ' a ' )
print ( ' ' in ' apple ' )
The not in operator returns the logical opposite result of in.
print ( ' x ' not in ' apple ' )
A. Ball
B. BALL
C. LLAB
Note 9.14.2 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
Each rule set contains an axiom which represents the starting point in the
transformations that will follow. The rules are of the form:
left hand side -> right hand side
where the left hand side is a single symbol and the right hand side is a sequence
of symbols. You can think of both sides as being simple strings. The way
the rules are used is to replace occurrences of the left hand side with the
corresponding right hand side.
Now let’s look at these simple rules in action, starting with the string A:
A
B Apply Rule 1 (A is replaced by B)
AB Apply Rule 2 (B is replaced by AB)
BAB Apply Rule 1 to A then Rule 2 to B
ABBAB Apply Rule 2 to B, Rule 1 to A, and Rule 2 to B
Notice that each line represents a new transformation for entire string. Each
character that matches a left-hand side of a rule in the original has been re-
placed by the corresponding right-hand side of that same rule. After doing the
replacement for each character in the original, we have one transformation.
So how would we encode these rules in a Python program? There are a
couple of very important things to note here:
Let’s look at a simple Python program that implements the example set of
rules described above.
def applyRules ( lhch ):
rhstr = " "
if lhch == ' A ' :
rhstr = ' B ' # Rule 1
elif lhch == ' B ' :
rhstr = ' AB ' # Rule 2
else :
rhstr = lhch # no rules apply so keep the
character
return rhstr
return newstr
return endString
return newstr
Pretty simple so far. As you can imagine this string will get pretty long
with a few applications of the rules. You might try to expand the string a
couple of times on your own just to see.
The last step is to take the final string and turn it into a picture. Let’s
assume that we are always going to go forward or backward by 5 units. In
addition we will also assume that when the turtle turns left or right we’ll
turn by 60 degrees. Now look at the string F-F++F-F. You might try to use
the explanation above to show the resulting picture that this simple string
CHAPTER 9. STRINGS 188
represents. At this point its not a very exciting drawing, but once we expand
it a few times it will get a lot more interesting.
To create a Python function to draw a string we will write a function called
drawLsystem The function will take four parameters:
• A turtle to do the drawing
• An expanded string that contains the results of expanding the rules
above.
• An angle to turn
• A distance to move forward or backward
def drawLsystem ( aTurtle , instructions , angle , distance ):
for cmd in instructions :
if cmd == ' F ' :
aTurtle . forward ( distance )
elif cmd == ' B ' :
aTurtle . backward ( distance )
elif cmd == ' + ' :
aTurtle . right ( angle )
elif cmd == ' - ' :
aTurtle . left ( angle )
Here is the complete program in activecode. The main function first creates
the L-system string and then it creates a turtle and passes it and the string to
the drawing function.
import turtle
return endString
return newstr
def applyRules ( ch ):
newstr = " "
if ch == ' F ' :
newstr = ' F - F ++ F -F ' # Rule 1
else :
newstr = ch # no rules apply so keep the
character
return newstr
def main () :
inst = createLSystem (4 , " F " ) # create the string
print ( inst )
t = turtle . Turtle () # create the turtle
wn = turtle . Screen ()
t . up ()
t . back (200)
t . down ()
t . speed (9)
drawLsystem (t , inst , 60 , 5) # draw the picture
# angle 60 , segment
length 5
wn . exitonclick ()
main ()
Feel free to try some different angles and segment lengths to see how the
drawing changes.
ix = start
found = False
while ix < len ( astring ) and not found :
if astring [ ix ] == achar :
found = True
else :
ix = ix + 1
if found :
return ix
else :
return -1
found = False
while ix < end and not found :
if astring [ ix ] == achar :
found = True
else :
ix = ix + 1
CHAPTER 9. STRINGS 192
if found :
return ix
else :
return -1
For more information consult the string module documentaiton (see Global
Module Index1 ).
Note 9.19.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
9.20 Summary
This chapter introduced a lot of new ideas. The following summary may prove
helpful in remembering what you learned.
Glossary
indexing ([]).Access a single character in a string using its position (starting
from 0). Example: 'This'[2] evaluates to 'i'.
1 http://docs.python.org/py3k/py-modindex.html
CHAPTER 9. STRINGS 193
in and not in operator (in, not in).The in operator tests whether one string
is contained inside another string. Examples: 'heck' in "I'll be checking
for you." evaluates to True. 'cheese' in "I'll be checking for you." eval-
uates to False.
9.21 Glossary
Glossary
collection data type.A data type in which the values are made up of com-
ponents, or elements, that are themselves values.
default value.The value given to an optional parameter if no argument for it
is provided in the function call.
dot notation.Use of the dot operator, ., to access functions inside a module,
or to access methods and attributes of an object.
immutable data type.A data type whose values cannot be changed. Mod-
ifying functions create a totally new object that does not change the original
one.
index.A variable or value used to select a member of an ordered collection,
such as a character from a string, or an element from a list.
optional parameter.A parameter written in a function header with an as-
signment to a default value which it will receive if no corresponding argument
is given for it in the function call.
slice.A part of a string (substring) specified by a range of indices. More gen-
erally, a subsequence of any sequence type in Python can be created using the
slice operator (sequence[start:stop]).
traverse.To iterate through the elements of a collection, performing a similar
operation on each.
whitespace.Any of the characters that move the cursor without printing visi-
ble characters. The constant string.whitespace contains all the white-space
characters.
1 http://en.wikipedia.org/wiki/Lexicographic_order
CHAPTER 9. STRINGS 194
9.22 Exercises
1.
2
1 2. In Robert McCloskey’s book Make Way for Ducklings, the names of
the ducklings are Jack, Kack, Lack, Mack, Nack, Ouack, Pack, and
Quack. This loop tries to output these names in order.
prefixes = " JKLMNOPQ "
suffix = " ack "
for p in prefixes :
print ( p + suffix )
Of course, that’s not quite right because Ouack and Quack are mis-
spelled. Can you fix it?
prefixes = " JKLMNOPQ "
suffix = " ack "
for p in prefixes :
print ( p + suffix )
====
o = self . getOutput ()
code = self . getEditorText ()
self . assertIn (" if " , code , " Needs ␣a␣
conditional . " )
self . assertIn (" for " , code , " Needs ␣a␣ loop . " )
self . assertIn (" Jack " , o , " J␣+␣ ack ␣=␣ Jack " )
self . assertIn (" Kack " , o , " K␣+␣ ack ␣=␣ Kack " )
self . assertIn (" Lack " , o , " L␣+␣ ack ␣=␣ Lack " )
self . assertIn (" Mack " , o , " M␣+␣ ack ␣=␣ Mack " )
self . assertIn (" Nack " , o , " N␣+␣ ack ␣=␣ Nack " )
self . assertIn (" Ouack " , o , " Don ' t␣ forget ␣ the ␣
misspellings .␣ Quack ␣ is ␣ required . ")
self . assertIn (" Pack " , o , " P␣+␣ ack ␣=␣ Pack " )
self . assertIn (" Quack " , o , " Don ' t␣ forget ␣ the ␣
misspellings .␣ Quack ␣ is ␣ required . ")
self . assertNotIn ( " Oack " , o , " Account ␣ for ␣
the ␣ misspellings .␣ Qack ␣ should ␣ not ␣ be ␣ in ␣
output . ")
self . assertNotIn ( " Qack " , o , " Account ␣ for ␣
the ␣ misspellings .␣ Qack ␣ should ␣ not ␣ be ␣ in ␣
output . ")
myTests () . main ()
3. Assign to a variable in your program a triple-quoted string that
contains your favorite paragraph of text - perhaps a poem, a speech,
instructions to bake a cake, some inspirational verses, etc.
CHAPTER 9. STRINGS 195
def count ( p ):
# your code here
====
====
myTests () . main ()
6
6. Write a function that reverses its string argument.
CHAPTER 9. STRINGS 196
====
myTests () . main ()
7
7.
8
8. Write a function that removes all occurrences of a given letter from
a string.
def remove_letter ( theLetter , theString ):
# your code here
====
myTests () . main ()
9
9. Write a function that recognizes palindromes. (Hint: use your
reverse function to make this easy!).
CHAPTER 9. STRINGS 197
====
myTests () . main ()
====
myTests () . main ()
11
10. Write a function that removes the first occurrence of a string from
another string.
def remove ( substr , theStr ):
# your code here
====
myTests () . main ()
12
11. Write a function that removes all occurrences of a string from an-
other string.
CHAPTER 9. STRINGS 199
====
myTests () . main ()
12. Here is another interesting L-System called a Hilbert curve. Use 90
degrees:
13 L
L -> +RF-LFL-FR+
R -> -LF+RFR+FL-
13. Here is a dragon curve. Use 90 degrees.:
14 FX
X -> X+YF+
Y -> -FX-Y
14. Here is something called an arrowhead curve. Use 60 degrees.:
15 YF
X -> YF+XF+Y
Y -> XF-YF-X
15. Try the Peano-Gosper curve. Use 60 degrees.:
16 FX
X -> X+YF++YF-FX--FXFX-YF+
Y -> -FX+YFYF++YF+FX--FX-Y
16.
17 The Sierpinski Triangle. Use 60 degrees.:
FXF--FF--FF
F -> FF
X -> --FXF++FXF++FXF--
18
17. Write a function that implements a substitution cipher. In a sub-
stitution cipher one letter is substituted for another to garble the
message. For example A -> Q, B -> T, C -> G etc. your function
CHAPTER 9. STRINGS 200
should take two parameters, the message you want to encrypt, and a
string that represents the mapping of the 26 letters in the alphabet.
Your function should return a string that is the encrypted version
of the message.
19
18. Write a function that decrypts the message from the previous exer-
cise. It should also take two parameters. The encrypted message,
and the mixed up alphabet. The function should return a string
that is the same as the original unencrypted message.
20
19. Write a function called remove_dups that takes a string and creates
a new string by only adding those characters that are not already
present. In other words, there will never be a duplicate letter added
to the new string.
def remove_dups ( astring ):
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
21
20. Write a function called rot13 that uses the Caesar cipher to encrypt
a message. The Caesar cipher works like a substitution cipher but
each character is replaced by the character 13 characters to ‘its right’
in the alphabet. So for example the letter a becomes the letter n. If
a letter is past the middle of the alphabet then the counting wraps
around to the letter a again, so n becomes a, o becomes b and so on.
Hint: Whenever you talk about things wrapping around its a good
idea to think of modulo arithmetic.
def rot13 ( mess ):
# Your code here
21. Modify this code so it prints each subtotal, the total cost, and aver-
age price to exactly two decimal places.
def checkout () :
total = 0
count = 0
moreItems = True
while moreItems :
price = float ( input ( ' Enter ␣ price ␣ of ␣ item ␣ (0 ␣
when ␣ done ) :␣ ' ))
if price != 0:
count = count + 1
total = total + price
print ( ' Subtotal :␣$ ' , total )
else :
moreItems = False
average = total / count
print ( ' Total ␣ items : ' , count )
print ( ' Total ␣$ ' , total )
print ( ' Average ␣ price ␣ per ␣ item :␣$ ' , average )
checkout ()
Chapter 10
Lists
10.1 Lists
A list is a sequential collection of Python data values, where each value is
identified by an index. The values that make up a list are called its elements.
Lists are similar to strings, which are ordered collections of characters, except
that the elements of a list can have any type and for any one list, the items
can be of different types.
print ( numbers )
print ( mixedlist )
newlist = [ numbers , vocabulary ]
print ( newlist )
Check your understanding
Checkpoint 10.2.1 A list can contain only integer items.
A. False
202
CHAPTER 10. LISTS 203
B. True
A. 4
B. 5
Checkpoint 10.3.2 What is printed by the following statements?
alist = [3 , 67 , " cat " , [56 , 57 , " dog " ], [ ] , 3.14 , False ]
print ( len ( alist ))
A. 7
B. 8
A. [ ]
B. 3.14
C. False
CHAPTER 10. LISTS 204
B. 2
C. CAT
Checkpoint 10.4.3 What is printed by the following statements?
alist = [3 , 67 , " cat " , [56 , 57 , " dog " ], [ ] , 3.14 , False ]
print ( alist [2][0])
A. 56
B. c
C. cat
D. Error, you cannot have two index values unless you are using slicing.
A. True
B. False
Checkpoint 10.5.2 What is printed by the following statements?
alist = [3 , 67 , " cat " , [56 , 57 , " dog " ], [ ] , 3.14 , False ]
print (57 in alist )
A. True
B. False
print ([0] * 4)
print ([1 , 2, [ " hello " , " goodbye " ]] * 2)
It is important to see that these operators create new lists from the elements
of the operand lists. If you concatenate a list with 2 items and a list with
4 items, you will get a new list with 6 items (not a list with two sublists).
Similarly, repetition of a list of 2 items 4 times will give a list with 8 items.
One way for us to make this more clear is to run a part of this example in
codelens. As you step through the code, you will see the variables being created
and the lists that they refer to. Pay particular attention to the fact that when
newlist is created by the statement newlist = fruit + numlist, it refers to
a completely new list formed by making copies of the items from fruit and
numlist. You can see this very clearly in the codelens object diagram. The
objects are different.
fruit = [ " apple " , " orange " , " banana " , " cherry " ]
numlist = [6 , 7]
zeros = [0] * 4
In Python, every object has a unique identification tag. Likewise, there is a
built-in function that can be called on any object to return its unique id. The
function is appropriately called id and takes a single parameter, the object
that you are interested in knowing about. You can see in the example below
that a real id is usually a very large integer value (corresponding to an address
in memory).
>>> alist = [4 , 5, 6]
>>> id ( alist )
4300840544
>>>
Check your understanding
Checkpoint 10.6.1 What is printed by the following statements?
alist = [1 , 3, 5]
blist = [2 , 4, 6]
print ( alist + blist )
A. 6
B. [1, 2, 3, 4, 5, 6]
C. [1, 3, 5, 2, 4, 6]
D. [3, 7, 11]
Checkpoint 10.6.2 What is printed by the following statements?
alist = [1 , 3, 5]
print ( alist * 3)
A. 9
B. [1, 1, 1, 3, 3, 3, 5, 5, 5]
C. [1, 3, 5, 1, 3, 5, 1, 3, 5]
D. [3, 9, 15]
CHAPTER 10. LISTS 206
A. [ [ ], 3.14, False]
B. [ [ ], 3.14]
alist = [ ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' ]
alist [1:3] = []
print ( alist )
We can even insert elements into a list by squeezing them into an empty
slice at the desired location.
alist = [ ' a ' , ' d ' , ' f ' ]
alist [1:1] = [ ' b ' , ' c ' ]
print ( alist )
alist [4:4] = [ ' e ' ]
print ( alist )
Check your understanding
Checkpoint 10.8.1 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
alist [2] = True
print ( alist )
A. [4, 2, True, 8, 6, 5]
B. [4, 2, True, 6, 5]
alist = [ ' a ' , ' b ' , ' c ' , ' d ' , ' e ' , ' f ' ]
del alist [1:5]
print ( alist )
As you might expect, del handles negative indices and causes a runtime
error if the index is out of range. In addition, you can use a slice as an index
for del. As usual, slices select all the elements up to, but not including, the
second index, but do not cause runtime errors if the index limits go too far.
Note 10.9.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
or
In one case, a and b refer to two different string objects that have the same
value. In the second case, they refer to the same object. Remember that an
object is something a variable can refer to.
We already know that objects can be identified using their unique identifier.
We can also test whether two names refer to the same object using the is
operator. The is operator will return true if the two references are to the same
object. In other words, the references are the same. Try our example from
above.
a = " banana "
b = " banana "
print ( a is b )
The answer is True. This tells us that both a and b refer to the same
object, and that it is the second of the two reference diagrams that describes
the relationship. Since strings are immutable, Python can optimize resources
by making two names that refer to the same string literal value refer to the
same object.
This is not the case with lists. Consider the following example. Here, a and
b refer to two different lists, each of which happens to have the same element
values.
a = [81 , 82 , 83]
b = [81 , 82 , 83]
print ( a is b )
print ( a == b )
The reference diagram for this example looks like this:
CHAPTER 10. LISTS 209
a and b have the same value but do not refer to the same object.
There is one other important thing to notice about this reference diagram.
The variable a is a reference to a collection of references. Those references
actually refer to the integer values in the list. In other words, a list is a
collection of references to objects. Interestingly, even though a and b are two
different lists (two different collections of references), the integer object 81 is
shared by both. Like strings, integers are also immutable so Python optimizes
and lets everyone share the same object for some commonly used small integers.
Here is the example in codelens. Pay particular attention to the id values.
a = [81 , 82 , 83]
b = [81 , 82 , 83]
print ( a is b )
print ( a == b )
10.11 Aliasing
Since variables refer to objects, if we assign one variable to another, both
variables refer to the same object:
a = [81 , 82 , 83]
b = a
print ( a is b )
In this case, the reference diagram looks like this:
Because the same list has two different names, a and b, we say that it
is aliased. Changes made with one alias affect the other. In the codelens
example below, you can see that a and b refer to the same list after executing
the assignment statement b = a.
a = [81 , 82 , 83]
b = [81 , 82 , 83]
print ( a == b )
CHAPTER 10. LISTS 210
print ( a is b )
b = a
print ( a == b )
print ( a is b )
b [0] = 5
print ( a )
Although this behavior can be useful, it is sometimes unexpected or un-
desirable. In general, it is safer to avoid aliasing when you are working with
mutable objects. Of course, for immutable objects, there’s no problem. That’s
why Python is free to alias strings and integers when it sees an opportunity to
economize.
Check your understanding
Checkpoint 10.11.1 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
blist = alist
blist [3] = 999
print ( alist )
A. [4, 2, 8, 6, 5]
B. [4, 2, 8, 999, 5]
Checkpoint 10.11.2
A. print(list1 == list2)
B. print(list1 is list2)
C. print(list1 is list3)
D. print(list2 is not list3)
E. print(list2 != list3)
b [0] = 5
CHAPTER 10. LISTS 211
print ( a )
print ( b )
Now we are free to make changes to b without worrying about a. Again,
we can clearly see in codelens that a and b are entirely different list objects.
newlist = [ origlist ] * 3
print ( newlist )
newlist is a list of three references to origlist that were created by the
repetition operator. The reference diagram is shown below.
newlist = [ origlist ] * 3
print ( newlist )
origlist [1] = 99
print ( newlist )
newlist shows the change in three places. This can easily be seen by noting
that in the reference diagram, there is only one origlist, so any changes to it
appear in all three references from newlist.
CHAPTER 10. LISTS 212
Here is the same example in codelens. Step through the code paying partic-
ular attention to the result of executing the assignment statement origlist[1]
= 99.
origlist = [45 , 76 , 34 , 55]
newlist = [ origlist ] * 3
print ( newlist )
origlist [1] = 99
print ( newlist )
Check your understanding
Checkpoint 10.13.1 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
blist = alist * 2
blist [3] = 999
print ( alist )
A. [4, 2, 8, 999, 5, 4, 2, 8, 6, 5]
B. [4, 2, 8, 999, 5]
C. [4, 2, 8, 6, 5]
Checkpoint 10.13.2 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
blist = [ alist ] * 2
alist [3] = 999
print ( blist )
mylist . reverse ()
print ( mylist )
mylist . sort ()
print ( mylist )
Table 10.14.1
Method Parameters Result Description
append item mutator Adds a new item to the end of a list
insert position, item mutator Inserts a new item at the position given
pop none hybrid Removes and returns the last item
pop position hybrid Removes and returns the item at position
sort none mutator Modifies a list to be sorted
reverse none mutator Modifies a list to be in reverse order
index item return idx Returns the position of first occurrence of item
count item return ct Returns the number of occurrences of item
remove item mutator Removes the first occurrence of item
Details for these and others can be found in the Python Documentation1 .
It is important to remember that methods like append, sort, and reverse
all return None. This means that re-assigning mylist to the result of sorting
mylist will result in losing the entire list. Calls like these will likely never
appear as part of an assignment statement (see line 8 below).
mylist = []
mylist . append (5)
mylist . append (27)
mylist . append (3)
mylist . append (12)
print ( mylist )
A. [False, 4, 2, True, 8, 6, 5]
B. [4, False, True, 2, 8, 6, 5]
C. [False, 2, True, 6, 5]
Checkpoint 10.14.4 What is printed by the following statements?
1 http://docs.python.org/py3k/library/stdtypes.html#
sequence-types-str-bytes-bytearray-list-tuple-range
CHAPTER 10. LISTS 215
alist = [4 , 2, 8, 6, 5]
temp = alist . pop (2)
temp = alist . pop ()
print ( alist )
A. [4, 8, 6]
B. [2, 6, 5]
C. [4, 2, 6]
Checkpoint 10.14.5 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
alist = alist . pop (0)
print ( alist )
A. [2, 8, 6, 5]
B. [4, 2, 8, 6, 5]
C. 4
D. None
Note 10.14.6 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
t = turtle . Turtle ()
inst = " FF [- F [- X ]+ X ]+ F [- X ]+ X "
drawLsystem (t , inst , 60 , 20)
When we run this example we can see that the picture is not very interesting,
but notice what gets printed out, and how the saved information about the
turtle gets added and removed from the end of the list. In the next example
we’ll make use of the information from the list to save and restore the turtle’s
position and heading when needed. We’ll use a longer example here so you get
an idea of what the kind of drawing the L-System can really make.
import turtle
t = turtle . Turtle ()
inst =
" FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF [- FFFFFFFFFFFFFFFF [- FFFFFFFF [- FFFF [- FF [ - F [- X ]+ X ]+ F
t . setposition (0 , -200)
t . left (90)
drawLsystem (t , inst , 30 , 2)
Rather than use the inst string supplied here, use the code from the string
chapter, and write your own applyRules function to implement this L-system.
CHAPTER 10. LISTS 217
This example only uses 6 expansions. Try it out with a larger number of
expansions. You may also want to try this example with different values for
the angle and distance parameters.
A. [4, 2, 8, 6, 5, 999]
B. Error, you cannot concatenate a list with an integer.
print ( numbers )
Take a moment to think about range(len(numbers)) until you understand
how it works. We are interested here in both the value and its index within
the list, so that we can assign a new value to it.
Check your understanding
Checkpoint 10.17.1 What is printed by the following statements?
alist = [4 , 2, 8, 6, 5]
blist = [ ]
for item in alist :
blist . append ( item +5)
print ( blist )
A. [4, 2, 8, 6, 5]
B. [4, 2, 8, 6, 5, 5]
C. [9, 7, 13, 11, 10]
D. Error, you cannot concatenate inside an append.
CHAPTER 10. LISTS 219
The following example shows how we can get the maximum value from a
list of integers.
nums = [9 , 3, 8, 11 , 5 , 29 , 2]
best_num = 0
for n in nums :
if n > best_num :
best_num = n
print ( best_num )
Here, we initialize best_num to zero, assuming that there are no negative
numbers in the list.
In the for loop, we check to see if the current value of n is greater than the
current value of best_num. If it is, then we want to update best_num so that
it now is assigned the higher number. Otherwise, we do nothing and continue
the for loop.
You may notice that the current structure could be a problem. If the
numbers were all negative what would happen to our code? What if we were
looking for the smallest number but we initialized best_num with zero? To get
around this issue, we can initialize the accumulator variable using one of the
numbers in the list.
nums = [9 , 3, 8, 11 , 5 , 29 , 2]
best_num = nums [0]
for n in nums :
if n > best_num :
best_num = n
print ( best_num )
The only thing we changed was the value of best_num on line 2 so that
the value of best_num is the first element in nums, but the result is still the
same!
A. 2
B. 5
C. 0
D. There is an error in the code so it cannot run.
Checkpoint 10.18.3 What is printed by the following statements?
list = [5 , 2, 1, 4, 9, 10]
min_value = 0
for item in list :
if item < min_value :
min_value = item
print ( min_value )
A. 10
B. 1
C. 0
D. There is an error in the code so it cannot run.
Checkpoint 10.18.4 Challenge For each word in words, add ‘d’ to the end
of the word if the word ends in “e” to make it past tense. Otherwise, add ‘ed’
to make it past tense. Save these past tense words to a list called past_tense.
CHAPTER 10. LISTS 222
words = [ " adopt " , " bake " , " beam " , " confide " , " grill " ,
" plant " , " time " , " wave " , " wish " ]
=====
from unittest . gui import TestCaseGui
class myTests ( TestCaseGui ):
def testNine ( self ):
self . assertEqual ( past_tense , [ ' adopted ' , ' baked ' ,
' beamed ' , ' confided ' , ' grilled ' , ' planted ' ,
' timed ' , ' waved ' , ' wished ' ], " Testing ␣ that ␣ the ␣
past_tense ␣ list ␣ is ␣ correct . ")
self . assertIn ( " else " , self . getEditorText () ,
" Testing ␣ output ␣( Don ' t␣ worry ␣ about ␣ actual ␣ and ␣
expected ␣ values ) . " )
self . assertIn ( " for " , self . getEditorText () , " Testing ␣
output ␣( Don ' t␣ worry ␣ about ␣ actual ␣ and ␣ expected ␣
values ) . " )
myTests () . main ()
things = [2 , 5 , 9]
print ( things )
doubleStuff ( things )
print ( things )
The parameter aList and the variable things are aliases for the same ob-
ject.
Since the list object is shared by two references, there is only one copy. If
a function modifies the elements of a list parameter, the caller sees the change
since the change is occurring to the original.
This can be easily seen in codelens. Note that after the call to doubleStuff,
the formal parameter aList refers to the same object as the actual parameter
things. There is only one copy of the list object itself.
CHAPTER 10. LISTS 223
things = [2 , 5 , 9]
doubleStuff ( things )
things = [2 , 5 , 9]
print ( things )
things = doubleStuff ( things )
print ( things )
Once again, codelens helps us to see the actual references and objects as
they are passed and returned.
def doubleStuff ( a_list ):
""" Return a new list in which contains doubles of the
elements in a_list . """
new_list = []
for value in a_list :
new_elem = 2 * value
new_list . append ( new_elem )
return new_list
things = [2 , 5 , 9]
things = doubleStuff ( things )
print ( yourlist )
The expression describes each element of the list that is being built. The
for clause iterates through each item in a sequence. The items are filtered by
the if clause if there is one. In the example above, the for statement lets item
take on all the values in the list mylist. Each item is then squared before it
is added to the list that is being built. The result is a list of squares of the
values in mylist.
To write the primes_upto function we will use the is_prime function to
filter the sequence of integers coming from the range function. In other words,
for every integer from 2 up to but not including n, if the integer is prime, keep
it in the list.
def primes_upto ( n):
""" Return a list of all prime numbers less than n
using a list comprehension . """
Note 10.23.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
Check your understanding
Checkpoint 10.23.2 What is printed by the following statements?
alist = [4 ,2 ,8 ,6 ,5]
blist = [ num *2 for num in alist if num %2==1]
print ( blist )
A. [4,2,8,6,5]
B. [8,4,16,12,10]
C. 10
D. [10].
A. 6
B. 8
C. 888
D. 999
print ( wds )
An optional argument called a delimiter can be used to specify which
characters to use as word boundaries. The following example uses the string
ai as the delimiter:
song = " The ␣ rain ␣ in ␣ Spain ... "
wds = song . split ( ' ai ' )
print ( wds )
Notice that the delimiter doesn’t appear in the result.
The inverse of the split method is join. You choose a desired separator
string, (often called the glue) and join the list with the glue between each of
the elements.
wds = [ " red " , " blue " , " green " ]
glue = ' ; '
s = glue . join ( wds )
print ( s )
print ( wds )
A. Poe
B. EdgarAllanPoe
C. EAP
D. William Shakespeare
split will break a string into a list of “words”, list will always break it into
a list of characters.
julia = julia [:3] + ( " Eat ␣ Pray ␣ Love " , 2010) + julia [5:]
print ( julia )
To create a tuple with a single element (but you’re probably not likely to
do that too often), we have to include the final comma, because without the
final comma, Python treats the (5) below as an integer in parentheses:
tup = (5 ,)
print ( type ( tup ))
CHAPTER 10. LISTS 228
x = (5)
print ( type ( x ))
Note 10.29.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
10.30 Glossary
Glossary
aliases.Multiple variables that contain references to the same object.
clone.To create a new object that has the same value as an existing object.
Copying a reference to an object creates an alias but doesn’t clone the object.
delimiter.A character or string used to indicate where a string should be split.
element.One of the values in a list (or other sequence). The bracket operator
selects elements of a list.
index.An integer variable or value that indicates an element of a list.
list.A collection of objects, where each object is identified by an index. Like
other types str, int, float, etc. there is also a list type-converter function
that tries to turn its argument into a list.
list traversal.The sequential accessing of each element in a list.
modifier.A function which changes its arguments inside the function body.
Only mutable types can be changed by modifiers.
mutable data type.A data type in which the elements can be modified. All
mutable types are compound types. Lists are mutable data types; strings are
not.
nested list.A list that is an element of another list.
object.A thing to which a variable can refer.
pattern.A sequence of statements, or a style of coding something that has
general applicability in a number of different situations. Part of becoming a
mature Computer Scientist is to learn and establish the patterns and algorithms
that form your toolkit. Patterns often correspond to your “mental chunking”.
pure function.A function which has no side effects. Pure functions only make
changes to the calling program through their return values.
sequence.Any of the data types that consist of an ordered collection of ele-
ments, with each element identified by an index.
side effect.A change in the state of a program made by calling a function that
is not a result of reading the return value from the function. Side effects can
only be produced by modifiers.
tuple.A sequential collection of items, similar to a list. Any python object can
be an element of a tuple. However, unlike a list, tuples are immutable.
10.31 Exercises
1.
2. Create a list called myList with the following six items: 76, 92.3, “hello”,
True, 4, 76. Begin with the empty list shown below, and add 6 statements
to add each item, one per item. The first three statements should use
the append method to append the item to the list, and the last three
statements should use concatenation.
CHAPTER 10. LISTS 230
myList = []
====
from unittest . gui import TestCaseGui
myTests () . main ()
3. Starting with the list of the previous exercise, write Python statements to
do the following:
====
from unittest . gui import TestCaseGui
myTests () . main ()
5. Write a Python function named max that takes a parameter containing a
nonempty list of integers and returns the maximum value. (Note: there
is a builtin function named max but pretend you cannot use it.)
CHAPTER 10. LISTS 231
====
from unittest . gui import TestCaseGui
myTests () . main ()
6. Write a function sum_of_squares(xs) that computes the sum of the squares
of the numbers in the list xs. For example, sum_of_squares([2, 3, 4])
should return 4+9+16 which is 29:
def sum_of_squares ( xs ) :
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
7. Write a function to count how many odd numbers are in a list.
def countOdd ( lst ):
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
CHAPTER 10. LISTS 232
====
from unittest . gui import TestCaseGui
myTests () . main ()
9. Sum up all the negative numbers in a list.
def sumNegatives ( lst ) :
# your code here
====
from unittest . gui import TestCaseGui
myTests () . main ()
10. Count how many words in a list have length 5.
def countWords ( lst ) :
# your code here
11.
12. Count how many words occur in a list up to and including the first occur-
rence of the word “sam”.
def count ( lst ):
# your code here
13. Although Python provides us with many list methods, it is good practice
and very instructive to think about how they are implemented. Implement
a Python function that works like the following:
a count
b in
CHAPTER 10. LISTS 233
c reverse
d index
e insert
14. Write a function replace(s, old, new) that replaces all occurences of
old with new in a string s:
test(replace('Mississippi', 'i', 'I'), 'MIssIssIppI')
s = 'I love spom! Spom is my favorite food. Spom, spom, spom, yum!'
test(replace(s, 'om', 'am'),
'I love spam! Spam is my favorite food. Spam, spam, spam, yum!')
====
from unittest . gui import TestCaseGui
myTests () . main ()
15. Here are the rules for an L-system that creates something that resembles
a common garden herb. Implement the following rules and try it. Use an
angle of 25.7 degrees.
H
H --> HFX[+H][-H]
X --> X[-FFF][+FFF]FX
16. Here is another L-System. Use an Angle of 25.
F
F --> F[-F]F[+F]F
17. Create a list named randlist containing 100 random integers between 0
and 1000 (use iteration, append, and the random module).
CHAPTER 10. LISTS 234
====
from unittest . gui import TestCaseGui
myTests () . main ()
Chapter 11
Files
235
CHAPTER 11. FILES 236
• data1.txt
• ../myData/data2.txt
• ../myData/data3.txt
• ../../otherFiles/extraData/data4.txt
CHAPTER 11. FILES 237
Here’s the important rule to remember: If your file and your Python pro-
gram are in the same directory you can simply use the filename like this:
open('myfile.txt', 'r'). If your file and your Python program are in different
directories then you must refer to one or more directories, either in a relative file
path to the file like this: open('../myData/data3.txt', 'r'), or in an absolute
file path like open('/users/bmiller/myFiles/allProjects/myData/data3.txt',
'r').
To process all of our climate change data, we will use a for loop to iterate
over the lines of the file. Using the split method, we can break each line into
a list containing all the fields of interest about climate change. We can then
take the values corresponding to year, global average temperature, and global
emmisions to construct a simple sentence.
ccfile = open ( " ccdata . txt " , " r " )
ccfile . close ()
Note 11.4.2 You can obtain a line from the keyboard with the input function,
and you can process lines of a file. However “line” is used differently: With
input Python reads through the newline you enter from the keyboard, but the
newline ('\n') is not included in the line returned by input. It is dropped.
When a line is taken from a file, the terminating newline is included as the last
character (unless you are reading the final line of a file that happens to not
have a newline at the end).
In the climate change example it is irrelevant whether the final line has a
newline character at the end or not, since it would be stripped off by the split
method call.
>>> print(linelist[0:4])
['1850\-0.37\2.24E-7\n',
'1860\-0.34\3.94E-7\n',
'1870\-0.28\6.6E-7\n',
'1880\-0.24\1.1\n']
>>>
>>> infile = open("ccdata.txt", "r")
>>> filestring = infile.read()
>>> print(len(filestring))
1282
>>> print(filestring[:256])
1850 -0.37 2.24E-7
1860 -0.34 3.94E-7
1870 -0.28 6.6E-7
1880 -0.24
>>>
Table 11.5.1
Method Name Use Explanation
write filevar.write(astring) Add astring to the end of the file. filevar must refer to a file
read(n) filevar.read() Reads and returns a string of n characters, or the entire file a
readline(n) filevar.readline() Returns the next line of the file with all text up to and inclu
readlines(n) filevar.readlines() Returns a list of strings, each representing a single line of the
Now let’s look at another method of reading our file using a while loop. This
is important because many other programming languages do not support the
for loop style for reading files but they do support the pattern we’ll show you
here.
infile = open ( " ccdata . txt " , " r " )
line = infile . readline ()
while line :
values = line . split ()
print ( ' In ' , values [0] , ' the ␣ average ␣ temp .␣ was ' ,
values [1] , ' °C ␣ and ␣ CO2 ␣ emmisions ␣ were ' , values [2] ,
' gigatons . ' )
line = infile . readline ()
infile . close ()
There are several important things to notice in this code:
On line 2 we have the statement line = infile.readline(). We call this
initial read the priming read. It is very important because the while condition
needs to have a value for the line variable.
The readline method will return the empty string if there is no more
data in the file. An empty string is an empty sequence of characters. When
Python is looking for a Boolean condition, as in while line:, it treats an
empty sequence type as False, and a non-empty sequence as True. Remember
that a blank line in the file actually has a single character, the \n character
(newline). So, the only way that a line of data from the file can be empty is if
you are reading at the end of the file, and the while condition becomes False.
Finally, notice that the last line of the body of the while loop performs
another readline. This statement will reassign the variable line to the next
line of the file. It represents the change of state that is necessary for the
iteration to function correctly. Without it, there would be an infinite loop
processing the same line of data over and over.
CHAPTER 11. FILES 240
infile . close ()
When we run this program, we see the lines of output on the screen. Once
we are satisfied that it is creating the appropriate output, the next step is to
add the necessary pieces to produce an output file and write the data lines
to it. To start, we need to open a new output file by adding another call
to the open function, outfile = open("emissiondata.txt",'w'), using the 'w'
flag. We can choose any file name we like. If the file does not exist, it will be
created. However, if the file does exist, it will be reinitialized as empty and
you will lose any previous contents.
Once the file has been created, we just need to call the write method
passing the string that we wish to add to the file. In this case, the string is
already being printed so we will just change the print into a call to the write
method. However, there is one additional part of the data line that we need
to include. The newline character needs to be concatenated to the end of the
CHAPTER 11. FILES 241
infile . close ()
outfile . close ()
• The resource we’re trying to fetch must exist! Check this using a browser.
• We’ll need permission to write to the destination filename, and the file
will be created in the “current directory” - i.e. the same folder that the
Python program is saved in.
• If we are behind a proxy server that requires authentication, (as some stu-
dents are), this may require some more special handling to work around
our proxy. Use a local resource for the purpose of this demonstration!
We will try to retrieve the content of the HTML of this page as in the
following code.
import urllib . request
the_text =
retrieve_page ( " https :// runestone . academy / runestone / books / published / thinkcspy / Files /
print ( the_text )
11.9 Glossary
Glossary
open.You must open a file before you can read its contents.
close.When you are done with a file, you should close it.
read.Will read the entire contents of a file as a string. This is often used in an
assignment statement so that a variable can reference the contents of the file.
readline.Will read a single line from the file, up to and including the first
instance of the newline character.
readlines.Will read the entire contents of a file into a list where each line of
the file is a string and is an element in the list.
write.Will add characters to the end of a file that has been opened for writing.
absolute file path.The name of a file that includes a path to the file from the
root directory of a file system. An absolute file path always starts with a /.
relative file path.The name of a file that includes a path to the file from the
current working directory of a program. An relative file path never starts with
a /.
CHAPTER 11. FILES 243
11.10 Exercises
1. The following sample file called studentdata.txt contains one line for
each student in an imaginary class. The student’s name is the first thing
on each line, followed by some exam scores. The number of scores might
be different for each student.Using the text file studentdata.txt write a
program that prints out the names of students that have more than six
quiz scores.
2. Using the text file studentdata.txt (shown in exercise 1) write a pro-
gram that calculates the average grade for each student, and print out
the student’s name along with their average grade.
3. Using the text file studentdata.txt (shown in exercise 1) write a program
that calculates the minimum and maximum score for each student. Print
out their name as well.
4. Here is a file called labdata.txt that contains some sample data from
a lab experiment.Interpret the data file labdata.txt such that each line
contains a an x,y coordinate pair. Write a function called plotRegression
that reads the data from this file and uses a turtle to plot those points
and a best fit line according to the following formulas:
y = \bar{y} + m(x - \bar{x})
m = \frac{\sum{x_iy_i - n\bar{x}\bar{y}}}{\sum{x_i^2}-n\bar{x}^2}
where \bar{x} is the mean of the x-values, \bar{y} is the mean of
the y- values and n is the number of points. If you are not familiar with
the mathematical \sum it is the sum operation. For example \sum{x_i}
means to add up all the x values.
Your program should analyze the points and correctly scale the window
using setworldcoordinates so that that each point can be plotted. Then
you should draw the best fit line, in a different color, through the points.
5. At the bottom of this page is a very long file called mystery.txt The lines
of this file contain either the word UP or DOWN or a pair of numbers.
UP and DOWN are instructions for a turtle to lift up or put down its
tail. The pairs of numbers are some x,y coordinates. Write a program
that reads the file mystery.txt and uses the turtle to draw the picture
described by the commands and the set of points.
Here is the mystery.txt file:
Chapter 12
Dictionaries
12.1 Dictionaries
All of the compound data types we have studied in detail so far — strings,
lists, and tuples — are sequential collections. This means that the items in
the collection are ordered from left to right and they use integers as indices to
access the values they contain.
Dictionaries are a different kind of collection. They are Python’s built-in
mapping type. A map is an unordered, associative collection. The associa-
tion, or mapping, is from a key, which can be any immutable type, to a value,
which can be any Python data object.
As an example, we will create a dictionary to translate English words into
Spanish. For this dictionary, the keys are strings and the values will also be
strings.
One way to create a dictionary is to start with the empty dictionary and
add key-value pairs. The empty dictionary is denoted {}
eng2sp = {}
eng2sp [ ' one ' ] = ' uno '
eng2sp [ ' two ' ] = ' dos '
eng2sp [ ' three ' ] = ' tres '
The first assignment creates an empty dictionary named eng2sp. The other
assignments add new key-value pairs to the dictionary. The left hand side gives
the dictionary and the key being associated. The right hand side gives the
value being associated with that key. We can print the current value of the
dictionary in the usual way. The key-value pairs of the dictionary are separated
by commas. Each pair contains a key and a value separated by a colon.
The order of the pairs may not be what you expected. Python uses complex
algorithms, designed for very fast access, to determine where the key-value
pairs are stored in a dictionary. For our purposes we can think of this ordering
as unpredictable.
Another way to create a dictionary is to provide a list of key-value pairs
using the same syntax as the previous output.
eng2sp = { ' three ' : ' tres ' , ' one ' : ' uno ' , ' two ' : ' dos ' }
print ( eng2sp )
It doesn’t matter what order we write the pairs. The values in a dictionary
are accessed with keys, not with indices, so there is no need to care about
ordering.
Here is how we use a key to look up the corresponding value.
244
CHAPTER 12. DICTIONARIES 245
eng2sp = { ' three ' : ' tres ' , ' one ' : ' uno ' , ' two ' : ' dos ' }
A. False
B. True
Checkpoint 12.1.3 What is printed by the following statements?
mydict = { " cat " :12 , " dog " :6 , " elephant " :23}
print ( mydict [ " dog " ])
A. 12
B. 6
C. 23
D. Error, you cannot use the index operator with a dictionary.
Notice that there are now 512 bananas—the dictionary has been modified.
Note also that the len function also works on dictionaries. It returns the
number of key-value pairs:
Check your understanding
Checkpoint 12.2.1 What is printed by the following statements?
mydict = { " cat " :12 , " dog " :6 , " elephant " :23}
mydict [ " mouse " ] = mydict [" cat " ] + mydict [ " dog " ]
print ( mydict [ " mouse " ])
A. 12
B. 0
C. 18
D. Error, there is no entry with mouse as the key.
for k in inventory :
print (" Got ␣ key " , k )
1 http://docs.python.org/py3k/library/stdtypes.html#mapping-types-dict
CHAPTER 12. DICTIONARIES 247
As we saw earlier with strings and lists, dictionary methods use dot nota-
tion, which specifies the name of the method to the right of the dot and the
name of the object on which to apply the method immediately to the left of
the dot. The empty parentheses in the case of keys indicate that this method
takes no parameters.
The values and items methods are similar to keys. They return view
objects which can be turned into lists or iterated over directly. Note that the
items are shown as tuples containing the key and the associated value.
inventory = { ' apples ' : 430 , ' bananas ' : 312 , ' oranges ' : 525 ,
' pears ' : 217}
for k in inventory :
print ( " Got " , k , " that ␣ maps ␣ to " , inventory [ k ])
Note that tuples are often useful for getting both the key and the value at
the same time while you are looping. The two loops do the same thing.
The in and not in operators can test if a key is in the dictionary:
inventory = { ' apples ' : 430 , ' bananas ' : 312 , ' oranges ' : 525 ,
' pears ' : 217}
print ( ' apples ' in inventory )
print ( ' cherries ' in inventory )
Note 12.3.2 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
Check your understanding
Checkpoint 12.3.3 What is printed by the following statements?
CHAPTER 12. DICTIONARIES 248
mydict = { " cat " :12 , " dog " :6 , " elephant " :23 , " bear " :20}
keylist = list ( mydict . keys () )
keylist . sort ()
print ( keylist [3])
A. cat
B. dog
C. elephant
D. bear
Checkpoint 12.3.4 What is printed by the following statements?
mydict = { " cat " :12 , " dog " :6 , " elephant " :23 , " bear " :20}
answer = mydict . get ( " cat ") // mydict . get ( " dog " )
print ( answer )
A. 2
B. 0.5
C. bear
D. Error, divide is not a valid operation on dictionaries.
Checkpoint 12.3.5 What is printed by the following statements?
mydict = { " cat " :12 , " dog " :6 , " elephant " :23 , " bear " :20}
print ( " dog " in mydict )
A. True
B. False
Checkpoint 12.3.6 What is printed by the following statements?
mydict = { " cat " :12 , " dog " :6 , " elephant " :23 , " bear " :20}
print (23 in mydict )
A. True
B. False
Checkpoint 12.3.7 What is printed by the following statements?
total = 0
mydict = { " cat " :12 , " dog " :6 , " elephant " :23 , " bear " :20}
for akey in mydict :
if len ( akey ) > 3:
total = total + mydict [ akey ]
print ( total )
A. 18
B. 43
C. 0
D. 61
CHAPTER 12. DICTIONARIES 249
A. 23
B. None
C. 999
D. Error, there are two different keys named elephant.
We can represent this collection as five rows, each row having five columns.
Using a list of lists representation, we will have a list of five items, each of
which is a list of five items. The outer items represent the rows and the items
in the nested lists represent the data in each column.
matrix = [[0 , 0, 0, 1, 0] ,
[0 , 0, 0, 0, 0] ,
[0 , 2, 0, 0, 0] ,
[0 , 0, 0, 0, 0] ,
[0 , 0, 0, 3, 0]]
One thing that you might note about this example matrix is that there are
many items that are zero. In fact, only three of the data values are nonzero.
This type of matrix has a special name. It is called a sparse matrix1 .
Since there is really no need to store all of the zeros, the list of lists rep-
resentation is considered to be inefficient. An alternative representation is to
use a dictionary. For the keys, we can use tuples that contain the row and
column numbers. Here is the dictionary representation of the same matrix.
matrix = {(0 , 3) : 1, (2 , 1) : 2, (4 , 3) : 3}
We only need three key-value pairs, one for each nonzero element of the
matrix. Each key is a tuple, and each value is an integer.
To access an element of the matrix, we could use the [] operator:
matrix[(0, 3)]
Notice that the syntax for the dictionary representation is not the same as the
syntax for the nested list representation. Instead of two integer indices, we use
one index, which is a tuple of integers.
There is one problem. If we specify an element that is zero, we get an error,
because there is no entry in the dictionary with that key. The alternative
version of the get method solves this problem. The first argument will be the
key. The second argument is the value get should return if the key is not in
the dictionary (which would be 0 since it is sparse).
matrix = {(0 , 3) : 1, (2 , 1) : 2, (4 , 3) : 3}
print ( matrix . get ((0 ,3) ))
1 http://en.wikipedia.org/wiki/Sparse_matrix
CHAPTER 12. DICTIONARIES 251
12.6 Glossary
Glossary
dictionary.A collection of key-value pairs that maps from keys to values. The
keys can be any immutable type, and the values can be any type.
key.A data item that is mapped to a value in a dictionary. Keys are used to
look up values in a dictionary.
key-value pair.One of the pairs of items in a dictionary. Values are looked
up in a dictionary by key.
mapping type.A mapping type is a data type comprised of a collection of keys
and associated values. Python’s only built-in mapping type is the dictionary.
Dictionaries implement the associative array1 abstract data type.
12.7 Exercises
1. Write a program that allows the user to enter a string. It then prints
a table of the letters of the alphabet in alphabetical order which occur
in the string together with the number of times each letter occurs. Case
should be ignored. A sample run of the program might look this this:
Please enter a sentence: ThiS is String with Upper and lower case Letters.
a 2
c 1
d 1
e 5
g 1
h 2
i 4
l 2
n 2
o 1
p 2
r 4
s 5
t 5
u 1
w 2
$
2 ../Labs/lab12_01.html
3 ../Labs/lab12_02.html
1 http://en.wikipedia.org/wiki/Associative_array
CHAPTER 12. DICTIONARIES 252
Be sure you understand why you get each result. Then apply what you have
learned to fill in the body of the function below, and add code for the tests
indicated:
def add_fruit ( inventory , fruit , quantity =0) :
pass
pirate = {}
pirate [ ' sir ' ] = ' matey '
pirate [ ' hotel ' ] = ' fleabag ␣ inn '
pirate [ ' student ' ] = ' swabbie '
pirate [ ' boy ' ] = ' matey '
pirate [ ' restaurant ' ] = ' galley '
pirate [ ' hello ' ] = ' avast '
pirate [ ' students ' ] = ' swabbies '
====
from unittest . gui import TestCaseGui
myTests () . main ()
Chapter 13
Exceptions
def A () :
B ()
def B () :
C ()
def C () :
D ()
def D ()
# processing
Function D determines that the current processing won’t work for some
reason and needs to send a message to the main function to try something
different. However, all that function D can do using normal flow-of-control
is to return a value to function C. So function D returns a special value to
function C that means “try something else”. Function C has to recognize this
value, quit its processing, and return the special value to function B. And so
forth and so on. It would be very helpful if function D could communicate
directly with the main function (or functions A and B) without sending a
255
CHAPTER 13. EXCEPTIONS 256
special value through the intermediate calling functions. Well, that is exactly
what an exception does. An exception is a message to any function currently
on the executing program’s “run-time-stack”. (The “run-time-stack” is what
keeps track of the active function calls while a program is executing.)
In Python, your create an exception message using the raise command.
The simplest format for a raise command is the keyword raise followed by
the name of an exception. For example:
raise ExceptionName
So what happens to an exception message after it is created? The normal
flow-of-control of a Python program is interrupted and Python starts looking
for any code in its run-time-stack that is interested in dealing with the message.
It always searches from its current location at the bottom of the run-time-
stack, up the stack, in the order the functions were originally called. A try:
except: block is used to say “hey, I can deal with that message.” The first try:
except: block that Python finds on its search back up the run-time-stack will
be executed. If there is no try: except: block found, the program “crashes”
and prints its run-time-stack to the console.
Let’s take a look at several code examples to illustrate this process. If func-
tion D had a try: except: block around the code that raised a MyException
message, then the flow-of-control would be passed to the local except block.
That is, function D would handle it’s own issues.
def main ()
A ()
def A () :
B ()
def B () :
C ()
def C () :
D ()
def D ()
try :
# processing code
if something_special_happened :
raise MyException
except MyException :
# execute if the MyException message happened
But perhaps function C is better able to handle the issue, so you could put
the try: except: block in function C:
def main ()
A ()
def A () :
B ()
def B () :
C ()
def C () :
try :
D ()
CHAPTER 13. EXCEPTIONS 257
except MyException :
# execute if the MyException message happened
def D ()
# processing code
if something_special_happened :
raise MyException
But perhaps the main function is better able to handle the issue, so you
could put the try: except: block in the main function:
def main ()
try :
A ()
except MyException :
# execute if the MyException message happened
def A () :
B ()
def B () :
C ()
def C () :
D ()
def D ()
# processing code
if something_special_happened :
raise MyException
Table 13.3.2
Math Exceptions Description
ArithmeticError Base class for all errors that occur for numeric calculation. You know a math error oc
OverflowError Raised when a calculation exceeds maximum limit for a numeric type.
FloatingPointError Raised when a floating point calculation fails.
ZeroDivisonError Raised when division or modulo by zero takes place for all numeric types.
Table 13.3.3
I/O Exceptions Description
FileNotFoundError Raised when a file or directory is requested but doesn’t exist.
IOError Raised when an input/ output operation fails, such as the print statement or the open
PermissionError Raised when trying to run an operation without the adequate access rights.
EOFError Raised when there is no input from either the raw_input() or input() function and th
KeyboardInterrupt Raised when the user interrupts program execution, usually by pressing Ctrl+c.
Table 13.3.4
Other Exceptions Description
Exception Base class for all exceptions. This catches most exception messages.
StopIteration Raised when the next() method of an iterator does not point to any object.
AssertionError Raised in case of failure of the Assert statement.
SystemExit Raised when Python interpreter is quit by using the sys.exit() function. If not hand
OSError Raises for operating system related errors.
EnvironmentError Base class for all exceptions that occur outside the Python environment.
AttributeError Raised in case of failure of an attribute reference or assignment.
NotImplementedError Raised when an abstract method that needs to be implemented in an inherited clas
All exceptions are objects. The classes that define the objects are organized
in a hierarchy, which is shown below. This is important because the parent
class of a set of related exceptions will catch all exception messages for itself
and its child exceptions. For example, an ArithmeticError exception will catch
itself and all FloatingPointError, OverflowError, and ZeroDivisionError ex-
ceptions.
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
CHAPTER 13. EXCEPTIONS 259
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- ResourceWarning
Example 2:
CHAPTER 13. EXCEPTIONS 260
Table 13.4.2
DON’T DO THIS: When you can just as easily
try : if 0 <= index < len (
value = my_list [ index ] value = my_list [ in
except IndexError : else :
value = -1 value = -1
Example 3:
Table 13.4.3
DON’T DO THIS: When you can just as easily
try : if key in my_diction
value = my_dictionary [ key ] value = my_diction
except KeyError : else :
value = -1 value = -1
If you call a function that potentially raises exceptions, and you can do
something appropriate to deal with the exception, then surround the code
that contains the function call with a try: except: block.Example: Suppose
you have a function that reads a file to set the state of an application when it
starts up. You should catch any errors related to reading the file and set the
state of the application to default values if they can’t be set from the file.
try :
load_state ( ' previous_state . txt ' )
except OSError :
set_state_to_defaults ()
If you call a function that potentially raises exceptions, and you can’t do
anything meaningful about the conditions that are raised, then don’t catch the
exception message(s).
try :
# Your normal code goes here .
# Your code should include function calls which might
raise exceptions .
except ExceptionName :
# If ExceptionName was raised , then execute this block .
def show_poly () :
try :
win = turtle . Screen () # Grab / create a resource , e . g .
a window
tess = turtle . Turtle ()
show_poly ()
In lines 20–22, show_poly is called three times. Each one creates a new
window for its turtle, and draws a polygon with the number of sides input
by the user. But what if the user enters a string that cannot be converted
to an int? What if they close the dialog? We’ll get an exception, but even
though we’ve had an exception, we still want to close the turtle’s window. Lines
17–18 does this for us. Whether we complete the statements in the try clause
successfully or not, the finally block will always be executed.
Notice that the exception is still unhandled — only an except clause can
handle an exception, so our program will still crash. But at least its turtle
window will be closed before it crashes!
CHAPTER 13. EXCEPTIONS 263
13.7 Glossary
Glossary
exception.An error that occurs at runtime.
handle an exception.To prevent an exception from terminating a program
by wrapping the block of code in a try / except construct.
raise.To cause an exception by using the raise statement.
13.8 Exercises
Write a function named readposint that uses the input dialog to prompt the
user for a positive integer and then checks the input to confirm that it meets
the requirements. It should be able to handle inputs that cannot be converted
to int, as well as negative int, and edge cases (e.g. when the user closes the
dialog, or does not enter anything at all.)
Chapter 14
Web Applications
In this chapter, you will learn to build server-side web applications, which
I will refer to simply as “web applications.”
264
CHAPTER 14. WEB APPLICATIONS 265
Process the Once the web browser has downloaded the re-
downloaded quested file, it needs to do something with it. Web
files browsers know how to render an HTML document,
appropriately. show images, play audio files, and so on. If the web
browser doesn’t know what to do with a file, it usu-
ally prompts the user to save the file, so the user
2 can do something with it.
Let’s take a specific example. Use your browser to access the following
URL:
https://docs.python.org/3/library/index.html1
Note 14.2.1 A URL (“Uniform Resource Locator”) is the address of a re-
source on the Web. It has three sections: the protocol (ex. https:) the
browser uses to request the resource, the server where the document is lo-
cated (ex. docs.python.org), and the path to the requested resource on the
server (ex. /3/library/index.html).
When you click on this link, here’s what happens:
1 The browser opens a network connection to the web server named docs.python.org
2 The browser requests a file located on the server at /3/library/index.html
3 The web server transmits the HTML file back to the browser
4 The browser renders the HTML document
Figure 14.2.2
If you want to see the file transmitted by the web server to the browser, right-
click in the browser window and choose View Page Source (your browser’s
option to view the source may be slightly different). The browser shows you
the file it downloaded from the web server.
Figure 14.4.1
1 https://google.com
CHAPTER 14. WEB APPLICATIONS 267
Now, take a good look at the URL in the title bar — notice the query
string? It’s a bit more complicated than the one I had you create by hand
earlier. But you can probably pick out the “q=Microsoft” if you look closely.
How did all of that get there? Well, when you clicked Search, the browser took
the information you typed into the form, packaged it up into a query string,
and transmitted it to the Google web server. You see, when you fill out a form
on a web page and click Submit, the browser uses the form data to construct
a URL, and then sends a normal request to the web server.
Even if you’re a novice at writing HTML pages, it’s not hard to learn to
create HTML forms. Take a look at this simplified version of the Google home
page:
< html >
< head >
< title > Google </ title >
</ head >
< body >
< div align = " center " >
< img
src = " https :// www . google . com / images / logo . png " >< br >< br >
< form action =" https :// google . com / search " >
Enter your search words : < input type = " text "
name =" q " >< br > < br >
< input type = " submit " name = " btnG " value = " Google ␣
Search " >
</ form >
</ div >
</ body >
</ html >
Focus on the region of this example in between the <form> tags. Here’s a
quick overview of this part of the page:
• The form is the region of the page in between the <form> and </form>
tags.
• The form can contain a mixture of text, regular HTML formatting tags,
and form <input> tags
• Each <input> tag has a type and a name attribute. The type attribute
specifies what kind of input area it is (“text” for a text box, “submit” for
submit button, etc.). The name attribute specifies a name for the input
area.
• When the user fills out the form and clicks the submit button, the
browser constructs a URL by taking the form’s action attribute (https:/
/google.com/search2 ), appending a ?, and constructing the query string
using the names of the form input areas, together with the data entered
by the user.
Try it out! Using Notepad, type in this example, and save it as google-
form.html. Open it in your browser; you should see something like this:
2 https://google.com/search
CHAPTER 14. WEB APPLICATIONS 268
Figure 14.4.2
Fill out the form, and, if Google still works as it did when this chapter was
written, you should see search results appear in your browser.
For more information about creating HTML forms, you might take a look
at the excellent tutorial at w3schools.com3 .
3 https://www.w3schools.com/html/html_forms.asp
CHAPTER 14. WEB APPLICATIONS 269
Note 14.5.1 If you are using a Mac or Linux computer, use the following
command to install flask:
pip3 install flask
and execute your flaskhello.py program using the following command:
python3 flaskhello.py
When you launch the program, you should see a message similar to the follow-
ing appear on the console:
* Serving Flask app "sample" (lazy loading)
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: on
* Restarting with stat
* Debugger is active!
* Debugger PIN: 244-727-575
* Running on http://localhost:5000/ (Press CTRL+C to quit)
Note 14.5.2 If you get an error message of some sort, it is possible that your
computer may be running a server application that is using the port number
that Flask wants to use. See the next section, “More About Flask,” for a
discussion of port numbers and how to address this issue.
Once the Flask server is running, use your browser to navigate to the following
URL:
http://localhost:5000/1
Your browser sends a request to the Flask server, and you should see a “Hello,
world!” message appear:
Figure 14.5.3
To send the request again, press the Reload button in your browser. You
should see the date and time change.
address of the computer that sent the request (127.0.0.1 is a special address
indicating the request came from the browser on the same computer that the
Flask server is running on); the date and time of the request; the path of the
incoming request (“/” in this case); and the status of the result (here, 200
indicates the request was successfully processed).
The Flask server continues running until you press Ctrl-C to stop it. At
that point, if you try to send a request to the application from the browser,
the browser will display an error message indicating that it cannot contact the
server. Go ahead and try this, so you can recognize what the error message
looks like in your particular browser.
Recall that every URL has at least three components: the protocol, server,
and the path. In our case the URL http://localhost:5000/2 has the server
name localhost, the path /, and an additional component: the port number,
5000. Let’s discuss some details about each of these.
Server name When you use the name localhost in a URL, the browser
attempts to connect to a server program running on your
computer. This is the usual scenario when you are devel-
oping a web application: the browser and the server ap-
plication are both running on the same computer. When
you deploy the application to be hosted on an actual
server, you will use the name of the server in the URL
instead of the name localhost. If you want to experiment
with deploying Flask applications to a public web server,
check out pythonanywhere.com3 , which (at the time of
writing) provides free hosting for Flask web applications.
Here, the Flask server binds to port 5001, and you would
need to use that port number instead of 5000 in the URL
in the browser.
2 http://localhost:5000/
3 https://pythonanywhere.com
CHAPTER 14. WEB APPLICATIONS 271
Here’s another version of the flaskhello.py program that has two different
pages. The first page displays a “Hello world” message and invites the user to
click a link to view the time. When the user clicks the link, the time appears.
from flask import Flask
from datetime import datetime
HELLO_HTML = """
< html >< body >
<h1 > Hello , world ! </ h1 >
Click <a href ="/ time "> here </ a > for the time .
</ body > </ html >
"""
TIME_HTML = """
< html >< body >
The time is {0}.
</ body > </ html >
"""
4 http://localhost:5000/blah
CHAPTER 14. WEB APPLICATIONS 272
1 To begin, the user enters the URL http://localhost:50005 , and the browser
sends the request to the application. The Flask server matches that path
“/” to the hello() function, invokes the function and returns the response
to the browser.
2 The user clicks the link, which triggers the browser to send a request with
the URL http://localhost:5000/time6 to the Flask server. The server
matches the path “/time” to the time() function, invokes the function
and returns a response containing the time to the browser.
Note that the user does not have to click the link in order to display the
time. For example, the user could enter the URL http://localhost:5000/time7
directly into the browser to bypass the greeting page and get directly to the
page showing the time.
The example above used the format() method to build an HTML string.
For more information on format(), see Section 9.5.
Also, notice how the example above defines separate HELLO_HTML and
TIME_HTML variables to hold the HTML. This helps reduce cluttering the
handler functions with HTML code, and separating the Python logic from the
HTML also improves the overall readability and maintainability of the code.
above, if Bing were a Flask application, it could access the values in the query
string like this:
q = request.args['q']
go = request.args['go']
This would retrieve the values ‘python flask’ and ‘Submit’ from the query string
and store them, respectively, in q and go.
Here is an enhanced version of the original flaskhello.py program that gets
the user’s name from the query string and uses it to greet the user:
from flask import Flask , request
from datetime import datetime
HELLO_HTML = """
< html >< body >
<h1 > Hello , {0}! </ h1 >
The time is {1}.
</ body > </ html > """
HOME_HTML = """
< html >< body >
<h2 > Welcome to the Greeter </ h2 >
< form action ="/ greet ">
What ' s your name ? < input type = ' text '
name = ' username ' > < br >
What ' s your favorite food ? < input type = ' text '
name = ' favfood ' > < br >
< input type = ' submit ' value = ' Continue ' >
</ form >
</ body > </ html > """
GREET_HTML = """
< html >< body >
<h2 > Hello , {0}! </ h2 >
{1}
</ body > </ html >
"""
• Lines 6-8 define the home() function, which defines the starting page for
the application. It displays a form that prompts for the user’s name and
favorite food.
• The form’s action attribute on Line 13 specifies that the form submission
will be directed to the path /greet. Processing for this path is defined
by the greet() function on lines 20-31.
CHAPTER 14. WEB APPLICATIONS 275
• Lines 22-29 extract the information submitted on the form and compute
a response message.
14.9 Glossary
Glossary
Client-side web applications.programs that are downloaded to a web browser
and executed on the user’s local machine. Client-side applications are typically
written in JavaScript and embedded in web pages.
Server-side web applications.programs that run on web server computers,
rather than on the user’s local machine. Typically, a server-side web application
displays a form with text boxes and other data collection mechanisms. The
user fills out the form, clicks a submit button, and the browser sends the form
to the web application on the server, which processes the request, and responds
with another web page.
web browser.an application software for accessing the World Wide Web.
When a user requests a web page from a particular website, the web browser
retrieves the necessary content from a web server and then displays the page
on the user’s device.
URL (Uniform Resource Locator).the address of a web page.
protocol.a system of rules that allows two or more entities of a communica-
tions system to transmit information. The protocol defines the rules, syntax,
semantics and synchronization of communication and possible error recovery
methods.
server.a computer or computer program which manages access to a centralized
resource or service in a network.
query string.the part of a URL that assigns values to specified parameters,
such as a search query in Google
HTML(Hypertext Markup Language) pages:.the standard markup lan-
guage for documents designed to be displayed in a web browser. It tells the
web browser that the user sees how it should look and what information should
be on the page.
IP address.a special address indicating the request came from the browser on
the same computer that the Flask server is running on.
Chapter 15
15.2.2 Messages
A messagebox can display information to a user. There are three variations
on these dialog boxes based on the type of message you want to display. The
functions’ first parameter gives a name for the dialog box which is displayed in
the window’s header. The second parameter is the text of the message. The
functions return a string which is typically ignored.
276
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 277
application_window = tk . Tk ()
minvalue =0.0 ,
maxvalue =100000.0)
if answer is not None :
print ( " Your ␣ salary ␣ is ␣" , answer )
else :
print ( " You ␣ don ' t␣ have ␣a␣ salary ? " )
application_window = tk . Tk ()
# Build a list of tuples for each file type the file dialog
should display
my_filetypes = [( ' all ␣ files ' , ' .* ' ) , ( ' text ␣ files ' , ' . txt ' )]
saving : " ,
filetypes = my_filetypes )
rgb_color , web_color =
colorchooser . askcolor ( parent = application_window ,
initialcolor =(255 ,
0, 0) )
Table 15.3.1
Widget Purpose
tk.Button, ttk.Button Execute a specific task; a “do this now” command.
tk.Menu Implements toplevel, pulldown, and popup menus.
ttk.Menubutton Displays popup or pulldown menu items when activated.
tk.OptionMenu Creates a popup menu, and a button to display it.
tk.Entry, ttk.Entry Enter one line of text.
tk.Text Display and edit formatted text, possibly with multiple lines.
tk.Checkbutton, ttk.Checkbutton Set on-off, True-False selections.
tk.Radiobutton, ttk.Radiobutton Allow one-of-many selections.
tk.Listbox Choose one or more alternatives from a list.
ttk.Combobox Combines a text field with a pop-down list of values.
tk.Scale, ttk.Scale Select a numerical value by moving a “slider” along a scale.
The following figure shows examples of these widgets. You can download
and run this python program, all_user_input_widgets.py1 , to interact with
the widgets.
and relocate widgets every time you develop a GUI program! Therefore, layout
managers are included in the Tkinter module to do this work for you. You just
have to give some basic positioning information to a layout manager so it can
calculate a position and a size for each widget.
There are three layout managers in the Tkinter module:
Table 15.4.1
Layout Manager Description
place You specify the exact size and position of each widget.
pack You specify the size and position of each widget relative to each other.
grid You place widgets in a cell of a 2-dimensional table defined by rows and columns.
You should never mix and match these layout managers. Use only one of
them for the widget layout within a particular “parent widget”. (Widgets are
organized in a hierarchy, which is explained in the next lesson.)
# or
programs this is typically sufficient. But for more complex programs you might
need to process “lower level” events, such as recognizing when the user’s cursor
is over a widget, or when a widget becomes the focus of user input. To handle
these types of events you need to implement event binding. This lesson
provides an overview of how to process any event that happens on a computer.
We will not use these techniques in most of the simple GUI programs we discuss,
but you should be aware of what is possible.
global my_counter
def increment_counter () :
global my_counter
my_counter [ ' text ' ] = str ( int ( my_counter [ ' text ' ]) + 1)
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 284
create_user_interface ( window )
def main () :
# Create the entire GUI program
program = CounterProgram ()
class CounterProgram :
• The code creates an instance of the class CounterProgram and starts the
GUI event-loop.
html
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 286
Every widget has an after method that will generate an event at a specific
time interval from the time it is called. The method takes at least 2 arguments:
the amount of time (in milliseconds) to wait before generating the event, and
the callback function to call after the time has elapsed. In the example below,
the function a_callback_function will be called one second (1000 milliseconds)
after the timer-event was created.
def a_callback_function () :
print ( " a_callback_function ␣ was ␣ called ." )
1 Using scratch paper, physically draw a rough sketch of your user interface.
2 Create the basic structure of your program and create the major frames
that will hold the widgets needed for your program’s interface. Give the
frames an initial size and color so that you can visually see them, given
that there are no widgets inside of them to determine their size.
3 Incrementally add all of the widgets you need for your program and size
and position them appropriately.
4 Create your callback functions, stub them out, and assign them to appro-
priate events. Verify that the events are executing the correct functions.
5 Incrementally implement the functionality needed for each callback func-
tion.
When you develop code using incremental development your program should
always be executable. You continually add a few lines of code and then test
them. If errors occur you almost always know were the errors came from! They
came from the lines of code you just added.
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 288
class WhackAMole :
import tkinter as tk
from tkinter import PhotoImage
def main () :
# Create the entire GUI program
program = WhackAMole ()
class WhackAMole :
NUM_MOLES_ACROSS = 4
mole_buttons = []
for r in range ( WhackAMole . NUM_MOLES_ACROSS ):
row_of_buttons = []
for c in range ( WhackAMole . NUM_MOLES_ACROSS ):
mole_button = tk . Button ( self . mole_frame ,
image = self . mole_photo )
mole_button . grid ( row =r , column =c , padx =8 ,
pady =8)
return mole_buttons
def main () :
# Create the entire GUI program
program = WhackAMole ()
class WhackAMole :
STATUS_BACKGROUND = " white "
NUM_MOLES_ACROSS = 4
mole_buttons = []
for r in range ( WhackAMole . NUM_MOLES_ACROSS ):
row_of_buttons = []
for c in range ( WhackAMole . NUM_MOLES_ACROSS ):
mole_button = tk . Button ( self . mole_frame ,
image = self . mole_photo )
mole_button . grid ( row =r , column =c , padx =8 ,
pady =8)
return mole_buttons
def main () :
# Create the entire GUI program
program = WhackAMole ()
class WhackAMole () :
STATUS_BACKGROUND = " white "
NUM_MOLES_ACROSS = 4
4 ../_static/Programs/whack_a_mole_v4.py
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 293
self . set_callbacks ()
mole_buttons = []
for r in range ( WhackAMole . NUM_MOLES_ACROSS ):
row_of_buttons = []
for c in range ( WhackAMole . NUM_MOLES_ACROSS ):
mole_button = tk . Button ( self . mole_frame ,
image = self . mole_photo )
mole_button . grid ( row =r , column =c , padx =8 ,
pady =8)
return mole_buttons
that matches the frame’s background, and the other image is a picture of a
mole. By replacing the image used for each label we can make the moles visible
or invisible. A label normally does not have an associated callback, so we bind
a left mouse click event, "<ButtonPress-1>" to each label. We can determine
whether the mouse click is a “hit” or a “miss” by examining the label under
the click to see which image is currently set to the label. We use timer events
to change the image on each label. Also notice the use of a messagebox to
protect the program from accidental quitting. The end result is shown below.
(whack_a_mole_v5.py5 )
import tkinter as tk
from tkinter import PhotoImage
from tkinter import messagebox
from random import randint
def main () :
# Create the entire GUI program
program = WhackAMole ()
class WhackAMole :
STATUS_BACKGROUND = " white "
NUM_MOLES_ACROSS = 4
MIN_TIME_DOWN = 1000
MAX_TIME_DOWN = 5000
MIN_TIME_UP = 1000
MAX_TIME_UP = 3000
self . set_callbacks ()
self . game_is_running = False
mole_labels = []
for r in range ( WhackAMole . NUM_MOLES_ACROSS ):
row_of_labels = []
for c in range ( WhackAMole . NUM_MOLES_ACROSS ):
mole_label = tk . Label ( self . mole_frame ,
image = self . mole_photo )
mole_label . grid ( row =r , column =c ,
sticky = tk . E + tk . W + tk . N + tk . S )
self . label_timers [ id ( mole_label )] = None
return mole_labels
if self . game_is_running :
hit_label = event . widget
if hit_label [ ' image ' ] ==
self . mole_cover_photo . name :
# MISSED ! Update the miss counter
self . miss_counter [ ' text ' ] =
str ( int ( self . miss_counter [ ' text ' ]) + 1)
else :
# HIT ! Update the hit counter
self . hit_counter [ ' text ' ] =
str ( int ( self . hit_counter [ ' text ' ]) + 1)
# Remove the mole and don ' t update the miss
counter
self . put_down_mole ( hit_label , False )
if self . game_is_running :
if timer_expired :
# The mole is going down before it was
clicked on , so update the miss counter
self . miss_counter [ ' text ' ] =
str ( int ( self . miss_counter [ ' text ' ]) + 1)
else :
# The timer did not expire , so manually
stop the timer
the_label . after_cancel ( self . label_timers [ id ( the_label ) ])
if self . game_is_running :
# Set a call to make the mole disappear in the
future
time_up = randint ( WhackAMole . MIN_TIME_UP ,
WhackAMole . MAX_TIME_UP )
timer_object = the_label . after ( time_up ,
self . put_down_mole ,
the_label , True )
self . label_timers [ id ( the_label )] = timer_object
15.11.3 Summary
We developed a complete GUI application in 5 well-designed stages. Hopefully
you see the value in incremental software development.
However, the end result is not necessarily easy to understand or modify for
future enhancements. The next lesson will introduce a scheme for breaking
complete software into more managable pieces.
The controller∗ needs to recognize these events and send them to appropri-
ate methods in the model. The controller needs to define callback functions for
these events and register the appropriate event with the appropriate callback.
Therefore, the controller needs access to the widgets in the view object. This
can easily be accomplished by passing a reference to the view object to the
controller when it is created. Summary ——-
CHAPTER 15. GUI AND EVENT DRIVEN PROGRAMMING 301
15.13 Exercises
This page left intentionally blank
15.14 Glossary
Glossary
icon.A small picture that represents some functionality in a computer program.
A user clicks on an icon to cause an action to be performed by a program.
widget.A visual element of a graphical user interface that allows a user to
give commands to an executing program. Example widgets include a command
button, a slider bar, or a list box.
graphical user interface.A user interacts with a computer program by point-
ing, clicking, and dragging icons and widgets in a window on a computer screen.
GUI.An abbreviation for a “graphical user interface.”
event-driven programming.A program that only executes tasks when a user
specially requests a task.
event loop.A built-in function of a GUI toolkit that “listens” for operating
system events and then calls an appropriate event-handler for each event.
event-handler.A function that processes an event. These functions are also
called callback functions.
Chapter 16
Recursion
302
CHAPTER 16. RECURSION 303
Python lists. We might say the the sum of the list numList is the sum of the
first element of the list (numList[0]), and the sum of the numbers in the rest
of the list (numList[1:]). To state it in a functional form:listSum(numList) =
first(numList) + listSum(rest(numList)) \label{eqn:listsum}In this equation
first(numList) returns the first element of the list and rest(numList) returns a
list of everything but the first element. This is easily expressed in Python.
def listsum ( numList ):
if len ( numList ) == 1:
return numList [0]
else :
return numList [0] + listsum ( numList [1:])
Let’s look at each one of these laws in more detail and see how it was used
in the listsum algorithm. First, a base case is the condition that allows the
algorithm to stop recursing. A base case is typically a problem that is small
enough to solve directly. In the listsum algorithm the base case is a list of
length 1.
To obey the second law, we must arrange for a change of state that moves
the algorithm toward the base case. A change of state means that some data
that the algorithm is using is modified. Usually the data that represents our
problem gets smaller in some way. In the listsum algorithm our primary data
structure is a list, so we must focus our state-changing efforts on the list. Since
the base case is a list of length 1, a natural progression toward the base case is
to shorten the list. This is exactly what happens on line 5 of the ActiveCode
in Section 16.2 when we call listsum with a shorter list.
The final law is that the algorithm must call itself. This is the very definition
of recursion. Recursion is a confusing concept to many beginning programmers.
As a novice programmer, you have learned that functions are good because you
can take a large problem and break it up into smaller problems. The smaller
problems can be solved by writing a function to solve each problem. When we
talk about recursion it may seem that we are talking ourselves in circles. We
have a problem to solve with a function, but that function solves the problem
by calling itself! But the logic is not circular at all; the logic of recursion is an
elegant expression of solving a problem by breaking it down into a smaller and
easier problems.
In the remainder of this chapter we will look at more examples of recursion.
In each case we will focus on designing a solution to a problem by using the
three laws of recursion.
CHAPTER 16. RECURSION 305
Checkpoint 16.3.1 How many recursive calls are made when computing the
sum of the list [2,4,6,8,10]?
A. 6
B. 5
C. 4
D. 3
Checkpoint 16.3.2 Suppose you are going to write a recusive function to
calculate the factorial of a number. fact(n) returns n ∗ n-1 ∗ n-2 ∗ … ∗ 1, and
the factorial of zero is definded to be 1. What would be the most appropriate
base case?
A. n == 0
B. n == 1
C. n >= 0
D. n <= 1
The next step is to figure out how to change state and make progress
toward the base case. Since we are working with an integer, let’s consider what
mathematical operations might reduce a number. The most likely candidates
are division and subtraction. While subtraction might work, it is unclear what
we should subtract from what. Integer division with remainders gives us a
clear direction. Let’s look at what happens if we divide a number by the base
we are trying to convert to.
Using integer division to divide 769 by 10, we get 76 with a remainder of 9.
This gives us two good results. First, the remainder is a number less than our
CHAPTER 16. RECURSION 306
Figure 16.4.2 Figure 4: Converting the Number 10 to its Base 2 String Rep-
resentation
Figure 16.4.2 shows that we get the results we are looking for, but it looks
like the digits are in the wrong order. The algorithm works correctly because
we make the recursive call first on line 6, then we add the string representation
of the remainder. If we reversed returning the convertString lookup and
returning the toStr call, the resulting string would be backward! But by
delaying the concatenation operation until after the recursive call has returned,
we get the result in the proper order.
Note 16.4.3 Self Check. Write a function that takes a string as a parameter
and returns a new string that is the reverse of the old string.
from test import testEqual
def reverse ( s ):
return s
• kayak
• aibohphobia
• Live not on evil
def isPal ( s ):
return False
Listing 1.
CHAPTER 16. RECURSION 309
def main () :
t = turtle . Turtle ()
myWin = turtle . Screen ()
t . left (90)
t . up ()
t . backward (100)
t . down ()
t . color ( " green " )
tree (75 , t )
myWin . exitonclick ()
main ()
Notice how each branch point on the tree corresponds to a recursive call,
and notice how the tree is drawn to the right all the way down to its shortest
twig. You can see this in Figure 16.5.1. Now, notice how the program works
its way back up the trunk until the entire right side of the tree is drawn. You
can see the right half of the tree in Figure 16.5.2. Then the left side of the
tree is drawn, but not by going as far out to the left as possible. Rather, once
again the entire right side of the left tree is drawn until we finally make our
way out to the smallest twig on the left.
CHAPTER 16. RECURSION 310
hello world
Figure 16.5.2 Figure 2: The First Half of the Tree
This simple tree program is just a starting point for you, and you will notice
that the tree does not look particularly realistic because nature is just not as
symmetric as a computer program. Here are a few ideas for how to explore
some interesting options to make your tree look more realistic.
Note 16.5.3 Self Check. Modify the recursive tree program using one or
all of the following ideas:
• Modify the angle used in turning the turtle so that at each branch point
the angle is selected at random in some range. For example choose the
angle between 15 and 45 degrees. Play around to see what looks good.
• Modify the branchLen recursively so that instead of always subtracting
the same amount you subtract a random amount in some range.
CHAPTER 16. RECURSION 311
def getMid ( p1 , p2 ):
return ( ( p1 [0]+ p2 [0]) / 2, ( p1 [1] + p2 [1]) / 2)
def main () :
myTurtle = turtle . Turtle ()
myWin = turtle . Screen ()
myPoints = [[ -100 , -50] ,[0 ,100] ,[100 , -50]]
sierpinski ( myPoints ,3 , myTurtle )
myWin . exitonclick ()
main ()
This program follows the ideas outlined above. The first thing sierpinski
does is draw the outer triangle. Next, there are three recursive calls, one for
each of the new corner triangles we get when we connect the midpoints.
Look at the code and think about the order in which the triangles will be
drawn. While the exact order of the corners depends upon how the initial set is
specified, let’s assume that the corners are ordered lower left, top, lower right.
Because of the way the sierpinski function calls itself, sierpinski works its
way to the smallest allowed triangle in the lower-left corner, and then begins
to fill out the rest of the triangles working back. Then it fills in the triangles
in the top corner by working toward the smallest, topmost triangle. Finally, it
fills in the lower-right corner, working its way toward the smallest triangle in
the lower right.
Sometimes it is helpful to think of a recursive algorithm in terms of a
diagram of function calls. Figure 16.6.2 shows that the recursive calls are
always made going to the left. The active functions are outlined in black, and
the inactive function calls are in gray. The farther you go toward the bottom
of Figure 16.6.2, the smaller the triangles. The function finishes drawing one
level at a time; once it is finished with the bottom left it moves to the bottom
middle, and so on.
CHAPTER 16. RECURSION 313
16.7 Glossary
Glossary
base case.A branch of the conditional statement in a recursive function that
does not give rise to further recursive calls.
data structure.An organization of data for the purpose of making it easier
to use.
immutable data type.A data type which cannot be modified. Assignments
to elements or slices of immutable types cause a runtime error.
infinite recursion.A function that calls itself recursively without ever reach-
ing the base case. Eventually, an infinite recursion causes a runtime error.
mutable data type.A data type which can be modified. All mutable types
are compound types. Lists and dictionaries (see next chapter) are mutable
data types; strings and tuples are not.
recursion.The process of calling the function that is already executing.
recursive call.The statement that calls an already executing function. Recur-
sion can even be indirect — function f can call g which calls h, and h could
make a call back to f.
recursive definition.A definition which defines something in terms of itself.
To be useful it must include base cases which are not recursive. In this way it
differs from a circular definition. Recursive definitions often provide an elegant
way to express complex data structures.
tuple.A data type that contains a sequence of elements of any type, like a list,
but is immutable. Tuples can be used wherever an immutable type is required,
such as a key in a dictionary (see next chapter).
tuple assignment.An assignment to all of the elements in a tuple using a
single assignment statement. Tuple assignment occurs in parallel rather than
in sequence, making it useful for swapping values.
CHAPTER 16. RECURSION 314
====
====
myTests () . main ()
Checkpoint 16.8.3 Modify the recursive tree program using one or all of the
following ideas:
• Modify the thickness of the branches so that as the branchLen gets
CHAPTER 16. RECURSION 315
• Modify the angle used in turning the turtle so that at each branch point
the angle is selected at random in some range. For example choose the
angle between 15 and 45 degrees. Play around to see what looks good.
• Modify the branchLen recursively so that instead of always subtracting
the same amount you subtract a random amount in some range.
If you implement all of the above ideas you will have a very realistic looking
tree.
Checkpoint 16.8.4 Find or invent an algorithm for drawing a fractal moun-
tain. Hint: One approach to this uses triangles again.
Checkpoint 16.8.5 Write a recursive function to compute the Fibonacci se-
quence. How does the performance of the recursive function compare to that
of an iterative version?
Checkpoint 16.8.6 Implement a solution to the Tower of Hanoi using three
stacks to keep track of the disks.
Checkpoint 16.8.7 Using the turtle graphics module, write a recursive pro-
gram to display a Hilbert curve.
Checkpoint 16.8.8 Using the turtle graphics module, write a recursive pro-
gram to display a Koch snowflake.
Checkpoint 16.8.9 Write a program to solve the following problem: You have
two jugs: a 4-gallon jug and a 3-gallon jug. Neither of the jugs have markings
on them. There is a pump that can be used to fill the jugs with water. How
can you get exactly two gallons of water in the 4-gallon jug?
Checkpoint 16.8.10 Generalize the problem above so that the parameters to
your solution include the sizes of each jug and the final amount of water to be
left in the larger jug.
Checkpoint 16.8.11 Write a program that solves the following problem:
Three missionaries and three cannibals come to a river and find a boat that
holds two people. Everyone must get across the river to continue on the jour-
ney. However, if the cannibals ever outnumber the missionaries on either bank,
the missionaries will be eaten. Find a series of crossings that will get everyone
safely to the other side of the river.
Checkpoint 16.8.12 Modify the Tower of Hanoi program using turtle graphics
to animate the movement of the disks. Hint: You can make multiple turtles
and have them shaped like rectangles.
Checkpoint 16.8.13 Pascal’s triangle is a number triangle with numbers
arranged in staggered rows such thata_{nr} = {n! \over{r! (n-r)!}}This equa-
tion is the equation for a binomial coefficient. You can build Pascal’s triangle
by adding the two numbers that are diagonally above a number in the triangle.
An example of Pascal’s triangle is shown below.
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
CHAPTER 16. RECURSION 316
Write a program that prints out Pascal’s triangle. Your program should accept
a parameter that tells how many rows of the triangle to print.
16.9 Exercises
Adding this blank exercises page to hold instructor written questions.
Chapter 17
317
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 318
from the functions onto the objects makes it possible to write more versatile
functions and makes it easier to maintain and reuse code.
The most important advantage of the object-oriented style is that it fits our
mental chunking and real-life experience more accurately. In real life our cook
method is part of our microwave oven — we don’t have a cook function sitting
in the corner of the kitchen, into which we pass the microwave! Similarly, we
use the cellphone’s own methods to send an sms, or to change its state to silent.
The functionality of real-world objects tends to be tightly bound up inside the
objects themselves. OOP allows us to accurately mirror this when we organize
our programs.
Some of the typical operations that one associates with points might be to
ask the point for its x coordinate, getX, or to ask for its y coordinate, getY.
You may also wish to calculate the distance of a point from the origin, or the
distance of a point from another point, or find the midpoint between two points,
or answer the question as to whether a point falls within a given rectangle or
circle. We’ll shortly see how we can organize these together with the data.
Now that we understand what a point object might look like, we can define
a new class. We’ll want our points to each have an x and a y attribute, so our
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 320
print ( " Nothing ␣ seems ␣ to ␣ have ␣ happened ␣ with ␣ the ␣ points " )
During the initialization of the objects, we created two attributes called x
and y for each, and gave them both the value 0.
Note 17.4.1 The asignments are not to x and y, but to self.x and self.y.
The attributes x and y are always attached to a particular instance. The
instance is always explicitly referenced with dot notation.
You will note that when you run the program, nothing happens. It turns
out that this is not quite the case. In fact, two Points have been created, each
having an x and y coordinate with value 0. However, because we have not
asked the point to do anything, we don’t see any other result.
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 321
print ( " Nothing ␣ seems ␣ to ␣ have ␣ happened ␣ with ␣ the ␣ points " )
The following program adds a few print statements. You can see that the
output suggests that each one is a Point object. However, notice that the is
operator returns False meaning that they are different objects (we will have
more to say about this in a later chapter).
class Point :
""" Point class for representing and manipulating x , y
coordinates . """
print ( p )
print ( q )
print ( p is q )
This should look familiar — we’ve used classes before to create more than
one object:
from turtle import Turtle
A function like Turtle or Point that creates a new object instance is called
a constructor. Every class automatically uses the name of the class as the
name of the constructor function. The definition of the constructor function is
done when you write the __init__ function.
It may be helpful to think of a class as a factory for making objects. The
class itself isn’t an instance of a point, but it contains the machinery to make
point instances. Every time you call the constructor, you’re asking the factory
to make you a new object. As the object comes off the production line, its
initialization method is executed to get the object properly set up with its
factory default settings.
The combined process of “make me a new object” and “get its settings
initialized to the factory default settings” is called instantiation.
Check Your Understanding
Checkpoint 17.4.2 What is the the output of the following print code?
class Car :
x = BMW is Tesla
y = type ( BMW ) == type ( Tesla )
print (x , y )
A. True True
B. True False
C. False True
D. False False
p = Point (7 , 6)
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 323
p = Point (7 , 6)
print ( p . getX () )
print ( p . getY () )
Note that the getX method simply returns the value of self.x from the
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 324
p = Point (7 , 6)
print ( p . distanceFromOrigin () )
Notice that the caller of distanceFromOrigin does not explicitly supply
an argument to match the self parameter. This is true of all method calls.
The definition will always have one additional parameter as compared to the
invocation.
class Point :
""" Point class for representing and manipulating x , y
coordinates . """
return self . y
p = Point (4 , 3)
q = Point (0 , 0)
print ( distance (p , q ))
distance takes two points and returns the distance between them. Note
that distance is not a method of the Point class. You can see this by looking
at the indentation pattern. It is not inside the class definition. The other
way we can know that distance is not a method of Point is that self is not
included as a formal parameter. In addition, we do not invoke distance using
the dot notation.
p = Point (7 , 6)
print ( p )
The print function shown above produces a string representation of the
Point p. The default functionality provided by Python tells you that p is an
object of type Point. However, it does not tell you anything about the specific
state of the point.
We can improve on this representation if we include a special method call
__str__. Notice that this method uses the same naming convention as the
constructor, that is two underscores before and after the name. It is common
that Python uses this naming technique for special methods.
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 326
p = Point (7 , 6)
print ( p )
When we run the program above you can see that the print function now
shows the string that we chose.
Now, you ask, don’t we already have an str type converter that can turn
our object into a string? Yes we do!
And doesn’t print automatically use this when printing things? Yes again!
But, as we saw earlier, these automatic mechanisms do not do exactly what
we want. Python provides many default implementations for methods that we
as programmers will probably want to change. When a programmer changes
the meaning of a special method we say that we override the method. Note
also that the str type converter function uses whatever __str__ method we
provide.
p = Point (3 , 4)
q = Point (5 , 12)
mid = p . halfway ( q)
print ( mid )
print ( mid . getX () )
print ( mid . getY () )
The resulting Point, mid, has an x value of 4 and a y value of 8. We can
also use any other methods since mid is a Point object.
In the definition of the method halfway see how the requirement to always
use dot notation with attributes disambiguates the meaning of the attributes
x and y: We can always see whether the coordinates of Point self or target
are being referred to.
Note 17.9.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
17.10 Glossary
Glossary
attribute.One of the named data items that makes up an instance.
class.A class can be thought of as a template for the objects that are instances
of it. It defines a data type. A class can be provided by the Python system or
be user-defined.
constructor.Every class has a “factory”, called by the same name as the class,
for making new instances. If the class has an initializer method, this method
is used to get the attributes (i.e. the state) of the new object properly set up.
initializer method.A special method in Python (called __init__) that is
invoked automatically to set a newly-created object’s attributes to their initial
(factory-default) state.
instance.An object whose type is of some class. Instance and object are used
interchangeably.
instantiate.To create an instance of a class, and to run its initializer.
CHAPTER 17. CLASSES AND OBJECTS - THE BASICS 328
17.11 Exercises
1. Add a distanceFromPoint method that works similar to distanceFromOrigin
except that it takes a Point as a parameter and computes the distance
between that point and self.
2. Add a method reflect_x to Point which returns a new Point, one which
is the reflection of the point about the x-axis. For example, Point(3,
5).reflect_x() is (3, -5)
3. Add a method slope_from_origin which returns the slope of the line
joining the origin to the point. For example,
18.1 Fractions
We have all had to work with fractions when we were younger. Or, perhaps
you do a lot of cooking and have to manage measurements for ingredients. In
any case, fractions are something that we are familiar with. In this chapter we
will develop a class to represent a fraction including some of the most common
methods that we would like fractions to be able to do.
A fraction is most commonly thought of as two integers, one over the other,
with a line separating them. The number on the top is called the numerator
and the number on the bottom is called the denominator. Sometimes people
use a slash for the line and sometimes they use a straight line. The fact is
that it really does not matter so long as you know which is the numerator and
which is the denominator.
To design our class, we simply need to use the analysis above to realize that
the state of a fraction object can be completely described by representing two
integers. We can begin by implementing the Fraction class and the __init__
method which will allow the user to provide a numerator and a denominator
for the fraction being created.
class Fraction :
myfraction = Fraction (3 , 4)
print ( myfraction )
329
CHAPTER 18. CLASSES AND OBJECTS - DIGGING A LITTLE DEEPER330
m = oldn
n = oldm % oldn
return n
m = oldn
n = oldm % oldn
return n
class Fraction :
print ( myfraction )
myfraction . simplify ()
print ( myfraction )
There are two important things to note about this implementation. First,
the gcd function is not a method of the class. It does not belong to Fraction.
Instead it is a function that is used by Fraction to assist in a task that needs
to be performed. This type of function is often called a helper function.
Second, the simplify method does not return anything. Its job is to modify
the object itself. This type of method is known as a mutator method because
it mutates or changes the internal state of the object.
18.3 Sameness
The meaning of the word same seems perfectly clear until you give it some
thought and then you realize there is more to it than you expected.
For example, if you say, Chris and I have the same car, you mean that his
car and yours are the same make and model, but that they are two different
cars. If you say, Chris and I have the same mother, you mean that his mother
and yours are the same person.
When you talk about objects, there is a similar ambiguity. For example, if
two Fractions are the same, does that mean they represent the same rational
number or that they are actually the same object?
We’ve already seen the is operator in the chapter on lists, where we talked
about aliases. It allows us to find out if two references refer to the same object.
class Fraction :
bottom
myfraction = Fraction (3 , 4)
yourfraction = Fraction (3 , 4)
print ( myfraction is yourfraction )
ourfraction = myfraction
print ( myfraction is ourfraction )
Even though myfraction and yourfraction refer to the same rational num-
ber, they are not the same object.
class Fraction :
myfraction = Fraction (3 , 4)
yourfraction = Fraction (3 , 4)
print ( myfraction is yourfraction )
print ( sameRational ( myfraction , yourfraction ))
notInLowestTerms = Fraction (15 , 20)
print ( sameRational ( myfraction , notInLowestTerms ))
Of course, if the two variables refer to the same object, they have both
shallow and deep equality.
Note 18.3.1 Beware of ==. “When I use a word,” Humpty Dumpty said,
in a rather scornful tone, “it means just what I choose it to mean — neither
more nor less.” Alice in Wonderland
Python has a powerful feature that allows a designer of a class to decide
what an operation like == or < should mean. (We’ve just shown how we can
control how our own objects are converted to strings, so we’ve already made
a start!) We’ll cover more detail later. But sometimes the implementors will
attach shallow equality semantics, and sometimes deep equality, as shown in
this little experiment:
p = Point (4 , 2)
s = Point (4 , 2)
print ( " == ␣ on ␣ Points ␣ returns " , p == s ) # by default , ==
does a shallow equality test here
a = [2 , 3]
b = [2 , 3]
print ( " == ␣ on ␣ lists ␣ returns " , a == b ) # by default , ==
does a deep equality test on lists
This outputs:
tions if they have the same denominator. The easiest way to find a common
denominator is to multiply the two individual denominators together. Any-
thing we do to the denominator needs to the done to the numerator. This
gives us the following equation for fraction addition:
a/b + c/d = (ad + cb)/bd
Our add method will take a Fraction as a parameter. It will return a new
Fraction representing the sum. We will use the equation shown above to
compute the new numerator and the new denominator. Since this equation
will not give us lowest terms, we will utilize a similar technique as was used
in the simplify method to find the greatest common divisor and then divide
each part of the new fraction.
def add ( self , otherfraction ):
m = oldn
n = oldm % oldn
return n
class Fraction :
f1 = Fraction (1 , 2)
f2 = Fraction (1 , 4)
f3 = f1 . add ( f2 )
print ( f3 )
One final modification to this method will be quite useful. Instead invoking
the add method, we can use the addition operator “+”. This requires that we
implement another special method, this time called __add__. The details of
the method are the same.
def __add__ ( self , otherfraction ):
Note 18.4.1 This workspace is provided for your convenience. You can use
this activecode window to try out anything you like.
18.5 Glossary
Glossary
deep copy.To copy the contents of an object as well as any embedded objects,
and any objects embedded in them, and so on; implemented by the deepcopy
function in the copy module.
deep equality.Equality of values, or two references that point to objects that
have the same value.
shallow copy.To copy the contents of an object, including any references to
embedded objects; implemented by the copy function in the copy module.
shallow equality.Equality of references, or two references that point to the
same object.
18.6 Exercises
1. We can represent a rectangle by knowing three things: the location of its
lower left corner, its width, and its height. Create a class definition for a
Rectangle class using this idea. To create a Rectangle object at location
(4,5) with width 6 and height 5, we would do the following:
r = Rectangle(Point(4, 5), 6, 5)
CHAPTER 18. CLASSES AND OBJECTS - DIGGING A LITTLE DEEPER336
Inheritance
p = Point (7 , 6)
print ( p )
Now, suppose we want to create a class that works like Point in every re-
spect, but also keeps track of a short description for the point. We could create
a LabeledPoint class by copying and pasting the definition for Point, chang-
ing the name to LabeledPoint, and modifying the class to suit our purposes.
However, any time you copy and paste code, keep in mind that you are copying
and pasting bugs that may exist in the code. Inheritance provides a way to
reuse the definition of Point without having to copy and paste.
We begin like this:
337
CHAPTER 19. INHERITANCE 338
ptStr = str ( pt )
labeledPtStr = str ( labeledPt )
In Line 4, the call to str(pt) invokes the __str__() method in Point,
because pt refers to an instance of Point. In Line 5, the call to str(labeledPt)
invokes the __str__() method in LabeledPoint, because labeledPt refers to
an instance of LabeledPoint.
19.3 Extending
If you compare the code in the __init__ methods of Point and LabeledPoint,
you can see that there is some duplication–the initialization of x and y. We
can eliminate the duplication by having LabeledPoint’s __init__() method
invoke Point’s __init__() method. That way, each class will be responsible
for initializing its own instance variables.
A method in a child class that overrides a method in the parent can invoke
the overridden method using super(), like this:
CHAPTER 19. INHERITANCE 339
class LabeledPoint :
and height. From a pure code reuse standpoint, inheritance seems plausible.
But wait–let’s apply the “is-a” linguistic test. Filling in the blanks in the
sentence template above, we get: “Rectangle is a type of Point.” Most people
would feel there is something wrong with that statement. A rectangle is not
a more specific type of a point. A rectangle contains points and consists of
points, but is not itself a point. Thus, it fails the linguistic test; composition
is the better choice here.
So what happens if you decide to ignore the linguistic test and go ahead and
make Rectangle inherit from Point? In some cases, you won’t run into trouble
right away. Often, the difficulties don’t start to crop up until later, when you
decide to add more methods to Point (the parent) that aren’t appropriate for
Rectangle (the child). This leads to a program that is confusing to understand
and contains bugs that occur when methods intended for Point are invoked
on Rectangle instances by mistake. Also, since inheritance is the strongest
form of relationship between classes, changes to code in a parent class have a
stronger likelihood of breaking code in its children than would tend to occur if
composition were used.
Inheritance is a powerful feature and, when used appropriately, a terrific
way to reuse code. But, like most power tools, it can cut you up pretty badly
if you don’t know what you are doing. Use it with caution and respect.
Acme Corporation
Mr. Abe Jones
Somewhere Ln 123
29609 SC Greenville
NETHERLANDS
Addresses in Ireland are complex, having up to 12 parts (such as building name
and number, primary and secondary thoroughfare, primary and secondary lo-
cality, town, county, …) plus an Eircode, a unique identifier assigned to each
of the ~2 million addresses in Ireland. For example, Abe might live at the
following address (English translation is given in parentheses, and would be
omitted):
CHAPTER 19. INHERITANCE 343
Abe Jones
Cnoc na Sceiche (The Hill of the Thorn)
Leac an Anfa (The Flagstone of the Storm)
Cathair na Mart (The City of the Beeves)
Co. Mhaigh Eo (The County of the Plain of the Yews)
A65 F4E2
IRELAND
(One would think that since each address has its own unique Eircode, it ought
to be possible to address mail to Abe Jones, A65 F4E2, IRELAND. On second
thought, perhaps that is not such a great idea. Can you imagine the practical
concerns with such a scheme?)
addr = Address ( ' Abe ␣ Jones ' , [ ' 123 ␣ Somewhere ␣ Ln ' ,
' Greenville ,␣ SC ␣␣ 29609 ' ], ' USA ' )
print ( addr )
This approach treats an address as a collection of unstructured bits of
information. If we want to look up an address, we can search by full name or
country, but if we want to find all addresses in Greenville, or all addresses in
zip code 29609, we can’t do it very easily, since information such as city and
zip code is mashed together in an unstructured address line along with the
state abbreviation.
An approach that stores addresses as structured pieces of information might
look like this:
class StructuredAddress :
def __init__ ( self , country , recipient , street , city ,
state , postalCode ) :
self . country = country
self . recipient = recipient
self . street = street
self . city = city
self . state = state
self . postalCode = postalCode
addr = StructuredAddress ( ' USA ' , ' Abe ␣ Jones ' , ' 103 ␣ Anywhere ␣
Ln ' ,
' Greenville ' , ' SC ' , ' 29609 ' )
addr . display ()
Now, if we have a list of StructuredAddress objects and we want to find all
of the ones that hold addresses in Greenville, we can do it much more easily:
for addr in addrList :
if addr . city == ' Greenville ' :
addr . display ()
Now that you’ve learned about isinstance(), you should know that, like
inheritance itself, isinstance() should be used sparingly. Code that invokes
isinstance() is often performing work on an object that the object should be
designed to do itself, and is not utilizing inheritance and polymorphism to its
full potential.
To make this loop better utilize inheritance and polymorphism, we need
a way to test each address to see if it is in a given city. Let’s add a method
to BasePostalAddress for this purpose. It will return a boolean indicating
whether the address is in a certain city.
class BasePostalAddress :
...
...
Unit Testing
sum = 0
for i in range ( lo , hi +1) :
sum += i
return sum
print ( sumnums (1 , 3) )
print ( sumnums (3 , 1) )
Notice that the first call to sumnums produces the correct answer (6), while
the second call produces an incorrect answer. sumnums works correctly only if
lo has a value that is less than, or equal to, hi.
This function trusts the calling code to provide parameter values that are
valid. If the caller provides a second parameter that is lower than the first
parameter, the function does not produce a correct result. That’s not the fault
of the function; the function isn’t designed to work correctly if lo > hi.
To make it clear that the function is designed to work correctly only if
lo <= hi, it’s a good idea to state that as a precondition in the function
documentation, like this:
def sumnums(lo, hi):
"""returns the sum of the numbers in the range [lo..hi]
348
CHAPTER 20. UNIT TESTING 349
Precondition: lo <= hi
"""
Note 20.2.1 Precondition. A precondition specifies a condition that must
be True if the function is to produce correct results.
A precondition places a constraint on the values of the parameters that the
caller can pass and expect to receive a valid result. Preconditions are boolean
expressions – comparisons that you might write in an if statement. We’ll have
more to say about preconditions later in the chapter.
Code that calls a function is responsible for passing parameters that satisfy
the function’s preconditions. If the calling code passes values that violate the
function’s preconditions, the function isn’t expected to work correctly. That’s
not the function’s fault: it’s the caller’s fault for passing parameters to the
function that the function is not designed to handle correctly. However, it
might be a good idea if we designed the function to check for invalid values,
and when it detects them, somehow report that it was called incorrectly.
Precondition : lo <= hi
"""
if lo > hi :
print ( ' Alert :␣ Invalid ␣ parameters ␣ to ␣ sumnums . ' )
return -1
sum = 0
for i in range ( lo , hi +1) :
sum += i
return sum
print ( sumnums (1 , 3) )
print ( sumnums (3 , 1) )
In this version, the function checks to see if the preconditions are violated,
and if so, it complains by printing a message and returns the value -1 to the
caller.
Note 20.2.2 Defensive Programming. The strategy of designing func-
tions that check their parameters embodies a principle of software design called
defensive programming, in which software checks for invalid inputs and re-
sponds in an appropriate way. Defensive programming is especially important
for mission critical systems, but it can be a helpful strategy in regular software
projects, as we’ll soon see.
This is an improvement over the original function, because now, if the
function is called with invalid data, the user will see a message that something
CHAPTER 20. UNIT TESTING 350
is wrong. However, the if statement adds three lines of code to the function.
That may not seem like much, but it clutters the code and, in a typical program
with several functions, those if statements will start to feel like undesirable
baggage. There’s a better way.
Precondition : lo <= hi
"""
assert lo <= hi
sum = 0
for i in range ( lo , hi +1) :
sum += i
return sum
print ( sumnums (1 , 3) )
print ( sumnums (3 , 1) )
In this version of sumnums, we’ve replaced the if statement with an assert
statement. Notice that the boolean condition of the assert statement is the
precondition, lo <= hi. When the function is called, if the condition is true,
the function completes normally and returns its result. If the condition is false,
the program stops with an AssertionError. So, the first call to sumnums(1, 3)
succeeds and the result, 6, appears. The second call to sumnums(3, 1) causes
the assert to fail and an error appears.
Notice how much more streamlined this version of the function is than the
version with the three-line if statement. Here, we’ve added just one line of
code to the original version. Using assertions is a relatively low-effort way to
create defensive functions.
CHAPTER 20. UNIT TESTING 351
A. True
B. False
Checkpoint 20.2.7 Consider the following function. Which assert should be
added to check its precondition?
def getfirst ( msg ):
""" returns first character of msg
C. assert msg[0]
D. none of these
This function uses a valid approach to rounding, but is not quite correct
(Melinda doesn’t realize it yet — can you spot the bug?).
Now she needs to test the new code. There are two basic approaches
Melinda could take to do her testing:
1 Put the function into the program, modify the program to call the func-
tion at the appropriate point, then run the program.
2 Test the function by itself, somehow.
A unit test program like this one can dramatically reduce the effort it takes
to test a new function, and can reduce the overall effort involved in adding
functionality to a program. The savings tradeoff depends on the amount of
effort required to write the test program, compared to the amount of effort
required to test the function in the context of the main program for which
the new function is being developed. Here, the function was relatively simple,
and it probably wouldn’t have taken Melinda too many iterations of testing
the function in the context of the main program, with its five pieces of input.
In this scenario, Melinda may not have saved much effort. However, if the
function were more complex, writing a unit test would probably have helped
reduce the overall effort. And, using some tricks I’ll show you in the next
sections, you can reduce the amount of effort required to write and run the
unit test, making the case for writing unit tests even more compelling.
the test written, you can dramatically speed up your edit-test-debug cycle.
The downside, of course, is that the unit test program itself takes more time
to develop.
print("Test 2: FAIL")
A. Unit test
B. Tested function
sum = 0
def add(x, y):
global sum
sum = x + y
A. Yes.
B. No.
Precondition: lo <= hi
"""
...
Precondition: lo <= hi
Postcondition: returns the sum of the numbers in the range [lo..hi]
"""
...
This docstring contains three elements: a brief description; a precondition; and
a postcondition. We’ve discussed the concept of a precondition earlier in this
chapter. The postcondition is new.
Note 20.4.2 Postcondition. A postcondition states the work the function
completed by the function if the precondition is satisfied.
Functions that include a precondition and a postcondition in their docstring
embody a software engineering idea called design by contract. The idea is
that a function specification forms a contract between the function and the
code calling the function. If the code calling the function passes parameters
that satisfy the function’s precondition, then the function should be expected
to produce what it says it will produce. If the parameters do not satisfy the
function’s precondition, then the function does not have to produce a valid
result. In the design by contract approach, a testable function is one where
the function’s postcondition can be verified by an assert statement.
CHAPTER 20. UNIT TESTING 358
A. len(msg) <= 0
B. len(msg) > 0
C. msg == ””
D. none of these
Precondition: lo <= hi
Postcondition: returns the sum of the numbers in the range [lo..hi]
"""
sum = 0
for i in range(lo, hi+1):
sum += i
return sum
As we’ve seen, to write a unit test, you devise test cases for the function,
and then write assert statements that call the function and check that the
function produced the expected results. The following assert statements would
be appropriate for a unit test for sumnums:
assert sumnums(1, 3) == 6
assert sumnums(1, 1) == 1
But what about the following?
assert sumnums(3, 1) == 0
Note that sumnums produces the value 0 for cases where the lo values exceeds
the hi value, as is the case in this assert. So, like the first two asserts above,
this assert would pass. However, it is not an appropriate assertion, because
the specification says nothing about what the function produces if lo is greater
than hi.
The unit test should be written such that it passes even if the function
implementation is altered in a way that causes some other value than 0 to be
returned if lo exceeds hi. For example, we might want to redesign the function
to be more efficient — for example, use Gauss’s formula for summing numbers,
as in the following:
def sumnums(lo, hi):
"""computes the sum of a range of numbers
Precondition: lo <= hi
Postcondition: returns the sum of the numbers in the range [lo..hi]
"""
CHAPTER 20. UNIT TESTING 360
A. assert repeat(’∗’, 0) == ’’
B. assert repeat(’∗’, -1) == ’’
====
from unittest . gui import TestCaseGui
myTests () . main ()
5 Run the unit test. If it fails, debug the function, and run the test again.
Repeat until the test passes.
Precondition: lo <= hi
Postcondition: returns the sum of the numbers in the range [lo..hi]
"""
Next, we write the unit test for it:
def sumnums ( lo , hi ):
""" computes the sum of a range of numbers
Precondition : lo <= hi
Postcondition : returns the sum of the numbers in the
range [ lo .. hi ]
"""
assert sumnums (1 , 3) == 6
assert sumnums (1 , 1) == 1
print ( " All ␣ tests ␣ passed ! ")
We run the unit test and it fails.
Next, we implement the body of sumnums:
def sumnums ( lo , hi ):
""" computes the sum of a range of numbers
Precondition : lo <= hi
Postcondition : returns the sum of the numbers in the
range [ lo .. hi ]
"""
sum = 0
for i in range ( lo , hi ):
sum += i
return sum
assert sumnums (1 , 3) == 6
assert sumnums (1 , 1) == 1
print ( " All ␣ tests ␣ passed ! ")
Now, run the tests. The tests indicate an assertion error, which points to a
bug in the function logic. Fix the bug, and test again. (If you’re not sure what
the bug is, try using Show in CodeLens and stepping through the code to
help you figure it out.)
CHAPTER 20. UNIT TESTING 363
1 It ensures that unit tests are written. This tends to lead to higher-quality,
robust code, with fewer bugs.
2 Writing the tests first helps the programmer to clarify the function spec-
ification. It’s not possible to write an assert for a function that has a
vague function docstring. This process forces the programmer to write a
clear docstring and to practice specification-based testing, because when
the tests are written, there is no function implementation to reference.
3 When the programmer writes the function and is ready to test it, the
test is all ready to go. There is no internal struggle about whether a unit
test should be written or not. The programmer runs the test, and gets
instant feedback about whether the function is working or not.
4 If the function fails to pass the test, the benefits of unit testing in helping
the programmer to quickly diagnose and fix the problem are instantly
available. The test-debug cycle is rapid.
5 When a programmer modifies an existing function for which unit tests
already exist, perhaps to add some more functionality, the existing unit
tests serve as a safety net. They check that the modifications made by
the programmer don’t break any of the old functionality.
6 The overall development time tends to be reduced. Perhaps counter-
intuitively, writing more code (the unit tests) actually speeds up the
overall development process, because of the benefits imparted by unit
testing.
7 Believe it or not, there are psychological benefits. As the programmer
works on the project, creating little tests and then writing code that
passes those tests, there is a sense of accomplishment and satisfaction
that comes every time a new test passes. Instead of spending hours of
frustration debugging a new function in the context of a complex program,
with few visible results, the test-first progress leads to more visible and
regular successes.
I hope you’ll try out Test-First Development on your next assignment and
experience some of these benefits for yourself!
Check your understanding
Checkpoint 20.6.2 Test-First Development often involves writing more code
than traditional development.
A. True
B. False
CHAPTER 20. UNIT TESTING 364
def test_round6 () :
assert round6 (9.7) == 10
assert round6 (8.5) == 8
=====
pyTests () . main ()
This code example defines two functions: the function to be tested, round6,
and a function named test_round6 that contains unit test code. When using
the pytest approach, you write your unit test as a function whose name must
start with the prefix test_. Inside the function, you write normal assert state-
ments to test the desired function. Notice that you do not write a line to call
the unit test function. Instead, when you launch pytest to run the unit tests,
pytest scans your script and executes only the functions with the prefix test_.
This ActiveCode environment simulates pytest by scanning for and execut-
ing functions with a test_ prefix when you click Run. Go ahead and try it
- rename the test_round6 function to test_itworks and try running the test
again.
def test_round6_rounds_down():
assert round6(8.5) == 8
If you use good pytest function names, when a pytest function has an assertion
failure, you can easily tell what the problem was.
• Windows:
pip install pytest
• Mac/Linux:
pip3 install pytest
CHAPTER 20. UNIT TESTING 366
After you have installed pytest, you run pytest unit tests from the com-
mand line window. To run pytest unit tests, try copying the code from the
ActiveCode example above and pasting it into a Python file named (ex.) my-
round.py. Then, use the pytest command to run your tests by opening a
command window, navigating to the folder where you stored myround.py, and
executing the following command:
pytest myround.py
myround.py:8: AssertionError
Let’s take a closer look at this report to understand what it’s telling you.
def test_round6 () :
CHAPTER 20. UNIT TESTING 367
====
from unittest . gui import TestCaseGui
testA = False
testB = False
testF = False
illegal = False
myTests () . main ()
20.8 Glossary
Glossary
assert statement.A statement that verifies that a boolean condition is true.
design by contract.An approach to designing functions that specifies function
behavior using preconditions and postconditions.
postcondition.Part of a function specification that states the work the func-
tion completed by the function if the precondition is satisfied.
precondition.A boolean condition that the caller of a function must ensure
is true in order for the function to produce correct results
specification-based tests.tests that are designed based only on the informa-
tion in the function specification, without considering any of the details in the
CHAPTER 20. UNIT TESTING 369
function implementation.
unit test.Code that tests a function to determine if it works properly
20.9 Exercises
1. A function named reverse takes a string argument, reverses it, and
returns the result:
1 def reverse(astring):
"""Returns the reverse of `astring`"""
def test_reverse () :
# Complete the assert statements below
assert ________________
assert ________________
assert ________________
====
testABC = False
testB = False
testEmpty = False
l = list ( astring )
l. reverse ()
return ' ' . join ( l )
myTests () . main ()
2
2. A function named stripletters takes a string argument, removes
all letters from it, and displays the result (see below). However, this
function is not testable.
Modify the function so that it can be tested with the assert state-
ments that follow.
CHAPTER 20. UNIT TESTING 371
print ( result )
====
myTests () . main ()
UNIT TESTING 372
1 https://docs.python.org/3/reference/expressions.html#operator-precedence