Main Practical Programming: An Introduction to Computer Science Using Python 3.6

Practical Programming: An Introduction to Computer Science Using Python 3.6

, ,
Classroom-tested by tens of thousands of students, this new edition of the bestselling intro to programming book is for anyone who wants to understand computer science. Learn about design, algorithms, testing, and debugging. Discover the fundamentals of programming with Python 3.6--a language that's used in millions of devices. Write programs to solve real-world problems, and come away with everything you need to produce quality code. This edition has been updated to use the new language features in Python 3.6.
Year: 2017
Edition: 3
Publisher: Pragmatic Bookshelf
Language: english
Pages: 412 / 397
ISBN 10: 1680502689
ISBN 13: 978-1680502688
File: PDF, 8.23 MB
Download (pdf, 8.23 MB)
Preview

You may be interested in

 

Most frequently terms

 
 
You can write a book review and share your experiences. Other readers will always be interested in your opinion of the books you've read. Whether you've loved the book or not, if you give your honest and detailed thoughts then people will find new books that are right for them.
What Readers Are Saying about

Practical Programming
I wish I could go back in time and give this book to my 10-year-old self when I
first learned programming! It’s so much more engaging, practical, and accessible
than the dry introductory programming books that I tried (and often failed) to
comprehend as a kid. I love the authors’ hands-on approach of mixing explanations
with code snippets that students can type into the Python prompt.
➤ Philip Guo
Creator of Online Python Tutor (www.pythontutor.com), Assistant Professor, Department of Cognitive Science, UCSD
Practical Programming delivers just what it promises: a clear, readable, usable
introduction to programming for beginners. This isn’t just a guide to hacking
together programs. The book provides foundations to lifelong programming skills:
a crisp, consistent, and visual model of memory and execution and a design recipe
that will help readers produce quality software.
➤ Steven Wolfman
Professor of Teaching, Department of Computer Science, University of British
Columbia

This excellent text reflects the authors’ many years of experience teaching Python
to beginning students. Topics are presented so that each leads naturally to the
next, and common novice errors and misconceptions are explicitly addressed. The
exercises at the end of each chapter invite interested students to explore computer
science and programming language topics.
➤ Kathleen Freeman
Director of Undergraduate Studies, Department of Computer and Information
Science, University of Oregon

Practical Programming, Third Edition
An Introduction to Computer Science Using Python 3.6

Paul Gries
Jennifer Campbell
Jason Montojo

The Pragmatic Bookshelf
Raleigh, North Carolina

Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in this book, and The Pragmatic
Programmers, LLC was aware of a trademark claim, the designations have been printed in
initial capital letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer,
Pragmatic Programming, Pragmatic Bookshelf, PragProg and the linking g device are trademarks of The Pragmatic Programmers, LLC.
Every precaution was taken in the preparation of this book. However, the publisher assumes
no responsibility for errors or omissions, or for damages that may result from the use of
information (including program listings) contained herein.
Our Pragmatic books, screencasts, and audio books can help you and your team create
better software and have more fun. Visit us at https://pragprog.com.
The team that produced this book includes:
Publisher: Andy Hunt
VP of Operations: Janet Furlow
Managing Editor: Brian MacDonald
Supervising Editor: Jacquelyn Carter
Development Editor: Tammy Coron
Indexing: Potomac Indexing
Copy Editor: Liz Welch
Layout: Gilson Graphics
For sales, volume licensing, and support, please contact support@pragprog.com.
For international rights, please contact rights@pragprog.com.

Copyright © 2017 The Pragmatic Programmers, LLC.
All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise,
without the prior consent of the publisher.
Printed in the United States of America.
ISBN-13: 978-1-6805026-8-8
Encoded using the finest acid-free high-entropy binary digits.
Book version: P1.0—December 2017

Contents
Acknowledgments
Preface .
.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

.

xi
xiii

.

1.

What’s Programming?
.
.
.
.
.
.
.
.
.
Programs and Programming
What’s a Programming Language?
What’s a Bug?
The Difference Between Brackets, Braces, and Parentheses
Installing Python

.

1
2
3
4
5
5

2.

Hello, Python .
.
.
.
.
.
.
.
.
.
.
How Does a Computer Run a Python Program?
Expressions and Values: Arithmetic in Python
What Is a Type?
Variables and Computer Memory: Remembering Values
How Python Tells You Something Went Wrong
A Single Statement That Spans Multiple Lines
Describing Code
Making Code Readable
The Object of This Chapter
Exercises

.

7
7
9
12
15
22
23
25
26
27
27

3.

Designing and Using Functions .
.
.
.
.
.
Functions That Python Provides
Memory Addresses: How Python Keeps Track of Values
Defining Our Own Functions
Using Local Variables for Temporary Storage
Tracing Function Calls in the Memory Model
Designing New Functions: A Recipe
Writing and Running a Program

.

.

.

31
31
34
35
39
40
47
58

Contents

Omitting a return Statement: None
Dealing with Situations That Your Code Doesn’t Handle
What Did You Call That?
Exercises
.

.

.

• vi
60
61
62
63

4.

Working with Text
.
.
.
.
.
Creating Strings of Characters
Using Special Characters in Strings
Creating a Multiline String
Printing Information
Getting Information from the Keyboard
Quotes About Strings
Exercises

.

.

.

65
65
68
70
70
73
74
75

5.

Making Choices .
.
.
.
.
.
.
.
.
.
.
A Boolean Type
Choosing Which Statements to Execute
Nested if Statements
Remembering Results of a Boolean Expression Evaluation
You Learned About Booleans: True or False?
Exercises

.

77
77
86
92
92
94
94

6.

A Modular Approach to Program Organization
Importing Modules
Defining Your Own Modules
Testing Your Code Semiautomatically
Tips for Grouping Your Functions
Organizing Our Thoughts
Exercises

.

99
100
104
110
112
113
113

7.

Using Methods .
.
.
.
.
.
.
Modules, Classes, and Methods
Calling Methods the Object-Oriented Way
Exploring String Methods
What Are Those Underscores?
A Methodical Review
Exercises

.

.

.

.

.

115
115
117
119
123
125
126

8.

Storing Collections of Data Using Lists .
Storing and Accessing Data in Lists
Type Annotations for Lists
Modifying Lists

.

.

.

.

.

129
129
133
133

.

.

.

Contents

Operations on Lists
Slicing Lists
Aliasing: What’s in a Name?
List Methods
Working with a List of Lists
A Summary List
Exercises

135
137
139
141
142
145
145
.

.

149
149
151
152
154
156
160
162
163
167
168

.
.
.
.
.
.
.
10. Reading and Writing Files .
What Kinds of Files Are There?
Opening a File
Techniques for Reading Files
Files over the Internet
Writing Files
Writing Example Calls Using StringIO
Writing Algorithms That Use the File-Reading Techniques
Multiline Records
Looking Ahead
Notes to File Away
Exercises

.

173
173
175
179
183
185
186
188
195
198
200
201

11. Storing Data Using Other Collection Types .
.
.
.
Storing Data Using Sets
Storing Data Using Tuples
Storing Data Using Dictionaries
Inverting a Dictionary
Using the in Operator on Tuples, Sets, and Dictionaries
Comparing Collections
Creating New Type Annotations

.

203
203
209
214
222
223
224
224

9.

Repeating Code Using Loops
.
.
.
.
Processing Items in a List
Processing Characters in Strings
Looping Over a Range of Numbers
Processing Lists Using Indices
Nesting Loops in Loops
Looping Until a Condition Is Reached
Repetition Based on User Input
Controlling Loops Using break and continue
Repeating What You’ve Learned
Exercises

• vii

.

.

Contents

A Collection of New Information
Exercises
.
.
.
12. Designing Algorithms .
Searching for the Two Smallest Values
Timing the Functions
At a Minimum, You Saw This
Exercises

• viii

226
226
.

.

.

.

.

.

229
230
238
240
240

.
.
.
.
13. Searching and Sorting .
Searching a List
Binary Search
Sorting
More Efficient Sorting Algorithms
Merge Sort: A Faster Sorting Algorithm
Sorting Out What You Learned
Exercises

.

.

.

.

.

243
243
250
256
265
266
270
272

14. Object-Oriented Programming .
.
.
.
.
.
Understanding a Problem Domain
Function isinstance, Class object, and Class Book
Writing a Method in Class Book
Plugging into Python Syntax: More Special Methods
A Little Bit of OO Theory
A Case Study: Molecules, Atoms, and PDB Files
Classifying What You’ve Learned
Exercises

.

.

275
276
277
280
285
288
293
297
298

.
.
.
15. Testing and Debugging .
Why Do You Need to Test?
Case Study: Testing above_freezing
Case Study: Testing running_sum
Choosing Test Cases
Hunting Bugs
Bugs We’ve Put in Your Ear
Exercises

.

.

.

.

.

.

303
303
304
309
315
316
317
317

.
16. Creating Graphical User Interfaces .
Using Module tkinter
Building a Basic GUI
Models, Views, and Controllers, Oh My!
Customizing the Visual Style

.

.

.

.

.

321
321
323
327
331

Contents

Introducing a Few More Widgets
Object-Oriented GUIs
Keeping the Concepts from Being a GUI Mess
Exercises
.
.
.
.
.
.
.
17. Databases .
Overview
Creating and Populating
Retrieving Data
Updating and Deleting
Using NULL for Missing Data
Using Joins to Combine Tables
Keys and Constraints
Advanced Features
Some Data Based On What You Learned
Exercises
Bibliography
Index .
.

.
.

.
.

.
.

.
.

.
.

.
.

.
.

• ix

335
338
339
340

.

.

.

.

.

343
343
344
348
351
352
353
357
358
364
365

.
.

.
.

.
.

.
.

.
.

369
371

Acknowledgments
This book would be confusing and riddled with errors if it weren’t for a bunch
of awesome people who patiently and carefully read our drafts.
We had a great team of people provide technical reviews for this edition and
previous editions: in no particular order, Frank Ruiz, Stefan Turalski, Stephen
Wolff, Peter W.A. Wood, Steve Wolfman, Adam Foster, Owen Nelson, Arturo
Martínez Peguero, C. Keith Ray, Michael Szamosi, David Gries, Peter Beens,
Edward Branley, Paul Holbrook, Kristie Jolliffe, Mike Riley, Sean Stickle, Tim
Ottinger, Bill Dudney, Dan Zingaro, and Justin Stanley. We also appreciate
all the people who reported errata: your feedback was invaluable.
Greg Wilson started us on this journey when he proposed that we write a
textbook, and he was our guide and mentor as we worked together to create
the first edition of this book.
Finally, we would like to thank our editor Tammy Coron, who set up a workflow
that made the tight timeline possible. Tammy, your gentle nudges kept us on
track (squirrel!) and helped us complete this third edition in record time.

report erratum • discuss

Preface
This book uses the Python programming language to teach introductory
computer science topics and a handful of useful applications. You’ll certainly
learn a fair amount of Python as you work through this book, but along the
way you’ll also learn about issues that every programmer needs to know:
ways to approach a problem and break it down into parts, how and why to
document your code, how to test your code to help ensure your program does
what you want it to, and more.
We chose Python for several reasons:
• It is free and well documented. In fact, Python is one of the largest and
best-organized open source projects going.
• It runs everywhere. The reference implementation, written in C, is used
on everything from cell phones to supercomputers, and it’s supported by
professional-quality installers for Windows, macOS, and Linux.
• It has a clean syntax. Yes, every language makes this claim, but during
the several years that we have been using it at the University of Toronto,
we have found that students make noticeably fewer “punctuation” mistakes
with Python than with C-like languages.
• It is relevant. Thousands of companies use it every day: it is one of the
languages used at Google, Industrial Light & Magic uses it extensively,
and large portions of the game EVE Online are written in Python. It is
also widely used by academic research groups.
• It is well supported by tools. Legacy editors like vi and Emacs all have
Python editing modes, and several professional-quality IDEs are available.
(We use IDLE, the free development environment that comes with a
standard Python installation.)

report erratum • discuss

Preface

• xiv

Our Approach
We have organized the book into two parts. The first covers fundamental programming ideas: how to store and manipulate information (numbers, text, lists,
sets, dictionaries, and files), how to control the flow of execution (conditionals
and loops), how to organize code (functions and modules), how to ensure your
code works (testing and debugging), and how to plan your program (algorithms).
The second part of the book consists of more or less independent chapters
on more advanced topics that assume all the basic material has been covered.
The first of these chapters shows how to create and manage your own types
of information. It introduces object-oriented concepts such as encapsulation,
inheritance, and polymorphism. The other chapters cover testing, databases,
and graphical user interface construction.

Further Reading
Lots of other good books on Python programming exist. Some are accessible
to novices, such as Introduction to Computing and Programming in Python: A
Multimedia Approach [GE13] and Python Programming: An Introduction to
Computer Science [Zel03]; others are for anyone with any previous programming
experience (How to Think Like a Computer Scientist: Learning with Python
[DEM02], Object-Oriented Programming in Python [GL07], and Learning Python
[Lut13]). You may also want to take a look at Python Education Special Interest
Group (EDU-SIG) [Pyt11], the special interest group for educators using Python.

Python Resources
Information about a variety of Python books and other resources is available at
http://wiki.python.org/moin/FrontPage.

After you have a good grasp of programming in Python, we recommend that
you learn a second programming language. There are many possibilities, such
as well-known languages like C, Java, C#, and Ruby. Python is similar in
concept to those languages. However, you will likely learn more and become
a better programmer if you learn a programming language that requires a
different mindset, such as Racket,1 Erlang,2 or Haskell.3 In any case, we
strongly recommend learning a second programming language.

1.
2.
3.

See http://www.ccs.neu.edu/home/matthias/HtDP2e/index.html.
See http://learnyousomeerlang.com.
See http://learnyouahaskell.com.

report erratum • discuss

What You’ll See

• xv

What You’ll See
In this book, we’ll do the following:
• We’ll show you how to develop and use programs that solve real-world
problems. Most of the examples will come from science and engineering,
but the ideas can be applied to any domain.
• We’ll start by teaching you the core features of Python. These features
are included in most modern programming languages, so you can use
what you learn no matter what you work on next.
• We’ll also teach you how to think methodically about programming. In
particular, we will show you how to break complex problems into simple
ones and how to combine the solutions to those simpler problems to create
complete applications.
• Finally, we’ll introduce some tools that will help make your programming
more productive, as well as some others that will help your applications
cope with larger problems.

Online Resources
All the source code, errata, discussion forums, installation instructions, and
exercise solutions are available at http://pragprog.com/book/gwpy3/practical-programming.

report erratum • discuss

CHAPTER 1

What’s Programming?

(Photo credit: NASA/Goddard Space Flight Center Scientific Visualization Studio)
Take a look at the pictures above. The first one shows forest cover in the
Amazon basin in 1975. The second one shows the same area twenty-six years
later. Anyone can see that much of the rainforest has been destroyed, but
how much is “much”?
Now look at this:

(Photo credit: CDC)

report erratum • discuss

Chapter 1. What’s Programming?

•2

Are these blood cells healthy? Do any of them show signs of leukemia? It
would take an expert doctor a few minutes to tell. Multiply those minutes by
the number of people who need to be screened. There simply aren’t enough
human doctors in the world to check everyone.
This is where computers come in. Computer programs can measure the differences between two pictures and count the number of oddly shaped platelets
in a blood sample. Geneticists use programs to analyze gene sequences;
statisticians, to analyze the spread of diseases; geologists, to predict the effects
of earthquakes; economists, to analyze fluctuations in the stock market; and
climatologists, to study global warming. More and more scientists are writing
programs to help them do their work. In turn, those programs are making
entirely new kinds of science possible.
Of course, computers are good for a lot more than just science. We used
computers to write this book. Your smartphone is a pretty powerful computer;
you’ve probably used one today to chat with friends, check your lecture notes,
or look for a restaurant that serves pizza and Chinese food. Every day,
someone figures out how to make a computer do something that has never
been done before. Together, those “somethings” are changing the world.
This book will teach you how to make computers do what you want them to
do. You may be planning to be a doctor, a linguist, or a physicist rather than
a full-time programmer, but whatever you do, being able to program is as
important as being able to write a letter or do basic arithmetic.
We begin in this chapter by explaining what programs and programming are.
We then define a few terms and present some useful bits of information for
course instructors.

Programs and Programming
A program is a set of instructions. When you write down directions to your
house for a friend, you are writing a program. Your friend “executes” that
program by following each instruction in turn.
Every program is written in terms of a few basic operations that its reader already
understands. For example, the set of operations that your friend can understand
might include the following: “Turn left at Darwin Street,” “Go forward three
blocks,” and “If you get to the gas station, turn around—you’ve gone too far.”
Computers are similar but have a different set of operations. Some operations
are mathematical, like “Take the square root of a number,” whereas others
include “Read a line from the file named data.txt” and “Make a pixel blue.”

report erratum • discuss

What’s a Programming Language?

•3

The most important difference between a computer and an old-fashioned
calculator is that you can “teach” a computer new operations by defining
them in terms of old ones. For example, you can teach the computer that
“Take the average” means “Add up the numbers in a sequence and divide by
the sequence’s size.” You can then use the operations you have just defined
to create still more operations, each layered on top of the ones that came
before. It’s a lot like creating life by putting atoms together to make proteins
and then combining proteins to build cells, combining cells to make organs,
and combining organs to make a creature.
Defining new operations and combining them to do useful things is the heart
and soul of programming. It is also a tremendously powerful way to think
about other kinds of problems. As Professor Jeannette Wing wrote in
Computational Thinking [Win06], computational thinking is about the following:
• Conceptualizing, not programming. Computer science isn’t computer programming. Thinking like a computer scientist means more than being
able to program a computer: it requires thinking at multiple levels of
abstraction.
• A way that humans, not computers, think. Computational thinking is a
way humans solve problems; it isn’t trying to get humans to think like
computers. Computers are dull and boring; humans are clever and
imaginative. We humans make computers exciting. Equipped with computing devices, we use our cleverness to tackle problems we wouldn’t dare
take on before the age of computing and build systems with functionality
limited only by our imaginations.
• For everyone, everywhere. Computational thinking will be a reality when
it becomes so integral to human endeavors it disappears as an explicit
philosophy.
We hope that by the time you have finished reading this book, you will see
the world in a slightly different way.

What’s a Programming Language?
Directions to the nearest bus station can be given in English, Portuguese,
Mandarin, Hindi, and many other languages. As long as the people you’re
talking to understand the language, they’ll get to the bus station.
In the same way, there are many programming languages, and they all can
add numbers, read information from files, and make user interfaces with
windows and buttons and scroll bars. The instructions look different, but

report erratum • discuss

Chapter 1. What’s Programming?

•4

they accomplish the same task. For example, in the Python programming
language, here’s how you add 3 and 4:
3 + 4

But here’s how it’s done in the Scheme programming language:
(+ 3 4)

They both express the same idea—they just look different.
Every programming language has a way to write mathematical expressions,
repeat a list of instructions a number of times, choose which of two instructions to do based on the current information you have, and much more. In
this book, you’ll learn how to do these things in the Python programming
language. Once you understand Python, learning the next programming language will be much easier.

What’s a Bug?
Pretty much everyone has had a program crash. A standard story is that you
were typing in a paper when, all of a sudden, your word processor crashed.
You had forgotten to save, and you had to start all over again. Old versions
of Microsoft Windows used to crash more often than they should have,
showing the dreaded “blue screen of death.” (Happily, they’ve gotten a lot
better in the past several years.) Usually, your computer shows some kind of
cryptic error message when a program crashes.
What happened in each case is that the people who wrote the program told
the computer to do something it couldn’t do: open a file that didn’t exist,
perhaps, or keep track of more information than the computer could handle,
or maybe repeat a task with no way of stopping other than by rebooting the
computer. (Programmers don’t mean to make these kinds of mistakes, they
are just part of the programming process.)
Worse, some bugs don’t cause a crash; instead, they give incorrect information.
(This is worse because at least with a crash you’ll notice that there’s a problem.) As a real-life example of this kind of bug, the calendar program that one
of the authors uses contains an entry for a friend who was born in 1978. That
friend, according to the calendar program, had his 5,875,542nd birthday this
past February. Bugs can be entertaining, but they can also be tremendously
frustrating.
Every piece of software that you can buy has bugs in it. Part of your job as a
programmer is to minimize the number of bugs and to reduce their severity.
In order to find a bug, you need to track down where you gave the wrong

report erratum • discuss

The Difference Between Brackets, Braces, and Parentheses

•5

instructions, then you need to figure out the right instructions, and then you
need to update the program without introducing other bugs.
Every time you get a software update for a program, it is for one of two reasons:
new features were added to a program or bugs were fixed. It’s always a game
of economics for the software company: are there few enough bugs, and are
they minor enough or infrequent enough in order for people to pay for the
software?
In this book, we’ll show you some fundamental techniques for finding and
fixing bugs and also show you how to prevent them in the first place.

The Difference Between Brackets, Braces, and Parentheses
One of the pieces of terminology that causes confusion is what to call certain
characters. Several dictionaries use these names, so this book does too:
()

Parentheses

[]

Brackets

{}

Braces (Some people call these curly brackets or curly braces, but we’ll
stick to just braces.)

Installing Python
Installation instructions and use of the IDLE programming environment are
available on the book’s website: http://pragprog.com/titles/gwpy3/practical-programming.

report erratum • discuss

CHAPTER 2

Hello, Python
Programs are made up of commands that tell the computer what to do. These
commands are called statements, which the computer executes. This chapter
describes the simplest of Python’s statements and shows how they can be
used to do arithmetic, which is one of the most common tasks for computers
and also a great place to start learning to program. It’s also the basis of almost
everything that follows.

How Does a Computer Run a Python Program?
In order to understand what happens when you’re programming, it helps to
have have a mental model of how a computer executes a program.
The computer is assembled from pieces of hardware, including a processor
that can execute instructions and do arithmetic, a place to store data such
as a hard drive, and various other pieces, such as a screen, a keyboard, an
Ethernet controller for connecting to a network, and so on.
To deal with all these pieces, every computer runs some kind of operating
system, such as Microsoft Windows, Linux, or macOS. An operating system,
or OS, is a program; what makes it special is that it’s the only program on
the computer that’s allowed direct access to the hardware. When any other
application (such as your browser, a spreadsheet program, or a game) wants
to draw on the screen, find out what key was just pressed on the keyboard,
or fetch data from storage, it sends a request to the OS (see the top image on
page 8).
This may seem like a roundabout way of doing things, but it means that only
the people writing the OS have to worry about the differences between one
graphics card and another and whether the computer is connected to a
network through Ethernet or wireless. The rest of us—everyone analyzing

report erratum • discuss

Chapter 2. Hello, Python

•8

Applications

Operating System

Storage Device

Screen

scientific data or creating 3D virtual chat rooms—only have to learn our way
around the OS, and our programs will then run on thousands of different
kinds of hardware.
Today, it’s common to add another layer between the programmer and the
computer’s hardware. When you write a program in Python, Java, or Visual
Basic, it doesn’t run directly on top of the OS. Instead, another program,
called an interpreter or virtual machine, takes your program and runs it for
you, translating your commands into a language the OS understands. It’s a
lot easier, more secure, and more portable across operating systems than
writing programs directly on top of the OS:
Python Program

Applications

Python Interpreter

Operating System

Storage Device

Screen

There are two ways to use the Python interpreter. One is to tell it to execute
a Python program that is saved in a file with a .py extension. Another is to
interact with it in a program called a shell, where you type statements one at
a time. The interpreter will execute each statement when you type it, do what
the statement says to do, and show any output as text, all in one window.
We will explore Python in this chapter using a Python shell.

report erratum • discuss

Expressions and Values: Arithmetic in Python

•9

Install Python Now (If You Haven’t Already)
If you haven’t yet installed Python 3.6, please do so now. (Python 2 won’t do; there
are significant differences between Python 2 and Python 3, and this book uses Python
3.6.) Locate installation instructions on the book’s website: http://pragprog.com/titles/gwpy3/
practical-programming.
Programming requires practice: you won’t learn how to program just by reading this
book, much like you wouldn’t learn how to play guitar just by reading a book on how
to play guitar.
Python comes with a program called IDLE, which we use to write Python programs.
IDLE has a Python shell that communicates with the Python interpreter and also
allows you to write and run programs that are saved in a file.
We strongly recommend that you open IDLE and follow along with our examples.
Typing in the code in this book is the programming equivalent of repeating phrases
back to an instructor as you’re learning to speak a new language.

Expressions and Values: Arithmetic in Python
You’re familiar with mathematical expressions like 3 + 4 (“three plus four”)
and 2 - 3 / 5 (“two minus three divided by five”); each expression is built out of
values like 2, 3, and 5 and operators like + and -, which combine their operands
in different ways. In the expression 4 / 5, the operator is “/” and the operands
are 4 and 5.
Expressions don’t have to involve an operator: a number by itself is an
expression. For example, we consider 212 to be an expression as well as a
value.
Like any programming language, Python can evaluate basic mathematical
expressions. For example, the following expression adds 4 and 13:
>>> 4 + 13
17

The >>> symbol is called a prompt. When you opened IDLE, a window should
have opened with this symbol shown; you don’t type it. It is prompting you
to type something. Here we typed 4 + 13, and then we pressed the Return (or
Enter) key in order to signal that we were done entering that expression.
Python then evaluated the expression.
When an expression is evaluated, it produces a single value. In the previous
expression, the evaluation of 4 + 13 produced the value 17. When you type the
expression in the shell, Python shows the value that is produced.

report erratum • discuss

Chapter 2. Hello, Python

• 10

Subtraction and multiplication are similarly unsurprising:
>>> 15 - 3
12
>>> 4 * 7
28

The following expression divides 5 by 2:
>>> 5 / 2
2.5

The result has a decimal point. In fact, the result of division always has a
decimal point even if the result is a whole number:
>>> 4 / 2
2.0

Types
Every value in Python has a particular type, and the types of values determine
how they behave when they’re combined. Values like 4 and 17 have type int
(short for integer), and values like 2.5 and 17.0 have type float. The word float
is short for floating point, which refers to the decimal point that moves around
between digits of the number.
An expression involving two floats produces a float:
>>> 17.0 - 10.0
7.0

When an expression’s operands are an int and a float, Python automatically
converts the int to a float. This is why the following two expressions both return
the same answer:
>>> 17.0 - 10
7.0
>>> 17 - 10.0
7.0

If you want, you can omit the zero after the decimal point when writing a
floating-point number:
>>> 17 - 10.
7.0
>>> 17. - 10
7.0

However, most people think this is bad style, since it makes your programs
harder to read: it’s very easy to miss a dot on the screen and see 17 instead
of 17..

report erratum • discuss

Expressions and Values: Arithmetic in Python

• 11

Integer Division, Modulo, and Exponentiation
Every now and then, we want only the integer part of a division result. For
example, we might want to know how many 24-hour days there are in 53
hours (which is two 24-hour days plus another 5 hours). To calculate the
number of days, we can use integer division:
>>> 53 // 24
2

We can find out how many hours are left over using the modulo operator,
which gives the remainder of the division:
>>> 53 % 24
5

Python doesn’t round the result of integer division. Instead, it takes the floor
of the result of the division, which means that it rounds down to the nearest
integer:
>>> 17 // 10
1

Be careful about using % and // with negative operands. Because Python takes
the floor of the result of an integer division, the result is one smaller than
you might expect if the result is negative:
>>> -17 // 10
-2

When using modulo, the sign of the result matches the sign of the divisor
(the second operand):
>>> -17 % 10
3
>>> 17 % -10
-3

For the mathematically inclined, the relationship between // and % comes from
this equation, for any two non-zero numbers a and b:
(b * (a // b) + a % b) is equal to a

For example, because -17 // 10 is -2, and -17 % 10 is 3; then 10 * (-17 // 10) + -17 %
10 is the same as 10 * -2 + 3, which is -17.
Floating-point numbers can be operands for // and % as well. With //, division
is performed and the result is rounded down to the nearest whole number,
although the type is a floating-point number:

report erratum • discuss

Chapter 2. Hello, Python
>>>
3.0
>>>
3.0
>>>
2.0
>>>
3.0
>>>
2.0

• 12

3.3 // 1
3 // 1.0
3 // 1.1
3.5 // 1.1
3.5 // 1.3

The following expression calculates 3 raised to the 6th power:
>>> 3 ** 6
729

Operators that have two operands are called binary operators. Negation is a
unary operator because it applies to one operand:
>>> -5
-5
>>> --5
5
>>> ---5
-5

What Is a Type?
We’ve now seen two types of numbers (integers and floating-point numbers),
so we ought to explain what we mean by a type. In Python, a type consists
of two things:
• A set of values
• A set of operations that can be applied to those values
For example, in type int, the values are …, -3, -2, -1, 0, 1, 2, 3, … and we have seen
that these operators can be applied to those values: +, -, *, /, //, %, and **.
The values in type float are a subset of the real numbers, and it happens that
the same set of operations can be applied to float values. We can see what
happens when these are applied to various values in Table 1, Arithmetic
Operators, on page 13. If an operator can be applied to more than one type
of value, it is called an overloaded operator.

Finite Precision
Floating-point numbers are not exactly the fractions you learned in grade
school. For example, look at Python’s version of the fractions 2⁄3 and 5⁄3:

report erratum • discuss

What Is a Type?

Symbol

Operator

Example

Result

-

Negation

-5

-5

+

Addition

11 + 3.1

14.1

-

Subtraction

5 - 19

-14

*

Multiplication

8.5 * 4

34.0

/

Division

11 / 2

5.5

//

Integer Division

11 // 2

5

%

Remainder

8.5 % 3.5

1.5

**

Exponentiation

2 ** 5

32

• 13

Table 1—Arithmetic Operators

>>> 2 / 3
0.6666666666666666
>>> 5 / 3
1.6666666666666667

The first value ends with a 6, and the second with a 7. This is fishy: both of
them should have an infinite number of 6s after the decimal point. The
problem is that computers have a finite amount of memory, and (to make
calculations fast and memory efficient) most programming languages limit
how much information can be stored for any single number. The number
2
0.6666666666666666 turns out to be the closest value to ⁄3 that the computer
can actually store in that limited amount of memory, and 1.6666666666666667
is as close as we get to the real value of 5⁄3.

Operator Precedence
Let’s put our knowledge of ints and floats to use in converting Fahrenheit to
Celsius. To do this, we subtract 32 from the temperature in Fahrenheit and
then multiply by 5⁄9:
>>> 212 - 32 * 5 / 9
194.22222222222223

Python claims the result is 194.22222222222223 degrees Celsius, when in fact it
should be 100. The problem is that multiplication and division have higher
precedence than subtraction; in other words, when an expression contains
a mix of operators, the * and / are evaluated before the - and +. This means
that what we actually calculated was 212 - ((32 * 5) / 9): the subexpression 32 * 5
is evaluated before the division is applied, and that division is evaluated before
the subtraction occurs.

report erratum • discuss

Chapter 2. Hello, Python

• 14

More on Numeric Precision
Integers (values of type int) in Python can be as large or as small as you like. However,
1
float values are only approximations to real numbers. For example, ⁄4 can be stored
exactly, but as we’ve already seen, 2⁄3 cannot. Using more memory won’t solve the
problem, though it will make the approximation closer to the real value, just as
writing a larger number of 6s after the 0 in 0.666… doesn’t make it exactly equal to 2⁄3.
The difference between 2⁄3 and 0.6666666666666666 may look tiny. But if we use
0.6666666666666666 in a calculation, then the error may get compounded. For example,
if we add 1 to 2⁄3, the resulting value ends in …6665, so in many programming languages, 1 + 2⁄3 is not equal to 5⁄3:
>>> 2 / 3 + 1
1.6666666666666665
>>> 5 / 3
1.6666666666666667

As we do more calculations, the rounding errors can get larger and larger, particularly
if we’re mixing very large and very small numbers. For example, suppose we add
10000000000 (10 billion) and 0.00000000001 (there are 10 zeros after the decimal point):
>>> 10000000000 + 0.00000000001
10000000000.0

The result ought to have twenty zeros between the first and last significant digit, but
that’s too many for the computer to store, so the result is just 10000000000—it’s as if
the addition never took place. Adding lots of small numbers to a large one can
therefore have no effect at all, which is not what a bank wants when it totals up the
values of its customers’ savings accounts.
It’s important to be aware of the floating-point issue. There is no magic bullet to solve
it, because computers are limited in both memory and speed. Numerical analysis,
the study of algorithms to approximate continuous mathematics, is one of the largest
subfields of computer science and mathematics.
Here’s a tip: If you have to add up floating-point numbers, add them from smallest
to largest in order to minimize the error.

We can alter the order of precedence by putting parentheses around
subexpressions:
>>> (212 - 32) * 5 / 9
100.0

Table 2, Arithmetic Operators Listed by Precedence from Highest to Lowest, on
page 15 shows the order of precedence for arithmetic operators.
Operators with higher precedence are applied before those with lower precedence. Here is an example that shows this:

report erratum • discuss

Variables and Computer Memory: Remembering Values

• 15

>>> -2 ** 4
-16
>>> -(2 ** 4)
-16
>>> (-2) ** 4
16

Because exponentiation has higher precedence than negation, the subexpression 2 ** 4 is evaluated before negation is applied.
Precedence

Operator

Operation

Highest

**

Exponentiation

-

Negation

*, /, //, %

Multiplication, division, integer division, and
remainder

+, -

Addition and subtraction

Lowest

Table 2—Arithmetic Operators Listed by Precedence from Highest to Lowest
Operators on the same row have equal precedence and are applied left to
right, except for exponentiation, which is applied right to left. So, for example,
because binary operators + and - are on the same row, 3 + 4 - 5 is equivalent
to (3 + 4) - 5, and 3 - 4 + 5 is equivalent to (3 - 4) + 5.
It’s a good rule to parenthesize complicated expressions even when you don’t
need to, since it helps the eye read things like 1 + 1.7 + 3.2 * 4.4 - 16 / 3. On the
other hand, it’s a good rule to not use parentheses in simple expressions such
as 3.1 * 5.

Variables and Computer Memory: Remembering Values
Like mathematicians, programmers frequently name values so that they can
use them later. A name that refers to a value is called a variable. In Python,
variable names can use letters, digits, and the underscore symbol (but they
can’t start with a digit). For example, X, species5618, and degrees_celsius are all
allowed, but 777 isn’t (it would be confused with a number), and neither is
no-way! (it contains punctuation). Variable names are case sensitive, so ph and
pH are two different names.
You create a new variable by assigning it a value:
>>> degrees_celsius = 26.0

This statement is called an assignment statement; we say that degrees_celsius is
assigned the value 26.0. That makes degrees_celsius refer to the value 26.0. We can

report erratum • discuss

Chapter 2. Hello, Python

• 16

use variables anywhere we can use values. Whenever Python sees a variable in
an expression, it substitutes the value to which the variable refers:
>>> degrees_celsius = 26.0
>>> degrees_celsius
26.0
>>> 9 / 5 * degrees_celsius + 32
78.80000000000001
>>> degrees_celsius / degrees_celsius
1.0

Variables are called variables because their values can vary as the program
executes. We can assign a new value to a variable:
>>> degrees_celsius = 26.0
>>> 9 / 5 * degrees_celsius + 32
78.80000000000001
>>> degrees_celsius = 0.0
>>> 9 / 5 * degrees_celsius + 32
32.0

Assigning a value to a variable that already exists doesn’t create a second
variable. Instead, the existing variable is reused, which means that the variable
no longer refers to its old value.
We can create other variables; this example calculates the difference between
the boiling point of water and the temperature stored in degrees_celsius:
>>> degrees_celsius = 15.5
>>> difference = 100 - degrees_celsius
>>> difference
84.5

Warning: = Is Not Equality in Python!
In mathematics, = means “the thing on the left is equal to the thing on the right.” In
Python, it means something quite different. Assignment is not symmetric: x = 12
assigns the value 12 to variable x, but 12 = x results in an error. Because of this, we
never describe the statement x = 12 as “x equals 12.” Instead, we read this as “x gets
12” or “x is assigned 12.”

Values, Variables, and Computer Memory
We’re going to develop a model of computer memory—a memory model—that will
let us trace what happens when Python executes a Python program. This memory
model will help us accurately predict and explain what Python does when it executes code, a skill that is a requirement for becoming a good programmer.

report erratum • discuss

Variables and Computer Memory: Remembering Values

• 17

The Online Python Tutor
Philip Guo wrote a web-based memory visualizer that matches our memory model
pretty well. Here’s the URL: http://pythontutor.com/visualize.html. It can trace both Python 2
and Python 3 code; make sure you select the correct version. The settings that most
closely match our memory model are these:
• Hide exited frames
• Render all objects on the heap
• Use text labels for pointers
We strongly recommend that you use this visualizer whenever you want to trace
execution of a Python program.
In case you find it motivating, we weren’t aware of Philip’s visualizer when we developed our memory model (and vice versa), and yet they match extremely closely.

Every location in the computer’s memory has a memory address, much like
an address for a house on a street, that uniquely identifies that location.
We’re going to mark our memory addresses with an id prefix (short for identifier) so that they look different from integers: id1, id2, id3, and so on.
Here is how we draw the floating-point value 26.0 using the memory model:
id1
26.0

This image shows the value 26.0 at the memory address id1. We will always
show the type of the value as well—in this case, float. We will call this box an
object: a value at a memory address with a type. During execution of a program, every value that Python keeps track of is stored inside an object in
computer memory.
In our memory model, a variable contains the memory address of the object
to which it refers:

In order to make the image easier to interpret, we usually draw arrows from
variables to their objects.
We use the following terminology:
• Value 26.0 has the memory address id1.
• The object at the memory address id1 has type float and the value 26.0.

report erratum • discuss

Chapter 2. Hello, Python

• 18

• Variable degrees_celsius contains the memory address id1.
• Variable degrees_celsius refers to the value 26.0.
Whenever Python needs to know which value degrees_celsius refers to, it looks
at the object at the memory address that degrees_celsius contains. In this
example, that memory address is id1, so Python will use the value at the
memory address id1, which is 26.0.

Assignment Statement
Here is the general form of an assignment statement:

«variable»

=

«expression»

This is executed as follows:
1. Evaluate the expression on the right of the = sign to produce a value. This
value has a memory address.
2. Store the memory address of the value in the variable on the left of the =.
Create a new variable if that name doesn’t already exist; otherwise, just reuse
the existing variable, replacing the memory address that it contains.
Consider this example:
>>> degrees_celsius = 26.0 + 5
>>> degrees_celsius
31.0

Here is how Python executes the statement degrees_celsius = 26.0 + 5:
1. Evaluate the expression on the right of the = sign: 26.0 + 5. This produces
the value 31.0, which has a memory address. (Remember that Python
stores all values in computer memory.)
2. Make the variable on the left of the = sign, degrees_celsius, refer to 31.0 by
storing the memory address of 31.0 in degrees_celsius.

Reassigning to Variables
Consider this code:
>>>
>>>
>>>
40
>>>
>>>
40

difference = 20
double = 2 * difference
double
difference = 5
double

report erratum • discuss

Variables and Computer Memory: Remembering Values

• 19

This code demonstrates that assigning to a variable does not change any
other variable. We start by assigning value 20 to variable difference, and then
we assign the result of evaluating 2 * difference (which produces 40) to variable
double.
Next, we assign value 5 to variable difference, but when we examine the value
of double, it still refers to 40.
Here’s how it works according to our rules. The first statement, difference = 20,
is executed as follows:
1. Evaluate the expression on the right of the = sign: 20. This produces the
value 20, which we’ll put at memory address id1.
2. Make the variable on the left of the = sign, difference, refer to 20 by storing
id1 in difference.
Here is the current state of the memory model. (Variable double has not yet
been created because we have not yet executed the assignment to it.)

The second statement, double = 2 * difference, is executed as follows:
1. Evaluate the expression on the right of the = sign: 2 * difference. As we see
in the memory model, difference refers to the value 20, so this expression
is equivalent to 2 * 20, which produces 40. We’ll pick the memory address
id2 for the value 40.
2. Make the variable on the left of the = sign, double, refer to 40 by storing id2
in double.
Here is the current state of the memory model:

When Python executes the third statement, double, it merely looks up the value
that double refers to (40) and displays it.

report erratum • discuss

Chapter 2. Hello, Python

• 20

The fourth statement, difference = 5, is executed as follows:
1. Evaluate the expression on the right of the = sign: 5. This produces the
value 5, which we’ll put at the memory address id3.
2. Make the variable on the left of the = sign, difference, refer to 5 by storing
id3 in difference.
Here is the current state of the memory model:

Variable double still contains id2, so it still refers to 40. Neither variable refers
to 20 anymore.
The fifth and last statement, double, merely looks up the value that double refers
to, which is still 40, and displays it.
We can even use a variable on both sides of an assignment statement:
>>>
>>>
3
>>>
>>>
6
>>>
>>>
36

number = 3
number
number = 2 * number
number
number = number * number
number

We’ll now explain how Python executes this code, but we won’t explicitly
mention memory addresses. Trace this on a piece of paper while we describe
what happens; make up your own memory addresses as you do this.
Python executes the first statement, number = 3, as follows:
1. Evaluate the expression on the right of the = sign: 3. This one is easy to
evaluate: 3 is produced.
2. Make the variable on the left of the = sign, number, refer to 3.
Python executes the second statement, number = 2 * number, as follows:

report erratum • discuss

Variables and Computer Memory: Remembering Values

• 21

1. Evaluate the expression on the right of the = sign: 2 * number. number currently refers to 3, so this is equivalent to 2 * 3, and 6 is produced.
2. Make the variable on the left of the = sign, number, refer to 6.
Python executes the third statement, number = number * number, as follows:
1. Evaluate the expression on the right of the = sign: number * number. number
currently refers to 6, so this is equivalent to 6 * 6, and 36 is produced.
2. Make the variable on the left of the = sign, number, refer to 36.

Augmented Assignment
In this example, the variable score appears on both sides of the assignment
statement:
>>>
>>>
50
>>>
>>>
70

score = 50
score
score = score + 20
score

This is so common that Python provides a shorthand notation for this
operation:
>>>
>>>
50
>>>
>>>
70

score = 50
score
score += 20
score

An augmented assignment combines an assignment statement with an operator to make the statement more concise. An augmented assignment statement
is executed as follows:
1. Evaluate the expression on the right of the = sign to produce a value.
2. Apply the operator attached to the = sign to the variable on the left of the
= and the value that was produced. This produces another value. Store
the memory address of that value in the variable on the left of the =.
Note that the operator is applied after the expression on the right is evaluated:
>>> d = 2
>>> d *= 3 + 4
>>> d
14

report erratum • discuss

Chapter 2. Hello, Python

• 22

All the operators (except for negation) in Table 2, Arithmetic Operators Listed
by Precedence from Highest to Lowest, on page 15, have shorthand versions.
For example, we can square a number by multiplying it by itself:
>>> number = 10
>>> number *= number
>>> number
100

This code is equivalent to this:
>>> number = 10
>>> number = number * number
>>> number
100

Table 3 contains a summary of the augmented operators you’ve seen plus a
few more based on arithmetic operators you learned about in Expressions
and Values: Arithmetic in Python, on page 9.
Symbol

Example

Result

+=

x = 7
x += 2

x refers to 9

-=

x = 7
x -= 2

x refers to 5

*=

x = 7
x *= 2

x refers to 14

/=

x = 7
x /= 2

x refers to 3.5

//=

x = 7
x //= 2

x refers to 3

%=

x = 7
x %= 2

x refers to 1

**=

x = 7
x **= 2

x refers to 49

Table 3—Augmented Assignment Operators

How Python Tells You Something Went Wrong
Broadly speaking, there are two kinds of errors in Python: syntax errors,
which happen when you type something that isn’t valid Python code, and
semantic errors, which happen when you tell Python to do something that it
just can’t do, like divide a number by zero or try to use a variable that doesn’t
exist.

report erratum • discuss

A Single Statement That Spans Multiple Lines

• 23

Here is what happens when we try to use a variable that hasn’t been created yet:
>>> 3 + moogah
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'moogah' is not defined

This is pretty cryptic; Python error messages are meant for people who already
know Python. (You’ll get used to them and soon find them helpful.) The first
two lines aren’t much use right now, though they’ll be indispensable when
we start writing longer programs. The last line is the one that tells us what
went wrong: the name moogah wasn’t recognized.
Here’s another error message you might sometimes see:
>>> 2 +
File "<stdin>", line 1
2 +
^
SyntaxError: invalid syntax

The rules governing what is and isn’t legal in a programming language are
called its syntax. The message tells us that we violated Python’s syntax
rules—in this case, by asking it to add something to 2 but not telling it what
to add.
Earlier, in Warning: = Is Not Equality in Python!, on page 16, we claimed that
12 = x results in an error. Let’s try it:
>>> 12 = x
File "<stdin>", line 1
SyntaxError: can't assign to literal

A literal is any value, like 12 and 26.0. This is a SyntaxError because when Python
examines that assignment statement, it knows that you can’t assign a value
to a number even before it tries to execute it; you can’t change the value of
12 to anything else. 12 is just 12.

A Single Statement That Spans Multiple Lines
Sometimes statements get pretty intricate. The recommended Python style is
to limit lines to 80 characters, including spaces, tabs, and other whitespace
characters, and that’s a common limit throughout the programming world.
Here’s what to do when lines get too long or when you want to split it up for
clarity.

report erratum • discuss

Chapter 2. Hello, Python

• 24

In order to split up a statement into more than one line, you need to do one
of two things:
1. Make sure your line break occurs inside parentheses.
2. Use the line-continuation character, which is a backslash, \.
Note that the line-continuation character is a backslash (\), not the division
symbol (/).
Here are examples of both:
>>>
...
5
>>>
...
5

(2 +
3)
2 + \
3

Notice how we don’t get a SyntaxError. Each triple-dot prompt in our examples
indicates that we are in the middle of entering an expression; we use them
to make the code line up nicely. You do not type the dots any more than you
type the greater-than signs in the usual >>> prompt, and if you are using
IDLE, you won’t see them at all.
Here is a more realistic (and tastier) example: let’s say we’re baking cookies.
The authors live in Canada, which uses Celsius, but we own cookbooks that
use Fahrenheit. We are wondering how long it will take to preheat our oven.
Here are our facts:
• The room temperature is 20 degrees Celsius.
• Our oven controls use Celsius, and the oven heats up at 20 degrees per
minute.
• Our cookbook uses Fahrenheit, and it says to preheat the oven to 350
degrees.
We can convert t degrees Fahrenheit to t degrees Celsius like this: (t - 32) * 5 /
9. Let’s use this information to try to solve our problem.
>>> room_temperature_c = 20
>>> cooking_temperature_f = 350
>>> oven_heating_rate_c = 20
>>> oven_heating_time = (
... ((cooking_temperature_f - 32) * 5 / 9) - room_temperature_c) / \
... oven_heating_rate_c
>>> oven_heating_time
7.833333333333333

report erratum • discuss

Describing Code

• 25

Not bad—just under eight minutes to preheat.
The assignment statement to variable oven_heating_time spans three lines. The
first line ends with an open parenthesis, so we do not need a line-continuation
character. The second ends outside the parentheses, so we need the linecontinuation character. The third line completes the assignment statement.
That’s still hard to read. Once we’ve continued an expression on the next line,
we can indent (by pressing the Tab key or by pressing the spacebar a bunch)
to our heart’s content to make it clearer:
>>> oven_heating_time = (
...
((cooking_temperature_f - 32) * 5 / 9) - room_temperature_c) / \
...
oven_heating_rate_c

Or even this—notice how the two subexpressions involved in the subtraction
line up:
>>> oven_heating_time = (
...
((cooking_temperature_f - 32) * 5 / 9) ...
room_temperature_c) / \
...
oven_heating_rate_c

In the previous example, we clarified the expression by working with indentation. However, we could have made this process even clearer by converting
the cooking temperature to Celsius before calculating the heating time:
>>> room_temperature_c = 20
>>> cooking_temperature_f = 350
>>> cooking_temperature_c = (cooking_temperature_f - 32) * 5 / 9
>>> oven_heating_rate_c = 20
>>> oven_heating_time = (cooking_temperature_c - room_temperature_c) / \
...
oven_heating_rate_c
>>> oven_heating_time
7.833333333333333

The message to take away here is that well-named temporary variables can
make code much clearer.

Describing Code
Programs can be quite complicated and are often thousands of lines long. It
can be helpful to write a comment describing parts of the code so that when
you or someone else reads it the meaning is clear.
In Python, any time the # character is encountered, Python will ignore the
rest of the line. This allows you to write English sentences:
>>> # Python ignores this sentence because of the # symbol.

report erratum • discuss

Chapter 2. Hello, Python

• 26

The # symbol does not have to be the first character on the line; it can appear
at the end of a statement:
>>> (212 - 32) * 5 / 9 # Convert 212 degrees Fahrenheit to Celsius.
100.0

Notice that the comment doesn’t describe how Python works. Instead, it is
meant for humans reading the code to help them understand why the code
exists.

Making Code Readable
Much like there are spaces in English sentences to make the words easier to
read, we use spaces in Python code to make it easier to read. In particular,
we always put a space before and after every binary operator. For example,
we write v = 4 + -2.5 / 3.6 instead of v=4+-2.5/3.6. There are situations where it
may not make a difference, but that’s a detail we don’t want to fuss about,
so we always do it: it’s almost never harder to read if there are spaces.
Psychologists have discovered that people can keep track of only a handful
of things at any one time (Forty Studies That Changed Psychology [Hoc04]).
Since programs can get quite complicated, it’s important that you choose
names for your variables that will help you remember what they’re for. id1,
X2, and blah won’t remind you of anything when you come back to look at your
program next week: use names like celsius, average, and final_result instead.
Other studies have shown that your brain automatically notices differences
between things—in fact, there’s no way to stop it from doing this. As a result,
the more inconsistencies there are in a piece of text, the longer it takes to
read. (JuSt thInK a bout how long It w o u l d tAKE you to rEa d this cHaPTer
iF IT wAs fORmaTTeD like thIs.) It’s therefore also important to use consistent
names for variables. If you call something maximum in one place, don’t call it
max_val in another; if you use the name max_val, don’t also use the name maxVal,
and so on.
These rules are so important that many programming teams require members
to follow a style guide for whatever language they’re using, just as newspapers
and book publishers specify how to capitalize headings and whether to use
a comma before the last item in a list. If you search the Internet for programming style guide (https://www.google.com/search?q=programming+style+guide), you’ll
discover links to hundreds of examples. In this book, we follow the style guide
for Python from http://www.python.org/dev/peps/pep-0008/.
You will also discover that lots of people have wasted many hours arguing
over what the “best” style for code is. Some of your classmates (and your

report erratum • discuss

The Object of This Chapter

• 27

instructors) may have strong opinions about this as well. If they do, ask them
what data they have to back up their beliefs. Strong opinions need strong
evidence to be taken seriously.

The Object of This Chapter
In this chapter, you learned the following:
• An operating system is a program that manages your computer’s hardware
on behalf of other programs. An interpreter or virtual machine is a program
that sits on top of the operating system and runs your programs for you.
The Python shell is an interpreter, translating your Python statements
into language the operating system understands and translating the
results back so you can see and use them.
• Programs are made up of statements, or instructions. These can be simple
expressions like 3 + 4 and assignment statements like celsius = 20 (which
create new variables or change the values of existing ones). There are
many other kinds of statements in Python, and we’ll introduce them
throughout the book.
• Every value in Python has a specific type, which determines what operations can be applied to it. The two types used to represent numbers are
int and float. Floating-point numbers are approximations to real numbers.
• Python evaluates an expression by applying higher-precedence operators
before lower-precedence operators. You can change that order by putting
parentheses around subexpressions.
• Python stores every value in computer memory. A memory location containing a value is called an object.
• Variables are created by executing assignment statements. If a variable
already exists because of a previous assignment statement, Python will
use that one instead of creating a new one.
• Variables contain memory addresses of values. We say that variables refer
to values.
• Variables must be assigned values before they can be used in expressions.

Exercises
Here are some exercises for you to try on your own. Solutions are available
at http://pragprog.com/titles/gwpy3/practical-programming.

report erratum • discuss

Chapter 2. Hello, Python

• 28

1. For each of the following expressions, what value will the expression give?
Verify your answers by typing the expressions into Python.
a. 9 - 3
b. 8 * 2.5
c.

9/2

d. 9 / -2
e.

9 // -2

f.

9%2

g. 9.0 % 2
h. 9 % 2.0
i.

9 % -2

j.

-9 % 2

k. 9 / -2.0
l.

4+3*5

m. (4 + 3) * 5
2. Unary minus negates a number. Unary plus exists as well; for example,
Python understands +5. If x has the value -17, what do you think +x should
do? Should it leave the sign of the number alone? Should it act like
absolute value, removing any negation? Use the Python shell to find out
its behavior.
3. Write two assignment statements that do the following:
a. Create a new variable, temp, and assign it the value 24.
b. Convert the value in temp from Celsius to Fahrenheit by multiplying
by 1.8 and adding 32; make temp refer to the resulting value.
What is temp’s new value?
4. For each of the following expressions, in which order are the subexpressions evaluated?
a. 6 * 3 + 7 * 4
b. 5 + 3 / 4
c.

5 - 2 * 3 ** 4

report erratum • discuss

Exercises

• 29

5. a. Create a new variable x, and assign it the value 10.5.
b. Create a new variable y, and assign it the value 4.
c.

Sum x and y, and make x refer to the resulting value. After this statement has been executed, what are the values of x and y?

6. Write a bullet list description of what happens when Python evaluates
the statement x += x - x when x has the value 3.
7. When a variable is used before it has been assigned a value, a NameError
occurs. In the Python shell, write an expression that results in a NameError.
8. Which of the following expressions results in SyntaxErrors?
a. 6 * -----------8
b. 8 = people
c.

((((4 ** 3))))

d. (-(-(-(-5))))
e.

4 += 7 / 2

report erratum • discuss

CHAPTER 3

Designing and Using Functions
Mathematicians create functions to make calculations (such as Fahrenheitto-Celsius conversions) easy to reuse and to make other calculations easier
to read because they can use those functions instead of repeatedly writing
out equations. Programmers do this too, at least as often as mathematicians.
In this chapter we will explore several of the built-in functions that come with
Python, and we’ll also show you how to define your own functions.

Functions That Python Provides
Python comes with many built-in functions that perform common operations.
One example is abs, which produces the absolute value of a number:
>>> abs(-9)
9
>>> abs(3.3)
3.3

Each of these statements is a function call.

Keep Your Shell Open
As a reminder, we recommend that you have IDLE open (or another Python editor)
and that you try all the code under discussion; this is a good way to cement your
learning.

The general form of a function call is as follows:

«function_name»(«arguments»)
An argument is an expression that appears between the parentheses of a
function call. In abs(-9), the argument is -9.

report erratum • discuss

Chapter 3. Designing and Using Functions

• 32

Here, we calculate the difference between a day temperature and a night
temperature, as might be seen on a weather report (a warm weather system
moved in overnight):
>>> day_temperature = 3
>>> night_temperature = 10
>>> abs(day_temperature - night_temperature)
7

In this call on function abs, the argument is day_temperature - night_temperature.
Because day_temperature refers to 3 and night_temperature refers to 10, Python
evaluates this expression to -7. This value is then passed to function abs,
which then returns, or produces, the value 7.
Here are the rules to executing a function call:
1. Evaluate each argument one at a time, working from left to right.
2. Pass the resulting values into the function.
3. Execute the function. When the function call finishes, it produces a value.
Because function calls produce values, they can be used in expressions:
>>> abs(-7) + abs(3.3)
10.3

We can also use function calls as arguments to other functions:
>>> pow(abs(-2), round(4.3))
16

Python sees the call on pow and starts by evaluating the arguments from left
to right. The first argument is a call on function abs, so Python executes it.
abs(-2) produces 2, so that’s the first value for the call on pow. Then Python
executes round(4.3), which produces 4.
Now that the arguments to the call on function pow have been evaluated,
Python finishes calling pow, sending in 2 and 4 as the argument values. That
means that pow(abs(-2), round(4.3)) is equivalent to pow(2, 4), and 24 is 16.
Here is a diagram indicating the order in which the various pieces of this
expression are evaluated by Python:

report erratum • discuss

Functions That Python Provides

• 33

We have underlined each subexpression and given it a number to indicate
when Python executes or evaluates that subexpression.
Some of the most useful built-in functions are ones that convert from one
type to another. Type names int and float can be used as functions:
>>> int(34.6)
34
>>> int(-4.3)
-4
>>> float(21)
21.0

In this example, we see that when a floating-point number is converted to an
integer, it is truncated, not rounded.
If you’re not sure what a function does, try calling built-in function help, which
shows documentation for any function:
>>> help(abs)
Help on built-in function abs in module builtins:
abs(x, /)
Return the absolute value of the argument.

The first line states which function is being described and which module
it belongs to. Here, the module name is builtins. Modules are an organizational
tool in Python and are discussed in Chapter 6, A Modular Approach, on
page 99.
The next part describes what the function does. The form of the function
appears first: function abs expects one argument. (The / indicates that there
are no more arguments.) After the form is an English description of what the
function does when it is called.
Another built-in function is round, which rounds a floating-point number to
the nearest integer:
>>>
4
>>>
3
>>>
4
>>>
-3
>>>
-4

round(3.8)
round(3.3)
round(3.5)
round(-3.3)
round(-3.5)

report erratum • discuss

Chapter 3. Designing and Using Functions

• 34

The function round can be called with one or two arguments. If called with one, as
we’ve been doing, it rounds to the nearest integer. If called with two, it rounds to
a floating-point number, where the second argument indicates the precision:
>>> round(3.141592653, 2)
3.14

The documentation for round indicates that the second argument is optional
by surrounding it with brackets:
>>> help(round)
Help on built-in function round in module builtins:
round(...)
round(number[, ndigits]) -> number
Round a number to a given precision in decimal digits (default 0 digits).
This returns an int when called with one argument, otherwise the
same type as the number. ndigits may be negative.

Let’s explore built-in function pow by starting with its help documentation:
>>> help(pow)
Help on built-in function pow in module builtins:
pow(x, y, z=None, /)
Equivalent to x**y (with two arguments) or x**y % z (with three arguments)
Some types, such as ints, are able to use a more efficient algorithm when
invoked using the three argument form.

This shows that the function pow can be called with either two or three arguments. The English description mentions that when called with two arguments
it is equivalent to x ** y. Let’s try it:
>>> pow(2, 4)
16

This call calculates 24. So far, so good. How about with three arguments?
>>> pow(2, 4, 3)
1

We know that 24 is 16, and evaluation of 16 % 3 produces 1.

Memory Addresses: How Python Keeps Track of Values
Back in Values, Variables, and Computer Memory, on page 16, you learned that
Python keeps track of each value in a separate object and that each object has a
memory address. You can discover the actual memory address of an object using
built-in function id:

report erratum • discuss

Defining Our Own Functions

• 35

>>> help(id)
Help on built-in function id in module builtins:
id(obj, /)
Return the identity of an object.
This is guaranteed to be unique among simultaneously existing objects.
(CPython uses the object's memory address.)

How cool is that? Let’s try it:
>>> id(-9)
4301189552
>>> id(23.1)
4298223160
>>> shoe_size = 8.5
>>> id(shoe_size)
4298223112
>>> fahrenheit = 77.7
>>> id(fahrenheit)
4298223064

The addresses you get will probably be different from what’s listed here since
values get stored wherever there happens to be free space. Function objects
also have memory addresses:
>>> id(abs)
4297868712
>>> id(round)
4297871160

Defining Our Own Functions
The built-in functions are useful but pretty generic. Often there aren’t builtin functions that do what we want, such as calculate mileage or play a game
of cribbage. When we want functions to do these sorts of things, we have to
write them ourselves.
Because we live in Toronto, Canada, we often deal with our neighbor to the
south. The United States typically uses Fahrenheit, so we convert from
Fahrenheit to Celsius and back a lot. It sure would be nice to be able to do
this:
>>> convert_to_celsius(212)
100.0
>>> convert_to_celsius(78.8)
26.0
>>> convert_to_celsius(10.4)
-12.0

report erratum • discuss

Chapter 3. Designing and Using Functions

• 36

Python Remembers and Reuses Some Objects
A cache is a collection of data. Because small integers—up to about 250 or so,
depending on the version of Python you’re using—are so common, Python creates
those objects as it starts up and reuses the same objects whenever it can. This speeds
up operations involving these values. The function id reveals this:
>>> i = 3
>>> j = 3
>>> k = 4 - 1
>>> id(i)
4296861792
>>> id(j)
4296861792
>>> id(k)
4296861792

What that means is that variables i, j, and k refer to the exact same object. This is
called aliasing.
Larger integers and all floating-point values aren’t necessarily cached:
>>> i = 30000000000
>>> j = 30000000000
>>> id(i)
4301190928
>>> id(j)
4302234864
>>> f = 0.0
>>> g = 0.0
>>> id(f)
4298223040
>>> id(g)
4298223016

Python decides for itself when to cache a value. The only reason you need to be aware
of it is so that you aren’t surprised when it happens; the output of your program is
not affected by when Python decides to cache.

However, the function convert_to_celsius doesn’t exist yet, so instead we see this
(focus only on the last line of the error message for now):
>>> convert_to_celsius(212)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'convert_to_celsius' is not defined

To fix this, we have to write a function definition that tells Python what to do
when the function is called.
We’ll go over the syntax of function definitions soon, but we’ll start with an
example:

report erratum • discuss

Defining Our Own Functions

• 37

>>> def convert_to_celsius(fahrenheit):
...
return (fahrenheit - 32) * 5 / 9
...

The function body is indented. Here, we indent four spaces, as the Python
style guide recommends. If you forget to indent, you get this error:
>>> def convert_to_celsius(fahrenheit):
... return (fahrenheit - 32) * 5 / 9
File "<stdin>", line 2
return (fahrenheit - 32) * 5 / 9
^
IndentationError: expected an indented block

Now that we’ve defined function convert_to_celsius, our earlier function calls will
work. We can even use built-in function help on it:
>>> help(convert_to_celsius)
Help on function convert_to_celsius in module __main__:
convert_to_celsius(fahrenheit)

This shows the first line of the function definition, which we call the function
header. (Later in this chapter, we’ll show you how to add more help documentation to a function.)
Here is a quick overview of how Python executes the following code:
>>> def convert_to_celsius(fahrenheit):
...
return (fahrenheit - 32) * 5 / 9
...
>>> convert_to_celsius(80)
26.666666666666668

1. Python executes the function definition, which creates the function object
(but doesn’t execute it yet).
2. Next, Python executes function call convert_to_celsius(80). To do this, it assigns
80 to fahrenheit (which is a variable). For the duration of this function call,
fahrenheit refers to 80.
3. Python now executes the return statement. fahrenheit refers to 80, so the
expression that appears after return is equivalent to (80 - 32) * 5 / 9. When
Python evaluates that expression, 26.666666666666668 is produced. We use
the word return to tell Python what value to produce as the result of the
function call, so the result of calling convert_to_celsius(80) is 26.666666666666668.
4. Once Python has finished executing the function call, it returns to the
place where the function was originally called.

report erratum • discuss

Chapter 3. Designing and Using Functions

• 38

Here is an image showing this sequence:
1

def convert_to_celsius(fahrenheit):
3 return (fahrenheit - 32) * 5 / 9

2

convert_to_celsius(80)

4

(rest of program)

A function definition is a kind of Python statement. The general form of a
function definition is as follows:
def

«function_name»(«parameters»):
«block»

Keywords Are Words That Are Special to Python
Keywords are words that Python reserves for its own use. We can’t use them except
as Python intends. Two of them are def and return. If we try to use them as either
variable names or as function names (or anything else), Python produces an error:
>>> def = 3
File "<stdin>", line 1
def = 3
^
SyntaxError: invalid syntax
>>> def return(x):
File "<stdin>", line 1
def return(x):
^
SyntaxError: invalid syntax

Here is a complete list of Python keywords (we’ll encounter most of them in this book):
False
None
True
and
as

assert
break
class
continue
def

del
elif
else
except
finally

for
from
global
if
import

in
is
lambda
nonlocal
not

or
pass
raise
return
try

while
with
yield

The function header (that’s the first line of the function definition) starts with
def, followed by the name of the function, then a comma-separated list of
parameters within parentheses, and then a colon. A parameter is a variable.
You can’t have two functions with the same name in the same file; it isn’t an
error, but if you do it, the second function definition replaces the first one, much
like assigning a value to a variable a second time replaces the first value.
Below the function header and indented (four spaces, as per Python’s style
guide) is a block of statements called the function body. The function body
must contain at least one statement.

report erratum • discuss

Using Local Variables for Temporary Storage

• 39

Most function definitions will include a return statement that, when executed,
ends the function and produces a value. The general form of a return statement
is as follows:
return

«expression»

When Python executes a return statement, it evaluates the expression and then
produces the result of that expression as the result of the function call.

Using Local Variables for Temporary Storage
Some computations are complex, and breaking them down into separate steps
can lead to clearer code. In the next example, we break down the evaluation
of the quadratic polynomial ax2+ bx + c into several steps. Notice that all the
statements inside the function are indented the same amount of spaces in
order to be aligned with each other. You may want to type this example into
an editor first (without the leading >>> and ...) and then paste it to the Python
shell. That makes fixing mistakes much easier:
>>> def quadratic(a, b, c, x):
...
first = a * x ** 2
...
second = b * x
...
third = c
...
return first + second + third
...
>>> quadratic(2, 3, 4, 0.5)
6.0
>>> quadratic(2, 3, 4, 1.5)
13.0

Variables like first, second, and third that are created within a function are called
local variables. Local variables get created each time that function is called, and
they are erased when the function returns. Because they only exist when the
function is being executed, they can’t be used outside of the function. This means
that trying to access a local variable from outside the function is an error, just
like trying to access a variable that has never been defined is an error:
>>> quadratic(2, 3, 4, 1.3)
11.280000000000001
>>> first
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'first' is not defined

A function’s parameters are also local variables, so we get the same error if
we try to use them outside of a function definition:

report erratum • discuss

Chapter 3. Designing and Using Functions

• 40

>>> a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined

The area of a program that a variable can be used in is called the variable’s
scope. The scope of a local variable is from the line in which it is defined up
until the end of the function.
As you might expect, if a function is defined to take a certain number of
parameters, a call on that function must have the same number of arguments:
>>> quadratic(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: quadratic() takes exactly 4 arguments (3 given)

Remember that you can call built-in function help to find out information
about the parameters of a function.

Tracing Function Calls in the Memory Model
Read the following code. Can you predict what it will do when we run it?
>>> def f(x):
...
x = 2 * x
...
return x
...
>>> x = 1
>>> x = f(x + 1) + f(x + 2)

That code is confusing, in large part because x is used all over the place.
However, it is pretty short and it only uses Python features that we have seen
so far: assignment statements, expressions, function definitions, and function
calls. We’re missing some information: Are all the x’s the same variable? Does
Python make a new x for each assignment? For each function call? For each
function definition?
Here’s the answer: whenever Python executes a function call, it creates a
namespace (literally, a space for names) in which to store local variables for
that call. You can think of a namespace as a scrap piece of paper; Python
writes down the local variables on that piece of paper, keeps track of them
as long as the function is being executed, and throws that paper away when
the function returns.
Separately, Python keeps another namespace for variables created in the
shell. That means that the x that is a parameter of function f is a different
variable than the x in the shell!

report erratum • discuss

Tracing Function Calls in the Memory Model

• 41

Reusing Variable Names Is Common
Using the same name for local variables in different functions is quite common. For
example, imagine a program that deals with distances—converting from meters to
other units of distance, perhaps. In that program, there would be several functions
that all deal with these distances, and it would be entirely reasonable to use meters
as a parameter name in many different functions.

Let’s refine our rules from Functions That Python Provides, on page 31, for
executing a function call to include this namespace creation:
1. Evaluate the arguments left to right.
2. Create a namespace to hold the function call’s local variables, including
the parameters.
3. Pass the resulting argument values into the function by assigning them
to the parameters.
4. Execute the function body. As before, when a return statement is executed,
execution of the body terminates and the value of the expression in the
return statement is used as the value of the function call.
From now on in our memory model, we will draw a separate box for each
namespace to indicate that the variables inside it are in a separate area of
computer memory. The programming world calls this box a frame. We separate
the frames from the objects by a vertical dotted line:
Frames

Objects

Frames for namespaces
go here

Objects go here

Using our newfound knowledge, let’s trace that confusing code. At the
beginning, no variables have been created; Python is about to execute the
function definition. We have indicated this with an arrow:
➤ >>> def f(x):
...
...
...
>>> x =
>>> x =

x = 2 * x
return x

1
f(x + 1) + f(x + 2)

As you’ve seen in this chapter, when Python executes that function definition,
it creates a variable f in the frame for the shell’s namespace plus a function

report erratum • discuss

Chapter 3. Designing and Using Functions

• 42

object. (Python didn’t execute the body of the function; that won’t happen
until the function is called.) Here is the result:
Objects

Frames

id1:function

shell
f

id1

f(x)

Now we are about to execute the first assignment to x in the shell.
>>> def f(x):
...
x = 2 * x
...
return x
...
➤ >>> x = 1
>>> x = f(x + 1) + f(x + 2)

Once that assignment happens, both f and x are in the frame for the shell:

Now we are about to execute the second assignment to x in the shell:
>>> def f(x):
...
x = 2 * x
...
return x
...
>>> x = 1
➤ >>> x = f(x + 1) + f(x + 2)

Following the rules for executing an assignment from Assignment Statement,
on page 18, we first evaluate the expression on the right of the =, which is f(x
+ 1) + f(x + 2). Python evaluates the left function call first: f(x + 1).
Following the rules for executing a function call, Python evaluates the argument, x + 1. In order to find the value for x, Python looks in the current frame.
The current frame is the frame for the shell, and its variable x refers to 1, so
x + 1 evaluates to 2.
Now we have evaluated the argument to f. The next step is to create a
namespace for the function call. We draw a frame, write in parameter x, and
assign 2 to that parameter:

report erratum • discuss

Tracing Function Calls in the Memory Model

• 43

Objects

Frames

id1:function

shell
f

id1

x

id2

f(x)

id2:int
1

id3:int
2

f
x

id3

Notice that there are two variables called x, and they refer to different values.
Python will always look in the current frame, which we will draw with a
thicker border.
We are now about to execute the first statement of function f:
>>> def f(x):
x = 2 * x
...
return x
...
>>> x = 1
>>> x = f(x + 1) + f(x + 2)

➤ ...

x = 2 * x is an assignment statement. The right side is the expression 2 * x.

Python looks up the value of x in the current frame and finds 2, so that
expression evaluates to 4. Python finishes executing that assignment statement
by making x refer to that 4:
Objects

Frames

id1:function

shell
f

id1

x

id2

f(x)

id2:int

id3:int
2

f
x

id4

1
id4:int
4

We are now about to execute the second statement of function f:
>>> def f(x):
...
x = 2 * x
➤ ...
return x
...
>>> x = 1
>>> x = f(x + 1) + f(x + 2)

report erratum • discuss

Chapter 3. Designing and Using Functions

• 44

This is a return statement, so we evaluate the expression, which is simply x.
Python looks up the value for x in the current frame and finds 4, so that is
the return value:
Objects

Frames

id1:function

shell
f

id1

x

id2

f(x)

id2:int

id3:int
2

f
x

id4

Return value

id4

1
id4:int
4

When the function returns, Python comes back to this expression: f(x + 1) +
f(x + 2). Python just finished executing f(x + 1), which produced the value 4. It
then executes the right function call: f(x + 2).
Following the rules for executing a function call, Python evaluates the argument, x + 2. In order to find the value for x, Python looks in the current frame.
The call on function f has returned, so that frame is erased: the only frame
left is the frame for the shell, and its variable x still refers to 1, so x + 2 evaluates to 3.
Now we have evaluated the argument to f. The next step is to create a
namespace for the function call. We draw a frame, write in the parameter x,
and assign 3 to that parameter:

Again, we have two variables called x.

report erratum • discuss

Tracing Function Calls in the Memory Model

• 45

We are now about to execute the first statement of function f:
>>> def f(x):
x = 2 * x
...
return x
...
>>> x = 1
>>> x = f(x + 1) + f(x + 2)

➤ ...

x = 2 * x is an assignment statement. The right side is the expression 2 * x.

Python looks up the value of x in the current frame and finds 3, so that
expression evaluates to 6. Python finished executing that assignment statement
by making x refer to that 6:
Objects

Frames

id1:function

shell
f

id1

x

id2

f(x)

id2:int

id3:int
2

f
x

id6

1
id4:int
4
id5:int
3
id6:int
6

We are now about to execute the second statement of function f:
>>> def f(x):
...
x = 2 * x
➤ ...
return x
...
>>> x = 1
>>> x = f(x + 1) + f(x + 2)

This is a return statement, so we evaluate the expression, which is simply x.
Python looks up the value for x in the current frame and finds 6, so that is
the return value (as shown in the figure on page 46).

report erratum • discuss

Chapter 3. Designing and Using Functions

• 46

Objects

Frames

id1:function

shell
f

id1

x

id2

f(x)

id2:int
1

id3:int
2

f

id4:int

x

id6

4

Return value

id6

id5:int
3
id6:int
6

When the function returns, Python comes back to this expression: f(x + 1) +
f(x + 2). Python just finished executing f(x + 2), which produced the value 6.
Both function calls have been executed, so Python applies the + operator to
4 and 6, giving us 10.
We have now evaluated the right side of the assignment statement; Python
completes it by making the variable on the left side, x, refer to 10:
Objects

Frames

id1:function

shell
f

id1

x

id7

f(x)

id2:int

id3:int
2

1
id4:int
4
id5:int
3
id6:int

id7:int

6

10

Phew! That’s a lot to keep track of. Python does all that bookkeeping for us,
but to become a good programmer it’s important to understand each individual step.

report erratum • discuss

Designing New Functions: A Recipe

• 47

Designing New Functions: A Recipe
Writing a good essay requires planning: deciding on a topic, learning the
background material, writing an outline, and then filling in the outline until
you’re done.
Similarly, writing a good function also requires planning. You have an idea
of what you want the function to do, but you need to decide on the details.
Every time you write a function, you need to figure out the answers to the following questions:
•
•
•
•
•

What do you name the function?
What are the parameters, and what types of information do they refer to?
What calculations are you doing with that information?
What information does the function return?
Does it work like you expect it to?

The function design recipe helps you find answers to all these questions.
This section describes a step-by-step recipe for designing and writing a
function. Part of the outcome will be a working function, but almost as
important is the documentation for the function. Python uses three double
quotes to start and end this documentation; everything in between is meant
for humans to read. This notation is called a docstring, which is short for
documentation string.
Here is an example of a completed function. We’ll show you how we came up
with this using a function design recipe (FDR), but it helps to see a completed
example first:
>>> def days_difference(day1: int, day2: int) -> int:
...
"""Return the number of days between day1 and day2, which are
...
both in the range 1-365 (thus indicating the day of the
...
year).
...
...
>>> days_difference(200, 224)
...
24
...
>>> days_difference(50, 50)
...
0
...
>>> days_difference(100, 99)
...
-1
...
"""
...
return day2 - day1
...

Here are the parts of the function, including the docstring:

report erratum • discuss

Chapter 3. Designing and Using Functions

• 48

• The first line is the function header. We have annotated the parameters
with the types of information that we expect to be passed to them (we
expect both day1 and day2 to refer to values of type int), and the int after the
-> is the type of value we expect the function to return. These type annotations are optional in Python, but we will use them throughout the book.
• The second line has three double quotes to start the docstring, which begins
with a description of what the function will do when it is called. The description
mentions both parameters and describes what the function returns.
• Next are some example calls and return values as we would expect to see
in the Python shell. (We chose the first example because that made day1
smaller than day2, the second example because the two days are equal,
and the third example because that made day1 bigger than day2.)
• Next are three double quotes to end the docstring.
• The last line is the body of the function.
There are five steps to the function design recipe. It may seem like a lot of
work at first, and you will often be able to write a function without rigidly
following these steps, but this recipe can save you hours of time when you’re
working on more complicated functions.
1. Examples. The first step is to figure out what name you want to give to
your function, what arguments it should have, and what information it
will return. This name is often a short answer to the question, “What does
your function do?” Type a couple of example calls and return values.
We start with the examples because they’re the easiest: before we write
anything, we need to decide what information we have (the argument
values) and what information we want the function to produce (the return
value). Here are the examples from days_difference:
...
...
...
...
...
...

>>> days_difference(200, 224)
24
>>> days_difference(50, 50)
0
>>> days_difference(100, 99)
-1

2. Header. The second step is to decide on the parameter names, parameter
types, and return type and write the function header. Pick meaningful
parameter names to make it easy for other programmers to understand
what information to give to your function. Include type annotations: Are
you giving it integers? Floating-point numbers? Maybe both? We’ll see a
lot of other types in the upcoming chapters, so practicing this step now

report erratum • discuss

Designing New Functions: A Recipe

• 49

while you have only a few choices will help you later. If the answer is,
“Both integers and floating-point numbers,” then use float because integers
are a subset of floating-point numbers.
Also, what type of value is returned? An integer, a floating-point number,
or possibly either one of them?
The parameter types and return type form a type contract because we are
claiming that if you call this function with the right types of values, we’ll
give you back the right type of value. (We’re not saying anything about
what will happen if we get the wrong kind of values.)
Here is the header from days_difference:
>>> def days_difference(day1: int, day2: int) -> int:

3. Description. Write a short paragraph describing your function: this is what
other programmers will read in order to understand what your function
does, so it’s important to practice this! Mention every parameter in your
description and describe the return value. Here is the description from
days_difference:
...
...
...

"""Return the number of days between day1 and day2, which are
both in the range 1-365 (thus indicating the day of the
year).

4. Body. By now, you should have a good idea of what you need to do in
order to get your function to behave properly. It’s time to write some code!
Here is the body from days_difference:
...

return day2 - day1

5. Test. Run the examples to make sure your function body is correct. Feel
free to add more example calls if you happen to think of them. For
days_difference, we copy and paste our examples into the shell and compare
the results to what we expected:
>>> days_difference(200, 224)
24
>>> days_difference(50, 50)
0
>>> days_difference(100, 99)
-1

Designing Three Birthday-Related Functions
We’ll now apply our function design recipe to solve this problem: Which day
of the week will a birthday fall upon, given what day of the week it is today

report erratum • discuss

Chapter 3. Designing and Using Functions

• 50

and what day of the year the birthday is on? For example, if today is the third
day of the year and it’s a Thursday, and a birthday is on the 116th day of the
year, what day of the week will it be on that birthday?
We’ll design three functions that together will help us do this calculation.
We’ll write them in the same file; until we get to Chapter 6, A Modular
Approach, on page 99, we’ll need to put functions that we write in the same
file if we want to be able to have them call one another.
We will represent the day of the week using 1 for Sunday, 2 for Monday, and
so on:
Day of the Week

Number

Sunday

1

Monday

2

Tuesday

3

Wednesday

4

Thursday

5

Friday

6

Saturday

7

We are using these numbers simply because we don’t yet have the tools to
easily convert between days of the week and their corresponding numbers.
We’ll have to do that translation in our heads.
For the same reason, we will also ignore months and use the numbers 1
through 365 to indicate the day of the year. For example, we’ll represent
February 1st as 32, since it’s the thirty-second day of the year.

How Many Days Difference?
We’ll start by seeing how we came up with function days_difference. Here are
the function design recipe steps. Try following along in the Python shell.
1. Examples. We want a clear name for the difference in days; we’ll use
days_difference. In our examples, we want to call this function and state
what it returns. If we want to know how many days there are between
the 200th day of the year and the 224th day, we can hope that this will
happen:
...
...

>>> days_difference(200, 224)
24

What are the special cases? For example, what if the two days are the
same? How about if the second one is before the first?

report erratum • discuss

Designing New Functions: A Recipe
...
...
...
...

• 51

>>> days_difference(50, 50)
0
>>> days_difference(100, 99)
-1

Now that we have a few examples, we can move on to the next step.
2. Header. We have a couple of example calls. The arguments in our function
call examples are all integers, and the return values are integers too, so
that gives us the type contract. In the examples, both arguments represent
a number of days, so we’ll name them day1 and day2:
>>> def days_difference(day1: int, day2: int) -> int:

3. Description. We’ll now describe what a call on the function will do. Because
the documentation should completely describe the behavior of the function,
we need to make sure that it’s clear what the parameters mean:
...
...
...

"""Return the number of days between day1 and day2, which are
both in the range 1-365 (thus indicating the day of the
year).

4. Body. We’ve laid everything out. Looking at the examples, we see that we
can implement this using subtraction. Here is the whole function again,
including the body:
>>> def days_difference(day1: int, day2: int) -> int:
...
"""Return the number of days between day1 and day2, which are
...
both in the range 1-365 (thus indicating the day of the
...
year).
...
...
>>> days_difference(200, 224)
...
24
...
>>> days_difference(50, 50)
...
0
...
>>> days_difference(100, 99)
...
-1
...
"""
...
return day2 - day1
...

5. Test. To test it, we fire up the Python shell and copy and paste the calls
into the shell, checking that we get back what we expect:
>>> days_difference(200, 224)
24
>>> days_difference(50, 50)
0
>>> days_difference(100, 99)
-1

report erratum • discuss

Chapter 3. Designing and Using Functions

• 52

Here’s something really cool. Now that we have a function with a docstring,
we can call help on that function:
>>> help(days_difference)
Help on function days_difference in module __main__:
days_difference(day1:int, day2:int) -> int
Return the number of days between day1 and day2, which are both
in the range 1-365 (thus indicating the day of the year).
>>> days_difference(200, 224)
24
>>> days_difference(50, 50)
0
>>> days_difference(100, 99)
-1

What Day Will It Be in the Future?
It will help our birthday calculations if we write a function to calculate what
day of the week it will be given the current weekday and how many days
ahead we’re interested in. Remember that we’re using the numbers 1 through
7 to represent Sunday through Saturday.
Again, we’ll follow the function design recipe:
1. Examples. We want a short name for what it means to calculate what
weekday it will be in the future. We could choose something like
which_weekday or what_day; we’ll use get_weekday. There are lots of choices.
We’ll start with an example that asks what day it will be if today is Tuesday
(day 3 of the week) and we want to know what tomorrow will be (1 day
ahead):
>>> get_weekday(3, 1)
4

Whenever we have a function that should return a value in a particular
range, we should write example calls where we expect either end of that
range as a result.
What if it’s Friday (day 6)? If we ask what day it will be tomorrow, we
expect to get Saturday (day 7):
>>> get_weekday(6, 1)
7

What if it’s Saturday (day 7)? If we ask what day it will be tomorrow, we
expect to get Sunday (day 1):

report erratum • discuss

Designing New Functions: A Recipe

• 53

>>> get_weekday(7, 1)
1

We’ll also try asking about 0 days in the future as well as a week ahead;
both of these cases should give back the day of the week we started with:
>>> get_weekday(1, 0)
1
>>> get_weekday(4, 7)
4

Let’s also try 10 weeks and 2 days in the future so we have a case where
there are several intervening weeks:
>>> get_weekday(7, 72)
2

2. Header. In our example calls, the arguments are all integers, and the
return values are integers too, so that gives us our type contract.
The first argument is the current day of the week, so we’ll name it current_weekday. The second argument is how many days from now to calculate.
We’ll pick the name days_ahead, although days_from_now would also be fine:
>>> def get_weekday(current_weekday: int, days_ahead: int) -> int:

3. Description. We need a complete description of what this function will do.
We’ll start with a sentence describing what the function does, and then
we’ll describe what the parameters mean:
...
...
...
...
...
...
...
...

"""Return which day of the week it will be days_ahead days
from current_weekday.
current_weekday is the current day of the week and is in
the range 1-7, indicating whether today is Sunday (1),
Monday (2), ..., Saturday (7).
days_ahead is the number of days after today.

Notice that our first sentence uses both parameters and also describes
what the function will return.
4. Body. Looking at the examples, we see that we can solve the first example
with this: return current_weekday + days_ahead. That, however, won’t work for
all of the examples; we need to wrap around from day 7 (Saturday) back
to day 1 (Sunday). When you have this kind of wraparound, usually the
remainder operator, %, will help. Notice that evaluation of (7 + 1) % 7 produces 1, (7 + 2) % 7 produces 2, and so on.

report erratum • discuss

Chapter 3. Designing and Using Functions

• 54

Let’s try taking the remainder of the sum: return current_weekday + days_ahead
% 7. Here is the whole function again, including the body:
>>> def get_weekday(current_weekday: int, days_ahead: int) -> int:
...
"""Return which day of the week it will be days_ahead days from
...
current_weekday.
...
...
current_weekday is the current day of the week and is in the
...
range 1-7, indicating whether today is Sunday (1), Monday (2),
...
..., Saturday (7).
...
...
days_ahead is the number of days after today.
...
...
>>> get_weekday(3, 1)
...
4
...
>>> get_weekday(6, 1)
...
7
...
>>> get_weekday(7, 1)
...
1
...
>>> get_weekday(1, 0)
...
1
...
>>> get_weekday(4, 7)
...
4
...
>>> get_weekday(7, 72)
...
2
...
"""
...
return current_weekday + days_ahead % 7
...

5. Test. To test it, we fire up the Python shell and copy and paste the calls
into the shell, checking that we get back what we expect:
>>> get_weekday(3, 1)
4
>>> get_weekday(6, 1)
7
>>> get_weekday(7, 1)
8

Wait, that’s not right. We expected a 1 on that third example, not an 8,
because 8 isn’t a valid number for a day of the week. We should have
wrapped around to 1.
Taking another look at our function body, we see that because % has
higher precedence than +, we need parentheses:

report erratum • discuss

Designing New Functions: A Recipe

• 55

>>> def get_weekday(current_weekday: int, days_ahead: int) -> int:
...
"""Return which day of the week it will be days_ahead days
...
from current_weekday.
...
...
current_weekday is the current day of the week and is in
...
the range 1-7, indicating whether today is Sunday (1),
...
Monday (2), ..., Saturday (7).
...
...
days_ahead is the number of days after today.
...
...
>>> get_weekday(3, 1)
...
4
...
>>> get_weekday(6, 1)
...
7
...
>>> get_weekday(7, 1)
...
1
...
>>> get_weekday(1, 0)
...
1
...
>>> get_weekday(4, 7)
...
4
...
>>> get_weekday(7, 72)
...
2
...
"""
...
return (current_weekday + days_ahead) % 7
...

Testing again, we see that we’ve fixed that bug in our code, but now we’re
getting the wrong answer for the second test!
>>> get_weekday(3, 1)
4
>>> get_weekday(6, 1)
0
>>> get_weekday(7, 1)
1

The problem here is that when current_weekday + days_ahead evaluates to a
multiple of 7, then (current_weekday + days_ahead) % 7 will evaluate to 0, not 7.
All the other results work well; it’s just that pesky 7.
Because we want a number in the range 1 through 7 but we’re getting an
answer in the range 0 through 6 and all the answers are correct except
that we’re seeing a 0 instead of a 7, we can use this trick:
a. Subtract 1 from the expression: current_weekday + days_ahead - 1.
b. Take the remainder.
c.

Add 1 to the entire result: (current_weekday + days_ahead - 1) % 7 + 1.

report erratum • discuss

Chapter 3. Designing and Using Functions

• 56

Let’s test it again:
>>>
4
>>>
7
>>>
1
>>>
1
>>>
4
>>>
2

get_weekday(3, 1)
get_weekday(6, 1)
get_weekday(7, 1)
get_weekday(1, 0)
get_weekday(4, 7)
get_weekday(7, 72)

We’ve passed all the tests, so we can now move on.

What Day Is My Birthday On?
We now have two functions related to day-of-year calculations. One of them
calculates the difference between two days of the year. The other calculates the
weekday for a day in the future given the weekday today. We can use these two
functions to help figure out what day of the week a birthday falls on given what
day of the week it is today, what the current day of the year is, and what day of
the year the birthday falls on. Again, we’ll follow the function design recipe:
1. Examples. We want a name for what it means to calculate what weekday
a birthday will fall