You are on page 1of 133

Python 1

Lesso n 1: Ge t t ing St art e d


A Bit o f Pytho n Histo ry
Unix and Co deRunner
Pro gramming in Pytho n
A First Pro gram
The Interactive Interpreter

Data in Pytho n
String Representatio ns
Numbers in Pytho n
Pro gram 2: Printing Simple Pytho n Expressio ns
A Few Sample Expressio ns

First Hurdle Cleared


Quiz 1 Quiz 2 Pro ject 1
Lesso n 2: Ent e ring and St o ring Dat a
Binding Values to Names
Names in Pytho n
Namespaces and Object Space

Mo re Pytho n Syntax Basics


Line Co ntinuatio ns
Multiple Statements o n One Line
Indentatio n
Co mments
Do cstrings
Using String Metho ds: Case Co nversio n

Reading and Co nverting User Input


The input() Functio n
Type Co nversio ns

Calculating with Sto red Values


Getting It Do ne
Quiz 1 Quiz 2 Pro ject 1
Lesso n 3: Making De cisio ns: T he if St at e m e nt
Co nditio ns in Pytho n
Making Decisio ns: if Statements
Cho o sing Between Alternatives: the else Clause
Multiple Cho ice Decisio ns
Co mbining Co nditio ns: 'and' and 'o r'
Testing fo r a Range o f Values: Chaining Co mpariso ns
Wrapping It Up
Quiz 1 Quiz 2 Pro ject 1
Lesso n 4: It e rat io n: Fo r and While Lo o ps
A Basic Fo r Lo o p
Breaking Out o f a Lo o p
While Lo o ps
Terminating the Current Iteratio n
Feel the Po wer
Quiz 1 Pro ject 1
Lesso n 5: Se que nce Co nt aine rs: List s and T uple s
Lists and Tuples
Writing Lists and Tuples
Accessing Sequence Values
Mo difying Lists
Slices with a Stride: Skipping Sequences
Other Functio ns and Metho ds to Use with Sequences
Testing fo r Presence in a Sequence
Manipulating Lists and Tuples
It Slices, It Dices...
Quiz 1 Quiz 2 Pro ject 1
Lesso n 6 : Se t s and Dict s
Creating Sets
Wo rking with Sets
Wo rking with Dicts
Applying Dicts: Co unting Wo rds
A Mo re Co mplex Applicatio n: Wo rd Pair Frequencies
Nice Wo rk!
Quiz 1 Quiz 2 Pro ject 1
Lesso n 7: St ring Fo rm at t ing
The fo rmat() Metho d
Functio n Arguments
Fo rmat Field Names
Fo rmat Specificatio ns
Padding and Alignment
Sign
Base Indicato r
Digit Separato r
Field Width
Precisio n
Field Type

Variable-Width Fields
A Simple Listing Pro gram
Check Yo u Out!
Quiz 1 Quiz 2 Pro ject 1
Lesso n 8 : Mo re Abo ut Lo o ping
Fun with the range() functio n.
Using the enumerate() functio n
A Mo re Co mplex While Lo o p Example
While Lo o ps and User Input Validatio n
Dicts and Lo o ps
A Mo re Co mplex Example
Lo o p This
Quiz 1 Quiz 2 Pro ject 1
Lesso n 9 : Re ading and Writ ing File s
Creating a New File
Writing to a File
Reading Files as Text
Appending to a File
Seeking to Arbitrary Po sitio ns
Mo re File Details
Creating a File-Based To -Do List
Reading Binary Data
Files fo r Miles
Quiz 1 Quiz 2 Pro ject 1
Lesso n 10 : Pyt ho n's Built -In Funct io ns
Party Fun with Built-In Functio ns
abs(x)
all(iterable)
any(iterable)
bo o l(x)
chr(i)
dict(arguments)
dir(arguments)
glo bals()
help(o bject)
len(s)
lo cals()
max(iterable)
min(iterable)
o rd(c)
po w(x, y[, z])
reversed(seq)
ro und(x[, n])
so rted(iterable)
sum(iterable)
zip(*iterables)
Fun with Built-In Functio ns
Quiz 1 Quiz 2 Pro ject 1
Lesso n 11: De f ining and Calling Yo ur Own Funct io ns
Explo ring Functio ns
Write Yo ur First Functio n
Parameters and Arguments
Parameters and Arguments
Returning Values
Multiple Return Values
Functio ns and Namespaces
Parameters That Receive Multiple Arguments
Putting It All To gether
A So lid Fo undatio n
Quiz 1 Quiz 2 Pro ject 1
Lesso n 12: T he Pyt ho n St andard Library
Increased Versatility
Namespaces
Pytho n Mo dules
Writing Mo dules to be Testable
Splitting Up Yo ur Pro grams
Other Ways to Impo rt a Mo dule
impo rt ... as
fro m ... impo rt ...

The System Path


Reduce, Reuse, Recycle!
Quiz 1 Quiz 2 Pro ject 1
Lesso n 13: Mo re Abo ut Funct io ns
Arbitrary Keywo rd Parameters
Parameters, Sequence-Parameters, and Dict-Parameters
Impo rting Functio ns and help()
Functio n Executio n by Dispatch
What's Yo ur Functio n?
Quiz 1 Quiz 2 Pro ject 1
Lesso n 14: Classe s and Obje ct -Orie nt e d Pro gram m ing
The Nature o f Objects
Defining Yo ur Own Object Classes
Class and Instance Namespaces
Defining Object Behavio r
Defining Behavio r as Metho ds
Pytho n Deep Magic: Ho o king into Pytho n's Class Mechanism
Using __init__()
Mo re o n Pytho n's Dunder Metho ds
Being Selfish
A So lid Fo undatio n

Quiz 1 Quiz 2 Pro ject 1


Lesso n 15: Exce pt io n Handling
Wo rking thro ugh Exceptio ns
Ho w to Catch an Exceptio n
Verifying Numeric Input
Handling Multiple Exceptio n Types
Handling Multiple Exceptio ns with One Handler
Raising Exceptio ns
Specific and Generic Exceptio ns
When to Use Exceptio ns
Exceptio nal Wo rk So Far!

Quiz 1 Pro ject 1


Lesso n 16 : Building and De bugging Who le Pro gram s
Putting it All To gether
The Art o f Co mputer Pro gramming
Design Techniques
Agile Pro gramming
Do cumenting and Testing Pytho n Co de
'Keep It Simple, Stupid' (KISS)
Refacto ring
Go Fo rth and Co de in Pytho n!

Quiz 1 Pro ject 1 Pro ject 2 Pro ject 3

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Getting Started
Welco me to the O'Reilly Scho o l o f Techno lo gy's (OST) Int ro duct io n t o Pyt ho n co urse! We're happy yo u've cho sen to learn
Pytho n pro gramming with us.

Course Objectives
When yo u co mplete this co urse, yo u will be able to :

sto re and manipulate user-input data using Pytho n.


implement basic Pytho n decisio ns, iteratio n, sequence co ntainers, sets, and dicts.
read and write files using Pytho n.
define custo m functio ns and call built-in Pytho n functio ns.
impo rt mo dules and namespaces fro m the Pytho n Standard Library.
define classes and instantiate o bjects using Pytho n's Class mechanism.
handle exceptio ns and do cument co de.
build and debug an entire pro gram written in Pytho n.

In this co urse, yo u will learn the basics o f pro gramming with Pytho n. Using the Co deRunner integrated learning enviro nment,
yo u'll learn abo ut expressio ns, variables, co nditio nals, lo o ps, lists, sets, dicts, functio ns, o bjects and exceptio ns.

Besides a bro wser and internet co nnectio n, all so ftware is pro vided o nline by the O'Reilly Scho o l o f Techno lo gy.

Learning with O'Reilly School of Technology Courses


As with every O'Reilly Scho o l o f Techno lo gy co urse, we'll take a user-active appro ach to learning. This means that yo u
(the user) will be active! Yo u'll learn by do ing, building live pro grams, testing them and experimenting with them—
hands-o n!

To learn a new skill o r techno lo gy, yo u have to experiment. The mo re yo u experiment, the mo re yo u learn. Our system
is designed to maximize experimentatio n and help yo u learn to learn a new skill.

We'll pro gram as much as po ssible to be sure that the principles sink in and stay with yo u.

Each time we discuss a new co ncept, yo u'll put it into co de and see what YOU can do with it. On o ccasio n we'll even
give yo u co de that do esn't wo rk, so yo u can see co mmo n mistakes and ho w to reco ver fro m them. Making mistakes
is actually ano ther go o d way to learn.

Abo ve all, we want to help yo u to learn to learn. We give yo u the to o ls to take co ntro l o f yo ur o wn learning experience.

When yo u co mplete an OST co urse, yo u kno w the subject matter, and yo u kno w ho w to expand yo ur kno wledge, so
yo u can handle changes like so ftware and o perating system updates.

Here are so me tips fo r using O'Reilly Scho o l o f Techno lo gy co urses effectively:

T ype t he co de . Resist the temptatio n to cut and paste the example co de we give yo u. Typing the co de
actually gives yo u a feel fo r the pro gramming task. Then play aro und with the examples to find o ut what else
yo u can make them do , and to check yo ur understanding. It's highly unlikely yo u'll break anything by
experimentatio n. If yo u do break so mething, that's an indicatio n to us that we need to impro ve o ur system!
T ake yo ur t im e . Learning takes time. Rushing can have negative effects o n yo ur pro gress. Slo w do wn and
let yo ur brain abso rb the new info rmatio n tho ro ughly. Taking yo ur time helps to maintain a relaxed, po sitive
appro ach. It also gives yo u the chance to try new things and learn mo re than yo u o therwise wo uld if yo u
blew thro ugh all o f the co ursewo rk to o quickly.
Expe rim e nt . Wander fro m the path o ften and explo re the po ssibilities. We can't anticipate all o f yo ur
questio ns and ideas, so it's up to yo u to experiment and create o n yo ur o wn. Yo ur instructo r will help if yo u
go co mpletely o ff the rails.
Acce pt guidance , but do n't de pe nd o n it . Try to so lve pro blems o n yo ur o wn. Go ing fro m
misunderstanding to understanding is the best way to acquire a new skill. Part o f what yo u're learning is
pro blem so lving. Of co urse, yo u can always co ntact yo ur instructo r fo r hints when yo u need them.
Use all available re so urce s! In real-life pro blem-so lving, yo u aren't bo und by false limitatio ns; in OST
co urses, yo u are free to use any reso urces at yo ur dispo sal to so lve pro blems yo u enco unter: the Internet,
reference bo o ks, and o nline help are all fair game.
Have f un! Relax, keep practicing, and do n't be afraid to make mistakes! Yo ur instructo r will keep yo u at it
until yo u've mastered the skill. We want yo u to get that satisfied, "I'm so co o l! I did it!" feeling. And yo u'll have
so me pro jects to sho w o ff when yo u're do ne.

Lesson Format
We'll try o ut lo ts o f examples in each lesso n. We'll have yo u write co de, lo o k at co de, and edit existing co de. The co de
will be presented in bo xes that will indicate what needs to be do ne to the co de inside.

Whenever yo u see white bo xes like the o ne belo w, yo u'll type the co ntents into the edito r windo w to try the example
yo urself. The CODE TO TYPE bar o n to p o f the white bo x co ntains directio ns fo r yo u to fo llo w:

CODE TO TYPE:

White boxes like this contain code for you to try out (type into a file to run).

If you have already written some of the code, new code for you to add looks like this.

If we want you to remove existing code, the code to remove will look like this.

We may also include instructive comments that you don't need to type.

We may run pro grams and do so me o ther activities in a terminal sessio n in the o perating system o r o ther co mmand-
line enviro nment. These will be sho wn like this:

INTERACTIVE SESSION:

The plain black text that we present in these INTERACTIVE boxes is


provided by the system (not for you to type). The commands we want you to type look lik
e this.

Co de and info rmatio n presented in a gray OBSERVE bo x is fo r yo u to inspect and absorb. This info rmatio n is o ften
co lo r-co ded, and fo llo wed by text explaining the co de in detail:

OBSERVE:

Gray "Observe" boxes like this contain information (usually code specifics) for you to
observe.

The paragraph(s) that fo llo w may pro vide additio n details o n inf o rm at io n that was highlighted in the Observe bo x.

We'll also set especially pertinent info rmatio n apart in "No te" bo xes:

Note No tes pro vide info rmatio n that is useful, but no t abso lutely necessary fo r perfo rming the tasks at hand.

T ip Tips pro vide info rmatio n that might help make the to o ls easier fo r yo u to use, such as sho rtcut keys.

WARNING Warnings pro vide info rmatio n that can help prevent pro gram crashes and data lo ss.

The CodeRunner Screen


This co urse is presented in Co deRunner, OST's self-co ntained enviro nment. We'll discuss the details later, but here's
a quick o verview o f the vario us areas o f the screen:
These video s explain ho w to use Co deRunner:

File Management Demo

Co de Edito r Demo

Co ursewo rk Demo

A Bit of Python History


First, here's a little backgro und info rmatio n to intro duce yo u to Pytho n. No cringing please—this will be the mo st
textbo o kish part o f the co urse. We like to pro vide a little histo ry fo r o ur students with a mo re philo so phical and
academic bent. Plus yo u'll have a better understanding o f yo ur pro gramming tasks if yo u have a better idea abo ut what
makes Pytho n tick.

The Pytho n language was created by Guido van Ro ssum in the late 19 8 0 s. It was intended to be simple to use and
easy to understand. The mo st interesting new feature o f the language was its use o f indentatio n to illustrate structure,
similar to the way we use indentatio n in o ur everyday pro se and written language.

Pytho n was built to have a small "co re," to keep it accessible, and a large library to make it versatile. Van Ro ssum was
interested in netwo rking. That interest pro mpted quick develo pment o f a useful set o f netwo rk libraries fo r the language;
many mo re libraries have been added since then.

To day, Pytho n is used just abo ut everywhere. Majo r users include Yo uTube, Go o gle, Yaho o !, CERN, and NASA, and
ITA—the co mpany that pro duces the ro ute search engine used by Orbitz, CheapTickets, travel agents—as well as
many do mestic and internatio nal airlines.

Pytho n is an interpreted language, which means Pytho n co de isn't translated into the binary instructio ns that
co mputers actually run. Instead, bytecode is created, and the interpreter uses that byteco de to tell it what to do . Pytho n
is also a dynamic language. This means that aspects o f yo ur pro gram which beco me fixed early o n in so me
languages, remain available fo r yo u to change in Pytho n, even while yo ur pro gram is running.

In this co urse, we'll be using the latest versio n o f Pytho n (3.1). Yo u may find that o ther peo ple are using o lder versio ns.
Fo rtunately, the differences between versio ns are mino r. We'll go o ver the changes yo u'll need to be aware o f in o rder
to wo rk with o lder versio ns as well.

Unix and CodeRunner


We use o ur Co deRunner Integrated Develo pment Enviro nment o n the Unix o perating system fo r this co urse. Unix and
Co deRunner allo w yo u to write Pytho n pro grams o n o ur co mputers so yo u do n't need to wo rry abo ut having any
special so ftware o n yo ur o wn co mputer. We have an entire OST co urse devo ted to Unix if yo u'd like a deeper
understanding o f that o perating system. Fo r this co urse, we'll just co ver the co ncepts yo u need to kno w, when yo u
need to kno w them.

In the next sectio n, we'll finally enter so me Pytho n co de and run it!

Programming in Python
A First Program
It is a traditio n when learning a new language in co mputer pro gramming to print the wo rds "hello wo rld" as a
first example. Pytho n can print "hello wo rld" in a single line o f co de, so that do esn't make fo r a great example
here. Instead, we'll lo o k at a slightly mo re co mplicated example that no t o nly prints "hello " and "go o dbye," but
also do es a little calculatio n alo ng the way.

Usually yo u'll enter a Pytho n pro gram in yo ur favo rite text edito r and then run it by typing a co mmand in a
co mmand shell (that's the term fo r o ne o f tho se special pro grams who se jo b in life is to display a pro mpt and
then let yo u type in a co mmand that executes when yo u press Enter). On a Unix o r Linux type o f system (that
includes OS X), the shell is bash, o r tcsh, o r so me o ther -sh, and the edito r is vim o r Emacs o r o ne o f many
o ther po ssibilities. On Windo ws, the shell is the DOS windo w (what yo u get by running "cmd") and the edito r
is No tepad o r Wo rdpad o r vim o r, again, any o f many o ther po ssibilities. (Yo u can also run pro grams o n
Windo ws by do uble-clicking their ico ns, but then the usual input and o utput streams are no t available.)

In this co urse we're go ing to use a co mpletely integrated enviro nment because we want the co urse to be
abo ut learning Pytho n, no t abo ut learning a particular edito r and o perating system. Later in the co urse, there
is a brief lesso n o n basic Unix co mmands and edito rs so that, when yo u're ready, yo u can transfer yo ur
kno wledge o f Pytho n to the real wo rld.

Let's get started o n yo ur first pro gram! First, we'll create a fo lder to keep all o f o ur Pytho n stuff o rganized. In
the left panel o f yo ur Co deRunner windo w, right-click Ho m e , and select Ne w f o lde r... as sho wn:

Enter the fo lder name pyt ho n1:


Note Yo u wo n't see this many fo lders in yo ur File Bro wser. OST edito rs wo rk o n a lo t o f co urses!

No w yo u sho uld be able to see yo ur pyt ho n1 fo lder listed in the File Bro wse r o n the left side o f yo ur
screen:

No w, in the edito r windo w area belo w this lesso n text, enter the co de belo w:

CODE TO TYPE:

print("Hello World")
print("I have", 3 + 4, "bananas")
print("Goodbye, World")

In the edito r menu bar, click the Save ico n: (we'll sho w that ico n fro m no w o n when we want yo u to save a
file). Select yo ur /pyt ho n1 fo lder and enter the file name he llo _wo rld.py:
To run the pro gram, o pen a Unix shell. Click the Ne w T e rm inal ico n at the to p o f the edito r windo w and,
when pro mpted, enter yo ur OST username and passwo rd (the passwo rd wo n't appear as yo u type it):

INTERACTIVE SESSION:

cold1 login: username


Password: yourpassword

Once lo gged in, yo u'll see a co ld1:~$ pro mpt. Change to yo ur /pyt ho n1 fo lder and then run the pro gram as
sho wn:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ python3 ./hello_world.py
Hello World
I have 7 bananas
Goodbye, World
cold1:~/python1$

Co ngratulatio ns! Yo u're o fficially a Pytho n pro grammer! Of co urse this pro gram isn't very co mplex, but the
interpreter has do ne the calculatio n yo u asked it to do . Pat yo urself o n the back! Yo u're o ff to a stro ng start.
Experiment with o ther calculatio ns.

Ho w did this wo rk? Let's lo o k a little clo ser:

OBSERVE:

cold1:~$ cd python1
cold1:~/python1$ python3 ./hello_world.py

First we used the Unix changed directo ry (cd) co mmand to change to the pyt ho n1 fo lder where o ur pro gram
is lo cated. Then we ran pyt ho n3, the current versio n o f the Pytho n interpreter, telling it to run the
he llo _wo rld.py pro gram lo cated in the current fo lder (./)

Note When yo u want to exit fro m the interactive sessio n, type e xit and press Ent e r, o r press Ct rl+d.

T he Interactive Interpreter
In Pytho n, yo u can run the interpreter in interactive mo de when yo u want to try things o ut and see results
printed right away. That instant feedback is really handy when yo u're learning a new language.

Co deRunner gives yo u access to interactive Pytho n sessio ns—click the New Terminal ico n, and in the
Terminal windo w, type yo ur OST lo gin and passwo rd (again, it do esn't appear while yo u're typing it), and then
type pyt ho n3:

INTERACTIVE SESSION:

cold1 login: your OST login


Password: your OST password
cold1:~$ python3
Python 3.1.4 (default, Oct 13 2011, 10:08:29)
[GCC 4.4.5 20110214 (Red Hat 4.4.5-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>

The pro mpt >>> indicates that the interpreter is ready fo r yo ur input.

If yo u enter o ne o f the lines fro m the pro gram yo u just ran, the o utput will appear. This interactive interpreter
windo w allo ws yo u to enter bo th statements and expressio ns (we'll co ver tho se in detail later). Statements
are executed pretty much as if they were part o f a pro gram; the expressio ns are evaluated and the resulting
value is printed (as lo ng as yo u're in interactive mo de).

Type the co mmands belo w in the interpreter windo w (Remember: when we say TYPE the code, do it. It's good
for you!). The interpreter prints a result fo r each expressio n. (Yo u'll see a different pro mpt after the fo urth line.
We'll talk abo ut that in a minute):

INTERACTIVE SESSION:

>>> "hello" + " world"


'hello world'
>>> 'hello' + ' world'
'hello world'
>>> """hello""" + ''' world'''
'hello world'
>>> """hello
... world"""
'hello\nworld'
>>>

So , what happened here? The first three lines are all examples o f string concatenation—a seco nd string is
appended to the first, giving a lo nger string as a result. Strings can have either single (') o r do uble (")
quo tatio n marks aro und them, and either o ne quo tatio n mark o r three at the beginning and end o f the string.
Use exactly the same co mbinatio n at bo th ends.

The last expressio n sho ws an impo rtant difference between the o ne-quo tatio n mark and the three-quo tatio n
mark fo rms. A string given in o ne-quo tatio n mark fo rm must begin and end o n the same line. Three-quo tatio n
mark strings can spread acro ss mo re than o ne line.

The fo urth example actually do es extend acro ss two lines, so the interpreter changed its pro mpt fro m >>> to
... (an ellipsis) after yo u entered the first line. The ellipsis lets yo u kno w that yo u've go t an inco mplete
statement o r expressio n, and the interpreter is waiting fo r yo u to finish it. When yo u co mpleted the string with
the seco nd line o f input, the interpreter then printed the value o f the two -line expressio n, and returned the
no rmal >>> pro mpt. Yo u can see that the line feed between he llo and wo rld is represented by \n, which is
kno wn in Pytho n as a string escape sequence.

Data in Python
In Pytho n there are vario us types o f data yo u can manipulate. The simplest are strings. There are also vario us numeric
data types: integers, flo ats, and co mplex numbers. Let's see ho w to write tho se values in yo ur pro grams.

String Representations
We've seen that Pytho n has several ways o f representing strings. Fo r regular strings, we use either o f the
o ne-quo tatio n mark fo rms. Use three-quo tatio n mark strings if, fo r example, the value yo u need to represent
co ntains newlines, o r co ntains quo tatio n marks itself. The interpreter represents certain characters using
escape sequences. Yo u can put escape sequences into yo ur strings to insert certain literal o r no n-printing
characters. Here's a list o f the mo st co mmo n sequences:

Escape Se que nce Is t ranslat e d int o


\" Do uble quo te
\' Single quo te (apo stro phe)
\\ Backslash
\r Carriage return
\n Line feed (newline)
\{newline} Igno res the newline, allo wing yo u to run a string acro ss multiple pro gram lines
\0 nn Character who se value in o ctal is nn
\xnn Character who se value in hexadecimal is nn

Yo u can build a really lo ng string using triple-quo tatio n mark strings and escaping the newlines, o r by placing
several different strings o ne after the o ther in yo ur so urce co de. Usually yo u'll extend tho se types o f
statements acro ss multiple lines using parentheses; the interpreter will assume a statement o r expressio n is
inco mplete if it runs into unmatched parentheses. Co ntinue the interpreter sessio n o r start a new o ne and try
these co mmands:

INTERACTIVE SESSION:

>>> """One\
... Two\
... Three"""
'OneTwoThree'
>>> ("One" "Two" "Three")
'OneTwoThree'
>>> 'OneTwoThree'
'OneTwoThree'

The interpreter sho uld print the same value back after yo u enter each o f the three strings. The first string yo u
entered spans three lines, but o nly printed o ut o ne.

Numbers in Python
In Pytho n, numbers are represented as yo u might expect. Integers are strings o f digits. The digits can be
preceded by a minus sign (-) fo r negative numbers. There is no limit o n integer values in Pytho n, altho ugh the
larger they get, the lo nger it takes yo u to do anything with them!

In Pytho n, yo u cannot use co mmas to separate gro ups o f digits like yo u so metimes do in text
Note do cuments.

A flo ating-po int number is made up o f an integer fo llo wed by a decimal po int and a fractio nal part. Yo u may
also use exponential notation if yo u like, by placing the letter E after the integer.

Co mplex numbers generally co nsist o f a real part and an imaginary part that's fo llo wed by a J ; the real part is
separated fro m the imaginary part by a plus o r minus sign. The imaginary number fo llo wed by the J can
co mprise a co mplex number in Pytho n as well. (Fo r yo u mathematicians wo ndering why i wasn't used, this is
standard engineering no tatio n. The rest o f us can just carry o n.)

Let's try so me o f this stuff o ut. If yo u do n't have an interpreter sessio n o pen, click the Ne w T e rm inal ico n and
type pyt ho n3 again. Then, try these numbers:

INTERACTIVE SESSION:

>>> 1
>>> -1000
>>> 12.34
>>> 1.234E2
>>> 1+2j
>>> 1j

Huh. it seems the interpreter do esn't always print a value the way yo u enter it. Flo ating po int numbers aren't
always exact, tho ugh the interpreter gets as clo se as po ssible. Altho ugh the erro rs are relatively small, yo u
want to keep them fro m accumulating to o much in lo ng strings o f calculatio ns. (Mo re o n that later.) If so me o f
this isn't quite clear to yo u yet, do n't wo rry. We're just getting started. We'll be talking abo ut it all lo ts mo re and
yo u'll have many chances to try things o ut and ask questio ns.

Program 2: Printing Simple Python Expressions


Yo u've seen that yo u can co ncatenate strings by adding them to gether. There are many mo re o peratio ns yo u
can perfo rm o n yo ur numbers in Pytho n:

Sym bo l Ope rat io n


+ Additio n
- Subtractio n
* Multiplicatio n
/ Divisio n
** Expo nentiatio n

A Few Sample Expressions


Create ano ther pro gram file in the edito r windo w:

CODE TO TYPE:

print("""--------------------
Some Calculations
--------------------""")
print(314159E-5)
print(10**6, 1j**2)
print(3 + 2 * 4, 1 / 3)
print("-" * 20)
print((3.14159 * 16) ** 2)
print(3.14159 * 16 ** 2)
print(20 * "-")
print("--------------------\nEnd of Calculations\n--------------------")

Save it in yo ur /pyt ho n1 fo lder as calculat io ns.py and run it in the Terminal tab:
INTERACTIVE SESSION:

cold1:~/python1$ python3 ./calculations.py


--------------------
Some Calculations
--------------------
3.14159
1000000 (-1+0j)
11 0.333333333333
--------------------
2526.6144583935998
804.24704
--------------------
--------------------
End of Calculations
--------------------
cold1:~/python1$

Take a minute to po nder. Think deeply and make sure yo u understand all o f yo ur results befo re go ing further.
Fo r example, yo u might wo nder, why does 3 + 2 * 4 give 11, and not 20? Hmm... so mething to think abo ut!
Feel free to talk with yo ur instructo r if yo u are in any way befuddled.

First Hurdle Cleared


Phew! That was a who le lo t o f intro ductio n there. Thanks fo r sticking with me. Keep it up, yo u're do ing great so far. See
yo u at the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Entering and Storing Data
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

give data meaningful names.


extract data fro m the user.
sto re data.

Welco me back. Let's get right to it, shall we? In Pytho n, explicit is better than implicit. The interpreter wo n't try to co nvert the string
"3.14159 " into a number fo r yo u implicitly—if yo u try to add that string to the integer 1, yo u'll get an erro r message:

We'll talk abo ut that mo re later in the lesso n; fo r no w, just let tho se terms marinate in yo ur mind. In the last lesso n, yo u saw ho w
to represent string and numeric data in Pytho n pro grams, and use the print () functio n to send expressio n values to the user.
No w we'll lo o k at ho w to sto re data and ho w to extract data from the user. Because interactive user input arrives to us in string
fo rm, we'll also need to be able to co nvert strings into o ther data types.

Binding Values to Names


Mo st pro gramming languages let yo u name yo ur data. Giving meaningful names to data makes yo ur co de easier to
read and helps yo u to recall its purpo se. It also allo ws yo u to run the same co de with different data values. And mo st
impo rtantly, giving yo ur data meaningful names means yo u can refer to the same piece o f data at different places in
yo ur pro gram: yo u can store data and then use it later.

In Pytho n, a value is given a name with the assignment statement. In its simplest fo rm, the assignment statement
co nsists o f a name, an equals sign, and a value. The value can be a single data item o r an expressio n.

Click to start a new interactive sessio n, and type these Pytho n statements:

INTERACTIVE SESSION:

cold1:~$ python3
>>> r = 32
>>> pi = 3.14159
>>> area = pi * r ** 2
>>> print(area)
3216.98816
>>> item = { 'link': "http://holdenweb.com", 'value': 99.99 }
>>> targetURL = item['link']
>>> print(targetURL)
http://holdenweb.com
>>> lst = range(5)
>>> print(lst)
range(0, 5)
>>> r = r + 1
>>> print(r)
33
These assignment statements all have pretty much the same fo rmat: nam e = value . They do n't represent
mathematical equatio ns, they are instructions to the computer. The statements are telling the co mputer to asso ciate the
value o n the right side o f the equals sign with the name o n the left side o f it. Once a name is bo und to a value, it stays
that way unless yo u change it.

When yo u read a statement like r = r + 1, be sure to read it like a pro grammer, no t a math student! Fo r us, it means to
take the value currently associated with the name r, add o ne to it, and then asso ciate this new value with the name. So if
the value o f r was 1112 befo re the statement was executed, it wo uld be 1113 afterward.

Names in Python
Every pro gramming language has rules abo ut which names are acceptable. In Pytho n, the interpreter requires
every name to begin with a letter (upper- o r lo wer-case) o r the undersco re character. The rest o f the name can
be made up o f letters, digits, o r undersco res. So , i, _privat e , Cam e lCase , and ve ry_lo ng_nam e _127 are
all valid names. But 12_nam e isn't valid, because it begins with a digit. m y-nam e is also invalid, because it
co ntains a hyphen.

Namespaces and Object Space


Values in Pytho n are sto red in memo ry allo cated fro m a heap (also kno wn as "o bject space"). The heap is an
expandable sto rage space. Namespaces ho ld names, which refer to values (o bjects in o bject space). Memo ry
usage in Pytho n is co nveniently auto matic. When yo u bind a name to a value with an assignment statement,
that binding takes place in the "current namespace." In a co mplex Pytho n pro gram, namespaces are created
and destro yed co ntinually.

Each Pytho n file yo u create is a module. Each mo dule has its o wn namespace (o ften called the global
namespace). An assignment statement at mo dule level affects the mo dule's glo bal namespace. When the
interpreter needs the value asso ciated with a specific name, it lo o ks fo r the name in a predefined list o f
places. Fo r mo dule-level co de, there are o nly two namespaces to co nsider: the mo dule glo bal namespace
and the built-in namespace that ho lds Pytho n's essential functio ns. Yo u'll learn to write functio ns and classes
later when we create instances o f classes. Every time yo u call a functio n o r create a new class o r instance, the
Pytho n interpreter creates a new namespace. That namespace beco mes unavailable when the related o bject
is destro yed.

Start the interactive interpreter windo w again and try these co mmands (remember, the >>> is a pro mpt, no t
so mething yo u have to type):
INTERACTIVE SESSION:

cold1:~$ python3
>>> a = 23
>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'a']
>>> dir(a)
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delatt
r__', '__divmod__',
'__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__
ge__', '__getattribute__',
'__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__int__', '__i
nvert__', '__le__',
'__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '_
_or__', '__pos__',
'__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__',
'__repr__', '__rfloordiv__',
'__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rr
shift__', '__rshift__',
'__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__',
'__sub__', '__subclasshook__',
'__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator',
'imag', 'numerator', 'real']

Note Yo u may see different results.

Co nsider these questio ns and answers as they relate to the co de yo u just typed:

Q. In which namespace was a value bo und to a?


A. The mo dule glo bal namespace o f the interactive sessio n.

Q. In which namespace did the interpreter lo cate the dir() functio n?


A. The built-in namespace.

Q. Which namespace do es dir() repo rt o n when called with no argument?


A. The mo dule glo bal namespace.

More Python Syntax Basics


Line Continuations
Under no rmal circumstances, each line o f yo ur Pytho n pro gram is a single statement. The exceptio ns are
when a line is explicitly co ntinued by the additio n o f a backslash, o r when a line ends befo re an o pening
paired delimiter (curly bracket, parenthesis, o r square bracket) is clo sed. When yo u enter statements and
expressio ns in the interactive interpreter, yo u no rmally see a >>> pro mpt, indicating that the interpreter is
waiting fo r yo u to enter a new statement o r expressio n. If yo u see a ... pro mpt instead, it means the interpreter
do es no t regard the current statement o r expressio n as co mplete. There are different ways to lay o ut a Pytho n
assignment. These next few assignments all bind the value 9 27 to the name "a." Type these co mmands in an
interactive sessio n:
INTERACTIVE SESSION:

cold1:~$ python3
>>> z = 100
>>> a = (3 + z) * 9
>>> print(a)
927
>>> a = \
... (3 + z) * 9
>>> print(a)
927
>>> a = (
... (3 + z)
... * 9
... )
>>> print(a)
927

Multiple Statements on One Line


Altho ugh multiple statements o n a single line can be separated by semico lo ns, we do n't reco mmend it. As
yo u'll disco ver do wn the ro ad, leading spaces are significant! Pytho n uses leading space to mark blo cks o f
co de, so if yo u start a co mmand line with a space, the co mmand generally will fail with an syntax erro r.

Let's try a few mo re examples in the interactive interpreter windo w (if yo u clo sed it, click to start a new
interactive sessio n):

INTERACTIVE SESSION:

cold1:~$ python3
>>> a = 1
>>> z = 2
>>> print(a, z)
1 2
>>> a = 1; z = 2
>>> print(a, z)
1 2
>>> a, z = 1, 2
>>> print(a, z)
1 2

In o ur first example, we have a different single assignment statement. Next, tho se same two statements
appear, separated by a semico lo n. Finally, there is an example o f what is called an unpacking assignment.
This has a co mma-separated list o f names o n the left and ano ther list o f values o n the right. Each value is
bo und to the co rrespo nding name.

Indentation
In the pro grams yo u've written so far, all statements have started in the first co lumn o f the line. Statements can
be indented when they are the o bject o f o ne o f Pytho n's compound statements. A set o f statements at the
same indentatio n level (including any co de indented within a statement) fo rm a blo ck, also called a suite. We'll
lo o k mo re clo sely at suites when we discuss co mpo und statements in future lesso ns. Fo r no w, just be sure
to start yo ur lines witho ut any leading spaces.

Comments
In a Pytho n pro gram text, the "#" character (po und sign, o cto tho rp, hash mark, call it what yo u will) intro duces
a co mment. The co mment runs to the end o f the line—it is disregarded by the interpreter. Co mments sho uld
o nly o ccur where whitespace is legal (fo r readability). Co mments help o ther pro grammers to make sense o f
yo ur pro gram, so include them o ften. As yo ur skill level increases, yo ur co mments may be less detailed, but
yo ur co de sho uld always be easy to read fo r bo th intent (the desired result o f the co de) and implementatio n
(the way the co de acco mplishes the intent). Use co mments as necessary to keep yo ur co de readable!
Docstrings
Any Pytho n expressio n is a valid statement (tho ugh statements are never expressio ns). A string o n its o wn,
as the first statement o f vario us Pytho n co nstructs (like mo dule, functio n, class, and metho d), is interpreted by
many to o ls as do cumentatio n. Using a three-quo te string allo ws yo u to add lo ts o f do cumentatio n to yo ur
pro grams. Use do cstrings extensively to do cument yo ur co de. Later examples will sho w yo u so me practical
do cstring co ntent. Fo r no w, let's try a new pro gram. Type this co de in the edito r windo w belo w:

CODE TO TYPE:

#
# This is a program that prints its own docstring
#
"""print_docstring.py prints its own docstring
(the string that's the first executable statement,
which in this case extends to three lines)."""
print(__doc__)

Save the pro gram in yo ur /pyt ho n1 fo lder as print _do cst ring.py, and go to an interactive sessio n to
change to the /pytho n1 fo lder and run it:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ python3 ./print_docstring.py
print_docstring.py prints its own docstring
(the string that's the first executable statement,
which in this case extends to three lines).
cold1:~/python1$

__do c__ in t he Mo dule Nam e space : In the co de abo ve, the interpreter reso lves the name
Note __do c__ by lo o king in the mo dule namespace. The name is always present, but if the mo dule
has no do cstring, it is set to the special value No ne .

No w what happens if we remo ve the do cstring—what happens when the print statement runs? Turn the string
into an assignment statement by putting "x = " at the beginning o f the first line after the co mments, as sho wn:

CODE TO TYPE:

#
# This is a program that prints its own docstring
#
x="""print_docstring.py prints its own docstring
(the string that's the first executable statement,
which in this case extends to three lines)."""
print(__doc__)

Save and run it. Can yo u think o f any o ther interesting variatio ns o n this pro gram? Go ahead and try a few o f
yo ur o wn experiments!

Using String Methods: Case Conversion


In the example belo w, replace each co mment with a Pytho n expressio n that returns the value described.

Do not use any literal strings—write expressions using methods of s only! Fo r example: s.capit alize ().

To see a list o f the metho ds o f a string, use dir(" " ) in the interactive interpreter.

Type in this co de:


CODE TO TYPE:
#
# case_convert.py
#
s = "this Is a Simple string"
slower = # s converted to lower case <--
supper = # s converted to UPPER CASE <--
stitle = # s converted to Title Case <--
print(s, slower, supper, stitle, sep="\n")

Save it in yo ur /pyt ho n1 fo lder as case _co nve rt .py and run it.

Test yo ur pro gram o n vario us strings by mo difying the assignment statement. Play with using the dir("string")
functio n to investigate string metho ds. Fo r example, try s.capitalize(), s.islo wer(), s.swapcase()...

It's a little tedio us to have to edit the pro gram each time yo u want to see what happens with a new value,
right? Next we will lo o k at a way o f allo wing the user to pro vide the strings that o ur pro gram o perates o n and
avo id all that extra wo rk!

Reading and Converting User Input


T he input() Function
To read data entered (interactively) by the user, yo u use the input () functio n. If yo u pro vide input () with a
string argument, that string (and o nly that string) will be printed as a pro mpt, immediately befo re reading an
input string fro m the user. Once the user types their input (ending it by pressing Ent e r), the functio n returns
the user's input (less the Enter) as a string. Unlike the lines yo u will read fro m files, user input has no trailing
newline. This is fine, but if yo u need a number fro m the user, yo u must perfo rm so me so rt o f conversion. Yo u
also need to handle any erro rs that may arise fro m yo ur attempts to co nvert (we'll let that slide fo r no w tho ugh
and push o nward!)

A co uple o f lines o f input are sho wn in the fo llo wing screen sho t. No tice that the input () functio n always
returns a string—even when the user actually types in a number:

T ype Conversions
As we mentio ned earlier, in Pytho n, "explicit is better than implicit," so we canno t add a string (even a string
who se value is a valid number) to a number. Instead, we have to explicitly co nvert the string first. The int ()
functio n takes a single string as an argument, and returns the integer represented by the string (o r raises an
exceptio n). The f lo at () functio n is similar, but takes any valid string representatio n o f a flo ating-po int number
instead (again raising an exceptio n if the string canno t be co nverted).

Yo u'll need an interactive terminal no w. Remember, if yo u do n't have o ne available, just click the ico n.
Type in these co mmands interactively:
INTERACTIVE SESSION:

cold1:~$ python3
>>> n = int(input("Enter a number: "))
Enter a number: 33
>>> x = float(input("Another number: "))
Another number: 45.67
>>> n, x
(33, 45.67)
>>> y = float(input("Final number: "))
Final number: abc.def
Traceback (most recent call last):
File "<console>", line 1, in <module>
ValueError: could not convert string to float: abc.def>>>

Feel free to try o ther inputs. Observe, to o , that the flo ating-po int number system used o n co mputers canno t
express 45.6 7 exactly, tho ugh it gets pretty clo se. This usually o nly happens with flo ating-po int numbers, no t
integers. If yo u haven't pro grammed befo re, just remember these "ro unding erro rs" make arithmetic slightly
inexact, so be sure they do n't make a difference to yo ur results. They can so metimes add up surprisingly
quickly. In the last o f the three cases abo ve, the user is entering text that canno t be co nverted into a number.
So Pytho n calls the actio n to a halt with an exception traceback that tells yo u what happened. (Pretty co o l,
huh?)

Because the o bservatio ns were made in an interactive interpreter after the traceback, yo u see ano ther >>>
pro mpt. If an unhandled exceptio n o ccurs when running a pro gram, the pro gram run is terminated. But this
isn't always yo ur desired result. Fo rtunately, there are ways yo u can handle these exceptio ns and avo id
pro gram terminatio n. Fo r no w, let's just type carefully when we need to pro vide numeric input!

Calculating with Stored Values


Okay! Let's put all this to gether in a sho rt sample pro gram that asks fo r the height, width, and depth o f a ro o m, and
calculates the surface area o f the walls. It'll give yo u an idea o f ho w real co de is written.

Type this co de in the edito r windo w belo w:

CODE TO TYPE:
#
# wall_area.py
#
h = float(input("Room height: "))
w = float(input("Room width : "))
d = float(input("Room depth : "))
area = 2 * (h * (w + d))
print("Area of walls:", area)

Save it in yo ur /pyt ho n1 fo lder as wall_are a.py, and run it in an interactive sessio n a few times, using different
inputs:

INTERACTIVE SESSION:

cold1:~/python1$ python3 ./wall_area.py


Room height: 12
Room width : 14
Room depth : 32
Area of walls: 1104.0
cold1:~/python1$

What happens if yo u give the pro gram a no n-numeric input? (Never fear. We'll sho w yo u ho w to deal with tho se
circumstances later.)
Getting It Done
We're co vering a lo t o f material in these early lesso ns, and we still have a lo ng way to go . Yo u're do ing really well so
far—stick with it—see yo u in the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Making Decisions: The if Statement
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

take different actio ns depending o n whether a specific condition is true.


co mpare and evaluate two values using the co mpariso n o perato r.
determine whether o ne string appears inside ano ther, using the in test.
test fo r several different co nditio ns.
use the e lif keywo rd instead o f e lse ... if ..
use the o r o perato r between the co nditio ns.

So far, we've co vered basic types o f statements in Pytho n—the assignment statement and the statement that calls a functio n.
The functio n we've used mo st o ften is print (), which has the handy side effect o f printing o ut the value o f o ne o r mo re
expressio ns.

One o f the mo st co mmo n needs in pro gramming is to make a decisio n and act o n it—fo r example, do ing o ne thing if a
custo mer answers Yes to a questio n, and ano ther if they answer No . The if statement gives us this po wer, allo wing us to take
different actio ns depending o n whether a specific condition is true.

Conditions in Python
In o rder to be able to make a decisio n, yo u need to evaluate so me co nditio n. The co nditio ns we co mpare mo st
frequently in Pytho n are o f two values, using the co mpariso n o perato r. Yo u can co mpare fo r vario us kinds o f equality
o r inequality:

Ope rat o r T rue whe n


a == b a and b have the same value
a != b a and b do no t have the same value
a<b a's value is less than b's
a <= b a's value is less than o r equal to b's
a>b a's value is greater than b's
a >= b a's value is greater than o r equal to b's

Co mparing numbers is pretty intuitive, but keep in mind that yo u can't use these o perato rs to co mpare co mplex
numbers. The o perands are two -dimensio nal, so they can't be laid o ut in a straight line; simple co mpariso ns like that
aren't valid. Instead, yo u must co mpare the abso lute values o f co mplex numbers, using the abs() functio n.

Co mparing strings is fairly straightfo rward as lo ng as yo u can alphabetize a list o f items. The characters in strings
have a defined o rder, so metimes called the collation sequence. Let's suppo se we want to co mpare strings a and b.
The interpreter lo o ks at the first character o f each string. If the first character o f a o ccurs earlier in the co llatio n sequence
than the first character o f b, then a is less than b. If the first character in a is greater than the first character in b, then a is
greater than b. If this initial attempt to co mpare the strings is inco nclusive, then the next characters in the sequence o f
the strings are co mpared until a determinatio n is made.

If the end o f o ne o f the strings is reached and additio nal characters still remain in the o ther, then the lo nger o f the two
strings is greater. If bo th strings have exactly the same characters in them, they are co nsidered equal. Yo u may see the
term "lexical co mpariso n" used to describe this metho d o f co mparing strings. Start a new terminal sessio n and verify
the fo llo wing results:
INTERACTIVE SESSION:

cold1:~$ python3
>>> a = 23.0
>>> b = 22
>>> a == b
False
>>> a != b
True
>>> a < b
False
>>> a <= b
False
>>> a > b
True
>>> a >= b
True
>>> p1 = "Python"
>>> p2 = "Perl"
>>> p1 == p2
False
>>> p1 != p2
True
>>> p1 < p2
False
>>> p1 <= p2
False
>>> p1 > p2
True
>>> p1 >= p2
True
>>> "this+" > "this"
True
>>> "that" == "that"
True
>>> "That" == "that"
False
>>> "That".upper() == "thAT".upper()
True
>>>

The last tests sho w that string co mpariso ns are case-sensitive. If yo u want to avo id case-sensitivity, use the uppe r()
o r lo we r() metho d to co nvert bo th strings to the same case.

In additio n, yo u can determine whether o ne string appears inside ano ther, using the in test:

INTERACTIVE SESSION:

cold1:~$ python3
>>> x = "nan"
>>> s = "Banana"
>>> x in s
True

The result o f the expressio n x in s is True when the substring x appears so mewhere inside the string s. Yo u can also
test to find o ut whether a string is a member o f a list o r a tuple (a tuple is a sequence o r o rdered list, o f finite length); x
in lt is true if x is an element o f lt , whether lt is a list o r a tuple.

Also , strings have several metho ds fo r yo u to use to determine whether the string has specific characteristics. The
mo st impo rtant o nes are sho wn in this table:

Me t ho d Exam ple T rue whe n ...


s.startswith(x) String s starts with the substring x
s.endswith(x) String s ends with the substring x
s.isalnum() All characters in s are alphanumeric and there is at least o ne character
s.isalpha() All characters in s are alphabetic and there is at least o ne character
s.isdigit() All characters in s are digits and there is at least o ne character
s.islo wer() All cased characters in s are lo wercase and there is at least o ne cased character
s.isupper() All cased characters in s are uppercase and there is at least o ne cased character

All o f these co nditio ns can be tested individually o r, as we'll see later, in co mbinatio n. Yo u can use the if statement to
cho o se whether o r no t to execute o ne o r mo re statements by testing a co nditio n and executing the statement if the
co nditio n is true. Yo u can also cho o se which sets o f statements to execute.

Making Decisions: if Statements


Expressio ns that the Pytho n interpreter will evaluate as True o r False (also called conditions) can be used to mo dify the
actio ns o f yo ur pro gram, using a basic if statement.

The if statement begins with the keywo rd if , fo llo wed by an expressio n, and ends with a co lo n. This line is always
fo llo wed by an indented suite—o ne o r mo re statements with an indentatio n level greater than that o f the if line. If the
co nditio n is true, then the indented suite is executed. All the statements in the suite must be indented to exactly the
same level. In the Pytho n wo rld, we use fo ur additio nal spaces fo r each new indentatio n level.

Okay, let's pro gram!

CODE TO TYPE:

#!/usr/local/bin/python3
"""Detect any mention of Python in the user's input."""

uin = input("Please enter a sentence: ")


if "python" in uin.lower():
print("You mentioned Python.")

By default, the Co deRunner edito r and yo ur web bro wser likely display tab characters as taking up eight
spaces. It is pro per Pytho n pro gramming practice to indent fo ur spaces. As such, we reco mmend that
Note yo u indent co de using the space bar rather than the Tab key. Alternatively, if yo u are familiar with a Linux
text edito r, yo u are welco me to use emacs o r vim, which are available o n the OST server.

Save it in yo ur /pyt ho n1 fo lder as f ind_pyt ho n.py and run it:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./find_python.py
Please enter a sentence: My python is a happy snake.
You mentioned Python.
cold1:~/python1$ ./find_python.py
Please enter a sentence: There's a pylon in the road.
cold1:~/python1$

Run the pro gram several times to verify that when the string "pytho n" is present in yo ur input, the pro gram prints "Yo u
mentio ned Pytho n." and when "pytho n" is NOT present, it do es no t. Make sure yo u test in all circumstances.

Because we added # !/usr/lo cal/bin/pyt ho n3 at the beginning o f the pro gram, we didn't need to call
Note pyt ho n3 specifically in the interactive sessio n. We'll use this fro m no w o n in o ur pro grams, but it might
no t wo rk o n o ther systems.
Choosing Between Alternatives: the else Clause
The basic if statement allo ws yo u to cho o se whether to execute an indented suite made up o f o ne o r mo re
statements. If yo u want to execute o ne set o f actio ns if the co nditio n is true and execute ano ther set if it is false, add an
e lse clause to the if statement. The e lse clause fo llo ws the first indented suite, and is fo llo wed by the indented suite
to execute if the if co nditio n is false. When the co nditio n is true, the first suite is executed; when it is false, the seco nd
suite is executed. Mo dify f ind_pyt ho n.py as sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
"""Detect any mention of Python in the user's input."""

uin = input("Please enter a sentence: ")


if "python" in uin.lower():
print("You mentioned Python.")
else:
print("Didn't see Python there.")

Save and run it. Test yo ur pro gram several times, using bo th types o f input. When yo ur pro gram includes alternative
behavio rs, it's impo rtant to test all the po ssible paths.

Multiple Choice Decisions


So metimes a decisio n isn't as simple as cho o sing between A o r B. Yo u may need to test fo r several different
co nditio ns, then take an actio n o n the first co nditio n that's true. In this case, using if ... e lse repeatedly gives rise to a
small pro blem. Chained if ... else statements mo ve co de to the right. e lse adds a level o f indentatio n, so if we have a
lo ng chain o f tests, the co de mo ves o ver to wards the right margin, which can make yo ur co de difficult to read. That's
no thing we can't handle, tho ugh! Take a lo o k:

OBSERVE:
if (condition 1):
suite 1
else:
if (condition 2):
suite 2
else:
if (condition 3):
suite 3
else:
...

To o verco me this, Pytho n has the e lif keywo rd, which yo u can use instead o f e lse ... if . Because a single e lif
inco rpo rates the functio ns o f bo th the e lse and the if statements, e lif do es no t intro duce an additio nal level o f
indentatio n:

OBSERVE:

if (condition 1):
suite 1
elif (condition 2):
suite 2
elif (condition 3):
suite 3
else:
...

Bo th o f o ur examples do the same thing, but the seco nd o ne is easier to read, and presents the chain o f cho ices much
mo re clearly. The e lse clause at the end is o ptio nal; if it's included, then the suite under it will be executed if no ne o f
the co nditio ns are true. Witho ut an e lse clause, the pro gram wo n't do anything at all if no ne o f the co nditio ns are true
(it will just co ntinue o n the line after suite 3).

No w suppo se we want to analyze a user's input to detect different pro gramming languages, and respo nd if we do n't
find any o f o ur languages mentio ned. Mo dify yo ur pro gram so that it uses e lif to select amo ng the alternatives. Edit
f ind_pyt ho n.py again so it lo o ks like this:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Detect any mention of several languages in the user's input."""

uin = input("Please enter a sentence: ")


if "python" in uin.lower():
print("You mentioned Python.")
elif "perl" in uin.lower():
print("Aha, a Perl user!")
elif "ruby" in uin.lower():
print("So you use Ruby, then?")
else:
print("Didn't see any languages there.")

Save and run the pro gram. Test yo ur results a few times. The first three times, mentio n o ne o f the target languages;
the fo urth time do n't mentio n a language at all. No w let's po nder a few questio ns to gether: What happens if o ur input
co ntains two languages? Do es the pro gram detect them bo th? Why o r why no t?

Combining Conditions: 'and' and 'or'


So metimes yo u want to take a particular actio n o nly when several co nditio ns are true. Yo u co uld do this by putting o ne
if inside ano ther, o r yo u co uld use the and o perato r between the co nditio ns. Similarly, if yo u want yo ur pro gram to
execute a particular actio n when at least o ne o f several co nditio ns is true, yo u co uld use the o r o perato r between the
co nditio ns.

Let's test the and and o r o peratio ns interactively:

INTERACTIVE SESSION:

cold1:~$ python3
>>> s = "ABC"
>>> if s.isupper() and s.startswith("A"):
... print("s is upper case starting with A")
...
s is upper case starting with A
>>>> s = "BBC"
>>> if s.isupper() and s.startswith("A"):
... print("s is upper case starting with A")
...
(Nothing prints.)
>>> if 1 == 2 or s.endswith("C"):
... print("Impossible happened or s ends with C")
...
Impossible happened or s ends with C
>>>

If two co nditio ns are jo ined by and, the result is true o nly if both co nditio ns are true. If two co nditio ns are jo ined by o r,
the result is true if either co nditio n is true, so even tho ugh 1 can never be equal to 2, in the seco nd example, the
co nditio n was still true.

Testing for a Range of Values: Chaining Comparisons


Co mpariso n o perato rs have a special feature; they can be "chained." Instead o f writing a < b and b < c, yo u can write
a < b < c. Altho ugh there are slight differences between the way the Pytho n interpreter evaluates the two expressio ns,
fo r no w yo u can regard them as equivalent.

Here are so me o f the o ther tests yo u can create with if statements. This pro gram uses the while statement. Create
this new pro gram as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
target = 63
guess = 0

while guess != target:


guess = int(input("Guess an integer: "))
if guess > target:
print ("Too high...")
elif guess < target:
print ("Too low...")
else:
print ("Just right!")

Save it in yo ur /pyt ho n1 fo lder as gue sse r.py and run it, entering a few guesses. Fo r every guess yo u make, the
pro gram repo rts whether yo ur guess is to o high o r to o lo w. With every guess, yo u clo se in o n the target number.
Belo w is the o utput fo r a typical run o f the pro gram:

INTERACTIVE SESSION:

cold1:~/python1$ ./guesser.py
Guess an integer: 22
Too low...
Guess an integer: 88
Too high...
Guess an integer: 50
Too low...
Guess an integer: 67
Too high...
Guess an integer: 58
Too low...
Guess an integer: 63
Just right!

Wrapping It Up
Yo u're lo o king go o d so far. But there's plenty mo re to learn still!

In the next lesso n, we'll lo o k at ho w we can write mo re po werful pro grams using loops. See yo u there!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Iteration: For and While Loops
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

use a f o r statement to lo o p o ver the characters in a string yo u enter, and an if statement to determine whether each
character is a vo wel.
execute a bre ak during a lo o p to terminate the lo o p immediately.

Glad to see yo u here again! We've co vered a co uple o f basic "o bject" types in Pytho n—strings and numbers. We've also
enco untered o ne o f Pytho n's sequence types—strings. Other Pytho n sequence types may co ntain mo re than just characters.
But befo re we try to understand Pytho n's co ntainer o bjects, let's take a lo o k at lo o ps.

Mo dern co mputers execute millio ns o r even billio ns o f instructio ns per seco nd. If we had to write o ut every instructio n, it wo uld
take a lifetime to write less than a seco nd's wo rth o f co de. Fo rtunately, we have lo o ps at o ur dispo sal. Lo o ps tell the co mputer
to execute the same sequence o f actio ns o ver and o ver. Thro ugh the use o f lo o ps, we can tell the co mputer to repeat the same
o peratio ns o n different pieces o f data, witho ut typing the instructio ns again each time.

At the end o f the last lesso n we wo rked with a pro gram that co ntained a while lo o p. Using a while lo o p, we can apply the same
lo gic repeatedly—in this case, until a specific co nditio n is true. Similarly, f o r lo o ps allo w yo u to repeat the same actio ns o n
each o f a number o f things. We'll take a clo ser lo o k at f o r lo o ps first.

A Basic For Loop


Suppo se yo u wanted to co unt the number o f vo wels in a string. Ho w wo uld yo u appro ach this task? Traditio nally, yo u
wo uld set a co unter to zero , then lo o p o ver the characters in the string, adding o ne to the co unter when a vo wel
character was fo und. After all the characters in the string were pro cessed, the co unter wo uld co ntain the to tal number o f
vo wels in the string.

Let's try an example that uses a f o r statement to lo o p o ver the characters in a string yo u enter, and an if statement to
determine whether each character is a vo wel. Type this co de in the edito r windo w:

CODE TO TYPE:
#!/usr/local/bin/python3
"""Counts the vowels in a user input string."""

s = input("Enter any string: ")


vcount = 0
for c in s:
if c in "aeiouAIEOU":
vcount += 1
print("C is ", c, "; Vowel count:", vcount)

Save it in yo ur /pyt ho n1 fo lder as vo we l_co unt e r.py and run it in the Terminal tab. The "Enter any string:" pro mpt
appears. The pro gram co unts the number o f vo wels in any string yo u enter and returns a to tal.

The f o r statement is fo llo wed by an indented suite (in this case, a single if statement). When the f o r statement
executes, the name s is bo und to a string. Fo r each character in the string, the interpreter executes the indented suite
with the name c, bo und to the current character. So , suppo se yo u entered "the." The first time thro ugh the lo o p, c wo uld
be "t." The seco nd time, it wo uld be "h," and the third time, it wo uld be "e." Each time aro und, the if statement checks to
see whether c co ntains a vo wel. If it do es, we add 1 to the vco unt co unter; o therwise no thing happens because there
is no e lse clause fo r the if . After all characters have been pro cessed, vco unt co ntains a co unt o f the vo wels within
the input string.

We had the pro gram print every time it went thro ugh the lo o p so yo u co uld see ho w it wo rks. No w, let's change o ur
pro gram to print o nly when it finishes reading the input string. To do that, we simply unindent the print statement so that
it falls o utside o f the lo o p. We'll also remo ve the co de that prints the value o f "c":
CODE TO TYPE:
#!/usr/local/bin/python3
"""Counts the vowels in a user input string."""

s = input("Enter any string: ")


vcount = 0
for c in s:
if c in "aeiouAIEOU":
vcount += 1
print("C is ", c, "; Vowel count:", vcount)

Save and run it again to see the difference.

Breaking Out of a Loop


The f o r lo o p is useful fo r pro cessing each element in a sequence. We'll lo o k at mo re co mplex sequences in the next
lesso n, but fo r no w we'll just use strings.

Suppo se yo u wanted to kno w where the first space appears in a string. One way to find o ut wo uld be to lo o p thro ugh
the string, co unting characters until yo u fo und a space. But o nce yo u fo und it, ho w wo uld yo u sto p co unting? Yo u
co uld set a flag to tell yo ur co mputer to sto p co unting after yo u fo und the space and co mpleted the lo o p, but then why
bo ther co mpleting the lo o p? It wo uld be mo re efficient to sto p lo o king at characters o nce yo u fo und the first space. To
do that, we use the bre ak statement. If yo u execute a bre ak during a lo o p, the lo o p terminates immediately.

Let's write a pro gram that prints o ut the po sitio n where the first space appears in a string. Enter this co de:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Program to locate the first space in the input string."""

s = input("Please enter a string: ")


pos = 0
for c in s:
if c == " ":
break
pos += 1
print("First space occurred at position", pos)

Save it in yo ur /pyt ho n1 fo lder as space _f inde r.py and run it:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./space_finder.py
Please enter a string: Space, the final frontier.
First space occurred at position 6

The co unt (po s) starts at 0 because that's the first po sitio n o f a string o r any o ther Pytho n sequence. Each time
thro ugh the lo o p, we test to see if the current character (c) is a space (" "). If it is, we hit the bre ak, exit the lo o p, and
print the value fro m po s; o therwise we add 1 to po s and the lo o p co ntinues. Be sure yo u get things in the right o rder!
Incrementing the co unt befo re testing and terminating the lo o p wo uld cause what's kno wn as an "o ff by 1 erro r."

But what do es the pro gram do if there's no space in the input? I'm glad yo u asked! It prints o ut a result as tho ugh a
space fo llo wed the input string, because the lo o p terminates after it has inspected each character in the string. Check it
o ut in yo ur pro gram by running it with an input co ntaining no spaces.

We need separate lo gic to verify that there really is a space in the string. Pytho n lo o ps co me with such extra lo gic built
in, in the shape o f the o ptio nal e lse clause. This clause is placed at the same indentatio n level as the f o r o r while
lo o p that it matches, and (just as with the if statement) is fo llo wed by an indented suite o f o ne o r mo re statements.
This suite is only executed if the lo o p terminates no rmally. If the lo o p ends because a bre ak statement is executed,
then the interpreter just skips o ver the e lse suite. In the case o f the space detectio n pro gram, we execute the bre ak
when we detect a space, so an e lse clause o n the f o r lo o p wo uld o nly run if there were no spaces in the input.
We need to mo dify o ur co de a bit mo re. In the first versio n, the print was lo cated at the end o f the lo o p, where it
always runs no matter what the o utco me o f the testing. No w we want it to be part o f the suite guarded by the if
statement, so it o nly runs when a space is fo und. Mo dify yo ur space_finder.py file as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Program to locate the first space in the input string."""

s = input("Please enter a string: ")


pos = 0
for c in s:
if c == " ":
print("First space occurred at position", pos)
break
pos += 1
else:
print("No spaces in that string")
print("First space occurred at position", pos)

Save and run it with a string that co ntains a space and then with a string that do esn't. The pro gram runs just fine either
way.

As yo ur pro grams beco me mo re co mplex, yo u will find that there are so metimes different ways to express the same
lo gic. In tho se cases, yo u sho uld "do the simplest thing that wo rks." Fo r example, in the bo dy o f the lo o p, we could
have put the statement that increments the co unter in the suite o f an e lse clause. We cho se no t to use an e lse
because if the expressio n c == " " tests as true, the bre ak statement will guarantee that po s isn't incremented (by
immediately exiting fro m the lo o p) befo re the assignment statement is executed.

While Loops
The f o r lo o p is useful when yo u want to apply the same lo gic to each member o f a sequence. But so metimes (like in
the guessing game at the end o f the last lesso n) yo u do n't have a finite sequence; yo u want actio ns to be repeated
until so me co nditio n is true.

Suppo se we want to split a string into wo rds. Defining wo rds by the spaces between them, we can lo cate the first
space with a f o r lo o p. No w we can mo dify the string each time we find a wo rd (by re-binding the name o f the string to a
new string with the wo rd remo ved) until there are no mo re wo rds left. That's the idea behind the next pro gram. Create a
new file as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Program to split a sentence into words."""

s = input("Please enter a sentence: ")


while True:
pos = 0
for c in s:
if c == " ":
print(s[:pos])
s = s[pos+1:]
break
pos += 1
else:
print(s)
break

Save it in yo ur /pyt ho n1 fo lder as se nt e nce _split t e r.py and run it. The while T rue clause in this pro gram sets up
a lo o p that will keep running until lo gic in the if /e lse suites causes a break. When yo u see while T rue in a pro gram,
either the pro grammer has included a bre ak statement to terminate the lo o p, o r the pro gram is designed fo r
co ntinuo us o peratio n—or the pro grammer has made a terrible mistake and the pro gram will never sto p running! In this
case, it's the fo rmer: the bre ak to terminate the while lo o p is inside the f o r lo o p's e lse clause. Run the pro gram and
enter a sentence. Yo u sho uld see each wo rd in the sentence o n a separate line.
Note In s[:po s] and s = s[po s+1:], we use a feature that we haven't co vered yet. Stay tuned!

Of co urse this pro gram isn't perfect—very few pro grams are! Try entering a sentence where the wo rds are separated by
multiple spaces. The pro gram prints empty lines, co rrespo nding to the "empty wo rds" between the spaces. We can fix
that, tho ugh. One way wo uld be to remo ve leading spaces befo re go ing into the f o r lo o p each time. Let's mo dify o ur
sentence_splitter.py to allo w multiple spaces between wo rds. Edit the pro gram as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Program to split a sentence into words."""

s = input("Please enter a sentence: ")


while True:
while s.startswith(" "):
s = s[1:]
pos = 0
for c in s:
if c == " ":
print(s[:pos])
s = s[pos+1:]
break
pos += 1
else:
print(s)
break

Save and run it.

When yo u run yo ur updated pro gram, yo u can enter as many spaces as yo u like between the wo rds and still get o ne
wo rd per line in the o utput. Can yo u figure o ut ho w yo u might use o r to igno re extra tabs between wo rds? What part o f
the pro gram wo uld yo u need to change to treat tabs as co mpletely equivalent to spaces? (Hint: yo u wo uld have to
accept sentences with just tabs between the wo rds.)

Terminating the Current Iteration


The bre ak statement can be used to terminate either a f o r o r a while lo o p. There is ano ther statement yo u can use to
terminates o nly the current iteratio n o f a lo o p, mo ving o n to the next iteratio n immediately.

In the final example fo r this lesso n, we'll pro cess lines o f input fro m the user. The user will indicate the end o f their
input by entering a blank line (simply pressing the Ent e r key), but we want them to be able to add co mments to their
input by entering lines beginning with the # character. These lines sho uldn't be pro cessed; they are just there to info rm
the reader. (Pytho n also accepts co mments—the # character tells the interpreter to igno re everything else up to the end
o f the line). We aren't especially co ncerned with the pro cessing that's do ne o n each line, so in this example we'll just
use the le n() functio n to print.

A co mment sho uld be indicated by the first printable character. Create a new file as sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
"""Demonstrating the continue statement."""

while True:
s = input("Enter a line (or Enter to quit): ")
if not s:
break
if s.startswith("#"):
continue
print("Length", len(s))

Save it in yo ur /pyt ho n1 fo lder as le ngt h_co unt e r.py and run it. Enter several lines, including at least o ne
co mment line that begins with "#." Co mment lines are pro cessed differently fro m regular lines because o f the
co nt inue statement, which immediately causes the pro gram to lo o p and ask fo r ano ther input. There are o ther ways
yo u co uld have achieved the same result.

Feel the Power


Once yo u understand ho w lo o ping lo gic wo rks, yo u're well o n the way to co mprehending the real po wer o f co mputers.
Lo o ping allo ws yo u to tell the co mputer to repeat the same set o f instructio ns again and again and again...

We must co nfess, there are easier ways to perfo rm the tasks that yo u pro grammed in this lesso n, but we want yo u to
understand what's go ing o n behind the scenes first. Start o r switch to an interactive sessio n and enter the fo llo wing
expressio ns:

INTERACTIVE SESSION:

>>> "spaces are our friends".find(" ")


6
>>> "What\tis a word?".split()
['What', 'is', 'a', 'word?']
>>>

The f ind() string metho d lo cates a given character inside the string (it finds the first o ccurrence o f the string passed as
its argument). The split () string metho d, when called witho ut arguments, splits the string up into its co nstituent wo rds,
which are assumed to be separated by o ne o r mo re white space characters. The strings inside the square brackets
co nstitute a list. We'll be lo o king at tho se (and their co usins, the tuples) in the next lesso n.

Well do ne. Go o d fo r yo u fo r sticking with it! No w yo u have a grasp o f a lo t o f the basics, yo u'll be able to take o n mo re
co mplex pro gramming challenges. See yo u at the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Sequence Containers: Lists and Tuples
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

write Lists and Tuples.


access the individual elements in a sequence with indexing.
index and slice elements.
mo dify lists.
use a third co mpo nent o f the slice specificatio n: the stride.
determine whether a sequence co ntains a specific value, using the in keywo rd.

Welco me back, my favo rite student! So far, we've co vered basic o bject types in Pytho n, such as strings and numbers. No w
we're ready to lo o k at Pytho n's "co ntainer" o bjects, starting with lists and tuples. Bo th lists and tuples are sequence types.
Because strings are sequence types as well, much o f what we learn here can be applied to strings as well.

Sequence types have a specific order, so it's easy to spo t a string's first and last characters. Similarly, lists and tuples present
elements in a particular o rder. Each element o f a sequence is numbered. The numbering always starts at zero . Yo u refer to an
individual element by fo llo wing the sequence name with a number in square brackets [ ].

Lists and Tuples


Pytho n uses bo th lists and tuples. In general, tuples are used when the po sitio n o f an element indicates so mething
abo ut its capability, and lists are used to ho ld elements that will be treated in the same manner. Pytho n do esn't enfo rce
these co nstraints, tho ugh; the o nly hard and fast rule fo r using lists and tuples is don't use tuples if you want to change
the sequence. Tuples are primarily fo r use when yo u need a no n-mo difiable sequence.

Writing Lists and Tuples


So metimes yo u'll want to write the co ntents o f a list right inside o f yo ur co de. To do that, write a co mma-separated list
o f the element values, surro unded by square brackets [ ].

Tuples are usually written as a co mma-separated list o f values surro unded by parentheses ( ) rather than brackets [ ],
but in many cases the parentheses () are o ptio nal. (Okay, I will refrain fro m including illustratio ns o f brackets [ ] and
parentheses ( ) no w. Yo u get the picture, right?) The interactive interpreter always puts parentheses aro und a tuple
when asked to display its representatio n, and we reco mmend yo u do the same, in o rder to facilitate readability.

Let's lo o k at so me sequences in actio n. Start an interactive terminal sessio n and type:


INTERACTIVE SESSION:

cold1:~$ python3
>>> lst1 = [1, 3, 5]
>>> lst2 = [2, 4, 6]
>>> tup1 = (9, 7, 5)
>>> tup2 = (8, 6, 4)
>>> dir(lst1)
['__add__', '__class__', '__contains__', ... , 'append', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> dir(tup1)
['__add__', '__class__', '__contains__', ... , 'count', 'index']
>>> lst1+lst2
[1, 3, 5, 2, 4, 6]
>>> tup1+tup2
(9, 7, 5, 8, 6, 4)
>>> lst1+tup1
Traceback (most recent call last):
File "<console>", line 1, in <module>
TypeError: can only concatenate list (not "tuple") to list
>>> clist = [lst1, lst2, tup1, tup2]
>>> print(clist)
[[1, 3, 5], [2, 4, 6], (9, 7, 5), (8, 6, 4)]

The results o f the calls to the dir() functio n sho w that a list has metho ds that a tuple do esn't have. We abbreviated the
o utput by remo ving many o f the special names beginning with a do uble undersco re. We'll learn mo re abo ut tho se
metho ds later, but fo r no w we'll fo cus o n the regular metho ds.

Yo u can put whatever yo u like in a list. Usually yo u'll enter simple values like strings and numbers. The clist list in the
example abo ve co ntains two o ther lists and two tuples.

Accessing Sequence Values


Once yo u have created a sequence, yo u can access its individual elements using indexing. To index a single element
fro m a sequence, yo u fo llo w it with a numeric value in square brackets (remember—the first element is numbered
zero !). Yo u can also take slices fro m the sequence, creating a new and usually smaller sequence. To slice a sequence,
yo u write two numeric values, separated by a co lo n (:), inside the square brackets. If yo u o mit the first value, the new
sequence starts with the first element o f the sliced sequence. If yo u o mit the last value, the new sequence ends with its
last element. Co ntinue the interactive terminal sessio n as sho wn:

INTERACTIVE SESSION:

>>> clist = [1, (2, 3, 4), "a", "Bright", "c"]


>>> clist [1]
(2, 3, 4)
>>> clist[1][1]
3
>>> clist[3][1:3]
'ri'
>>> stuff = clist[2:4]
>>> stuff
['a', 'Bright']
>>> stuff2 = clist[2:5]
>>> stuff2
['a', 'Bright', 'c']
>>> stuff[0]
'a'
>>> "Strings are sequences too"[:7]
'Strings'

Indexing and slicing are fundamental o peratio ns in Pytho n, so make sure that yo u understand why each expressio n
evaluates the way it do es. Be aware that when yo u slice a sequence, the seco nd index isn't the index o f the last
element in the slice. This is actually very useful. It wo uld be co nfusing if clist [2:4 ] didn't give yo u a list 2 elements
lo ng, so element 4 isn't included in that slice. So , to get the fo urth element in o ur slice, we referenced the no nexistent
element 5. Because strings are also sequences, we can cho p strings up witho ut to o much difficulty.

Modifying Lists
Altho ugh strings and tuples are also sequences, they are immutable. Once created, they can't be changed (altho ugh
yo u can still index and slice them to extract individual elements o r sub-sequences). Lists, ho wever, can be changed. In
the same way that yo u can bind a new value to a name with an assignment, yo u can also bind a new value to an
element o f a list. Let's check o ut o ne way yo u can mo dify a list. Start o r co ntinue the interactive terminal sessio n as
sho wn:

INTERACTIVE SESSION:

>>> stuff = [1, (2, 3, 4), "a", "Bright", "c"]


>>> stuff[1] = "Not a tuple"
>>> stuff
[1, 'Not a tuple', 'a', 'Bright', 'c']
>>> stuff[0] = 0
>>> stuff[3] = 'b'
>>> stuff
[0, 'Not a tuple', 'a', 'b', 'c']
>>> stuff[2:4]
['a', 'b']
>>> stuff[2:4] = [1, 2, 3]
>>> stuff
[0, 'Not a tuple', 1, 2, 3, 'c']
>>>

So far, we've just been just replacing single elements o f the list. It's also po ssible to replace a slice. When yo u do that,
make sure that yo u also assign ano ther sequence. Any sequence will do —a list, tuple, o r string. If yo u assign a string
to a slice, each character in the string beco mes a new element o f the list. Try experimenting with these po ssibilities.

Because yo u can replace any slice o f a list, yo u can delete the slice by assigning an empty sequence to it. But there are
less labo r-intensive ways to replace a slice o f a list. Pytho n's de l statement was designed especially fo r deleting
things. Yo u can use it o n a single element o r a slice. If yo u kno w that a list co ntains a certain value, but yo u do n't kno w
the value's index, yo u can use the list's re m o ve () metho d to delete it fro m the list. If the same value o ccurs mo re than
o nce, o nly the first o ccurrence is deleted. Let's give it a try. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> dlist = ['a', 'b', 'c', '1', '2', 1, 2, 3]


>>> dlist[6]
2
>>> del dlist[6]
>>> dlist
['a', 'b', 'c', '1', '2', 1, 3]
>>> dlist[:3]
['a', 'b', 'c']
>>> del dlist[:3]
>>> dlist
['1', '2', 1, 3]
>>> dlist.remove(1)
>>> dlist
['1', '2', 3]
In the last example, element 2 (the integer 1) was remo ved, no t element 0 (the string '1'). In Pytho n,
numbers and strings are distinctive, and it do esn't co nvert fro m o ne to the o ther unless yo u specifically
tell it to do so .
Note
Also , remember that deletio n o nly wo rks fo r lists. Deleting an element o f a sequence wo uld be the same
as mo difying the sequence, and yo u can't mo dify tuples and strings.

As we saw in an earlier example, we can add elements to a list. Ano ther way to include mo re elements is to use the
list's appe nd() metho d. Yo u call the metho d and give it a new element to be appended to the list. It's also po ssible to
insert elements at a specific po sitio n, and again there are two ways to do this. The simplest way is to use the list's
inse rt () metho d, which yo u call with a po sitio n (index value) and a value to be inserted. Or yo u co uld also assign the
new value to an empty slice—any slice with the same value fo r the lo wer and upper indexes is bo und to be empty.
Let's experiment with adding new elements to a list. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> elist = [] # The empty list


>>> elist.append('a')
>>> elist
['a']
>>> elist.append('b')
>>> elist
['a', 'b']
>>> elist.append((1, 2, 3))
>>> elist
['a', 'b', (1, 2, 3)]
>>> len(elist)
3
>>> elist[1:1]
[]
>>> elist[1:1] = ["new second element"]
>>> elist
['a', 'new second element', 'b', (1, 2, 3)]
>>> elist.insert(3, "4th")
>>> elist
['a', 'new second element', 'b', '4th', (1, 2, 3)]
>>> len(elist)
5

One o f the limitatio ns we run into with slice assignment is that the replacement must be a sequence, so we usually
append o r insert it. If yo u have a sequence o f elements that yo u want to insert, keep in mind that slice assignment
requires much less co de than mo st o ther techniques.

If yo u call a list's appe nd() metho d with a sequence argument (like yo u did with e list .appe nd((1, 2, 3))
Note in the example abo ve), that entire sequence beco mes the last element o f the list.

Slices with a Stride: Skipping Sequences


A slice specifies a subsequence o f a sequence. No w suppo se yo u do n't want to include every element, but instead
yo u want to use every seco nd o r third element. The easiest way to do this wo uld be to use a third co mpo nent o f the
slice specificatio n: the stride. The stride specifies ho w many elements to skip in the slice befo re extracting the next
element. The stride is separated fro m the first two co mpo nents with a co lo n; so yo ur slice specificatio n is like
[first:last:stride].

When yo u specify o nly two slice co mpo nents, by default the stride is 1; it takes every element in the slice. A stride o f 2
takes every seco nd element, and so o n. Stride values can be negative as well as po sitive. Slicing always wo rks by
setting the index to the first slicing co mpo nent and then increasing the index by the stride value, until the index reaches
o r go es past the seco nd slicing co mpo nent. When the stride is negative, the first slicing co mpo nent must be higher
than the seco nd. Type the co mmands belo w as sho wn:
INTERACTIVE SESSION:

>>> alf = "abcdefghijklmnopqrstuvwxyz"


>>> alf[2:13]
'cdefghijklm'
>>> alf[2:13:2]
'cegikm'
>>> alf[2:13:-2]
''
>>> alf[13:2:-2]
'nljhfd'
>>> alf[13:2]
''
>>> alf[::-1]
'zyxwvutsrqponmlkjihgfedcba'

One way to get the reverse o f a sequence is to slice the who le thing by o mitting the first and seco nd slice co mpo nents
and then use a stride o f -1. So , if yo u want to replace a list with its reverse, rather than use the list's reverse() metho d
lst.reverse(), yo u can write lst = lst[::-1]. Pytho n sequences are no thing if no t versatile!

Other Functions and Methods to Use with Sequences


So metimes yo u'll have a string that yo u want to break up into a list o f wo rds. The split () metho d helps yo u to do just
that. If yo u call the string witho ut any arguments, it will split the string. If yo u call it with o ne argument (fo r example, a
space " "), it will use that argument as a separato r, returning a list o f the strings that appear between its o ccurrences.

If yo u give a seco nd argument, it sho uld be an integer. This info rms the interpreter o f the maximum number o f times to
reco gnize the separato r, which limits the number o f elements in the returned list.

To get the sum o f the numbers in a sequence, pass the sequence to the sum () functio n as an argument. The
interpreter will raise an exceptio n if there is a no n-numeric element in the sequence. To get the length o f any sequence,
use the le n() functio n.

To find the number o f times a particular element appears in a list o r tuple, use the co unt () metho d, with the element
value yo u are seeking as the argument.

Testing for Presence in a Sequence


To determine whether a sequence co ntains a specific value, use the in keywo rd, which returns either T rue o r False .
Sequences also have an inde x() metho d that will return the lo west index value at which a given element o ccurs. Yo u
have to be careful using inde x() tho ugh, as it will raise an exceptio n if the element isn't present. To avo id the
exceptio n, yo u can use an if test to ensure that the value is present, but it's better just to handle the exceptio n, and
avo id do ing the search twice. We'll co ver the if statement and exceptio n handling in detail later.

Manipulating Lists and Tuples


Create a new pro gram file as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Simpler program to list the words of a string."""

s = input("Enter your string: ")


words = s.strip().split()
for word in words:
print(word)

Save it in yo ur /pyt ho n1 fo lder as be t t e r_se nt e nce _split t e r.py and run it. This co de perfo rms the same tasks as
the o ne we wro te in the last lesso n, but it uses features built into the Pytho n language. No w type in a string that
co ntains so me white space, press Ent e r, and examine the result. Yo u sho uld see the list o f wo rds, printed o ne per
line.
OBSERVE:

s = input("Enter your string: ")


words = s.strip().split()
for word in words:
print(word)

This co de applies the st rip() metho d to string s, which returns a string with no leading o r trailing white space. The
split () metho d is then applied to the already stripped string, returning a list o f the wo rds. The f o r lo o p iterates o ver the
list, printing each wo rd o n a separate line.

No w let's do so mething a little mo re co mplex with lists. We'll take a lo ng piece o f text and find o ut ho w many lines,
wo rds, and characters it co ntains. To determine the number o f characters, use the le n() metho d. We co unt the lines by
splitting the text to get a list o f them. Finally, we split each line into wo rds and accumulate a to tal by adding the number
o f wo rds in each line to gether.

Create a new file in the edito r windo w as sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
"""Count the words, lines and characters in a chunk of text."""

gettysburg = """\
Four score and seven years ago our
fathers brought forth on this continent,
a new nation, conceived in Liberty, and
dedicated to the proposition that
all men are created equal.

Now we are engaged in a great civil war,


testing whether that nation, or
any nation so conceived and so dedicated,
can long endure. We are met on
a great battle-field of that war. We have
come to dedicate a portion of that
field, as a final resting place for those
who here gave their lives that that
nation might live. It is altogether
fitting and proper that we should do this."""

charct = len(gettysburg)

lines = gettysburg.split("\n")
linect = len(lines)

wordct = 0
for line in lines:
words = line.split()
wordct += len(words)

print("The text contains", linect, "lines,", wordct, "words, and", charct, "characters.
")

Save it in yo ur /pyt ho n1 fo lder as paragraph_st at s.py and run it. If yo u typed in exactly the same input text, yo u'll
see T he t e xt co nt ains 16 line s, 10 2 wo rds, and 5 5 7 charact e rs.

So me o perating systems may give different results; fo r example, Unix reco rds a newline as o ne
Note character, while Windo ws reco rds it as two .

Okay, no w let's mo dify o ur pro gram to keep a co unt o f wo rd lengths, so we kno w ho w many o ne-letter, two -letter, and
three-letter wo rds there are, and so o n. Mo dify yo ur paragraph_stats.py file as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Count the words, lines and characters in a chunk of text."""

gettysburg = """\
Four score and seven years ago our
fathers brought forth on this continent,
a new nation, conceived in Liberty, and
dedicated to the proposition that
all men are created equal.

Now we are engaged in a great civil war,


testing whether that nation, or
any nation so conceived and so dedicated,
can long endure. We are met on
a great battle-field of that war. We have
come to dedicate a portion of that
field, as a final resting place for those
who here gave their lives that that
nation might live. It is altogether
fitting and proper that we should do this."""

lengthct = [0]*20 # a list of 20 zeroes


charct = len(gettysburg)

lines = gettysburg.split("\n")
linect = len(lines)

wordct = 0
for line in lines:
words = line.split()
wordct += len(words)
for word in words:
lengthct[len(word)] += 1

print("The text contains", linect, "lines,", wordct, "words, and", charct, "characters.
")
for i, ct in enumerate(lengthct):
if ct:
print("Length", i, ":", ct)

In the new pro gram, we begin by creating a list o f co unts. The idea is that the co unt o f n-letter wo rds will be kept in
le ngt hct [n], and we assume that no wo rd will be lo nger than 19 characters. So metimes that kind o f assumptio n can
be dangero us, but fo r no w, fo r experimentatio n's sake, we'll just go with it. In the lo o p that pro cesses each line, we
have added a lo o p to iterate o ver the wo rds. The length o f each wo rd is used as an index into the le ngt hct list, and
that element is incremented by o ne (they all start at zero ). Finally, when the text has been fully pro cessed, there is a bit
mo re co de used to o utput the co unt o f wo rds o f each length. The o nly real wrinkle here is the if statement that o mits
tho se lengths fo r which there aren't any wo rds.

Save and run it. Yo ur o utput will lo o k like this:


So far, so go o d. Go o n and experiment so me mo re. Mo dify the text so it co ntains a wo rd o f twenty characters o r mo re
(like "deinstitutio nalizing"). What happens when yo u run the pro gram? Ho w co uld yo u make the pro gram wo rk again?
Can yo u think o f a way yo u might mo dify the pro gram to keep a co unt o f the individual wo rds, so yo u co uld see ho w
many times each wo rd was used? Using o nly sequences, this is pretty difficult, but no t impo ssible.

It Slices, It Dices...
Yo u've learned quite a bit abo ut Pytho n's sequence types and just ho w useful they can be. Next, we'll check o ut
Pytho n's mapping types.

Phew. This isn't easy, but yo u're do ing really well. Keep it up, and I'll see yo u in the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Sets and Dicts
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

create sets.
use sets and dicts.

Go o d to have yo u back! We'll go o ver so me backgro und info rmatio n first and then get to wo rk o n so me examples. Lists and
tuples are versatile data structures, but they have o ne fundamental pro perty that yo u just can't get aro und: elements are retrieved
by number. That's fine when yo u're wo rking with elements that are numbered, but o n o ccasio n yo u'll want to be less specific.
That's when sets and dicts co me in handy.

Sets are similar to lists. Yo u can use the in keywo rd to find o ut whether a particular value appears as an element within a list o r
a set. The interpreter finds members within lists by checking each element o f the list, o ne after the o ther, until it finds the value it's
lo o king fo r, o r gets to the end o f the list. The interpreter finds elements in sets using a much faster metho d "under the ho o d"
than the linear scan used fo r lists.

Using a list is fine when yo ur pro gram co ntains just a few elements, but the number may gro w o ver time, particularly when the
data is being sto red in a file o r a database. As the number o f elements in yo ur pro gram gro ws, pro gram perfo rmance beco mes
increasingly slo w. That co uld cause pro blems. In tho se cases, it's better to use a set in the first place.

The same value can appear multiple times in a list, but in a set, a value can appear o nly o nce. When yo u "add" an element to a
set that co ntains that particular element already, the set remains the same. Because o f this feature, yo u can't predict the o rder in
which the set elements will o ccur if yo u lo o p o ver them with a f o r lo o p. When yo u add an element, the o rder may change
co mpletely. In o ther wo rds, altho ugh sets are collections o r containers, sets aren't sequences. There is no co ncept o f "po sitio n"
fo r set elements. Co nversely, in a list, yo u can determine the po sitio n o f a given element, using the inde x() metho d.

Dicts are similar to lists as well. A dict sto res values that can be retrieved by indexing, but the index values in a dict do n't need to
be numerical. All o f this will make mo re sense after we wo rk thro ugh a few examples.

Creating Sets
Yo u write a set as a co mma-separated list o f elements inside braces { }—fo r example, yo u'd type the first three natural
numbers as {1, 2, 3} . Yo u can also use Pytho n's built-in se t () functio n. This is usually called with a single sequence
argument, and creates a set that co ntains all the sequence's elements.

Pytho n includes two separate data types fo r handling sets. As with lists and tuples, yo u build regular sets, then yo u can
add o r remo ve elements. Yo u can also build fro zen sets, which stay the same o nce yo u have created them and raise
an exceptio n at any attempt to change them. A set is an uno rdered co llectio n o f items with no duplicate elements; lists
are o rdered and sets are no t. Set o bjects also suppo rt vario us o peratio ns like unio n, intersectio n, and difference. If
yo u're no t familiar with all this stuff yet, do n't panic! We'll go o ver all o f it in detail here and in later lesso ns.

Working with Sets


Okay, no w it's time to get friendly with set o peratio ns! Start an interactive terminal sessio n and enter the fo llo wing
co mmands:
INTERACTIVE SESSION:

cold1:~$ python3
>>> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1}
{1, 2, 3}
>>> vowels1 = {"a", "e", "i", "o", "u"}
>>> vowels2 = set("aieou")
>>> vowels1 == vowels2
True
>>> languages = {"perl", "python", "c++", "ruby"}
>>> languages.add("php")
>>> languages
{'python', 'php', 'ruby', 'c++', 'perl'}
>>> "perl" in languages
True
>>> "java" in languages
False
>>> {'python', 'ruby'} < languages
True
>>> set("the quick brown fox") & vowels1
{'i', 'u', 'e', 'o'}
>>> vowels1 - set("the quick brown fox")
{'a'}
>>> set("the quick brown fox") - vowels1
{' ', 'c', 'b', 'f', 'h', 'k', 'n', 'q', 'r', 't', 'w', 'x'}
>>>

Note In the result fro m se t (" t he quick bro wn f o x" ) & vo we ls, the duplicate elements are eliminated.

The examples abo ve used integers, characters, and strings, but mo st Pytho n o bjects can be elements o f a set. Yo u
can co mpute the intersection o f two sets using the & o perato r, and the difference between two sets with the - o perato r.
There are a number o f o ther o peratio ns yo u can perfo rm o n sets as well. Many, but no t all, o f the o peratio ns can be
perfo rmed using either o perato rs o r a metho d call o n o ne o f the sets.

Assume that s and t are sets in the fo llo wing table:

Ope rat io n Me t ho d Call Re t urns


x in s - True if x is an element o f set s.
s <= t s.issubse t (t ) True if every element o f s is also an element o f t .
True if every element o f s is also an element o f t but there is
s <t -
also an element o f t that is no t in s.
s >= t s.issupe rse t (t ) True if every element o f t is also an element o f s.
True if every element o f t is also an element o f s but there is
s >t -
also an element o f s that is no t in t .
- s.isdisjo int (t ) True if s and t have no element in co mmo n.
s |t s.unio n(t ) The set co ntaining all elements o f s and all elements o f t .
s &t s.int e rse ct io n(t ) The set co ntaining all elements that are in bo th s and t .
s-t s.dif f e re nce (t ) The set co ntaining all elements that are in s but no t in t .
The set co ntaining all elements that are in s o r t but no t in
s^t s.sym m e t ric_dif f e re nce (t )
bo th.
s |= t s.updat e (t ) No ne , but adds all elements o f t to s.
No ne , but leaves s co ntaining o nly elements that o riginally
s &= t s.int e rse ct io n_updat e (t )
belo nged to bo th t and s.
s -= t s.dif f e re nce _updat e (t ) No ne , but remo ves any elements o f t fro m s.
No ne , but leaves s co ntaining all elements that belo ng to t o r
s ^= t s.sym m e t ric_dif f e re nce _updat e (t )
s but no t bo th.
Let's use a set to keep track o f ho w many different wo rds there are in a given piece o f text. Create a new file as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Count the number of different words in a text."""

text = """\
Baa, baa, black sheep,
Have you any wool?
Yes sir, yes sir,
Three bags full;
One for the master,
And one for the dame,
And one for the little boy
Who lives down the lane."""

for punc in ",?;.":


text = text.replace(punc, "")
print(text)
words = set(text.lower().split())
print("There are", len(words), "distinct words in the text.")

Save it in yo ur /pyt ho n1 fo lder as wo rd_co unt e r.py and run it.

This is a classic pro blem we can run into when wo rking with text in o ur pro grams. Pytho n lets yo u so lve it in a unique
way. First, it uses a f o r lo o p to remo ve all the punctuatio n (punc) characters (,?;.) fro m the string, replacing each o ne
with an empty string (""). Next, it prints the text so yo u can co nfirm that the punctuatio n has been remo ved. Finally, it
co nverts the text to lo wer-case, splits the text at each run o f white space, and creates a set fro m the resulting list.

Pytho n remo ves the punctuatio n to ensure that o nly wo rds are present in the text. "Baa" is no t the same as "Baa," (with
a co mma), so the punctuatio n must be remo ved. The text is co nverted to lo wer case befo re splitting so that, fo r
example, "One" and "o ne" will no t be treated as unique wo rds. A set canno t co ntain duplicate entries. The number o f
elements in the set (given by the le n() functio n) is co mprised o f the number o f different wo rds in the text.

To see ano ther applicatio n o f sets, let's write a pro gram that co mpares two inputs and prints o ut the wo rds they have
in co mmo n and vario us o ther pieces o f info rmatio n. Type the co de belo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Find matching words in two input lines."""

words1 = set(input("Sentence 1: ").lower().split())


words2 = set(input("Sentence 2: ").lower().split())
print("Words in both strings", words1 & words2)
print("Unique to sentence 1:", words1 - words2)
print("Unique to sentence 2:", words2 - words1)

Save it in yo ur /pyt ho n1 fo lder as wo rd_m at che r.py and run it, and then enter two different sentences with so me
wo rds in co mmo n, as sho wn:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./word_matcher.py
Sentence 1: Four score and seven years ago
Sentence 2: Four and twenty blackbirds were baked in a pie
Words in both strings {'and', 'four'}
Unique to sentence 1: {'ago', 'seven', 'score', 'years'}
Unique to sentence 2: {'a', 'blackbirds', 'in', 'pie', 'twenty', 'were', 'baked'}
cold1:~/python1$
The pro gram prints the sets o f wo rds, telling yo u which are co mmo n to bo th sentences and which are unique to each
sentence. Because the sets are no t so rted, the pro gram prints them in unpredictable o rder. To o verco me this issue,
mo dify the pro gram to make use o f Pytho n's so rt e d() functio n. Edit yo ur co de as sho wn in blue:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Find matching words in two input lines."""

words1 = set(input("Sentence 1: ").lower().split())


words2 = set(input("Sentence 2: ").lower().split())
print("Words in both strings", sorted(words1 & words2))
print("Unique to sentence 1:", sorted(words1 - words2))
print("Unique to sentence 2:", sorted(words2 - words1))

Save and run it, and enter the same two sentences. The o utput o f the first versio n o f this pro gram printed sets as its
results, but this mo dified versio n prints lists. When applied to a set, the so rt e d() functio n so rts the elements o f the set
into a list. This displays o ur results in a predictable (alphabetical) o rder.

Working with Dicts


The dict is a useful structure fo r sto ring values against arbitrary keys. Let's take a lo o k. Start an interactive interpreter
sessio n and type the co mmands sho wn belo w:

INTERACTIVE SESSION:

>>> d = {'Steve': 'Python', 'Peter': 'Perl', 'Rob': 'Ruby'}


>>> d['Rob']
'Ruby'
>>> d['Peter'] = "C#"
>>> d
{'Steve': 'Python', 'Peter': 'C#', 'Rob': 'Ruby'}
>>> d['Peter']
'C#'
>>> del d['Peter']
>>> d
{'Steve': 'Python', 'Rob': 'Ruby'}
>>> d['Guido'] = 'Python'
>>> d
{'Steve': 'Python', 'Rob': 'Ruby', 'Guido': 'Python'}
>>> d.keys()
dict_keys(['Steve', 'Guido', 'Rob'])
>>> for k in d.keys():
... print(k)
...
Steve
Rob
Guido
>>> for k in d.items():
... print(k)
...
('Steve', 'Python')
('Rob', 'Ruby')
('Guido', 'Python')
>>> d[(1, 2)] = "Tuple"
>>> d[1] = "Integer"
>>> d
{(1, 2): 'Tuple', 1: 'Integer', 'Rob': 'Ruby', 'Steve': 'Python', 'Guido': 'Python'}
>>> d[1]
'Integer'
>>> d[1.0] = "Hello there"
>>> d[1+0j]
'Hello there'
Here yo u can see so me o f the mo st impo rtant aspects o f dict behavio r. Dict literals use braces { } like sets do , but each
element is represented by a key, fo llo wed by a co lo n and the value asso ciated with that key. In the example abo ve, yo u
can see strings, numbers and tuples being used as keys. There are so me types o f o bject yo u can't use as keys, but
let's no t wo rry abo ut that just yet. We've go t eno ugh to wrap o ur brains aro und fo r no w!

In additio n to creating dicts with a literal representatio n, yo u can also add new key-value pairs, and replace the value
asso ciated with an existing key, using assignment statements. If yo u assign to an existing key in the dict, then the
assigned value replaces the previo usly asso ciated value. If no value is asso ciated with the key (in o ther wo rds, if the
key do es no t currently exist in the dict), then the key is added and the assigned value is asso ciated with the key.

Numeric keys receive slightly different treatment. Yo u might expect that d[1], d[1.0 ], and d[1+0 j] wo uld refer to
different values in the dict, but tho se three keys are all numerically equal, and so assigning to d[1.0 ] o verwrites the
value assigned to d[1], and the same value can be retrieved by referencing d[1+0 j].

Yo u can also see in o ur example that dicts have a ke ys() metho d that returns the keys o f the dict. This is kno wn in
Pytho n as an iterator. We'll lo o k at iterato rs in so me detail in a later co urse, but fo r the mo ment all yo u need to kno w is
that yo u can iterate o ver it, and each time aro und the lo o p, yo u get ano ther key fro m the dict. The same is true o f the
dict's it e m s() metho d, o nly this iterato r yields key-value pairs rather than the keys fro m the dict.

The dict is a flexible o bject type. Yo u can perfo rm the fo llo wing o peratio ns o n a dict d:

Expre ssio n De script io n


d[k] Returns the item fro m d asso ciated with key k, raising a KeyErro r exceptio n if k is no t present.
len(d) Returns the number o f items in the dict.
del d[k] Remo ves d[k] fro m d, raising a KeyErro r exceptio n if k is no t present.
k in d Returns True if d has a key k; o therwise returns False.
k no t in d Returns True if d do es no t have a key k; o therwise returns False.
Returns the value o f d[k] if that key exists; o therwise returns de f ault (if the default value is no t
d.get(k, default)
given, returns No ne rather than raising a KeyErro r exceptio n).
Updates the dict, o verwriting any existing keys that appear in o t he r, which can either be ano ther dict
d.update(o ther)
o r a sequence o f key-value pairs.

Remember, yo u learn mo re by experimenting. Play aro und with a dict o r two in an interactive co nso le until yo u are
co mfo rtable with the way they wo rk.

Applying Dicts: Counting Words


No w that yo u kno w ho w dicts wo rk, let's apply the co ncept to a classic text pro cessing pro blem: co unting the
o ccurrences o f wo rds within a text. In a previo us exercise, we put the wo rds fro m a piece o f text into a set, but there
was no way to asso ciate a co unt with each wo rd—all we can do with a set is detect whether an item is present.

Because the dict is able to asso ciate a value with the key, we can use each wo rd as a key in the dict and have the
asso ciated value be the number o f times the wo rd appears in the text. Open yo ur wo rd_co unt e r.py pro gram, click

the Save As ( ) ico n, and save it in the /pyt ho n1 fo lder as a new file named wo rd_f re que ncy.py. Then, edit it as
sho wn:
CODE TO TYPE:
#!/usr/local/bin/python3
"""Count the frequency of each word in a text."""

text = """\
Baa, baa, black sheep,
Have you any wool?
Yes sir, yes sir,
Three bags full;
One for the master,
And one for the dame,
And one for the little boy
Who lives down the lane."""

for punc in ",?;.":


text = text.replace(punc, "")
freq = {}
for word in text.lower().split():
if word in freq:
freq[word] += 1
else:
freq[word] = 1
for word in sorted(freq.keys()):
print(word, freq[word])

Save and run it. Yo u'll see o utput sho wing the number o f times each wo rd appears in the text. Wo rd splitting wo rks in
the same way as befo re, but no w, each time a wo rd is examined, the pro gram checks to find o ut whether the wo rd has
appeared befo re. If it has no t, then a new entry is made in the dict with a value o f o ne. If it has (if it is already fo und in the
f re q dict), the current co unt is incremented.

A slight mo dificatio n to the pro gram allo ws us to dispense with the if statement. Edit wo rd_f re que ncy.py as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Count the frequency of each word in a text."""

text = """\
Baa, baa, black sheep,
Have you any wool?
Yes sir, yes sir,
Three bags full;
One for the master,
And one for the dame,
And one for the little boy
Who lives down the lane."""

for punc in ",?;.":


text = text.replace(punc, "")
freq = {}
for word in text.lower().split():
freq[word] = freq.get(word, 0)+1
for word in sorted(freq.keys()):
print(word, freq[word])

Save and run it. Yo u see the same results as befo re. This versio n o f the pro gram uses the same statement to update
the co unt, even if the wo rd has been seen befo re. It uses the ge t () metho d with a default value o f zero to retrieve the
existing co unt, so if the wo rd hasn't been seen befo re, the assignment inserts a value o f o ne against the new key.

A More Complex Application: Word Pair Frequencies


In the final example o f this lesso n, we'll do a slightly mo re co mplex co unting task. Fo r each wo rd in the input, we will
keep a co unt o f the number o f times it was fo llo wed by each o f the o ther wo rds that immediately fo llo w it in the text.
This invo lves keeping a dict fo r each wo rd. The keys o f this seco nd dict will be the wo rds that immediately fo llo w the
o riginal wo rd. The values will be the number o f times that particular wo rd fo llo wed the o riginal wo rd.
With yo ur wo rd_frequency.py pro gram o pen in the edito r windo w, click the Save As ( ) ico n and save the file in yo ur
/pyt ho n1 fo lder as pair_f re que ncy.py. Edit the new pro gram as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Count the frequency of each word in a text."""

text = """\
Baa, baa, black sheep,
Have you any wool?
Yes sir, yes sir,
Three bags full;
One for the master,
And one for the dame,
And one for the little boy
Who lives down the lane."""

for punc in ",?;.":


text = text.replace(punc, "")
words = {}
textwords = text.lower().split()
firstword = textwords[0]
for nextword in textwords[1:]:
if firstword not in words:
words[firstword] = {}
words[firstword][nextword] = words[firstword].get(nextword, 0)+1
firstword = nextword
for word in sorted(words.keys()):
d = words[word]
for word2 in sorted(d.keys()):
print(word, ":", word2, d[word2])

Save and run it.

Since we have to pro cess wo rds in pairs, we set f irst wo rd to be the first wo rd in the text. The lo o p then lo o ps o ver the
rest o f the text (t e xt wo rds[1:]), assigning the wo rd to ne xt wo rd. At the end o f each pass thro ugh the lo o p,
ne xt wo rd is assigned to f irst wo rd, so that at the start o f each iteratio n we have a co nsecutive pair o f wo rds in
f irst wo rd and ne xt wo rd.

The pro gram makes sure that there is an entry fo r the first wo rd in the wo rds dict: each entry starts o ut as an empty dict,
which will be used to sto re the number o f o ccurrences o f individual following wo rds. Then it uses the same technique
that the seco nd versio n o f wo rd_frequency.py did to update the co unt o f the following wo rd. The printing o f the o utput
has beco me a little mo re co mplex, because each wo rd requires yo u to print o ut each following wo rd. So in the o utput
phase, we have nested lo o ps: o ne lo o p inside ano ther.

Nice Work!
Yo u've just added sets and dicts to yo ur pro gramming to o l kit—no easy feat! Excellent! In the next lesso n, we'll fo cus
o n o utput, and ways to co ntro l the fo rmat o f the o utput pro duced by yo ur pro grams.

I like what I'm seeing so far! Keep it up and see yo u in the next lesso n...

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
String Formatting
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

use the fo rmat() Metho d.


create a string to be used as a fo rmat, then call the string's f o rm at () metho d to pro duce a fo rmatted value o r set o f
values.
use the field name to tell the fo rmatting engine which value is to be fo rmatted.
specify a field's type, specificatio ns, and alignment.
create a simple listing pro gram.

Up until no w yo ur pro grams created o utput using the print () functio n, which simply sends the o utput to the screen witho ut
embellishment. But so metimes yo u'll need yo ur o utput to be fo rmatted in a particular way. Pytho n has so me really co nvenient
fo rmatting features that can help with that.

The format() Method


To pro duce a fo rmatted value o r set o f values, yo u create a string to be used as a fo rmat, then call the string's
f o rm at () metho d. The fo rmat string can be made up o f literal text (which beco mes part o f the fo rmatted string) and
replacement fields. The replacement fields are surro unded by curly brackets ({ } ). Yo u pro vide the values yo u want to
fo rmat as arguments to the metho d. The values are interpo lated into the fo rmat string to pro duce a fo rmatted string,
which beco mes the result o f the metho d call. The replacement fields co ntain either the po sitio n o r the name o f the
argument who se value sho uld be used (yo u'll learn mo re abo ut named arguments later).

Let's lo o k at so me o f the capabilities that this o ffers. Start an interactive sessio n and enter the fo llo wing co mmands to
see ho w fo rmatting wo rks:

INTERACTIVE SESSION:

cold1:~$: python3
>>> "{2}, {1}, and {0}".format("George", "Paul", "John")
'John, Paul, and George'
>>> "{who} is a smart {what}".format(what='cookie', who='Sylvia')
'Sylvia is a smart cookie'
>>> "The fifth element of the first argument is {0[5]}".format(
... ["Dallas", "Zorg", "Cornelius", "Ruby", "Billy", "Leelo"])
'The fifth element of the first argument is Leelo'
>>> d = {'Cher': "Sarkisian", 'Sonny': "Bono"}
>>> "Sonny's surname is {0[Sonny]}".format(d)
"Sonny's surname is Bono"
>>> "Cher's surname is {lookup[Cher]}".format(lookup=d)
"Cher's surname is Sarkisian"
>>> for first, last in d.items():
... print("{0:10} {1:10}".format(first, last))
...
Cher Sarkisian
Sonny Bono
>>> fmt = "{0:>6} = {0:>#16b} = {0:#06x}"
>>> for i in 1, 23, 456, 7890:
... print(fmt.format(i))
...
1 = 0b1 = 0x0001
23 = 0b10111 = 0x0017
456 = 0b111001000 = 0x01c8
7890 = 0b1111011010010 = 0x1ed2

Yo u can see that Pytho n has so me very po werful string-fo rmatting capabilities. No w we need to understand the rules
and ways to write fo rmats that will give us the o utput we want. We'll go o ver these rules in the next few sectio ns.
The curly brackets play a vital ro le in fo rmatting strings. Each sequence o f characters surro unded by a pair o f curly
brackets is replaced by so me representatio n o f an argument to the f o rm at () metho d.

Function Arguments
The f o rm at () metho d, like all Pytho n functio ns, can be called with two types o f argument. The first type, and the o ne
yo u are mo st familiar with, is called positional, because it is identified by the po sitio n it o ccupies in the argument list.
The seco nd type is called keyword; it's preceded by a name and an equals sign.

If a call has any po sitio nal arguments, they must always appear befo re any keywo rd arguments. Thus, " ..." .f o rm at (a,
b, k1=c, k2=d) is legal, but " ..." .f o rm at (k1=c, k2=d, a, b) is no t (it will be flagged as a syntax erro r by the interpreter).

The arguments to the f o rm at () metho d call are the values to be fo rmatted. The fo rmat string o n which the metho d is
called specifies ho w the values are to be represented, by including replacement fields. Other text in the fo rmat string
(that do es no t appear between curly brackets) is simply co pied to the o utput literally.

To include actual curly brackets in the o utput, simply put two curly brackets to gether, {{ o r } } . These
Note do ubled curly brackets can never o ccur in a replacement field, and so they are treated specially.

Format Field Names


The first part o f the replacement field, immediately fo llo wing the o pening curly bracket, is the field name. This tells the
fo rmatting engine which value is to be fo rmatted. The field name begins with either a number, which specifies a
po sitio nal argument to the f o rm at () metho d, o r a name, which specifies a named argument. This can be fo llo wed by
extra info rmatio n that allo ws yo u to index the selected argument (which will presumably be an indexable o bject such
as a list, tuple, o r dict) o r access o ne o f its attributes.

Exam ple Fie ld Nam e Me aning


1 The seco nd po sitio nal argument
nam e The keywo rd argument called nam e
0 .at t r The at t r attribute o f the first po sitio nal argument
2[0 ] Element 0 o f the third po sitio nal argument (which must be a list, tuple, o r dict)
t e st [ke y] The element asso ciated with key ke y in the keywo rd argument named t e st

These features alo ne can get yo u pretty far. Let's experiment no w and get mo re co mfo rtable pro gramming by writing a
slightly unusual pro gram. Usually we expect to pro vide variable data to a pro gram and fo rmat its results in a standard
way. This time we'll pro vide yo u with standard data and let yo u enter fo rmat specificatio ns that will select specific
elements fo r display.

Type the fo llo wing co de as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Accept format strings from the user and format fixed data."""
i = 42
r = 31.97
c = 2.2 + 3.3j
s = "String"
lst = ["zero", "one", "two", "three", "four", "five"]
dct = {"Jim": "Dandy",
"Stella": "DuBois",
1: "integer"}
while True:
fmt = input("Format string: ")
if not fmt:
break
fms = "{"+fmt+"}"
print("Format:", fms, "output:", fms.format(i, r, c, s, e=lst, f=dct))

Save it in yo ur /pyt ho n1 fo lder as f o rm at t ing.py and run it; verify that yo u get the answers sho wn fo r the inputs
given in the fo llo wing table:

Input Out put Explanat io n


0 {0 } : 42 First po sitio nal argument
1 {1} : 31.9 7 Seco nd po sitio nal argument
{2.imag} :
2.imag The im ag attribute o f the third po sitio nal argument
3.3
{{{3}}} : A left curly bracket (specified by {{) fo llo wed by the fo urth po sitio nal argument, fo llo wed by a
{{3}}
{String} right curly bracket (specified by } } )
e[0 ] {e[0 ]} : zero Element zero o f the keywo rd argument named e
{f[Stella]} :
f[Stella] The element o f the keywo rd argument named f indexed by the string " St e lla"
DuBo is
f[1] integer The element o f the keywo rd argument named f , indexed by the integer 1

To exit the pro gram, press Ent e r. The pro gram takes whatever yo u enter, wraps it inside curly brackets, and uses the
co nstructed string as a fo rmatting string against fo ur po sitio nal arguments and two keywo rd arguments. The print ()
call will o nly o utput a single value, but yo u can vary the fo rmat to get all kinds o f results.

If yo u do n't understand the results, yo ur instructo r can help cast so me light o n the to pic.

Format Specifications
The fo rmatting mechanism has so me pretty so phisticated ways to select what is fo rmatted. No w let's see abo ut
actually formatting the selected value. We do that by fo llo wing the field name with a co lo n and a format specification.
This can include details abo ut the filling mechanism to be used, ho w the o utput is to be aligned in the field, ho w to treat
the signs o f numbers, ho w wide the field sho uld be, ho w many digits o f precisio n to allo w, o r what type o f co nversio n
sho uld be perfo rmed o n the selected value.

The vario us co mpo nents o f the fo rmat specificatio n must appear in a prescribed o rder. No co mpo nent is required.

Padding and Alignment


Padding clears an area aro und the co ntent (inside the bo rder) o f an element. Yo u do n't need to specify a
padding character, but if yo u do specify padding, yo u must specify the field's alignment as well. There are fo ur
different characters that yo u can use to specify the field's alignment. If the alignment specifier is preceded by
so me o ther character, that character is used to pad the field to the requested width; o therwise the space
character is used. The alignment o ptio ns are:

Alignm e nt
Me aning
Opt io n
The field is left-aligned in the available space, with any padding to its right. This is the default
<
when no alignment is specified.
> The field is right-aligned in the available space, with any padding to its left.
(Valid o nly fo r numeric types). Fo rces the padding to be placed after the sign but befo re any
= digits. This can be used to print padded numeric values with the signs all aligned abo ve each
o ther. Pad characters are typically "0 " o r "*".
The field is centered within the available space. Padding characters will be added o n the left
^
and right.

No padding is required if the value o ccupies the who le width o f the field. If no width is specified, this will
always be the case, and no padding will ever be inserted.

Sign
As yo u may have guessed, we do n't specify signs fo r no n-numeric values. The interpreter wo uld raise a
Value Erro r exceptio n if it fo und such a sign specificatio n. There are three ways we can use signs:

Opt io n Me aning
+ Insert a + sign fo r po sitive values, a - sign fo r negative values.
- Insert a - sign fo r negative values, no sign fo r po sitive values.
space Insert a - sign fo r negative values, a space fo r po sitive values

Base Indicator
The base indicatio n can o nly be requested fo r integers who se values are being displayed in hexadecimal,
o ctal, o r binary (simmer do wn, we're go ing to talk abo ut this stuff mo re in a few minutes). To request it,
include a hash mark (# ) in the fo rmat specificatio n. When a base indicato r is requested, binary numbers are
preceded by 0 b, o ctal numbers by 0 o and hexadecimal numbers by 0 x.

Digit Separator
To use co mmas as tho usands separato rs (fo r example, 9 ,9 9 9 ,9 9 9 ), insert a co mma in the fo rmat
specificatio n. This may restrict yo ur pro grams' po rtability, as so me lo cales use a co mma as a decimal po int
and a perio d as a tho usands separato r. To keep yo ur co de as po rtable as po ssible, use lo cale-dependent
types o f specificatio ns (mo re o n this in a few minutes).

Field Width
The field width is a decimal integer specifying the to tal width o f the o utput generated by the fo rmat specifier. As
a special case, if the field width begins with a zero character ('0 '), it is treated as a sho rthand fo r a pad
character o f '0 ' and a fill type o f '=' (zero es between the sign and the digits). This is illegal fo r no n-numeric
values and will raise a Value Erro r exceptio n under tho se circumstances.

Precision
Precisio n is specified as a perio d fo llo wed by a decimal number. Fo r numeric values, this indicates ho w
many significant digits to display:

INTERACTIVE SESSION:

>>> "{0:15.5}".format(987.654)
' 987.65'
>>> "{0:15.5}".format(98765.432)
' 9.8765e+04'

Fo r o ther types o f values, it indicates ho w many characters will be used fro m the field co ntent.

Field T ype
Last o f all co mes a letter that dictates which type o f value sho uld be fo rmatted. Fo r string values, the letter can
be o mitted, o r can be s. All numeric types can also be fo rmatted with a field type o f s, in which case the
resulting value befo re alignment and truncatio n (yeah, I said it: truncation—aka limiting the number o f digits
right o f the decimal po int) is the same as that pro duced by applying the built-in st r() co nversio n. Co mplex
number values canno t be fo rmatted in the same way as real and integer values; instead, yo u must fo rmat the
real and imaginary parts separately. Yo u can access these parts using the .re al and .im ag attribute qualifiers
in the field names. Integer and lo ng values can be fo rmatted with these field types:

T ype Fie ld T ype


b Binary: fo rmats the number in base 2.
c Character: co nverts the number to the co rrespo nding Unico de character.
d Decimal: fo rmats the integer in base 10 .
o Octal: fo rmats the integer in base 8 .
Hexadecimal: fo rmats the number in base 16 , using lo wer-case letters a thro ugh f fo r the digits
x
fro m 10 to 15.
X Hexadecimal: like x, but uses upper-case letters.
Like d, but uses the lo cale settings to determine the decimal po int and tho usands separato r
n
characters.
No
Treated the same as d.
co de
Flo ating-po int and decimal values use a separate set o f type co des:

T ype Fie ld T ype


e Expo nential no tatio n: fo rmats in scientific no tatio n using e to indicate the expo nent.
E Same as e but uses an upper-case expo nent indicato r.
Fixed-po int. Displays the number as a fixed-po int number, using "nan" to represent "no t a number"
f
and "inf" to represent infinity.
F Same as f but upper-case: uses "NAN" and "INF."
General fo rmat. Uses fixed-po int fo rmat unless the number is to o large, in which case it uses
g
expo nent no tatio n with lo wer-case indicato rs.
G Like g but uses upper-case indicato rs.
n Like g but uses the current lo cale settings to determine decimal po int and tho usands separato rs.
% Multiplies the number by 10 0 and displays in f fo rmat fo llo wed by a percent sign.
No Treated similarly to g except that it always pro duces at least o ne digit after the decimal po int and by
co de default uses a precisio n o f 12.

Variable-Width Fields
The field width and the precisio n are numeric values. If yo u want these values to be reliant o n pro gram data, yo u can
pass the width and precisio n as arguments to the f o rm at () metho d and then use a nested field name inside the
fo rmat specificatio n. This nested field name (which must refer to an integer value) is substituted fo r the field width o r
precisio n as the fo rmatting takes place. So , fo r example, " {0 :{1} .{2} f } " .f o rm at (1234 .5 6 7 8, 18, 3) displays the
number 1234.56 78 to three decimal places in a field 18 characters wide.

Let's try a few examples. Start up an interactive sessio n and enter the co mmands sho wn:

INTERACTIVE SESSION:

>>> "{0:010.4f}".format(-123.456)
'-0123.4560'
>>> "{0:+010.4f}".format(-123.456)
'-0123.4560'
>>> for i in 1, 2, 3, 4, 5:
... "{0:10.{1}f}".format(123.456, i)
...
' 123.5'
' 123.46'
' 123.456'
' 123.4560'
' 123.45600'
>>> n = {'value': 987.654, 'width': 15, 'precision': 5}
>>> "{0[value]:{0[width]}.{0[precision]}}".format(n)
' 987.65'

The numerical ro unding is always co rrect. And by using dict access, yo u can carry the value, field width, and precisio n
(alo ng with o ther values yo u might need) all within a single o bject.

A Simple Listing Program


This example pro gram lists the names, ages, and weights o f a number o f individuals. Currently the data is sto red as a
list o f tuples. We'll list the data using fo rmatting statements. Enter this co de in the edito r windo w:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Produce a listing of people's names, ages and weights."""
data = [
("Steve", 59, 202),
("Dorothy", 49, 156),
("Simon", 39, 155),
("David", 61, 135)]
for row in data:
print("{0[0]:<12s} {0[1]:4d} {0[2]:4d}".format(row))

Save it in yo ur /pyt ho n1 fo lder as pe rso n_list .py and run it. While this pro gram wo rks, the co rrespo ndence
between related data items seems a little o bscure. Mo dify the pro gram as sho wn belo w to extract the individual items
fro m the ro w and pass them as separate arguments to the f o rm at () call:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Produce a listing of people's names, ages and weights."""
data = [
("Steve", 59, 202),
("Dorothy", 49, 156),
("Simon", 39, 155),
("David", 61, 135)]
for name, age, weight in data:
print("{0:<12s} {1:4d} {2:4d}".format(name, age, weight))

Save and run it again. The results are the same, but which co de do yo u think is easier to read?

Okay, no w let's make the name field wider. We'll use the perio d as a pad character to help the reader fo llo w the line
fro m the name to the age and weight. Mo dify the pro gram a third time—add a padding character befo re the alignment
indicatio n and increase the field width:

CODE TO TYPE:

#!/usr/local/bin/python3
#!/usr/local/bin/python3
"""Produce a listing of people's names, ages and weights."""
data = [
("Steve", 59, 202),
("Dorothy", 49, 156),
("Simon", 39, 155),
("David", 61, 135)]
for name, age, weight in data:
print("{0:.<30s} {1:4d} {2:4d}".format(name, age, weight))

Save and run it again.

Check You Out!


Yo u've learned so much abo ut Pytho n's fo rmatting features! They can really help make the o utput fro m yo ur pro grams
readable and usable.

In the next lesso n, we'll return to functio ns and talk abo ut the ro le o f keywo rd arguments and parameters like the o nes
we used with the string f o rm at () metho d in this lesso n.

See yo u there!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
More About Looping
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

use the range() functio n with lo o ps.


use the enumerate() functio n.
use the While lo o p when yo u need to validate user input.
use lo o ps to add, retrieve, and delete data.
create a dictio nary using an enumerated lo o p.
co mbine the pieces o f co de and pro gramming skills yo u learn in this lesso n to make a pro gram that prepares a list
o f invitatio ns.

Earlier, yo u learned abo ut f o r and while lo o ps. The f o r lo o p repeats the lo o p bo dy o nce fo r each element o f a co ntainer. The
while lo o p repeats the lo o p bo dy co ntinuo usly, testing befo re each executio n whether so me co nditio n is true; it sto ps o nly
when the co nditio n beco mes false (o r a bre ak statement is executed, which terminates any lo o p). In this lesso n, we'll sho w
yo u so me o ther co o l things yo u can do with lo o ps.

Fun with the range() function.


Can yo u say 'Pytho n is fun' 1,0 0 0 times fast? Yo u might no t be able to , but Pytho n can!

INTERACTIVE SESSION:

>>> for i in range(1000):


... print("Python is fun!")
...
Python is fun!
Python is fun!
[... 996 lines omitted ...]
Python is fun!
Python is fun!
>>> range(1000)
range(0, 1000)
>>> type(range(1000))
<class 'range'>

Yo u just printed Pyt ho n is f un! o ne tho usand times, using the range () functio n, which generates arithmetic
pro gressio ns. When we ask the interpreter to print o ut the result o f a call to range (10 0 0 ), it do esn't print o ut a list o r a
tuple, as yo u might expect. In fact, range () returns a special type o f o bject kno wn as a range o bject. Yo u can iterate
o ver this o bject just like yo u can iterate o ver a list [0 , 1, 2, ..., 9 9 8 , 9 9 9 ]. Using the o bject is different fro m using a list
because it pro duces the numbers o ne by o ne as needed. This saves time and sto rage space that wo uld be needed to
co nstruct a list instead.

The last example printed a string co nstant. In this next example, we'll print o ut so me numbers:

INTERACTIVE SESSION:

>>> for i in range(4):


... print(i)
...
0
1
2
3

Did yo u no tice that the 4 did no t print? The range starts at zero , so the given end po int is never part o f the generated
sequence. This may be co nfusing at first, but the interpreter has go o d reaso n fo r do ing it like that. Yo u'll see in this next
example:

INTERACTIVE SESSION:

>>> names = ['John', 'Paul', 'George', 'Ringo']


>>> for i in range(3):
... print(names[i])
...
John
Paul
George

(No thing perso nal, Ringo ; we just wanted to make a po int.) Generally, if yo u want to print o nly the names, yo u wo uldn't
lo o p o ver the indexes and use them to select the appro priate list elements. Instead yo u wo uld lo o p o ver the list
directly. If yo u ever see co de like f o r i in range (le n(so m e t hing)), that no rmally indicates what's so metimes called a
code smell. I kno w, funny, right? It's co de that wo rks, but still stinks a little. Co de smells are usually an indicatio n that
so mething needs to be changed.

By no w yo u can see that range () is a bit like indexing—it starts co unting at zero (unless yo u tell it to start so mewhere
else) and go es o n until just befo re it gets to the end value. What if yo u want a range o f numbers that starts at 5 and
ends at 7? Yo u give range () two arguments instead o f o ne:

INTERACTIVE SESSION:

>>> for i in range(5, 8):


... print(i)
...
5
6
7

Remember the stride we used with lists? We can do it in range () as well. Add a third argument as sho wn:

INTERACTIVE SESSION:

>>> for i in range(10, 40, 10):


... print(i)
...
10
20
30

Yo u can also use a negative stride if yo u want a numerically descending sequence. In the next example, yo u'll see that
again, the sequence sto ps befo re it actually reaches the final value:

INTERACTIVE SESSION:

>>> for i in range(10, -30, -10):


... print(i)
...
10
0
-10
-20

Using the enumerate() function


The range functio n is really useful and po werful. But what if yo u need to step thro ugh a set o f numbers by tens and
track which iteratio n yo u are in? Fo r example, when co unting by tens:

OBSERVE:

0 10
1 20
2 30
3 40
4 50

We can do that, right? We'll pro vide a co unter variable and increase it with each iteratio n:

INTERACTIVE SESSION:

>>> c = 0
>>> for i in range(10, 60, 10):
... print(c, i)
... c += 1
...
0 10
1 20
2 30
3 40
4 50

This metho d wo rks, but Pytho n gives us a better way: the functio n e num e rat e (). Like range (), it generates a
sequence o f values, but in this case, the values are tuples, each co ntaining two elements. The first element is a co unter
that starts at zero , and the seco nd element is the current item fro m the sequence that was given as an argument to
e num e rat e (). In a f o r lo o p, yo u can use a tuple o f two names to receive the elements, similar to the unpacking
assignments we used earlier. In the example belo w, i is the index and e is the element fro m the sequence:

INTERACTIVE SESSION:

>>> for i, e in enumerate(range(10, 60, 10)):


... print(i, e)
0 10
1 20
2 30
3 40
4 50

No w we'll take a lo o k at two ways to print o ut a numbered list o f names. There's mo re than o ne way to do it; Pytho n
has an o lder way o f fo rmatting, no t deprecated, still wo rks, based o n the C language printf. Then it has a new
"fo rmatting mini-language" mo re like C#, intro duced with Pytho n 3 but also back-po rted to 2.6 and abo ve, using
numbers in {curly brackets} to identify o bjects to fo rmat, and the .fo rmat() functio n we learned abo ut in the last lesso n.
The fo rmat() versio n has mo re bells and whistles and makes it easier to do certain things. Also , o ne co uld argue it's
cleaner in no t requiring a separate o perato r. Here's an example using the o ld way:

INTERACTIVE SESSION:

>>> names = ['John', 'Paul', 'George']


>>> for i, name in enumerate(names):
... print('%s. %s' % (i+1, name))
...
1. John
2. Paul
3. George
No w, the same thing using the new way o f fo rmatting:

INTERACTIVE SESSION:

>>> for i, name in enumerate(names):


... print('{0}. {1}'.format(i+1, name))
...
1. John
2. Paul
3. George

Same results, different metho ds. We'll usually use the .fo rmat metho d in this co urse, but yo u're likely to enco unter the
%s metho d in the real wo rld, so we'll use it o ccasio nally.

In the abo ve examples, we add o ne to the co unt because, altho ugh Pytho n co unts fro m zero , we humans
Note no rmally prefer to start at o ne.

A More Complex While Loop Example


Suppo se yo u want to print a list o f all the facto rials under 10 0 0 . In mathematics, N facto rial is written as "N!" A facto rial
is calculated by multiplying successive numbers to gether:

OBSERVE: Facto rial Calculatio ns

1! = 1 = 1
2! = 1 x 2 = 2
3! = 1 x 2 x 3 = 6
4! = 1 x 2 x 3 x 4 = 24

I'm abo ut to get mathematical and academic o n yo u fo r a minute here, so settle in. The textbo o k definitio n o f n factorial
(as lo ng as n is a no n-negative integer) is the pro duct o f all po sitive integers less than o r equal to n. Facto rials are
used in calculus, co mbinato rics, and pro bability theo ry.

Yo u could figure o ut all facto rials under 10 0 0 by figuring o ut the pattern o f calculatio ns manually, but that wo uld get
pretty tedio us with larger sets, do n't yo u think? In o rder to avo id that ago ny and its inherent po tential fo r erro rs, let's
use a while lo o p to reso lve the calculatio n instead. Create a new file in the edito r windo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Print all factorials less than 1000."""

c = 0
f = 1
while (f < 1000):
print(f)
c += 1
f = 1
for n in range(c, 0, -1):
f = f * n

Save it in yo ur /pyt ho n1 fo lder as f act o rial.py and run it. The pro gram prints all the facto rials under 10 0 0 .

There are actually two lo o ps here. The first (o r outer) lo o p uses the c variable to simply co unt upwards. The seco nd (o r
inner) lo o p generates the facto rial, based o n the value o f the co unter.

Each iteratio n o f the outer lo o p increments o ur co unter variable c by 1, co pies that to n, and resets the facto rial variable
f to 1. The inner lo o p do es its wo rk by taking the value o f n, which is simply a co py o f the co unter, and multiplying that
repeatedly against the facto rial variable.

So , if yo u already kno w N!, then yo u can pro duce (N+1)! (the next value in the sequence) by multiplying N! by N+1. Yo u
can make this pro gram even mo re efficient by avo iding the seco nd lo o p, since the seco nd lo o p wo uld be run fo r each
facto rial. This saves a lo t o f wo rk. Give it a try. Edit the co de as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Print all factorials less than 1000."""

c = 1
f = 1
while (f < 1000):
print(f)
c += 1
f *= c

Save and run it. The pro gram pro duces the same sequence o f values, but it do es no t repeat wo rk unnecessarily. This
beco mes mo re impo rtant as yo ur pro grams expand.

While Loops and User Input Validation


We can use the While lo o p when we need to validate user input. It lets us return the user back to the pro mpt until they
pro vide a valid respo nse. To implement this feature, we create an infinite lo o p that can o nly be bro ken by co rrect actio n
by the user.

Suppo se we want to fo rce the user to pro vide a yes o r no respo nse. Create a new file in the edito r windo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Validate user input"""

while True:
s = input("Type 'yes' or 'no':")
if s == 'yes':
break
if s == 'no':
break
print("Wrong! Try again.")
print(s)

Save it in yo ur /pyt ho n1 fo lder as validat e _input .py and run it. The co nso le asks yo u to type yes o r no . Instead,
type spam and press Ent e r. The co nso le respo nds with Wro ng! T ry again.. If yo u enter anything besides ye s o r no ,
yo u'll get the same respo nse. When yo u finally enter ye s o r no , yo u break the While lo o p and yo ur entry is printed.

The pro blem with this pro gram is that it do esn't adapt itself well to mo re o ptio ns. Fo r example, if yo u need to add
m aybe as a po ssible respo nse, that invo lves adding two lines o f co de and mo difying a third. With yo ur

validat e _input .py in the edito r windo w, click the Save As ico n to save it in yo ur /pyt ho n1 fo lder as
be t t e r_validat e _input .py, and edit it as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Validate user input"""

valid_inputs = ['yes', 'no', 'maybe']


input_query_string = 'Type %s: ' % ' or '.join(valid_inputs)
while True:
s = input(input_query_string)
if s in valid_inputs:
break
print("Wrong! Try again.")
print(s)

Save and run it. In this new pro gram, the valid_input s list variable is used to build the string that queries the user fo r
input. It's also used to validate the user's input. So in o rder to add an o ptio n, yo u can just replace valid_input s =
['ye s', 'no ', 'm aybe '] with valid_input s = ['ye s', 'no ', 'm aybe ', 'another option'].

Mo re so phisticated user interface validatio n while lo o ps are used in applicatio ns such as o perating systems and web
site registratio n systems.

Dicts and Loops


Earlier, we learned abo ut a useful co nstruct fo r handling data called Dicts. In this next set o f examples, we'll use lo o ps
to add, retrieve, and delete data. Eventually we'll co mbine everything into o ne large example to handle invitatio ns to a
party.

In the first example, yo u'll create a dictio nary using the wo rds o f the phrase Pyt ho n is awe so m e , using an
enumerated lo o p to do all the hard wo rk:

INTERACTIVE SESSION:

>>> data = {}
>>> for index, word in enumerate('Python is awesome'.split(' ')):
... data[index] = word
...
>>> print(data)
{0: 'Python', 1: 'is', 2: 'awesome'}

Keep this interactive sessio n o pen. First yo u created an empty dict, then enumerated o ver a list co ntaining the wo rds
split o ut o f the "Pytho n is aweso me" string. With each executio n o f the lo o p bo dy, yo u added the index o f the lo o p as a
dict key, using the wo rd as the value o f the dict element. Yo u can do this o ver any list o f data, fro m a list o f wo rds to
lines o f text in a file.

Our next example uses the it e m s() metho d fo r retrieving data fro m a dict. it e m s() returns a generato r o bject, which
then pro duces two -element tuples o f keys and their co rrespo nding values fro m the dict:

INTERACTIVE SESSION:

>>> data.items()
dict_items([(0, 'Python'), (1, 'is'), (2, 'awesome')])
>>> for element in data.items():
... print(element)
...
(0, 'Python')
(1, 'is')
(2, 'awesome')
>>> for key, value in data.items():
... print(key, value)
...
0 Python
1 is
2 awesome

The last two co mmands yo u entered are extremely useful, because they allo w yo u to access all the data in a dict
quickly. This is a very co mmo n pattern in wo rking with dicts in Pytho n. The dict's it e m s() metho d pro duces (key,
value) pairs, and the f o r lo o p unpacks the tuples and binds them to ke y and value , respectively.

Of co urse, there will be times when yo u'll need to remo ve key/value pairs fro m a dict. Suppo se yo u had a dict who se
keys were wo rds, and yo u wanted to remo ve all noise words (wo rds that are no t no rmally indexed, such as 'is' and
'at'). Yo u can use a lo o p to acco mplish this task:
INTERACTIVE SESSION:

>>> noise = ['is', 'at']


>>> data
{0: 'Python', 1: 'is', 2: 'awesome'}
>>> for key, value in data.items():
... if value in noise:
... del data[key]
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> data
{0: 'Python', 2: 'awesome'}

The data was deleted, but the deletio n changed the size o f data.items, which Pytho n repo rts as an erro r. To avo id this
pro blem, yo u need to pro duce a separate list rather than iterating o ver the dict's items (o r keys) directly:

INTERACTIVE SESSION:

>>> data = {}
>>> for index, word in enumerate('Python is awesome'.split(' ')):
... data[index] = word
...
>>> for key, value in list(data.items()):
... if value in noise:
... del data[key]
...
>>> data
{0: 'Python', 2: 'awesome'}

We used the same techniques here that we used in earlier examples to lo o p thro ugh the key/values o f the dictio nary.
And in this new example, when o ne key/value matched o ne o f the listed prepo sitio ns, it deleted the element o f the dict
that co ntained that no ise wo rd. Can yo u think o f a data structure that wo uld have been better than a list to ho ld the
no ise wo rds?

A More Complex Example


Go o d pro grammers build applicatio ns o ut o f smaller co de pieces. Our final example in this lesso n will give yo u a
chance to do just that. Yo u'll co mbine the pieces o f co de and pro gramming skills yo u've learned in this lesso n to
make a pro gram that prepares a list o f invitatio ns. The pro gram will take input as co mmands fro m the user. There are
five co mmands: "add" to add a name to the invitatio n list, "delete" to delete a name, "appro ve" to appro ve an invitatio n
that has been added, "list" to list the current invitatio ns, and "quit" to terminate the pro gram's o peratio ns.

Create a new file in the edito r windo w as sho wn:


CODE TO TYPE:

#!/usr/local/bin/python3
invites = {}
options = ['add', 'list', 'approve', 'delete', 'quit']
prompt = 'Pick an option from the list (%s): ' % ', '.join(options)
status_1 = 'unapproved'
status_2 = 'approved'
while True:
inp = input(prompt)
if inp not in options:
print('Please pick a valid option')
continue
if inp == 'add':
name = input('Enter name:')
if not name:
continue
invites[name] = status_1
elif inp == 'list':
for name, status in invites.items():
print('%s (%s)' % (name, status))
elif inp == 'approve':
for name in invites:
if invites[name] == status_1:
break
else:
print('There must be %s status invites. Please pick another option' % statu
s_1)
continue
while True:
print('Please enter a valid name from the list below')
unapproved = []
for name in invites:
if invites[name] == status_1:
unapproved.append(name)
print(", ".join(unapproved))
name = input('Enter name:')
if not name:
break # user changed mind about approving
if name in unapproved:
invites[name] = status_2
print('%s %s' % (name, status_2))
break
elif inp == 'delete':
if not invites:
print('There must be invites before you delete any of them')
continue # user changed mind about deleting
while True:
print('Please enter a valid name from the list below')
for name, status in invites.items():
print('%s (%s)' % (name, status))
name = input('Enter name:')
if not name:
break
if name in invites:
del invites[name]
print('%s deleted' % name)
break
elif inp == 'quit':
print('Quitting invites')
print('The final invitation list follows')
for name, status in invites.items():
print('%s (%s)' % (name, status))
break

Save it in yo ur /pyt ho n1 fo lder as invit e .py and run it. The pro gram is really just o ne input validatio n lo o p that
checks to make sure that the user has entered o ne o f the five available co mmands. If the user has no t do ne this, the
pro gram repeats the request fo r input. Mo st o f the co mmands require further input, and each co mmand allo ws the user
to just press the Ent e r key to igno re the co mmand and request ano ther.

We used the %s metho d fo r fo rmatting o ur pro mpts here. Yo u sho uld be able to change the pro gram to
Note use the .fo rmat() metho d.

Loop This
We lo ve lo o ps because they let us repeat the same lo gic again and again as necessary. This means that yo ur
pro gram can execute so me pretty co mplex behavio rs, particularly when o ne lo o p co ntains o thers.

In the next lesso n, we'll learn ho w pro grams can use and sto re info rmatio n in files. See yo u there!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Reading and Writing Files
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

create a file.
write to a file.
read files as text.
append to a file.
seek to arbitrary po sitio ns.
create a file-based to -do list.
read binary data.

So far, yo ur pro grams have used values that were either enco ded in the pro gram o r pro vided by the user, and the data
disappeared after the sessio n ended. But so metimes yo u'll need to use data fro m o utside so urces, o r to permanently save
data yo u've created o r mo dified in a pro gram. Pytho n has built-in functio ns to handle actio ns such as creating, writing, and
reading files. In this lesso n, yo u'll learn ho w to use files to create, retrieve, and change data.

Creating a New File


To create a file, yo u use the o pe n() functio n. This functio n returns a file o bject. If yo u try to o pen a file that do es no t
exist, the interpreter creates a file with that name fo r yo u. To see ho w the o pe n() functio n wo rks to create a file, start an
interactive sessio n and enter these co mmands:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ python3
>>> f = open('funnies.txt', 'w')
>>> f
<_io.TextIOWrapper name='funnies.txt' encoding='UTF-8'>

This statement assigns the result o f the call to the o pe n() functio n to the variable f . The o pe n() functio n o pens a file
to read, write, o r append. The first argument gives the name 'f unnie s.t xt ' to the wo rking file (because we changed to
the /pyt ho n1 fo lder befo re we started the pytho n3 interpreter, this file will reside in that fo lder). The seco nd argument
'w' tells o pe n() that we want to writ e to the file.

When yo u ask the interpreter to display that variable, it displays the name o f the o pen file asso ciated with a particular
o bject. Right-click the /pyt ho n1 fo lder in yo ur File Bro wser o n the left, and select Re lo ad—it no w co ntains an empty
f unnie s.t xt file. (Do n't delete the file o r clo se the interactive co nso le because yo u'll need access to it in the next
sectio n!)

Note Depending o n yo ur enviro nment, yo u might see an enco ding type o ther than UTF-8 .

Writing to a File
Writing to a file is a go o d way to save info rmatio n. Pytho n pro vides two different ways to write to a text file. Let's return
to the interactive seesio n and take a lo o k:
INTERACTIVE SESSION:

>>> f = open('funnies.txt', 'w')


>>> f.write('Larry\n')
6
>>> f.write('Curly\n')
6
>>> f.write('Moe\n')
4
>>> names = ['Groucho\n', 'Chico\n', 'Harpo\n']
>>> f.writelines(names)
>>> f.close()

The writ e () metho d adds the string (fo r example, 'Mo e \n') to the current co ntent o f yo ur funnies.txt file, and returns the
length o f the string added (fo r example, 4—including the \n as o ne character). The writ e line s() metho d takes a list o f
strings and adds each element to the funnies.txt file. Unlike the print () functio n, neither metho d adds newlines to the
co ntent it writes, so we include '\n' with each string so it will be o n a separate line in the file. The clo se () metho d
makes sure that all data is written o ut to the file and that the co nnectio n between it and the pro gram is dro pped.

Lo o k at f unnie s.t xt no w if yo u like—yo u'll see the six names yo u added. Be sure to clo se it befo re yo u
Note co ntinue with the lesso n.

Reading Files as Text


No w that yo u have so me sample data in the f unnie s.t xt file, let's see what Pytho n pro vides to read its co ntents.
Reo pen the file in a readable mo de. When yo u o pen a file fo r reading, the file o bject returned by the o pe n() functio n is
iterable, which means that if yo u use it in a f o r lo o p, each iteratio n gets the next line fro m the file until there are no
mo re lines left. Go back to the interactive sessio n and type in the co mmands as sho wn:

INTERACTIVE SESSION:

>>> f = open('funnies.txt', 'r')


>>> f.read()
'Larry\nCurly\nMoe\nGroucho\nChico\nHarpo\n'
>>> f = open('funnies.txt', 'r')
>>> f.readline()
'Larry\n'
>>> f.readlines()
['Curly\n', 'Moe\n', 'Groucho\n', 'Chico\n', 'Harpo\n']
>>> f = open('funnies.txt', 'r')
>>> for line in f:
... print(line)
...
Larry

Curly

Moe

Groucho

Chico

Harpo

>>> f.read()
''
>>> f.close()

No tice that we o pened the f unnie s.t xt file three times. That's because the file co ntent is "used up" by using the
re ad(), re adline (), and re adline s() metho ds, and we have to reo pen the file to return to the to p. re ad() returns all o f
the co ntent o f the file as a single string. re adline s() returns the file co ntent as a list o f lines. re adline () returns the
next line fro m the file, so when yo u called it o nce and then called re adline s(), the seco nd call returned a list that didn't
include the first line o f the file. The last metho d, f .re ad() returns no thing because the "po inter" is at the end o f the file.

When we're do ne with the file, we clo se it with the clo se () metho d. This releases reso urces that Pytho n was using to
lo o k at o r write to the file. So me pro grammers assume files will clo se auto matically at the end o f a pro gram, but it's
better pro gramming "hygiene" to clo se files when yo u finish using them.

Appending to a File
There are six lines o f text in yo ur funnies.txt file. Let's add so me mo re. If yo u o pen an existing file with the write o ptio n
w, yo u truncate the file's co ntents and pro duce an empty file—any new input will replace the file's o riginal co ntents. So
we don't use the write (w) o ptio n, using the append o ptio n (a) instead, as the seco nd argument to o pe n(). The next
example sho ws the append functio nality at wo rk. Enter these co mmands in yo ur interactive Pytho n co nso le:

INTERACTIVE SESSION:

>>> f = open('funnies.txt','a')
>>> f.write('A child of five could understand this. Fetch me a child of five.\n')
65
>>> f.write('Room service? Send up a larger room.\n')
37
>>> f.close()
>>> f = open('funnies.txt', 'r')
>>> for line in f:
... print(line[:-1])
...
Larry
Curly
Moe
Groucho
Chico
Harpo
A child of five could understand this. Fetch me a child of five.
Room service? Send up a larger room.
>>>
>>> f.close()

So , yo u o pened an existing file to append co ntent, and wro te in two new lines befo re clo sing it. When yo u o pened it
again, all o f the o ld co ntent was fo llo wed by the new co ntent yo u had just written. In this example, yo u used [:-1] to
slice each line to exclude the last character (the newline) fro m the end. This prevents yo ur co de fro m pro ducing the
blank lines that were printed o ut in the previo us example.

Seeking to Arbitrary Positions


As we've seen, when a file is being read o r written, it has a "current po sitio n." Yo u can change this po sitio n using the
se e k() metho d. The first argument sho uld be the po sitio n yo u want to mo ve to within the file (an integer—the
beginning o f the file is always po sitio n 0 ).

If yo u give a seco nd integer argument, it must be 0 , 1, o r 2:

Value Me aning
Po sitio n is relative to the start o f the file (the first argument canno t be negative). This is the default if yo u
0
do n't supply an argument.
Po sitio n is relative to the current po sitio n (the first argument can be negative to mo ve backward o r po sitive
1
to mo ve fo rward).
2 Po sitio n is relative to the end o f the file (the first argument must be negative).

Co ntinue yo ur interactive sessio n:


INTERACTIVE SESSION:

>>> f = open('funnies.txt', 'r')


>>> f.seek(115)
115
>>> f.read()
'Send up a larger room.\n'
>>> f.close()

Yo u can't se e k() past the end o f a file. To find the current po sitio n in a file, call the t e ll() metho d.

More File Details


Pytho n file o bjects give yo u many handy attributes and metho ds that yo u can use to analyze a file, including to o ls to
figure o ut the name o f the file asso ciated with the file o bject, whether a file is o pened o r clo sed, readable, writable, ho w
it handles erro rs, and if it is seekable. Type the co mmands as sho wn belo w:

INTERACTIVE SESSION:

>>> f = open('funnies.txt','a')
>>> f.name
'funnies.txt'
>>> f.readable()
False
>>> f.writable()
True
>>> f.seekable()
True
>>> f.encoding
'UTF-8'
>>> f.errors
'strict'
>>> f.closed
False
>>> f.close()
>>> f.closed
True

Creating a File-Based To-Do List


The built-in o pe n() functio n pro vides o ne metho d to add persistence to yo ur applicatio ns. In this case, persistence
means that when yo u turn o ff o r quit the applicatio n, the data remains available. So when yo u use an applicatio n to
sto re info rmatio n, yo u can end yo ur Pytho n sessio n, turn o ff yo ur co mputer, and still co me back and find that data later.
Persistence can take many fo rms, fro m the types o f files we're using in this lesso n, to database reco rds, to
audio /video files, to vario us do cument fo rmats.

So phisticated persistence engines are called databases. Mo st o f the wo rld's data is sto red in databases. These are
integrated sets o f lo gically o rganized files o r reco rds. Databases can sto re text, integers, dates, images, and much
mo re. Usually, databases use the relatio nal mo del, but there are also hierarchical, o bject, netwo rk, and flat-file mo dels.

To demo nstrate the po wer o f persistence, and ways to take advantage o f it, we'll create a to -do list applicatio n as o ur
next example. Create a new file as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""File-based to-do list maintainer."""

otasks = open('open_tasks.txt','a')
otasks.close()
dtasks = open('done_tasks.txt','a')
dtasks.close()
options = ('add','done','quit')
string_input = 'Pick an option from the list (%s): ' % ', '.join(options)
while True:
open_tasks = open('open_tasks.txt','r').readlines()
if open_tasks:
print('-' * 10)
print('Open Tasks')
print('-' * 10)
for i, task in enumerate(open_tasks):
print(i, task.strip())
done_tasks = open('done_tasks.txt','r').readlines()
print('-' * 12)
print('Done Tasks')
print('-' * 12)
for i, task in enumerate(done_tasks):
print(i, task.strip())

inp = input(string_input)
if inp not in options:
print('Please pick a valid option')
continue
if inp == 'add':
new_task = input('Enter new task: ')
tasks = open('open_tasks.txt','a')
tasks.write(new_task + '\n')
tasks.close()
if inp == 'done':
while True:
done_task = input('Please enter the number of your completed task: ').strip
()
if done_task.isdigit():
done_task = int(done_task)
break
print('Please enter a task number')
open_tasks = open('open_tasks.txt','r').readlines()
for i, task in enumerate(open_tasks):
if i == done_task:
print('Task removed: {0}'.format(task))
open_tasks.remove(task)
f = open('open_tasks.txt','w')
f.writelines(open_tasks)
f.close()
f = open('done_tasks.txt','a')
f.write(task)
f.close()
break
if inp == 'quit':
break

Save it in yo ur /pyt ho n1 fo lder as t o do .py, and run it. Witho ut adding any tasks, type quit and press Ent e r. This
pro gram starts o ut by o pening each o f two data files to append, and then clo ses them immediately. This fo rces the
co mputer to create the files, in case this is the very first run. Right-click yo ur /pyt ho n1 fo lder in the File Bro wser at left
and select Re lo ad, and yo u'll see the two new files, o pe n_t asks.t xt and do ne _t asks.t xt .

No w, run the pro gram again and create a few tasks. Quit the pro gram and start it again. The tasks yo u added are still
there! And just like that, yo u've implemented a persistence engine that uses the flat file mo del! Open the files and yo u'll
see yo ur tasks have been added to o pe n_t asks.t xt .
Yo u used the string isdigit () metho d to make sure that yo ur user input fo r task numbers wo uld co nsist
Note o f numerical digits. This prevents the pro gram fro m raising exceptio ns when it co nverts the string to a
number with the int () functio n.

Reading Binary Data


So far yo u've sto red simple text data, which is easy to read with any text edito r. Ho wever, simple text data is no
substitute fo r the audio files that sto re o ur favo rite music! But if we o pen audio files with a text edito r, it displays what
appears to be a lo t o f gibberish. Actually, these files are sto ring the audio data enco ded in binary fo rm. This data is
impo ssible fo r us to read witho ut a special to o l called a he x e dit o r. Fo rtunately, yo ur co mputer do esn't have the
same limitatio ns. And because the binary file do esn't have to be co mprehensible to humans, in many cases it can
represent data mo re efficiently than a simple text file.

All the audio , image, and video files o n yo ur co mputer are binary files. So are any files co mpressed into zip o r tar
fo rmat. In fact, the majo rity o f pro grams o n yo ur co mputer—such as yo ur favo rite bro wser—are co mprised o f binary
files, the no table exceptio n being the Pytho n pro grams yo u are writing as part o f this co urse. And even tho se Pytho n
pro grams are co mpiled into binary fo rmat befo re the co mputer actually runs them!

No w that yo u have a backgro und in binary data and files, let's check o ut ho w Pytho n can handle a binary file. We'll use
wget to grab the image belo w:

Type the fo llo wing co de in an interactive co nso le:

INTERACTIVE TERMINAL SESSION:

cold1:~$ cd python1
cold1:~/python1$ wget "https://courses.oreillyschool.com/Python1/images/lessons/python-
logo.gif"
--2011-11-14 13:14:26-- https://courses.oreillyschool.com/Python1/images/lessons/pytho
n-logo.gif
Resolving courses.oreillyschool.com... 199.27.144.89
Connecting to courses.oreillyschool.com|199.27.144.89|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 2549 (2.5K) [image/gif]
Saving to: "python-logo.gif"
100%[===============================================================>] 2,549 --.-K/s in
0s
2011-11-14 13:14:27 (26.8 MB/s) - "python-logo.gif" saved [2549/2549]
cold1:~/python1$ python3
>>> i = open('python-logo.gif', 'rb')
>>> i
<_io.BufferedReader name='python-logo.gif'>
>>> print(i.read(1))
b'G'
>>> print(i.read(1))
b'I'
>>> print(i.read(1))
b'F'
>>> i.read(10)
b'89a\xd3\x00G\x00\xf7\x00\x00'
>>> i.tell()
13
>>> i.seek(0)
0
>>> i.read(3)
b'GIF'
>>> i.close()
When yo u first lo o k at binary data, it can be pretty daunting. But even so , at a glance we can see a useful metho d and a
handy bit o f info rmatio n. The re ad() metho d fetches the byte(s) yo u request. Subsequent re ad() requests are fired
fro m yo ur current lo catio n in the file. The first three bytes pro vide the fo rmat o f the file yo u are examining (in this case,
GIF). This way a pro gram can figure o ut ho w to handle a file even if the file extensio n is missing. In fact, all mo dern
bro wsers check this info rmatio n befo re displaying images fo r yo u.

So , what abo ut the b'89 a\xd3\x0 0 G\x0 0 \xf 7 \x0 0 \x0 0 '? Well, that's part o f the image co ntent used to generate the
Pytho n lo go . Our example abo ve also sho ws the t e ll() and se e k() metho ds. se e k(0 ) "rewinds" the file to the
beginning.

Adding an integer argument to the re ad() metho d instructs yo ur pro gram to read the given number o f bytes. If there
aren't eno ugh bytes in the file, re ad(n) returns as many as there are. This means that if yo u get an empty sequence o f
bytes back, yo u are at the end o f the file.

Finally, the "strings" that yo u get when yo u read a file in binary mo de are what we call byte strings—each byte is eight
bits, so the ordinal value o f the characters is in the range 0 to 255. If yo u aren't familiar with the binary system, do n't
wo rry. Just be aware that Pytho n strings in binary differ fro m regular Pytho n strings in that yo u can represent pretty
much any character (as lo ng as yo ur character set includes it).

Files for Miles


So no w yo u kno w a little mo re abo ut files, the basic way to pro vide persistent sto rage o f info rmatio n. Files are the
basis o f mo st co mputer-based info rmatio n sto rage, so there is a huge amo unt o f literature that co vers ho w to sto re
vario us types o n info rmatio n in files. Fo r no w, the basics will suffice. Yo u can write data o ut fro m o ne pro gram run, and
read it back in to make use o f it in ano ther pro gram (o r a different run o f the same pro gram). This is what gives
co mputers the po wer to run systems with lo ng-term memo ry.

I'm thinking yo u're feeling pretty co nfident abo ut wo rking with files no w. But if yo u have any questio ns, go ahead and
ask yo ur mento r. They're here to help! Go o d jo b so far and see yo u in the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Python's Built-In Functions
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

use vario us built-in functio ns.

In every previo us lesso n, yo u've used so me o f Pytho n's built-in functio ns. The first built-in functio n yo u used was print () back
in lesso n 1. Since then yo u've used built-in functio ns like range (), o pe n(), and mo re. Built-in functio ns are an invaluable part o f
yo ur Pytho n to o l kit. In this lesso n, we'll learn even mo re abo ut them.

First we'll go o ver so me examples that use Pytho n built-in functio ns, and then explo re the functio ns themselves.

Party Fun with Built-In Functions


Suppo se yo u're thro wing a party. Each invitatio n to yo ur party might have 0 , 1, 2, o r mo re peo ple attached to it. Yo u are
sto ring the invitatio ns in a pair o f lists. The first list ho lds the names o f the attendees; the co rrespo nding element in the
seco nd list is the size o f the invited gro up. Yo u need to kno w the to tal number o f peo ple attending in o rder to buy the
right amo unt o f fo o d fo r the party, and fo r seating purpo ses, yo u need to kno w who has the largest gro up. Pytho n's
built-in functio ns will help yo u to execute bo th o f these tasks. Start an interactive sessio n as sho wn belo w:

INTERACTIVE SESSION:

cold1:~$ python3
>>> invites = ["Jay", "Conan", "Jimmy", "Craig"]
>>> attendees = [3, 2, 0, 5]
>>> sum(attendees)
10
>>> zipped = zip(attendees, invites)
>>> party = tuple(zipped)
>>> party
((3, 'Jay'), (2, 'Conan'), (0, 'Jimmy'), (5, 'Craig'))
>>> max(party)
(5, 'Craig')
>>> for people, name in party:
... print(people, name)
...
3 Jay
2 Conan
0 Jimmy
5 Craig
>>> for people, name in sorted(party):
... print(people, name)
...
0 Jimmy
2 Conan
3 Jay
5 Craig

Keep the co nso le o pen. This example helps demo nstrate a co uple o f new functio ns: sum () returns the to tal o f all the
elements in its argument; zip() interleaves (that is, alternates, like the teeth o f a zipper) the elements o f any number o f
sequences. If yo u call zip() with two arguments, when yo u lo o p o ver the result yo u get a sequence o f two -element
tuples; call it with three arguments and yo u get three-element tuples. zip() do esn't return a list o r a tuple, but
so mething called a generato r; we called the t uple () functio n o n it so we co uld see the data witho ut needing to lo o p
o ver it.

Next, using the same data, let's check to see if any o r all invitatio ns have any attendees and the to tal number o f
invitatio ns. Type the co mmands belo w as sho wn:
INTERACTIVE SESSION:

>>> any(attendees)
True
>>> all(attendees)
False
>>> len(attendees)
4

The any() functio n returns T rue if any element o f its argument is true. all() returns T rue if all o f the elements o f its
argument are true. le n() returns the number o f elements in the argument.

The rest o f this lesso n pro vides an alphabetical reference guide to Pytho n's built-in functio ns, with brief examples. As
yo u beco me mo re familiar with Pytho n, yo u'll find new and inno vative ways to make use o f these built-in functio ns.

abs(x)
The abs() functio n returns the abso lute value o f an integer, flo ating po int, o r co mplex number. The returned value is
always po sitive. If the input value is a negative integer o r flo ating-po int number, then the abso lute value is the negated
argument. If the argument is co mplex, a po sitive result will still be returned, but it's a co mplicated calculatio n (the
square ro o t o f the sum o f the squares o f the real and imaginary co mpo nents). Take a lo o k. Type the co mmands belo w
as sho wn:

INTERACTIVE SESSION:

>>> abs(3.14)
3.14
>>> abs(-3.14)
3.14
>>> abs(3+4j)
5.0

all(iterable)
The all() functio n returns T rue if all elements o f the supplied iterable are true (o r if there are no elements: technically,
yo u co uld say it returns False if any element evaluates as false). So if all elements in a list, tuple, o r set match
Pytho n's definitio n o f being true, then all() returns T rue . Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> lst = [1, 2, 3, 4, 5, 6]


>>> all(lst)
True
>>> lst.append('')
>>> all(lst)
False
>>> all([])
True
>>> t1 = ("Tuple")
>>> all(t1)
True
>>> t2 = ("Tuple", "")
>>> all(t2)
False
>>> s = {}
>>> all(s)
True
any(iterable)
The any() functio n is the co nverse o f the all() functio n. any() returns T rue if any element o f the iterable evaluates true.
If the iterable is empty, the functio n returns False . type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> lst = ["", 0, False, 0.0, None]


>>> any(lst)
False
>>> lst.append("String")
>>> any(lst)
True
>>> any([])
False
>>> any(("", 0))
False
>>> any(("", 1))
True
>>> any({})
False
>>> any({0: "zero"})
False
>>> any({"zero": 0})
True

bool(x)
The bo o l functio n co nverts the value to a Bo o lean, using the standard Pytho n truth testing pro cedure. If x is false o r
o mitted, it returns False ; o therwise it returns T rue . Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> bool("Python is fun!")


True
>>> t = []
>>> bool(t)
False
>>> bool(0)
False
>>> bool()
False
>>> bool(1)
True

chr(i)
The chr() functio n returns a string o f o ne character, which has the o rdinal value equal to the given integer. Type the
co mmands belo w as sho wn:
INTERACTIVE SESSION:

>>> chr(90)
'Z'
>>> alphabet = ''
>>> for letter in range(65, 91):
... alphabet += chr(letter)
...
>>> alphabet
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

dict(arguments)
dict () creates a new data dictio nary with items taken fro m the arguments. If no arguments are passed, an empty
dictio nary is created. Yo u can call dict () with a tuple o r list as its argument. In tho se cases, each o f the argument's
elements must be a two -element (key, value) list o r tuple. Yo u can also use a sequence o f keyword arguments. We will
co ver tho se in the lesso n o n functio ns, but in sho rt, a keywo rd argument is a name fo llo wed by an equals sign and a
value. Try this example:

INTERACTIVE SESSION:

>>> {'number': 3, 'string': 'abc', 'numbers': [3, 4, 5]}


{'numbers': [3, 4, 5], 'number': 3, 'string': 'abc'}
>>> dict([(1, "one"), [2, "two"], (3, "three")])
{1: 'one', 2: 'two', 3: 'three'}
>>> dict(zip("ABCDEF", range(10, 16)))
{'A': 10, 'C': 12, 'B': 11, 'E': 14, 'D': 13, 'F': 15
>>> dict(
... number=3,
... string="abc",
... numbers=[3, 4, 5]
... )
{'number': 3, 'string': 'abc', 'numbers': [3, 4, 5]}

dir(arguments)
The dir() functio n can accept any argument: string, integer, dictio nary, functio n, class, o r metho d. Witho ut arguments,
dir() returns the list o f names in the current lo cal sco pe. If an argument is given, then the result is a list o f the names in
the namespace o f the given o bject. The list returned is always so rted in alphabetical o rder. Type the co mmands belo w
as sho wn:
INTERACTIVE SESSION:

>>> p = 'Python'
>>> dir(p)
['__add__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format_
_', '__ge__', '_
_getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '_
_iter__', '__le__
', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__red
uce_ex__', '__rep
r__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__
', '_formatter_fi
eld_name_split', '_formatter_parser', 'capitalize', 'center', 'count', 'encode', 'endsw
ith', 'expandtabs
', 'find', 'format', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifi
er', 'islower', '
isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', '
lstrip', 'maketra
ns', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstri
p', 'split', 'spl
itlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

globals()
The glo bals() functio n returns a dictio nary representing the current glo bal symbo l table. This is always the
namespace dictio nary o f the current mo dule. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> list(globals().items())
[('__builtins__', <module 'builtins' (built-in)>), ('__name__', '__main__'), ('__doc__'
, None), ('__package__', None)]
>>> first = "Hello"
>>> second = "Goodbye"
>>> list(globals().items())
[('__builtins__', <module 'builtins' (built-in)>), ('__package__', None), ('second', 'G
oodbye'), ('__name__', '__main__'), ('__doc__', None), ('first', 'Hello')]

If yo u see mo re keys listed than are displayed in this example, it's pro bably because yo u've been trying
Note different snippets o f co de.

help(object)
The he lp() functio n is yo ur new best friend. Invo ke the built-in help system o n any o bject and it will return usage
info rmatio n o n the o bject. Fo r experienced Pytho n pro grammers, this is the first to o l to use when trying to figure o ut
so mething they do n't understand. Once yo u start writing mo re advanced Pytho n pro grams, yo u'll learn ho w to write
yo ur o wn help text.

In an interactive Pytho n co nso le, use the he lp(object) functio n o n any variable, string, integer, list, tuple, set, o r built-in
functio n, including the he lp() functio n. So me o f the text wo n't make sense to yo u right no w, but yo u'll still find this
functio n very useful. To scro ll thro ugh larger help do cuments, press the space bar. To exit, press q. Type the
co mmands as sho wn:
INTERACTIVE SESSION:

>>> help(globals)
Help on built-in function globals in module builtins:

globals(...)
globals() -> dictionary

Return the dictionary containing the current scope's global variables.


>>> help(len)
Help on built-in function len in module builtins:

len(...)
len(object) -> integer

Return the number of items of a sequence or mapping.


>>>

len(s)
le n(s) returns the length o f an o bject. The argument pro vided may be a sequence (string, tuple, o r list) o r a mapping
(dictio nary). Type in these co mmands:

INTERACTIVE SESSION:

>>> s = "Python"
>>> len(s)
6
>>> lst = [1, 2, 3]
>>> len(lst)
3
>>> d = {"a":"b", "c":"d", "e":"f"}
>>> len(d)
3

locals()
The lo cals() functio n returns a dictio nary representing the current lo cal symbo l table. Unless it's called inside a
functio n, it will return the same list as glo bals(). Type in this co mmand:

INTERACTIVE SESSION:

>>> locals()
{'__builtins__': <module 'builtins' (built-in)>, '__name__': '__main__', '__doc__': Non
e, '__package__': None}

Just like the glo bals() functio n, yo u will likely see mo re keys than we sho w in this example. That's
Note perfectly fine; it means yo u've pro bably been testing different snippets o f co de. Go o d fo r yo u!

max(iterable)
The m ax() functio n, with a single argument iterable, returns the largest item o f a no n-empty iterable (such as a string,
tuple, o r list). With mo re than o ne argument, it returns the largest o f the arguments. Type these co mmands:
INTERACTIVE SESSION:

>>> lst1 = [16, 32, 8, 64, 2, 4]


>>> max(lst1)
64
>>> lst2 = ['one', 'two', 'three', 'One', 'Two', 'Three']
>>> max(lst2)
'two'
>>> max(42, 76, -104)
76
>>> max(1, 2, "three")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() > int()

Do n't clo se the sessio n—we'll use lst1 and lst2 with the next functio n! The first result is 6 4. The seco nd result o f 'two '
might have surprised yo u, but Pytho n co mpares strings "lexico graphically" (like they wo uld be so rted fo r a dictio nary,
but with all the lo wer-case letters greater than any upper-case o ne), no t by the meaning o f the wo rds. The last
expressio n caused an erro r, because yo u can't co mpare strings and integers: they are fundamentally different types.

min(iterable)
The o ppo site o f the m ax() functio n, m in(it e rable ) returns the smallest item o f a no n-empty iterable (such as a string,
tuple, o r list). With mo re than o ne argument, it returns the smallest o f the arguments. Type these co mmands:

INTERACTIVE SESSION:

>>> min(lst1)
2
>>> min(lst2)
'One'
>>> min(42, 76, -104)
-104
>>> min(1, 2, 'three')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: str() > int()

The first result is 2. The seco nd result o f 'One' seems to make sense, but be aware that Pytho n returned the lo west
value o f an alphanumeric so rt, "O" being less than "T": Pytho n neither kno ws no r cares abo ut the meaning o f the
wo rds. The fo urth expressio n raised an exceptio n here as well, because yo u can't co mpare strings and integers.

ord(c)
o rd(c) is the inverse o f the chr() functio n we discussed earlier. Given a string o f length o ne, it returns an integer
representing the o rdinal value o f the character. Fo r example, o rd('A') returns the integer 6 5. Type these co mmands:
INTERACTIVE SESSION:

>>> alphabet = 'ABCDEFGH'


>>> for letter in alphabet:
... print(ord(letter), letter)
...
65 A
66 B
67 C
68 D
69 E
70 F
71 G
72 H

pow(x, y[, z])


po w(x, y[, z]) returns x to the po wer y. If a third argument z is given, then the result is reduced mo dulo z (then yo u get
the remainder after dividing (x raised to the po wer y) by z).

Yo u might have played with a calculato r at o ne time o r ano ther, using repeated multiplicatio n to raise a number to
successive po wers. In the next example, Pytho n auto mates the calculatio ns fo r yo u. Type these co mmands:

INTERACTIVE SESSION:

>>> pow(2, 2)
4
>>> pow(2, 3)
8
>>> pow(2, 4)
16
>>> for i in range(5, 12):
... print(pow(2, i), pow(2, i, 100))
...
32 32
64 64
128 28
256 56
512 12
1024 24
2048 48

reversed(seq)
re ve rse d(se q) is a reverse iterato r o n an o bject o f the type that yo u can lo o p thro ugh and pro cess. The list and
t uple types are suppo rted with this functio n, but the se t type is no t (because the elements o f a set aren't o rdered).
Type these co mmands:

INTERACTIVE SESSION:

>>> lst = [1, 2, 3]


>>> reversed(lst)
<list_reverseiterator object at 0x01E4DC70>
>>> for i in reversed(lst):
>>> print(i)
...
3
2
1
round(x[, n])
The ro und(x[, n]) functio n ro unds the decimal value x to the nearest integer. If yo u give a seco nd argument n, it
ro unds to that number o f decimal places. Type these co mmands:

INTERACTIVE SESSION:

>>> round(33.5)
34
>>> round(33.3333333333, 2)
33.33

sorted(iterable)
so rt e d(it e rable ) returns a new so rted list fro m the items in iterable. This arranges yo ur lists, tuples, and sets in a
kno wn o rder. Type these co mmands:

INTERACTIVE SESSION:

>>> numbers = [3, 1, 6, 7, 1100, 10]


>>> sorted(numbers)
[1, 3, 6, 7, 10, 1100]
>>> t = ['Beta','beta','alpha','Alpha']
>>> sorted(t)
['Alpha', 'Beta', 'alpha', 'beta']
>>> lst2 = ['one', 'two', 'three', 'One', 'Two', 'Three']
>>> sorted(lst2)
['One', 'Three', 'Two', 'one', 'three', 'two']

The first so rted list pro vides an expected result. The seco nd list yo u may no t have anticipated. Pytho n so rts in
alphanumeric o rder, but all upper-case letters so rt lo wer than all lo wer-case letters.

Yo u can also use keywo rd arguments to specify ho w the so rt keys sho uld be created, and whether to so rt in
ascending o r descending o rder. Suppo se yo u want to have a case-insensitive search. Yo u can do this by using a
functio n as the ke y argument o f the so rt. In this case, yo u use the Pytho n string type's lo wer-case metho d. In the
seco nd example, yo u request a descending so rt with the re ve rse keywo rd argument. Type these co mmands:

INTERACTIVE SESSION:

>>> t = ['Beta','beta','alpha','Alpha']
>>> sorted(t, key=str.lower)
['alpha', 'Alpha', 'Beta', 'beta']

When yo u use the lo we r() functio n o n o therwise identical strings like 'Beta' and 'beta', Pytho n treats
Note them as identical, keeping them in the same o rder they were input, so 'beta' might no t appear befo re
'Beta' when yo u try the abo ve example.

INTERACTIVE SESSION:

>>> t = ['Bete','beta','alphie','Alpha']
>>> sorted(t, key=str.lower)
['Alpha', 'alphie', 'beta', 'Bete']
>>> sorted(t, reverse=True)
['beta', 'alphie', 'Bete', 'Alpha']
sum(iterable)
sum (it e rable ) sums the numeric values in an iterable such as a list, tuple, o r set. sum (it e rable ) do es no t wo rk with
strings because yo u can't do math o n strings (when yo u add two strings yo u are really using an o peratio n called
concatenation). Type these co mmands:

INTERACTIVE SESSION:

>>> s = {1, 2, 3}
>>> sum(s)
6
>>> lst = ['Python','is','fun!']
>>> sum(lst)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

So we are able to add up numbers, but things break do wn o n letters and wo rds. To co mbine strings in a list, rely o n the
string jo in() metho d as sho wn belo w:

INTERACTIVE SESSION:

>>> lst = ['Python','is','fun!']


>>> ' '.join(lst)
'Python is fun!'

zip(*iterables)
The zip() functio n takes iterables and aggregates elements fro m each o f the iterables into a new iterable o bject. That
might so und co mplicated, but the example belo w will help illustrate the co ncept. Type these co mmands:

INTERACTIVE SESSION:

>>> lst_1 = ['Python','is','fun']


>>> lst_2 = [1000, 2000, 3000]
>>> lst_3 = [10, 9, 8, 7, 6, 5]
>>> list(zip(lst_1, lst_2))
[('Python', 1000), ('is', 2000), ('fun', 3000)]
>>> list(zip(lst_1, lst_2, lst_3))
[('Python', 1000, 10), ('is', 2000, 9), ('fun', 3000, 8)]

In the first result, we used the list () functio n to create a list o f three tuples. The seco nd example is no t so clear, as we
are missing the last two elements o f lst _3. That's because the zip functio n igno red iteratio ns fo r which it didn't have
elements in all o f the supplied iterables. This enables us to create dicts using the zip() functio n. Try it o ut:
INTERACTIVE SESSION:

>>> lst_1 = ['Python','is','fun']


>>> lst_3 = [10, 9, 8, 7, 6, 5]
>>> d = {}
>>> for k, v in zip(lst_1, lst_3):
... d[k] = v
...
>>> d
{'Python': 10, 'fun': 8, 'is': 9}
>>> zip((1, 2), (3, 4))
<zip object at 0x01AD1E18>

zip() returned a generato r called a "zip o bject."

Fun with Built-In Functions


Yo u've wo rked with lo ts o f different functio ns in this lesso n, and used them to get a real idea o f ho w they wo rk.

Keep yo ur interpreter windo w o pen to test yo ur understanding o f new functio ns as yo u co me into co ntact with them.
Experiment and try to find their limits. Use the he lp() functio n to learn mo re abo ut the built-in functio ns to o .

Yo u're lo o king go o d so far. Keep up the great wo rk!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Defining and Calling Your Own Functions
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

define and call yo ur o wn functio ns.


access the arguments using the names o f the parameters.
return a value that yo ur co de displays via the built-in print () functio n.
access arguments using the names o f the parameters.
use functio ns to handle namespaces.
create parameters that receive multiple arguments.

Exploring Functions
Hi and welco me to a new lesso n! We're mo ving right alo ng, huh? Let's keep it go ing. While wo rking thro ugh examples
so far in this co urse, yo u typed similar pieces o f co de o ver and o ver again. Take a lo o k at this snippet o f co de fro m o ur
earlier complex file handling example:

OBSERVE:

open_tasks = open('open_tasks.txt','r').readlines()
if open_tasks:
print('-' * 10)
print('Open Tasks')
print('-' * 10)
for i, task in enumerate(open_tasks):
print(i, task.strip())
done_tasks = open('done_tasks.txt','r').readlines()
print('-' * 10)
print('Done Tasks')
print('-' * 10)
for i, task in enumerate(done_tasks):
print(i, task.strip())

Yo u typed in almo st exactly the same co de twice. Wo uldn't it be nice if yo u co uld just write it o nce and then call it
whenever yo u needed it, like yo u've do ne with Pytho n's vario us built-in functio ns? Fo rtunately, yo u can! Lo o k at the
same co de, this time rewritten using a functio n:

OBSERVE:
def task_report(task_file):
tasks = open(task_file,'r').readlines()
if tasks:
print('-' * 10)
print(task_file.replace('_',' ').replace('.txt','').title())
print('-' * 10)
for i, task in enumerate(tasks):
print(i, task.strip())
task_report('open_tasks.txt')
task_report('done_tasks.txt')

The seco nd example defines a functio n t ask_re po rt . It executes the same task as the first example, but o perates by
calling the functio n twice. The differences between the two examples are in the file name and the heading that was
printed o ut. The file name is a formal parameter (t ask_f ile ) o f the functio n, and the heading is created by using
re place () to change the undersco re ('_') to a space (' ') and the extensio n ('.t xt ') to no thing ('') in the file name, and
then applying title case to the remainder with t it le (). (The net result? 'o pen_tasks.txt' beco mes 'Open Tasks' and
'do ne_tasks.txt' beco mes 'Do ne Tasks.')

By defining and using this functio n, we saved three who le lines o f co de. Impressed? No ?! Yo u sho uld be. But wait,
there's mo re!
No w, suppo se yo u need to add three mo re types o f task state to yo ur co de: "no t yet co nfirmed," "in testing," and
"under review." Witho ut o ur task_repo rt functio n, we wo uld have had to add 18 lines o f co de to acco mplish this task!
But using the functio n, we can pro cess each file with a single line, and get the jo b do ne with just three lines o f co de!
Take a lo o k at the example:

OBSERVE: Sample functio n co de


def task_report(task_file):
tasks = open(task_file,'r').readlines()
if tasks:
print('-' * 10)
print(task_file.replace('_',' ').replace('.txt','').title())
print('-' * 10)
for i, task in enumerate(tasks):
print(i, task.strip())
task_report('open_tasks.txt')
task_report('done_tasks.txt')
task_report('not_yet_confirmed.txt')
task_report('in_testing.txt')
task_report('under_review.txt')

Go o d Pytho n develo pers never repeat a stanza o f co de twice. Instead, we put it into a functio n, and call that functio n as
o ften as we need it. If yo u see lo ts o f repetitive co de, it generates that yucky code smell I mentio ned earlier. The co de
might wo rk, but changing it, maintaining it, and using it in o ther places will be harder than it needs to be and the co de
will be mo re pro ne to erro rs.

Write Your First Function


Let's take a sho t at writing a functio n. We'll write so me co de that averages a list o f values. In the edito r windo w, type the
co de as sho wn belo w:

CODE TO TYPE:

#!/usr/local/bin/python3
def average(lst):
""" Averages a list, tuple, or set of numeric values"""
return sum(lst) / len(lst)

tst_lst = [1, 2, 3, 4]
print('Average this list: {0}'.format(tst_lst))
print(average(tst_lst))
t = (243, 132, 987, 342, 13)
print('Average this tuple: ',t)
print(average(t))
s = {1, 2, 3, 4, 25}
print('Average this set: {0}'.format(s))
print(average(s))

Save it in yo ur /pyt ho n1 fo lder as ave rage .py, and run it:

INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./average.py
Average this list: [1, 2, 3, 4]
2.5
Average this tuple: (243, 132, 987, 342, 13)
343.4
Average this set: {25, 2, 3, 4, 1}
7.0

Ho w do es it wo rk?
OBSERVE:

#!/usr/local/bin/python3
def average(lst):
""" Averages a list, tuple, or set of numeric values"""
return sum(lst) / len(lst)

tst_lst = [1, 2, 3, 4]
print('Average this list: {0}'.format(tst_lst))
print(average(tst_lst))
t = (243, 132, 987, 342, 13)
print('Average this tuple: ',t)
print(average(t))
s = {1, 2, 3, 4, 25}
print('Average this set: {0}'.format(s))
print(average(s))

The functio n o ccupies o nly the first three lines o f co de in this example. The Pytho n keywo rd de f intro duces a functio n
definitio n. It must be fo llo wed by the f unct io n nam e and the list o f f o rm al param e t e rs in parentheses. The co de
that makes up the functio n is called the function body. The functio n bo dy must be indented. The string " " " Ave rage s a
list , t uple , o r se t o f num e ric value s" " " is the functio n's do cumentatio n string, o ften abbreviated as docstring. The
interpreter uses do cstrings to give pro grammers info rmatio n abo ut ho w the functio n wo rks and ho w it sho uld be
called. Finally, the last line tells the functio n to re t urn the sum () o f the values entered, divided by the number o f values
as determined by the le n() functio n. This returned value beco mes the value o f the functio n call during evaluatio n o f
expressio ns.

Our functio n is fo llo wed by test co de that lets us verify that the functio n wo rks co rrectly. Each time the ave rage ()
functio n is written with a list o f numbers in it, such as ave rage (t st _lst ) o r even ave rage ([10 ,20 ,30 ,4 0 ,5 0 ]), o ur
functio n co de is run with tho se numbers as fo rmal parameters.

In the average.py example, we used the name lst fo r o ur parameter. It co uld have any name, but fo r the sake o f clarity,
use a name that makes the purpo se o f the variable clear. Also , be careful no t to use names o f existing Pytho n
functio ns o r o ther o bjects. Yo u do n't want to use list o r t uple as variable o r parameter names, fo r example, because
they are the names o f Pytho n built-in functio ns. If yo u do , yo ur pro gram may behave in co mpletely inco mprehensible
ways.

Parameters and Arguments


Parameters are the names yo u give to the inputs to the functio n when the functio n is defined. Arguments are the values
yo u pro vide when yo u call the functio n. Inside the functio n bo dy, yo ur co de can access the arguments using the names
o f the parameters.

Suppo se yo u want to write a functio n that prints o ut the elements in a list, and yo u want to pro vide an o ptio n to have
the functio n print the list in reverse o rder. To do this, yo u'll use positional and keyword parameters. Type the co de as
sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
def print_list(lst, rev=False):
""" prints the contents of a list. """
if rev:
lst = reversed(lst)
for i in lst:
print(i)

print_list(['Printing', 'a', 'list'])


print()
print_list(['Printing', 'a', 'reversed', 'list'], True)
print()
print_list(lst=['A', 'list', 'with', 'specified', 'arguments'],rev=False)

Save it in yo ur /pyt ho n1 fo lder as print _list .py, and run it. This functio n takes two parameters. Yo u're familiar with
the first parameter, lst ; the seco nd parameter, re v=False , intro duces a new feature—a keywo rd parameter, which has
a default value (the value fo llo wing the equals sign, which in this case is False ). If yo u call the functio n witho ut passing
an argument co rrespo nding to the re v parameter, it uses that default value.
The functio n's co de lo o ks at the value o f re v, and if it is true, it re-binds the parameter to a reversed co py o f the list. It
do es this rather than reversing the list in place, because such a reversal wo uld affect co de o utside o f the functio n
(tho ugh there's no thing illegal abo ut changing a mutable o bject inside o f a functio n, yo u want to make sure that the
users o f the functio n kno w they sho uld expect such changes. We'll go o ver parameters and arguments in greater detail
in future lesso ns).

Returning Values
The first functio n yo u wro te in this lesso n, ave rage (), returned a value that yo ur co de then displayed via the built-in
print () functio n. When a functio n call is written in an expressio n (fo r example, in print (ave rage (t st _lst ))), the value
o f the functio n call in that expressio n is actually the value that the functio n returned in its re t urn statement (2.5). But the
seco nd functio n yo u created, print _list (), did no t include a re t urn statement. This is equivalent to the functio n ending
with re t urn No ne . So all functio ns will return so me value, but by co nventio n, functio ns that do n't need to return
anything can implicitly return No ne . If the functio n isn't intended to return a value, it's co nfusing to add an explicit
re t urn statement.

Yo u can either use the functio n calls in co ntro l flo w co de (that is, co de that co ntro ls the o rder in which tasks are
executed, such as if o r while statements) o r save the values returned by functio ns, binding them to a variable in an
assignment statement and using that value again and again witho ut needing to rerun the functio n. To see these
principles in actio n, create a new file as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
def structure_list(text):
"""Returns a list of punctuation in a text"""
punctuation_marks = "!?.,:;"
punctuation = []
for mark in punctuation_marks:
if mark in text:
punctuation.append(mark)
return punctuation

text_block = """\
Python is used everywhere nowadays.
Major users include Google, Yahoo!, CERN and NASA (a team of 40 scientists and engineer
s
is using Python to test the systems supporting the Mars Space Lander project).
ITA, the company that produces the route search engine used by Orbitz, CheapTickets,
travel agents and many international and national airlines, uses Python extensively.
The YouTube video presentation system uses Python almost exclusively, despite their
application requiring high network bandwidth and responsiveness.
This snippet of text taken from chapter 1"""

for line in text_block.splitlines():


print(line)
p = structure_list(line)
if p:
print("Contains:", p)
else:
print("No punctuation in this line of text")
if ',' in p:
print("This line contains a comma")
print('-'*80)

Save it in yo ur /pyt ho n1 fo lder as re t urn_value .py, and run it. The st ruct ure _list () functio n accepts a single
parameter called text. This value is checked to find co mmo n punctuatio n marks. These results are placed into a list and
that list is returned.

The tricky part is the lo o p itself and what it do es with the returned value o f st ruct ure _list (). Instead o f immediately
printing the value, we save it to the variable p. This variable is subsequently used in two different if statements. The first
checks to see if the list p is empty, then prints an appro priate result. Then the variable is used again to determine
whether o r no t a co mma is present.

Multiple Return Values


So , what if yo u need to return two values? Suppo se that, in additio n to the punctuatio n in o ur last example, yo u also
want to return the lo catio n o f the wo rd "Pytho n." Yo u co uld write a seco nd functio n, but it's o ften mo re efficient when
the two results require related lo gic in o rder to have yo ur functio n return ano ther value. Try o ut the example belo w and
get a better lo o k at this co ncept:

CODE TO TYPE:

#!/usr/local/bin/python3
def structure_list(text):
"""Returns a list of punctuation and the location of the word 'Python' in a text"""
punctuation_marks = "!?.,:;"
punctuation = []
for mark in punctuation_marks:
if mark in text:
punctuation.append(mark)
return punctuation, text.find('Python')

text_block = """\
Python is used everywhere nowadays.
Major users include Google, Yahoo!, CERN and NASA (a team of 40 scientists and engineer
s
is using Python to test the systems supporting the Mars Space Lander project).
ITA, the company that produces the route search engine used by Orbitz, CheapTickets,
travel agents and many international and national airlines, uses Python extensively.
The YouTube video presentation system uses Python almost exclusively, despite their
application requiring high network bandwidth and responsiveness.
This snippet of text taken from chapter 1"""

for line in text_block.splitlines():


print(line)
p, l = structure_list(line)
if p:
print("Contains:", p)
else:
print("No punctuation in this line of text")
if ',' in p:
print("This line contains a comma")
if l >= 0:
print("Python is first used at {0}".format(l))
print('-'*80)

Save and run it. We mo dified the functio n to return a two -element tuple. The first element is the punctuatio n as
co mputed in the previo us versio n. The seco nd element is the lo catio n o f the wo rd "Pytho n." If the wo rd do esn't exist in
the text, -1 is returned, as determined by the f ind() metho d's specificatio n.

The functio n result is assigned to two separate variables using an unpacking assignment, and an additio nal test is
made o n the returned index value to determine whether to repo rt the presence o f the wo rd "Pytho n."

Functions and Namespaces


Using functio ns in Pytho n has the added benefit o f helping us begin to understand namespaces.

When yo u call a functio n, Pytho n dynamically creates a new namespace and binds the argument values to the
appro priate parameter names. Assignments made during executio n o f the functio n call result in bindings in the functio n
call namespace. When the functio n returns, the namespace is auto matically destro yed, and any bindings inside the
namespace are lo st.

Yo u can sum up ho w functio ns handle namespaces in Pytho n by understanding these two rules:

1. Variables bo und within a Pytho n functio n bo dy o nly exist in namespaces created by calls o f that functio n.
2. Variables bo und in the glo bal namespace can be accessed by functio ns, but may no t be bo und unless
specifically declared to be glo bal.

Let's test o ut the first rule. As yo u will see, the variable c defined belo w is assigned inside o f the t e st () functio n. Start
an interactive sessio n and enter the co mmands sho wn:
INTERACTIVE SESSION:

>>> def test(a, b):


... c = a + b
... return c
...
>>> test(1, 2)
3
>>> c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'c' is not defined

And no w let's test the seco nd rule. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> def test_a():


... print(a)
...
>>> test_a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test_a
NameError: global name 'a' is not defined
>>> a = "Python"
>>> test_a()
Python

Yo u can see that when the functio n attempts to access a glo bal variable a, the functio n fails in its first call, because a
has no t yet been created in the glo bal enviro nment. The interpreter kno ws that a is no t lo cal to the functio n because the
functio n bo dy co ntains no assignment to it. Once the variable is created by an assignment in the mo dule namespace,
a call to the functio n succeeds witho ut raising an exceptio n.

So , if any assignment is made to a variable inside a functio n bo dy, the variable is lo cal to the functio n. Changing a
glo bal variable inside a functio n bo dy isn't a best practice, but so metimes it's a necessary evil. To achieve that end,
yo u use a glo bal statement to declare that the variable, altho ugh assigned inside o f the functio n bo dy, is in the
mo dule (glo bal) sco pe. To demo nstrate this, type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> def test_a():


... global a
... a = "XML"
... print(a)
...
>>> a = "Python"
>>> test_a()
XML
>>> print(a)
XML

Here the value " Pyt ho n" is bo und to a in mo dule sco pe. After the functio n is called, yo u can see that a has been re-
bo und by the assignment inside o f the functio n.

Parameters That Receive Multiple Arguments


So metimes when yo u create a Pytho n functio n, yo u do n't kno w ho w many arguments yo u are go ing to get and yo u
want the caller to be able to pro vide any number o f arguments. Fo r example, yo u may want to create a functio n that
takes all the numbers given as parameters and multiply them to gether. To do this, we use a special parameter
specificatio n, *nam e . There can be o nly o ne such parameter, and it must fo llo w any standard po sitio nal and/o r
keywo rd parameters.

When yo u prefix the parameter with the asterisk (*) character in the functio n definitio n, this tells the interpreter to co llect
any unmatched po sitio nal arguments into a tuple and then bind the tuple to the name fo llo wing the asterisk in the
called functio n's namespace. Inside o f yo ur functio n, this tuple can be used like any o ther Pytho n iterable. Let's check it
o ut. Create a new file in the edito r windo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
def multiplier(*args):
""" Multiply the arguments together and return the result.
Return 0 if nothing is provided.
"""
if not args:
return 0
product = args[0]
for a in args[1:]:
product *= a
return product

print(multiplier())
print(multiplier(1,2,3,4))
print(multiplier(6,7,8,9,10,11,12,13))
print(multiplier(10,20,100))

Save it in yo ur /pyt ho n1 fo lder as argum e nt _list .py, and run it. The m ult iplie r() functio n, o ur single parameter
args (which yo u can think o f as the "sequence parameter") is prefixed with *, so all po sitio nal arguments to a call will
appear inside o f this tuple. The rest o f the functio n is made up o f familiar co de (if anything is unfamiliar, ask yo ur
instructo r fo r a little help). We can call the functio n with any number o f arguments.

The * sequence parameter must fo llo w any standard po sitio nal o r keywo rd parameters. This can be useful when
regular arguments are also required. Fo r instance, yo u may want to pro vide an o ptio nal amo unt to be added to the
pro duct. Yo u'd acco mplish that by using a keywo rd argument with a default value o f zero . Let's see ho w this is do ne.
Mo dify the pro gram as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
def multiplier(total=0.0, *args):
""" Multiply the arguments together, add a prior total, and return the result.
Return 0 if nothing is provided.
"""
if not args:
return total
product = args[0]
for a in args[1:]:
product *= a
print("product:", product)
return product + total

print(multiplier())
print(multiplier(1,2,3,4))
print(multiplier(6,7,8,9,10,11,12,13))
print(multiplier(10,20,100))

Save and run it. The first parameter o f each set is no w passed as the t o t al, and the rest as args.

Putting It All Together


When yo u were in grade scho o l, yo u learned that six times seven (6 x 7) was equivalent to adding six to itself seven
times (6 + 6 + 6 + 6 + 6 + 6 + 6 ). Calculating this the lo ng way to o k time, so yo u memo rized the end result. If yo u
learned yo ur "times tables" at scho o l, yo u can pro bably still respo nd immediately, even no w, when asked "what is six
times seven?" Sto ring so mething in memo ry to save the tro uble o f wo rking it o ut each time yo u need the answer is
called caching.
Caching is taking calculated values fro m arguments and sto ring them so that yo u can return the values if asked to
co mpute a result fro m the same arguments again later. This way, instead o f calculating the same thing a hundred
times, yo u save each calculatio n the first time yo u make it, and recall it when needed. When applied to a functio n, this
caching technique is o ften referred to as memoization.

To illustrate, we will use the built-in input () metho d to pro mpt fo r two numeric values. The co de do es multiplicatio n
the o ld way (6 + 6 + 6 + 6 + 6 + 6 + 6 ). Finally, we'll use the ability o f functio ns to use the glo bal namespace to cache
the results, so when yo u try it with big numbers (10 millio n * 10 millio n), yo u do n't need to repeat lengthy calculatio ns.

In the co de example belo w, we create a kid() functio n to do the math. Rather than intro duce so me ho rrendo usly
co mplicated functio n that wo uld be difficult to understand, we'll use a mo re manageable functio n. kid() do es
multiplicatio n the hard way! Create a new file in the edito r windo w and type the co de sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
""" Demonstrates the need for caching """

def kid(a, b):


""" Multiplication the hard way """
c = 0
for i in range(b):
c += a
return c

while True:
a = input('enter a number: ')
b = input('enter another number: ')
a = int(a)
b = int(b)
print(kid(a,b))

Save it in yo ur /pyt ho n1 fo lder as caching.py, and run it. Try it with small numbers first, perhaps 4 and 5. Then try
so mething large like 5 and 10 0 0 0 0 0 0 (o ne and seven zero s). Yo u'll have to wait awhile as the co mputer adds 5 ten
millio n times. That crazy kid takes fo rever to do basic math!

No w, mo dify yo ur kid() functio n so that it maintains a reco rd o f the arguments it has been called with, and saves
previo usly-co mputed results in a glo bal dict so that befo re it even starts to perfo rm a calculatio n, it can pro vide a
previo usly-co mputed result, thereby saving time. Edit the co de belo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
""" Demonstrates the need for caching """

global_cache = {}

def kid(a, b):


""" Multiplication the hard way """
if (a, b) in global_cache:
return global_cache[(a, b)]

c = 0
for i in range(b):
c += a
global_cache[(a, b)] = c
return c

while True:
a = input('enter a number: ')
b = input('enter another number: ')
a = int(a)
b = int(b)
print(kid(a,b))
print(global_cache)
print('-'*40)
No w try the pro gram again. Enter 5 * 10 0 0 0 0 0 0 . Wait a few seco nds fo r the respo nse and try it again. Yo u'll no tice the
seco nd time it returns almo st instantly.

Here, when the functio n is called, it immediately checks the glo bal glo bal_cache dict to see whether this particular set
o f arguments has been used befo re. If it has, the cached result is immediately returned, bypassing the lengthy
co mputatio n. If the argument set isn't fo und in glo bal_cache , then it is co mputed in the usual way, but befo re the
result is returned, it is added to the glo bal_cache so this new result can be pro duced immediately if we ever need it
again.

A Solid Foundation
In this lesso n, yo u started to learn ho w to write functio ns, understand the difference between parameters and
arguments, ho w return values wo rk, and a little mo re abo ut namespaces. I'm really impressed with yo ur pro gress so
far! No w that yo u have a pretty go o d grip o n Pytho n basics, let's mo ve o n and learn abo ut mo dules and impo rts, and
even mo re abo ut namespacing.

See yo u in the next lesso n!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
The Python Standard Library
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

emplo y the principle of modularity.


co nstruct many independent namespaces and handle them separately.
impo rt Pytho n mo dules.
lo cate mo dules.

Increased Versatility
Let's get to wo rk and discuss a key co ncept in pro gramming, the principle of modularity. The idea behind it is that
unrelated parts o f a system sho uld be kept separate fro m each o ther, and related parts sho uld be gro uped to gether.

Pytho n co mes with a large set o f library mo dules and packages (we'll talk mo re abo ut packages in a later co urse—
they're like mo dules, but with a bit mo re structure). It's well wo rth learning abo ut the standard library because it
co ntains mo dules that can save yo u time and effo rt, and also allo w yo u to do so me really co o l stuff with Pytho n.

Let's try a few experiments using the standard library. First we'll figure o ut ho w to impo rt a Pytho n library mo dule. Type
the co mmands sho wn belo w in an interactive sessio n:

INTERACTIVE SESSION:

cold1:~$ python3
>>> import textwrap
>>> textwrap.wrap("This is a very long piece of text. This should appear as shorter lin
es.", 12)
['This is a', 'very long', 'piece of', 'text. This', 'should', 'appear as', 'shorter',
'lines']
>>> import time
>>> time.time()
1327529513.914024
>>> time.gmtime()
time.struct_time(tm_year=2012, tm_mon=1, tm_mday=25, tm_hour=22, tm_min=12, tm_sec=7, t
m_wday=2, tm_yday=25, tm_isdst=0)
>>> time.asctime(time.gmtime())
'Wed Jan 25 22:13:04 2012'
>>> import base64
>>> base64.encodestring(b"This is a byte string")
__main__:1: DeprecationWarning: encodestring() is a deprecated alias, use encodebytes()
b'VGhpcyBpcyBhIGJ5dGUgc3RyaW5n\n'
>>> s = base64.encodebytes(b"This is a byte string")
>>> base64.decodestring(s)
__main__:1: DeprecationWarning: decodestring() is a deprecated alias, use decodebytes()
b'This is a byte string'
>>> base64.decodebytes(s)
b'This is a byte string'

Here yo u made use o f functio nality fro m three standard library mo dules—textwrap, time, and base6 4. We have linked
the name o f each mo dule to the appro priate sectio n o f Pytho n's standard library do cumentatio n. Yo u get access to the
reso urces o f a mo dule by qualifying the mo dule's name with the name o f the appro priate reso urce. So "a.b" means
"lo o k in a's namespace and return what is bo und to the name b there."

The Deprecatio nWarning message is in o ur co de to remind tho se pro grammers using earlier versio ns o f Pytho n that
o ur strings are no w Unico de. In o lder versio ns, strings were by default made up o f ASCII (8 -bit) characters. In Pytho n 3,
the base 6 4 .e nco de st ring() functio n has been renamed base 6 4 .e nco de byt e s(). The o ld name is still available,
but no t fo r lo ng, so a message is printed to alert pro grammers to use the newer name.
Namespaces
Earlier, we discussed Pytho n's object space, the lo catio n where data o bjects like integers and strings are sto red. We
also learned that when yo u run a pro gram, the interpreter creates a namespace. Within namespace, values in object
space are bo und to names by assignment statements, functio n definitio ns, and such.

A Pytho n pro gram has a "glo bal" namespace, where names are bo und by assignments and functio n definitio ns within
the main bo dy o f the pro gram. When yo u call a functio n, Pytho n dynamically creates a new namespace and binds the
argument values to the parameter names. Assignments made during executio n o f the functio n call (no rmally) result in
bindings in the functio n call ("lo cal") namespace. When the functio n returns, the namespace is auto matically
destro yed, and any bindings inside the namespace are lo st. On o ccasio n, this means that so me o f the values will no
lo nger have references. When that happens, the memo ry used to sto re tho se values beco mes reclaimable as
garbage. (Do n't wo rry if yo u do n't have a grip o n all o f this stuff just yet. It'll make mo re sense when we get to the
experimentatio n!)

When we write large pro grams "mo no lithically" (as who le chunks), we may inadvertently use the same name fo r two
different purpo ses at different places in the pro gram. We can avo id that pro blem by inco rpo rating the principle o f
mo dularity into o ur wo rk; we'll write pro grams as co llectio ns o f small chunks that are relatively independent o f o ne
ano ther. This will also make o ur pro grams easier to read and understand.

With Pytho n, we are able to co nstruct many independent namespaces and handle them separately. The same name
can be defined in two different namespaces, because the uses do n't co llide. When the interpreter lo o ks fo r the value
bo und to a particular name, it lo o ks in three specific namespaces. First, it lo o ks in the lo cal namespace (assuming a
functio n call is active). Next, it lo o ks in the glo bal namespace. Finally, it lo o ks in the "built-in" namespace, which ho lds
the names o f o bjects that are hard-wired into the Pytho n interpreter, like exceptio ns and built-in functio ns.

Python Modules
A mo dule is a co llectio n o f statements that are executed. Every pro gram yo u have written so far in this co urse is a
Pytho n mo dule. Yo u wro te them as stand-alo ne pro grams. When yo u run a mo dule as a pro gram, the interpreter
terminates after all o f the co de has been executed. Running the pro gram is o ne way to cause its co de to be executed.
Ano ther way is to import it. When yo u write im po rt m o dx in yo ur pro gram, the interpreter lo o ks fo r the m o dx.py file. It
also lo o ks fo r its co mpiled versio n: m o dx.pyc. If m o dx.pyc is up to date, it will save the interpreter the wo rk o f
co mpiling it.

If the file is no t fo und, an ImportError exceptio n is raised. Otherwise, the interpreter executes the co de in the mo dule,
and binds the mo dule's namespace to the name o f the mo dule in the current namespace. So , if m o dx defines a
functio n f (), after yo u have impo rted the mo dule, yo u can call that functio n with m o dx.f ()—the do t o perato r tells the
interpreter to lo o k up the name f in the namespace bo und to the name m o dx.

Suppo se mo dule z defines functio n g(), mo dule y impo rts mo dule z, and yo ur pro gram impo rts mo dule y. Yo u co uld
call the functio n as y.z.g(). The interpreter wo uld lo o k up y in the lo cal namespace, retrieving the namespace o f
mo dule y. Then it wo uld lo o k up z in that namespace, retrieve the namespace o f mo dule z, and in that namespace
lo o k up the name g and retrieve the functio n.

Okay, I think we've go t eno ugh to think abo ut. Let's get busy with so me practical applicatio n! We'll create a pro gram
called im po rt e r.py that impo rts a mo dule called m o da, that in turn impo rts a mo dule called m o db. The pro gram is
go ing to call a functio n defined in m o db. Create the m o da.py, m o db.py, and im po rt e r.py pro grams, respectively,
as sho wn, in yo ur /pyt ho n1 fo lder:

CODE TO TYPE:

"""moda.py: Imports modb to gain indirect access to the triple function."""

import modb

CODE TO TYPE:

"""modb.py: Defines a function that can be used by importing the module."""

def triple(x):
"""Simple function returns its argument times 3."""
return x*3
CODE TO TYPE:
#!/usr/local/bin/python3
"""importer.py: imports moda and calls a function from a module moda imports."""

import moda
print(moda.modb.triple("Yippee! "))

Save them all, and run the im po rt e r.py pro gram. When it runs, it impo rts mo dule mo da. This binds the mo da
mo dule's namespace to the name m o da in the pro gram's (glo bal) namespace. When mo dule mo da is impo rted, its
co de is executed. This causes mo dule mo db to be impo rted, binding it to the name m o db o n mo dule mo da's
namespace. When mo db is impo rted by mo da, its co de is executed, and the de f statement binds the name t riple to
the functio n definitio n in mo db's namespace.

No w when the interpreter sees the statement print (m o da.m o db.t riple (" Yippe e ! " )), it lo o ks up the name m o da in
the glo bal namespace, then lo o ks up the name m o db in that namespace, and finally lo o ks up the name t riple in that
namespace. This final lo o kup returns a reference to the triple functio n, which is then called with the argument "Yippee! "
and yo ur pro gram will print "Yippee! Yippee! Yippee! ".

The namespace labeled "GLOBAL NAMESPACE" is actually the glo bal namespace o f the im po rt e r mo dule run as
the main pro gram. This diagram sho ws the relatio nship between the namespaces o f the vario us mo dules:

Writing Modules to be Testable


In later co urses we will talk abo ut testing co de. But even befo re we start using the unittest mo dule, we can start writing
impo rtable mo dules to do so me basic testing.

When a mo dule is impo rted by a pro gram, the interpreter binds the special name __nam e __ in the mo dule's
namespace to its name. When a mo dule is run as a pro gram, __nam e __ receives a special value "__main__". Yo u
can assume that yo ur mo dule will be impo rted, but if it gets run as a pro gram (that is, if __name__ == "__main__"),
then the user isn't trying to use it, but instead wants to test it.
So me standard library mo dules have a sectio n at the end that co ntains the statement:

if __nam e __ == " __m ain__"

The co de that fo llo ws that statement is there to test the mo dule's functio nality.

We'll write co de like that to test o ur functio ns as well, and make it easier to verify that they wo rk as intended. The mo re
yo u do to make yo ur mo dules self-testing, the easier it is to detect when a small change has bro ken the co de.

Splitting Up Your Programs


So far almo st all o f o ur pro grams have been made up o f single pro gram files. As the pro grams get mo re co mplex,
we'll build them as co llectio ns o f co mpo nents. A co mpo nent yo u build fo r o ne pro gram might be useful in ano ther.
Yo u co uld just copy the co mpo nent's co de, but then if yo u needed to mo dify it, yo u'd have to mo dify each co py
separately. This makes extra wo rk fo r yo u and increases the chance o f erro rs.

Fo rtunately, Pytho n lets yo u write yo ur co de as a co llectio n o f modules, each o f which is a separate text file. This
makes it easier to use yo ur co de in vario us co ntexts.

Let's take a pro gram that uses functio ns and split it into two pieces. Create this pro gram in the edito r windo w:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Contains functions to manipulate number representations."""
def commafy(val):
if len(val) < 4:
return val
out = []
while val:
out.append(val[-3:])
val = val[:-3]
return ",".join(reversed(out))

def commareal(val):
if "." in val:
before, after = val.split(".", 1)
else:
before, after = val, "0"
return "{0}.{1}".format(commafy(before), after)

# Testing code only ...


if __name__ == "__main__":
for i in [0, 1, 12, 123, 1234, 12345, 123456,
1234567, 12345678, 123456789, 1234567890]:
print(i, ":", commafy(str(i)), ":", commareal("{0:.2f}".format(i/1000)))

Save it in yo ur /pyt ho n1 fo lder as f uncs.py and run it.

The first mo dule defines the required functio ns. The seco nd pro duces results by calling o ne o f the functio ns. It gains
access to the functio n it needs by impo rting the mo dule that defines it.

The co m m af y functio n takes a who le number (which is assumed to be a string co mprising all digits) and, beginning
fro m the right, splits it into chunks o f three digits. The value string is sho rtened to remo ve each chunk after it is added to
the o ut list. Any chunk o f less than three digits that remains at the end will be captured auto matically by slicing. When
no digits remain, the o ut list is reversed to put the chunks in the co rrect o rder, and the chunks are jo ined to gether with
co mmas to pro vide the functio n's return value.

The co m m are al() functio n takes a string representatio n o f a real number o r integer. If the string co ntains a decimal
po int, it is split aro und that. If there is no decimal po int, a single "0 " is used. The co m m af y() functio n is used to insert
co mmas into the po rtio n befo re the decimal po int, and the o utput string is co nstructed fro m the "co mmafied" po rtio n
befo re the decimal po int and the unchanged po rtio n after the decimal po int.

Altho ugh this mo dule is designed to be impo rted by o ther pro grams, it will test itself if it's run as a main pro gram. It
iterates o ver a set o f integers, printing o ut the number, its "co mmafied" versio n, and the co m m are al() value o f the
number divided by 1,0 0 0 and represented to two decimal places. When the mo dule is impo rted, the co nditio n if
__nam e __ == " __m ain__" is false, so the testing co de do es no t execute.
No w, create this pro gram:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Take user input, convert to float, and print
out the number to two decimal places, with commas."""
import funcs

while True:
inval = input("Enter a number: ")
if not inval:
break
number = float(inval)
print(funcs.commareal("{0:.2f}".format(number)))

Save it in yo ur /pyt ho n1 fo lder as f uncalls.py and run it. This pro gram perfo rms an infinite lo o p, terminated fro m
within when the user presses Ent e r witho ut typing a number in respo nse to the "Enter a number" pro mpt. Otherwise,
the user's input is co nverted to a flo ating-po int number, and is fo rmatted back into a string representatio n with two
decimal places. The result o f the co m m are al() functio n is printed back to the user (via f uncs.py) befo re the lo o p
repeats.

Other Ways to Import a Module


The im po rt statement has so me useful variatio ns that can alter the way impo rted items are made available in the
impo rting namespace.

import ... as
What if yo u need to impo rt a mo dule, but yo u've already used its name in yo ur co de? Yo u can avo id rewriting
yo ur co de using the im po rt ... as syntax, which allo ws yo u to impo rt a mo dule using a name o f yo ur cho ice
rather than its natural name. So , if yo u write im po rt t im e as t , the mo dule is impo rted in the standard way,
but rather than being bo und to its standard name in the impo rting namespace, the mo dule namespace is
bo und to the name t . No w yo u can write a call o n the asct im e () functio n in the mo dule as t .asct im e (), and
co ntinue to use the name "time" fo r o ther purpo ses.

The t im e namespace is no w called t in the __m ain__ namespace:

from ... import ...


So metimes yo u'll just want to bring the names fro m a mo dule into the impo rting namespace so they can be
used directly rather than qualifying the mo dule name. Do this sparingly tho ugh, because o nce yo u've do ne
this, it beco mes mo re difficult to lo cate vario us reso urces in the pro gram.

An alternative way to handle situatio ns where the name "time" is already in use, is to impo rt the "asctime"
name into the current namespace directly with f ro m t im e im po rt asct im e , and write the calls o n the
functio n as asct im e (). Because the __m ain__ namespace co ntains no direct reference to the t im e mo dule,
o ther names in t im e 's namespace are no t available to the __m ain__ mo dule. The name asct im e is co pied
fro m the t im e mo dule's namespace to the __m ain__ namespace:

Under mo st circumstances, yo u do no t want to use f ro m ... im po rt ... to impo rt all names defined in a
mo dule using the statement f ro m m o dule im po rt *. While this may seem like a great way to define the
necessary symbo ls, it puts the impo rted mo dule in charge o f what gets lo aded into yo ur namespace. Unless
yo u are really familiar with the impo rted mo dule's co de, yo u'll have no way o f kno wing whether it defined
symbo ls that yo u're already using. If it did define them, they will o verwrite yo ur definitio ns o r yo ur symbo ls will
o verwrite the definitio n fro m the mo dules. Either way, yo u'll receive no no tificatio n that this has happened, and
yo u will be left with a tricky debugging exercise.

Certain well-written and so phisticated library mo dules (such as the Tkinter graphical user interface library)
reco mmend this fo rm o f impo rt. Do no t try to emulate this in yo ur o wn designs—it is an invitatio n to disaster!

The System Path


Ho w do es the interpreter kno w where to find mo dules? It lo o ks fo r mo dule m o dnam e by searching in a specific list o f
directo ries fo r a file called m o dnam e .py.

Let's lo o k at the system path. It is defined, appro priately eno ugh, in a mo dule called sys. Yo u have to impo rt it befo re
yo u can examine it. To see what's o n the path, type the fo llo wing co mmands in an interactive sessio n:

INTERACTIVE SESSION:

>>> import sys


>>> for p in sys.path:
... print(p)
...

/usr/local/python34/lib/python34.zip
/usr/local/python34/lib/python3.4
/usr/local/python34/lib/python3.4/plat-linux
/usr/local/python34/lib/python3.4/lib-dynload
/usr/local/python34/lib/python3.4/site-packages
>>>

When the interpreter lo o ks fo r a mo dule, it searches these paths, starting at the to p o f the list, and sto pping when it
finds the mo dule. This path can be useful to kno w if yo u have a pro gram that do esn't seem to be finding the mo dule
yo u wanted it to find.

Reduce, Reuse, Recycle!


Yo u're picking this stuff up like a pro ! Yo u've learned ho w yo ur pro grams can make use o f external functio nality, and
ho w yo u can split yo ur o wn pro grams up to make them mo re mo dular. This will make them easier to manage, help
yo u to write co de that can be used in lo ts o f different pro grams, and make yo u an efficient pro grammer! Yo u'll reduce
yo ur wo rk by reusing and recycling yo ur co de. In the next lesso n, we'll revisit functio ns and learn abo ut even mo re
features. See yo u there!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
More About Functions
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

capture keyword arguments who se names do no t co rrespo nd to the name o f any parameter.
specify keywo rd parameters in a functio n that has a dict-parameter.
impo rt functio ns and help().
execute functio ns by dispatch.

No w that yo u've go t the basics o f functio ns do wn, we'll build o n that kno wledge with keywo rd parameters, switches, impo rting
functio ns, and mo re!

Arbitrary Keyword Parameters


We learned earlier that when an unkno wn number o f po sitio nal arguments will be pro vided, yo u can capture the extra
o nes (that do n't co rrespo nd to any o f the fo rmal parameters) by specifying a parameter name that is preceded by a
single asterisk (*). In much the same way, yo u can capture keyword arguments who se names do no t co rrespo nd to the
name o f any parameter. To do that, we'll prefix the last defined parameter with two asterisks, and call a dict-parameter.
Create a new pro gram in the edito r windo w as sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
""" Demonstrates capture of keyword arguments"""

def keywords(**kwargs):
"Prints the keys and arguments passed through"
for key in kwargs:
print("{0}: {1} ".format(key, kwargs[key]))

def keywords_as_dict(**kwargs):
"Returns the keyword arguments as a dict"
return kwargs

if __name__ == "__main__":
keywords(guido="Founder of Python", python="Used by NASA and Google")
print(keywords_as_dict(guido="Founder of Python", python="Used by NASA and Google")
)

Save it in yo ur /pyt ho n1 fo lder as ke ywo rd_args.py, and run it. Yo u o utput lo o ks like this:

OBSERVE:

python: Used by NASA and Google


guido: Founder of Python
{'python': 'Used by NASA and Google', 'guido': 'Founder of Python'}

The pro gram has two functio ns that capture general keywo rd arguments. When yo u call such a functio n, the interpreter
matches up the po sitio nal and keywo rd arguments with their co rrespo nding parameters, then takes any unmatched
keywo rd arguments and puts them into a dict, which it binds to the dict-parameter. The first functio n, ke ywo rds(),
iterates o ver the keys o f the dict, printing the keys (which are the names o f the unmatched keywo rd arguments) and the
asso ciated values (which are the values fo llo wing the equals signs). The seco nd functio n, ke ywo rds_as_dict (), just
returns the keywo rd arguments, demo nstrating that the dict-parameter is in fact a dict.

Parameters, Sequence-Parameters, and Dict-Parameters


So metimes yo u need to mix different argument-passing metho ds. In an earlier lesso n, yo u learned ho w to include
specific po sitio nal parameters in a functio n that also uses a sequence-parameter. Yo u can also specify keywo rd
parameters in a functio n that has a dict-parameter.
Suppo se yo u want a functio n that prints the descriptio n o f a co llege co urse including a name that is a standard
po sitio nal parameter, an instructo r, any number o f students, and po ssibly o ther staff with assigned ro les. To do this in
Pytho n, yo u co mbine multiple types o f parameters. Yo u'll use po sitio nal parameters, as well as a sequence-
parameter and a dict-parameter. Let's give it a try in a pro gram. Type the co de belo w as sho wn:

CODE TO TYPE:
#!/usr/local/bin/python3
def description(name, instructor, *students, **staff):
"""Print out a course description.
name: Name of the course
instructor: Name of the instructor
*students, ...: List of student names (positional arguments)
**staff, ...: List of additional staff (keyword arguments)
"""
print("=" * 40)
print("Course Name:", name)
print("Instructor:", instructor)
print("-" * 40)
for title, name in staff.items():
print(title.capitalize(), ": ", name)
print("{0:-^40}".format(" registered students "))
for student in students:
print(student)

if __name__ == "__main__":
description("Python 101",
"Steve Holden",
"Georgie Peorgie",
"Mary Lamb",
"Penny Rice",
publisher="O'Reilly School of Technology",
author="Python Software Foundation"
)
description("Django 101",
"Jacob Kaplan-Moss",
"Baa-Baa Blacksheep",
"Mary Contrary",
"Missy Muffet",
"Peter Piper",
publisher="O'Reilly School of Technology",
author="Django Software Foundation",
editor="Daniel Greenfeld"
)

Save it in yo ur /pyt ho n1 fo lder as co urse s.py, and run it:


INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./courses.py
========================================
Course Name: Python 101
Instructor: Steve Holden
----------------------------------------
Publisher : O'Reilly School of Technology
Author : Python Software Foundation
--------- registered students ----------
Georgie Peorgie
Mary Lamb
Penny Rice
========================================
Course Name: Django 101
Instructor: Jacob Kaplan-Moss
----------------------------------------
Publisher : O'Reilly School of Technology
Editor : Daniel Greenfeld
Author : Django Software Foundation
--------- registered students ----------
Baa-Baa Blacksheep
Mary Contrary
Missy Muffet
Peter Piper

Let's take a clo ser lo o k:


OBSERVE:
#!/usr/local/bin/python3
def description(name, instructor, *students, **staff):
"""Print out a course description.
name: Name of the course
instructor: Name of the instructor
*students, ...: List of student names (positional arguments)
**staff, ...: List of additional staff (keyword arguments)
"""
print("=" * 40)
print("Course Name:", name)
print("Instructor:", instructor)
print("-" * 40)
for title, name in staff.items():
print(title.capitalize(), ": ", name)
print("{0:-^40}".format(" registered students "))
for student in students:
print(student)

if __name__ == "__main__":
description("Python 101",
"Steve Holden",
"Georgie Peorgie",
"Mary Lamb",
"Penny Rice",
publisher="O'Reilly School of Technology",
author="Python Software Foundation"
)
description("Django 101",
"Jacob Kaplan-Moss",
"Baa-Baa Blacksheep",
"Mary Contrary",
"Missy Muffet",
"Peter Piper",
publisher="O'Reilly School of Technology",
author="Django Software Foundation",
editor="Daniel Greenfeld"
)

The first and seco nd parameters (nam e and inst ruct o r) are po sitio nal, and so are bo und to the first and seco nd
arguments o f any call. Any additio nal po sitio nal arguments are placed into the st ude nt s tuple. Finally, any keywo rd
arguments are placed into the st af f dict.

The nam e and inst ruct o r parameters are printed o ut. The functio n then iterates o ver the items (each item is a (key,
value) pair o f the st af f dict-parameter) to print details abo ut any additio nal staff. Finally, the functio n lo o ps thro ugh the
st ude nt s to list the individuals taking the class.

Take care when using sequence- and dict-parameters. With regular (po sitio nal and keywo rd)
parameters, yo u can usually determine the interface o f the functio n (that is, ho w it sho uld be called)
fro m the functio n and parameter names. When sequence- and dict-parameters are used, this is
mo re difficult to determine.
WARNING
If yo u do use sequence- and dict-parameters, make sure yo u do cument the purpo se o f each
parameter in the functio n's do cstring. This is go o d practice in any case, but especially so when the
interface is mo re co mplex.

Let's take a clo ser lo o k at what o ur do cstrings give us. Try these co mmands in an interactive sessio n:
INTERACTIVE SESSION:

>>> import courses


>>> help(courses.description)
Help on function description in module courses:

description(name, instructor, *students, **staff)


Print out a course description.
name: Name of the course
instructor: Name of the instructor
*students: List of student names (positional arguments)
**staff: List of additional staff (keyword arguments)

(END)

By do cumenting yo ur functio n co rrectly, yo u've pro vided useful info rmatio n to anyo ne who impo rts yo ur mo dule. (Yo ur
fello w pro grammers thank yo u!) Of co urse, the mo dule itself can also have useful do cumentatio n, tho ugh in this case,
there just wasn't much to pro vide. Co ntinue yo ur previo us interactive sessio n to verify that yo ur do cumentatio n
appears as expected:

INTERACTIVE SESSION:

>>> help(courses)
Help on module courses:

NAME
courses

FUNCTIONS
description(name, instructor, *students, **staff)
Print out a course description.
name: Name of the course
instructor: Name of the instructor
*students, ...: List of student names (positional arguments)
**staff, ...: List of additional staff (keyword arguments)

FILE
/users/smiller/python1/courses.py

(END)

Nice! The interpreter created a manual page fo r yo ur mo dule, just fro m the do cumentatio n strings that yo u entered.
No w anyo ne who wants to use yo ur mo dule can impo rt it into an interactive sessio n and learn all abo ut it using
Pytho n's standard he lp() functio n. I like it!

Importing Functions and help()


In the previo us lesso n, yo u learned abo ut impo rts, including ho w to bring functio ns yo u've written into o ther pro grams.
No w let's go o ver a handy trick that all Pytho n develo pers lo ve. First, we'll impo rt the keywo rd_args.py mo dule yo u
wro te earlier in this lesso n and run the built-in he lp() functio n o ver it. To get o ut o f the help interface, just press q. Then
type the co mmands belo w as sho wn:
INTERACTIVE SESSION:

>>> import keyword_args


>>> help(keyword_args)
Help on module keyword_args:

NAME
keyword_args - Demonstrates capture of keyword arguments

FUNCTIONS
keywords(**kwargs)
Prints the keys and arguments passed through

keywords_as_dict(**kwargs)
Returns the keyword arguments as a dict

FILE
/users/smiller/python1/keyword_args.py

(END)

So , thanks to the he lp() metho d, we can use the interactive interpreter to find impo rtant info rmatio n abo ut the functio ns
we've written. These co de statements are really driven by the do cstrings yo u write into yo ur Pytho n co de. All o f the
functio ns o f a mo dule are part o f its do cumentatio n.

Sweet. If all o f this isn't eno ugh to make yo u start sprinkling do c strings aro und yo ur co de, then no thing will persuade
yo u! Yo u can do cument mo dules, functio ns, and classes just by making their first executable statement a
do cumentatio n string. That's the kind o f simple po wer that makes Pytho n famo us!

Function Execution by Dispatch


So far, when yo u've needed to co ntro l the flo w o f a pro gram in Pytho n, yo u've used the if statement to cho o se
between two alternatives. But what if yo u need to select fro m multiple o ptio ns? One way is to use if , e lif , and e lse , but
that can beco me unwieldy—especially when large numbers o f alternatives are invo lved. If yo u had a hundred o r a
tho usand lines o f co de between the if statements, the resulting pro gram co uld likely be difficult to read, and even mo re
difficult to maintain.

Thankfully, Pytho n gives yo u a go o d way to wo rk aro und this using to o ls yo u've already learned. Yo u can write each
alternative set o f actio ns as a functio n, and then use a dictio nary to define lo gic flo w. The keys represent po ssible
actio ns, and the functio ns are the actio ns themselves. This so unds a lo t mo re co mplex than it actually is; let's use an
example to clarify things:

INTERACTIVE SESSION:

>>> def add(a, b):


... return a + b
...
>>> def sub(a, b):
... return a - b
...
>>> sw = {'adder':add, 'subber':sub}
>>> sw['adder'](3,2)
5
>>> sw['subber'](3,2)
1
>>> sw
{'adder': <function add at 0x397588>, 'subber': <function sub at 0x397618>}

First we created the two simple functio ns, add() and sub(), then we placed them inside the sw dict. Then we called
them (like any o ther Pytho n dict) by referencing their keys, and passed in arguments. This pro vides a nice, clean way o f
o rganizing and calling functio ns. In the last two lines o f the example, we printed o ut the lo gic flo w. When a dict o f
functio ns is used this way, it is called a dispatch table.
Ready fo r a mo re co mplex example? Go o d! We'll put five functio ns into a dict, then use a while lo o p and an input
statement to act as o ur user interface. We'll dispatch the appro priate functio n acco rding to the user's input. A lo t o f this
will lo o k familiar to yo u. Let's go ahead and get it wo rking. Create a new pro gram as sho wn belo w:

CODE TO TYPE:

#!/usr/local/bin/python3
""" A program designed to display switching in Python """

import sys

def print_text(text, *args, **kwargs):


"""Print just the text value"""
print('text: ' + text)

def print_args(text, *args, **kwargs):


"""Print just the argument list"""
print('args:')
for i, arg in enumerate(args):
print('{0}: {1}'.format(i, arg))

def print_kwargs(text, *args, **kwargs):


"""Print just the keyword arguments"""
print('keyword args:')
for k, v in kwargs.items():
print('{0}: {1}'.format(k, v))

def print_all(text, *args, **kwargs):


"""Prints everything"""
print_text(text, *args, **kwargs)
print_args(text, *args, **kwargs)
print_kwargs(text, *args, **kwargs)

def quit(text, *args, **kwargs):


"""Terminates the program."""
print("Quitting the program")
sys.exit()

if __name__ == "__main__":
switch = {
'text': print_text,
'args': print_args,
'kwargs': print_kwargs,
'all': print_all,
'quit': quit
}

options = switch.keys()
prompt = 'Pick an option from the list ({0}): '.format(', '.join(options))
while True:
inp = input(prompt)
option = switch.get(inp, None)
if option:
option('Python','is','fun',course="Python 101",publisher="O'Reilly")
print('-' * 40)
else:
print('Please select a valid option!')

Save it in yo ur /pyt ho n1 fo lder as swit ch.py, and run it. Try all the different o ptio ns. Also , try typing so mething that
isn't o ne o f the o ptio ns. Befo re we start reviewing this pro gram, take a minute and check o ut the difference between this
pro gram and earlier o nes in the co urse. Do esn't this o ne just look cleaner?

No w, let's lo o k at the functio ns:


OBSERVE:

""" A program designed to display switching in Python """

import sys

def print_text(text, *args, **kwargs):


"""Print just the text value"""
print('text: ' + text)

def print_args(text, *args, **kwargs):


"""Print just the argument list"""
print('args:')
for i, arg in enumerate(args):
print('{0}: {1}'.format(i, arg))

def print_kwargs(text, *args, **kwargs):


"""Print just the keyword arguments"""
print('keyword args:')
for k, v in kwargs.items():
print('{0}: {1}'.format(k, v))

def print_all(text, *args, **kwargs):


"""Prints everything"""
print_text(text, *args, **kwargs)
print_args(text, *args, **kwargs)
print_kwargs(text, *args, **kwargs)

def quit(text, *args, **kwargs):


"""Terminates the program."""
print("Quitting the program")
sys.exit()

if __name__ == "__main__":
switch = {
'text': print_text,
'args': print_args,
'kwargs': print_kwargs,
'all': print_all,
'quit': quit
}

options = switch.keys()
prompt = 'Pick an option from the list ({0}): '.format(', '.join(options))
while True:
inp = input(prompt)
option = switch.get(inp, None)
if option:
option('Python','is','fun',course="Python 101",publisher="O'Reilly")
print('-' * 40)
else:
print('Please select a valid option!')

All o f the functio ns insist o n the same arguments, even if mo st o f them o nly use a po rtio n o f tho se arguments. The
f irst t hre e f unct io ns are clear eno ugh; the f o urt h f unct io n just calls all three o f them, and the last f unct io n
uses the Pytho n standard library sys mo dule to quit the pro gram.

No w, let's mo ve o n to everything that fo llo ws if __nam e __ == " __m ain__" :. First, we create the swit ch dict , which
has five elements—the values are each o f the previo usly defined functio ns. Then, we co nstruct an o pt io ns list fro m
the swit ch.ke ys()—keys o f the switch dict. Then, we pro mpt the user fo r an o ptio n and start the input lo o p.

In the input lo o p, o pt io n = swit ch.ge t (inp, No ne ) takes the user's o ptio n and either finds the functio n in questio n o r
returns a No ne o bject. If an o ptio n is fo und (if o pt io n), then the parameters are passed to the user-selected functio n.
If no o ptio n is fo und, the user is pro mpted to 'Ple ase se le ct a valid o pt io n!'.

The result is a cleaner applicatio n where reuse o r integratio n o f new functio ns is much easier. Fo r example, let's add in
the de script io n() functio n fro m the co urse s.py mo dule yo u wro te earlier in this lesso n. Mo dify the co de and the
switch dict as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
""" A program designed to display switching in Python """

import sys
import courses

def print_text(text, *args, **kwargs):


"""Print just the text value"""
print('text: ' + text)

def print_args(text, *args, **kwargs):


"""Print just the argument list"""
print('args:')
for i, arg in enumerate(args):
print('{0}: {1}'.format(i, arg))

def print_kwargs(text, *args, **kwargs):


"""Print just the keyword arguments"""
print('keyword args:')
for k, v in kwargs.items():
print('{0}: {1}'.format(k, v))

def print_all(text, *args, **kwargs):


"""Prints everything"""
print_text(text, *args, **kwargs)
print_args(text, *args, **kwargs)
print_kwargs(text, *args, **kwargs)

def quit(text, *args, **kwargs):


"""Terminates the program."""
print("Quiting the program")
sys.exit()

if __name__ == "__main__":
switch = {
'text': print_text,
'args': print_args,
'kwargs': print_kwargs,
'all': print_all,
'course': courses.description,
'quit': quit
}

options = switch.keys()
prompt = 'Pick an option from the list ({0}): '.format(', '.join(options))
while True:
inp = input(prompt)
option = switch.get(inp, None)
if option:
option('Python','is','fun',course="Python 101",publisher="O'Reilly")
print('-' * 40)
else:
print('Please select a valid option!')

Save and run it. Cho o se the co urse o ptio n; yo ur results may seem a little silly, but they are co rrect based o n the
argument being passed to the functio n—and the instructo r does exist, and we think students are fun! See ho w easily we
can integrate new functio nality into o ur pro gram? The lo gic do esn't change at all, o nly the data that drives it.

What's Your Function?


In this lesso n, we reinfo rced what yo u already knew abo ut functio ns and impo rts. Yo u learned ho w to take co de written
inside o f functio ns and use it in o ther places, and that do cumentatio n in do cstrings can be really useful. Yo u've reaped
the benefits o f splitting yo ur o wn pro grams to make them mo re mo dular. And finally, yo u've seen ho w yo ur earlier
wo rk co uld have been written mo re efficiently to benefit fro m this mo dular appro ach. In the next lesso n, yo u'll learn
abo ut Pytho n's classes and o bject-o riented pro gramming.

Keep in mind, as we push o n, that go o d practice fo r Pytho n develo pers means never repeating any stanza o f co de
twice. Instead, put it into a functio n, and call the functio n twice!

Alright then, let's keep this train ro lling!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Classes and Object-Oriented Programming
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

create the individual instances that behave acco rding to their (built-in) type definitio n.
define yo ur o wn o bject classes.
define o bject behavio r.
bind a name during the executio n o f the class bo dy.
define yo ur o wn data types called classes.
use __init__().

The Nature of Objects


In Pytho n, they say "everything is an o bject." Let's explo re this idea using lists as an example. Every list co ntains
specific and likely different elements. But all lists have certain capabilities in co mmo n as well. Yo u can append items to
a list, retrieve individual elements by indexing, and so o n. So o bjects have two distinct features. First, each o bject has
its o wn unique data, private to that o bject and distinct fro m the o ther o bjects in its class. Seco nd, each o bject is an
instance o f so me class o r type, which specifies ho w it can behave, o r, in o ther wo rds, which metho ds and o peratio ns
can be used with that o bject.

The Pytho n language co ntains so me built-in data types. The interpreter kno ws ho w o bjects o f a given type sho uld
behave, but o f co urse, it has no idea which instances o f which types yo ur pro grams will create. So , the interpreter
co ntains the definitions o f the data types, but yo ur pro gram creates the individual instances, each o f which behaves
acco rding to its (built-in) type definitio n.

In o ur first example here, we'll explo re the nature o f o ne o f Pytho n's o bjects: the co mplex number. Type the co mmands
as sho wn:
INTERACTIVE SESSION:

>>> c = 3+4j
>>> type(c)
<class 'complex'>
>>> dir(c)
['__abs__', '__add__', '__bool__', '__class__', '__delattr__', '__divmod__', '__doc__',
'__eq__',
'__float__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs_
_', '__gt__',
'__hash__', '__init__', '__int__', '__le__', '__lt__', '__mod__', '__mul__', '__ne__',
'__neg__',
'__new__', '__pos__', '__pow__', '__radd__', '__rdivmod__', '__reduce__', '__reduce_ex_
_',
'__repr__', '__rfloordiv__', '__rmod__', '__rmul__', '__rpow__', '__rsub__', '__rtruedi
v__',
'__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '
conjugate',
'imag', 'real']
>>> c
(3+4j)
>>> c.__add__
<method-wrapper '__add__' of complex object at 0x01A84110>
>>> c.real
3.0
>>> c.imag
4.0
>>> type(c.imag)
<class 'float'>
>>> c.imag = 2.5
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute

The interpreter repo rts that the type o f c is <class 'co m ple x'>. The call o n dir(c) sho ws us that many metho ds have
names that begin with do uble undersco res— a lo t o f the names represent o perato rs that yo u may want to use o n a
co mplex number (add, subtract, divide, and so o n). Two o f the names do no t begin with do uble undersco res: "real"
and "imag." In mathematics, co mplex numbers have a real and an imaginary part. Each co mplex number in Pytho n has
two attributes called re al and im ag; tho se names are bo und to flo ating-po int numbers. Yo u can access the value o f
each attribute separately, but because all numbers in Pytho n are immutable, the interpreter wo n't allo w yo u to change
them.

Defining Your Own Object Classes


In keeping with a lo ng-standing traditio n in the o bject-o riented pro gramming wo rld, Pytho n lets yo u define yo ur o wn
data types called classes. In Pytho n we tend to reserve the wo rd "type" to mean a class that is built into the interpreter,
and "class" to mean tho se defined by the pro grammer. Pytho n uses the co mpo und class statement to intro duce a
class definitio n. The indented suite that fo llo ws the class statement co ntains descriptio ns o f the vario us metho ds that
sho uld be available. The simplest suite is a single pass statement. Let's take a lo o k. Type the co mmands belo w as
sho wn:
INTERACTIVE SESSION:

>>> class First:


... pass
...
>>> First
<class '__main__.First'>
>>> first = First()
>>> first
<__main__.First object at 0x02699A90>
>>> dir(first)
['__class__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '
__getattribute__',
'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__'
, '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'
, '__weakref__']
>>> first.name = "My first object"
>>> first.location = "Here"
>>> first.__dict__
{'name': 'My first object', 'location': 'Here'}
>>> first.name
'My first object'
>>> type(first.__dict__)
<class 'dict'>

We establish the type with a class statement. Then we create an instance o f o ur new class named f irst , by calling
First () as tho ugh it were a functio n. The interpreter identifies the instance by its name and address in hexadecimal
(base 16 ): "<__main__.First o bject at 0 x0 26 9 9 A9 0 >". This instance o f yo ur class is equipped to behave in certain
ways. The behavio rs sho wn in the result o f the dir(f irst ) call are co mmo n to all Pytho n o bjects.

Unlike built-in instances o f classes, when using classes yo u create yo urself, yo u can bind values to named attributes.
These bindings wo rk just like the binding o f values to keys in a dict, because, in fact, they are dicts. Assignment to a
do tted name results in that name being added as a key to a dict named __dict __, with the asso ciated value beco ming
the dict value. Fo r mo st names, inst .nam e is equivalent to inst .__dict __[" nam e " ].

Class and Instance Namespaces


The class statement takes an indented suite as its bo dy. When yo u bind a name during the executio n o f the class
bo dy, that class, like an instance, will have a namespace. Bindings in that class bo dy are created within the class
namespace. To fully understand that, run the fo llo wing co mmands in an interactive sessio n:
INTERACTIVE SESSION:

>>> class Second:


... one = "Depp"
... two = "Pitt"
...
>>> dir(Second)
['__class__', '__delattr__', '__dict__', '__doc__', ... ,
'__weakref__', 'one', 'two']
>>> Second.__dict__
dict_proxy({'__module__': '__main__', 'two': 'Pitt', 'one': 'Depp', '__dict__': <attrib
ute '__dict__' of '
Second' objects>, '__weakref__': <attribute '__weakref__' of 'Second' objects>, '__doc_
_': None})

>>> Second.__dict__.keys()
['__module__', 'two', 'one', '__dict__', '__weakref__', '__doc__']
>>> Second.__dict__["one"]
'Depp'
>>> Second.one
'Depp'
>>> second = Second()
>>> dir(second)
['__class__', '__delattr__', '__dict__', '__doc__', ...,
'__weakref__', 'one', 'two']
>>> second.__dict__
{}
>>> second.two
'Pitt'
>>> Second.two = "Clooney"
>>> second.two
'Clooney'

Do n't clo se that interactive sessio n; we'll be using it again sho rtly. Our example sho ws so me subtle differences
between classes and instances. Altho ugh each co ntains a __dict __, the instance was a dict already, and bindings to
the instance are seen o nly in that dict. In the class, ho wever, the bo und names also appear as part o f the class's
namespace, and __dict __ is no lo nger a dict, but so mething called a dict_pro xy. A dict_pro xy pro vides a selective
view o f the class's namespace. These differences are significant to a Pytho n implementer, but fo r no w yo u can file this
info rmatio n away.

Mo re impo rtantly, no tice that the names o ne and t wo have been bo und in the class namespace, and no w also appear
in the instance namespace (tho ugh no t in its __dict __). In additio n, they have the same value in the instance
namespace as they do in the class namespace. If yo u rebind the name in the class namespace, it also changes in the
instance. Our example demo nstrates that names that appear to be in the instance namespace are actually defined in
the class.

We'll take a clo ser lo o k at the relatio nship between a class and its instances later. Fo r the mo ment, just be aware that
yo u can access attributes o f the class in any o f its instances. If yo u bind the same attribute to the instance, it do es no t
change the class at all—the binding remains lo cal to the instance. Co ntinuing the interactive sessio n, type the
co mmands belo w as sho wn:
INTERACTIVE SESSION:

>>> second2 = Second()


>>> second2.one
'Depp'
>>> second2.one = "Bloom"
>>> Second.one = "DiCaprio"
>>> second.one
'DiCaprio'
>>> second2.one
'Bloom'
>>> dir(second2)
['__class__', '__delattr__', '__dict__', ..., 'two', 'one']
>>> second2.__dict__
{'one': 'Bloom'}

Here we created a seco nd Se co nd instance, named se co nd2, which initially sho wed the same value as the class fo r
its o ne attribute. When we assigned "Blo o m" to the se co nd2 instance's o ne attribute, it o verrides the class attribute,
but o nly fo r that o ne instance. The se co nd instance's o ne attribute still reflects the class's value fo r that attribute.
When the Se co nd class's o ne attribute is rebo und, the se co nd instance's o ne attribute also changes, but no t that o f
the se co nd2 instance. (Phew! Did yo u catch all that?)

The attributes o f a class can be accessed by all instances o f that class but, as we've just seen, an assignment to an
instance attribute o f the same name will o verride the class attribute. Check o ut the last two expressio ns in the last
sessio n; no t o nly do es the se co nd2 instance have a o ne attribute (the o ne inherited fro m the Se co nd class) in its
namespace, it also has a o ne attribute in its __dict __ as a result o f being bo und to se co nd2.o ne . The interpreter is
lo o king in an instance's __dict __ first, and o nly lo o ks in the namespace if it fails to find the attribute in the dict.

Defining Object Behavior


Ho pefully it's starting to feel natural to yo u to write functio ns that o perate o n instances o f classes. No w let's suppo se
Pytho n didn't have co mplex numbers, and yo u had to implement them yo urself. Ho w wo uld yo u create a new co mplex
number, and ho w wo uld yo u add two co mplex numbers to gether? Yo u co uld define a class called Cplx (Pytho n
already uses co m ple x fo r the existing co mplex data type), then write a cplx() functio n to create a co mplex number
fro m the values o f its real and imaginary parts. Then yo u co uld implement a cadd() functio n that takes two co mplex
numbers and returns the sum o f the two as its result. If yo u were feeling really ambitio us, yo u co uld also write a cst r
functio n to call fro m inside print () to o utput co mplex values.

The resulting co de, with a co uple o f calls o n the functio ns to test the co de, might lo o k like the pro gram we'll create
no w. Create a new pro gram as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:
pass

def cplx(real, imag):


c = Cplx()
c.real = real
c.imag = imag
return c

def cadd(c1, c2):


c = Cplx()
c.real = c1.real+c2.real
c.imag = c1.imag+c2.imag
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = cplx(0.0, 0.0)
one = cplx(1.0, 0.0)
i = cplx(0.0, 1.0)
result = cadd(zero, cadd(one, i))
print(cstr(result))

Save it in yo ur /pyt ho n1 fo lder as cplx.py, and run it. The result 1.0 +1.0 j prints. Yo u aren't using very much o f
Pytho n's class mechanism tho ugh. To do that, yo u need to separate the creatio n o f the instances fro m their
initializatio n. Then yo u'll rename the cplx() functio n to cinit (), and change its co de so that it o perates o n an existing
rather than a new instance, initialize it and return the instance. This initially co mplicates yo ur calling co de, because yo u
no w have to create the instances befo re initializing them, but do n't wo rry abo ut that no w. Let's play with so me co de!
Mo dify yo ur pro gram as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:
pass

def cplx(real, imag):


c = Cplx()
c.real = real
c.imag = imag
return c

def cinit(c, real, imag):


c.real = real
c.imag = imag

def cadd(c1, c2):


c = Cplx()
c.real = c1.real+c2.real
c.imag = c1.imag+c2.imag
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = Cplx()
cinit(zero, 0.0, 0.0)
one = Cplx()
cinit(one, 1.0, 0.0)
i = Cplx()
cinit(i, 0.0, 1.0)
result = cadd(zero, cadd(one, i))
print(cstr(result))

Save and run it. It prints the same result as befo re—after all, it's really the same co de.

Defining Behavior as Methods


So far, we've fo cused o n the data attributes o f classes and their instances. We kno w that when a class and o ne o f its
instances bo th have the same name, the instance attribute "wins." We can access a class's attributes via the instance,
as lo ng as the instance do esn't have its o wn attribute with the same name. But assignment is o nly o ne way to bind
values to a class. Ano ther way is thro ugh the de f statement used to define functio ns.

Go ahead and edit cplx.py so that the functio ns beco me metho ds o f the class:

Note To indent the functio n declaratio ns, just select the blo ck o f co de yo u want to indent and press T ab.
CODE TO TYPE:
#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:
pass

def cinit(c, real, imag):


c.real = real
c.imag = imag

def cadd(c1, c2):


c = Cplx()
c.real = c1.real+c2.real
c.imag = c1.imag+c2.imag
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = Cplx()
Cplx.cinit(zero, 0.0, 0.0)
one = Cplx()
Cplx.cinit(one, 1.0, 0.0)
i = Cplx()
Cplx.cinit(i, 0.0, 1.0)
result = Cplx.cadd(zero, Cplx.cadd(one, i))
print(Cplx.cstr(result))

Save and run it. Yo u might see warnings o n the de f lines stating that the metho ds sho uld have self as the first
parameter, but yo u can igno re them fo r no w. Yo u'll still get this result: 1.0 +1.0 j.

By declaring a functio n as part o f the class bo dy, we bind the functio n name within the class namespace rather than the
mo dule namespace. This means that, to call the functio n, it must be preceded by the class name and a do t. Because
the class bo dy is no lo nger empty, yo u do n't need the pass statement any mo re.

No w let's break yo ur co de! Do n't wo rry; we'll fix it right up o nce yo u understand the details o f the breakage. The Cplx
class has three new attributes—cinit , cadd, and cst r. Yo u can access class attributes (attributes bo und in the class
namespace) thro ugh an instance o f the class. So yo u'd think that yo u co uld access tho se metho ds thro ugh the
instance, rather than the class. But when yo u change the co de to do that, a strange erro r o ccurs. Mo dify cplx.py to call
the metho ds o n the instances as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:

def cinit(c, real, imag):


c.real = real
c.imag = imag

def cadd(c1, c2):


c = Cplx()
c.real = c1.real+c2.real
c.imag = c1.imag+c2.imag
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = Cplx()
zero.cinit(zero, 0.0, 0.0)
one = Cplx()
one.cinit(one, 1.0, 0.0)
i = Cplx()
i.cinit(i, 0.0, 1.0)
result = zero.cadd(zero, one.cadd(one, i))
print(result.cstr(result))

Save and run it. Yo u might be surprised to see a traceback and erro r message:

OBSERVE:

Traceback (most recent call last):


File "./cplx.py", line 21, in <module>
zero.cinit(zero, 0.0, 0.0)
TypeError: cinit() takes exactly 3 positional arguments (4 given)

This message may be a bit difficult to understand. It says that ze ro .cinit (ze ro , 0 .0 , 0 .0 ) has fo ur arguments, but it's
clear that it pro vides o nly three. Where is the so urce o f the fo urth argument?

When the interpreter sees a reference to a class's metho d relative to an instance, it assumes that the metho d will need
to kno w which instance it was being called upo n. Co nsequently, it inserts the instance as the first argument
auto matically. Metho ds are being called with to o many arguments because the interpreter assumes yo u will want a
reference to the instance, and inserts it auto matically. The fix fo r yo ur co de is to remo ve the explicit instance
arguments. Fix cplx.py as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:

def cinit(c, real, imag):


c.real = real
c.imag = imag

def cadd(c1, c2):


c = Cplx()
c.real = c1.real+c2.real
c.imag = c1.imag+c2.imag
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = Cplx()
zero.cinit(zero, 0.0, 0.0)
one = Cplx()
one.cinit(one, 1.0, 0.0)
i = Cplx()
i.cinit(i, 0.0, 1.0)
result = zero.cadd(zero, one.cadd(one.cadd(i))
print(result.cstr(result))

Save and run it. Yo u sho uld get 1.0 +1.0 j as yo ur result again.

Python Deep Magic: Hooking into Python's Class Mechanism


The co de yo u have develo ped so far wo rks, but it's a little o n the ugly side. Separating the creatio n o f o bjects fro m their
initializatio n means that two lines o f co de are required to create a co mplex number. To remedy the ugly, we'll unleash
so me o f Pytho n's "deep magic!" (Ho w co o l is that?) Deep magic refers to pro gramming techniques that are no t widely
kno wn, and that may be kept secret deliberately. But yo u, my friend, are abo ut to learn so me Pytho n deep magic to cast
abo ut yo urself! Let's start with the special metho d Pytho n pro vides to beautify yo ur co de: __init __().

Using __init__()
When yo u create an instance o f a class by calling it, the interpreter lo o ks to see whether the class has an
__init __() metho d. If it finds __init __(), it calls that metho d o n the newly-created instance. Because it's an
instance metho d call, the new instance is inserted as the first argument to the call. Further, if the call to the
class has any arguments, they are passed to __init __() as additio nal arguments.

The __init __() metho d m ust no t return a value. If __init __() returns so mething, it affects the
Note instance creatio n pro cess. This causes the interpreter to raise an exceptio n, and yo ur pro gram
to fail. Yo u'll learn abo ut instance creatio n in mo re detail later.

By renaming the Cplx class's cinit () metho d to __init __(), yo u can sho rten the co de that creates and
initializes the new instance to a single line. Very nice. Pytho n users appreciate elegance and simplicity. Ugly
Pytho n co de may be a sign that the language isn't being used to its full advantage. Let's try a bit mo re
experimentatio n. Edit cplx.py belo w as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:

def __init__(c, real, imag):


c.real = real
c.imag = imag

def cadd(c1, c2):


c = Cplx(c1.real+c2.real, c1.imag+c2.imag)
return c

def cstr(c):
return "%s+%sj" % (c.real, c.imag)

if __name__ == "__main__":
zero = Cplx(0.0, 0.0)
one = Cplx(1.0, 0.0)
i = Cplx(0.0, 1.0)
result = zero.cadd(one.cadd(i))
print(result.cstr())

Save and run it. Yo u'll get 1.0 +1.0 j fo r a result yet again. Pytho n o bjects tend to have a lo t o f tho se special
metho ds with names that begin and end with do uble undersco res. To make discussing them easier,
"__init__()" is o ften pro no unced "dunder-init"; "dunder" being an abbreviatio n fo r "do uble under." We'll
co nvert the o ther metho ds o f yo ur co mplex class to "dunder" metho ds in a bit.

More on Python's Dunder Methods


When printing in Pytho n, yo u get lo ts o f help fro m the print () functio n. Witho ut go ing into to o much detail, the
functio n co nverts each argument into a string by calling the o bject's __st r__() metho d. So each class in
Pytho n can determine exactly ho w its instances get printed by defining a __st r__() metho d. Yo u can rename
yo ur cst r() metho d to __st r__() and print Cplx instances directly.

Similarly, when yo u write a + b in Pytho n, the interpreter tries to execute the task in a number o f ways: first it
tries to co mpute a.__add__(b) (which requires that a has a __add__ metho d). If that do esn't wo rk, Pytho n
tries to co mpute b.__radd__(a). So , to enable yo ur pro gram to add Cplx o bjects, rename the cadd metho d
to __add__.

Being Selfish
Let's take ano ther quick peek at the first argument o f yo ur class's metho ds—the o ne that the interpreter puts in
auto matically when yo u call a metho d o n an instance. Experienced Pytho n pro grammers wo uld be able to
interpret the co de in the last listing, but they wo uld want to kno w why the argument was called c o r c1.

There is an almo st universal co nventio n that the first argument o f a metho d sho uld be called se lf . Reading
o ther peo ple's pro grams is difficult eno ugh, so it's impo rtant to stick to co nventio n—no t o nly will it make yo ur
co de easier fo r o ther pro grammers to read, it will make it easier fo r you to read as well, and that's an
impo rtant time saver.

So ho w sho uld the co de lo o k when yo u make all the changes discussed in the last two sectio ns? Edit
cplx.py belo w as sho wn:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Initial implementation of complex numbers."""

class Cplx:

def __init__(self, real, imag):


self.real = real
self.imag = imag

def __add__(self, c2):


c = Cplx(self.real+c2.real, self.imag+c2.imag)
return c

def __str__(self):
return "%s+%sj" % (self.real, self.imag)

if __name__ == "__main__":
zero = Cplx(0.0, 0.0)
one = Cplx(1.0, 0.0)
i = Cplx(0.0, 1.0)
result = zero + one + i
print(result)

Save and run it. Yo u'll still get a result o f 1.0 +1.0 j.

A Solid Foundation
Ho w do es it feel to be an up-and-co ming Pytho n pro grammer? Yo u've really co me a lo ng way! Yo u've
learned the basics o f o bject-o riented pro gramming in Pytho n. The Pytho n interpreter o ffers a lo t o f ho o ks in
the fo rm o f __xxx__() metho ds that yo u can use to make yo ur o wn classes as co nvenient and natural to
wo rk with as the built-in Pytho n types.

In future lesso ns, yo u'll do lo ts mo re o bject-o riented pro gramming; I'm co nfident yo u can handle it!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Exception Handling
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

handle exceptio ns.


identify and lo cate exceptio ns.
handle multiple exceptio n types.
handle multiple exceptio ns with o ne handler.
flag erro r co nditio ns fro m yo ur o wn co de.

Working through Exceptions


As yo u've wo rked thro ugh the lesso ns and tried o ut the co de, yo u've seen plenty o f Pytho n erro r messages. Mo st o f
them have been syntax errors, which are caused by mistakes made while entering co de examples. The rest, caused by
all o ther kinds o f mistakes, are called exceptions.

Syntax erro rs can and will crash yo ur pro gram, but so o n yo u'll kno w exactly ho w to diagno se and fix them! Let's go
right to wo rk. Type the co mmands belo w in an interactive sessio n as sho wn:

INTERACTIVE SESSION:

>>> print('Hello, world)


File "<stdin>", line 1
print('Hello, world)
^
SyntaxError: EOL while scanning string literal
>>> print('Hello, world')
Hello, world

To handle this so rt o f erro r message, co rrect the syntax o f yo ur co de so it makes sense to the interpreter. This is the
mo st co mmo n kind o f bug, and no w yo u kno w ho w to squash it!

But even if yo ur co de is syntactically co rrect, it can still thro w exceptio ns when yo u run it. The mo st co mmo n
exceptio ns are TypeErro r, KeyErro r, and NameErro r. The o dds are pretty go o d that yo u've enco untered them already
during this co urse, fo r instance if yo u mistyped a variable name o r entered a no n-numeric value that yo ur pro gram tried
to co nvert into a number. Let's take a lo o k at so mething like that. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> 'chapter ' + 15


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
>>> snakes = {'python':'fun','mamba':'dance'}
>>> snakes['cobra']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'cobra'
>>> print(my_var)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'my_var' is not defined

Keep this interactive sessio n o pen because we'll be do ing ano ther co de example with the snake s dict.

The first lesso n o f exceptio n handling is learning to catch exceptio ns, and then handle them so that they do n't bring
yo ur pro gram crashing do wn. The next level o f exceptio n handling teaches yo u ho w to handle different types o f
exceptio ns at the same time.

How to Catch an Exception


As yo u saw in the interactive sessio n abo ve, the interpreter raises a KeyErro r exceptio n when a dict do es no t
co ntain a key specified as an index fo r retrieval. Yo u catch erro rs using t ry/e xce pt statements like the o ne in
o ur next example. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> try:
... snakes['cobra']
... except KeyError:
... print('Exception detected')
...
Exception detected

The t ry statement attempts to execute the co de co ntained in its indented suite. That suite may be made up o f
several lines o f co de, but this example attempts to evaluate o nly the expressio n snake s['co bra']. (This key
was cho sen intentio nally because it will raise an exceptio n. We kno w yo u can handle it!). This causes the
interpreter to trigger the exceptio n handler fo r the KeyErro r exceptio n, the e xce pt statement. The except suite
co ntains the expressio n print ('Exce pt io n de t e ct e d').

Co ngratulatio ns—yo u caught an exceptio n! Of co urse, the exceptio n handler do es no thing fo r yo u if yo u do n't
handle the co rrect exceptio n. The next example illustrates this po int. Type the co de belo w as sho wn:

INTERACTIVE SESSION:

>>> try:
... 3/0
... except KeyError:
... print("Exception detected")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: int division or modulo by zero
>>>

Altho ugh the t ry statement has an exceptio n handler, it do esn't handle the actual exceptio n
(Zero Divisio nErro r) that is raised. In this case, the interpreter behaves as if there is no handler. In the
interactive interpreter, this means yo u see a "stack traceback." If an unhandled exceptio n happens when yo u
are running a pro gram, yo u still get the stack traceback, and then the pro gram terminates.

Verifying Numeric Input


In earlier lesso ns, yo u used mathematical algo rithms to learn abo ut integers, lo o ps, and functio ns. In so me
cases tho ugh, yo u ran into pro blems verifying numeric input. A go o d example is the so rt o f input () pro blem
sho wn here. Type the co mmands belo w as sho wn:

INTERACTIVE SESSION:

>>> inp = input('Integer: ')


Integer: four
>>> 10 + int(inp)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'four'

Exceptio n handling co mbined with a lo o p is really handy. Yo u write an infinite lo o p, and break o ut o f it when
the user's input do es no t raise an exceptio n. Let's try that pro blem again. Type the co mmands as sho wn:
INTERACTIVE SESSION:

>>> while True:


... inp = input("Integer: ")
... try:
... print(int(inp)+10)
... break
... except ValueError:
... print("Please enter an integer")
...
Integer: thing
Please enter an integer
Integer: python
Please enter an integer
Integer: 12.3
Please enter an integer
Integer: 12
22
>>>

This lo o p wo n't blo w up if a user enters no n-numeric data fo r a numeric field, which is a reaso nably co mmo n
pattern in Pytho n co ding.

Handling Multiple Exception T ypes


If yo u do n't catch an exceptio n, it will ultimately be raised to the interpreter. But if a t ry statement is co ntained
inside ano ther o ne, the o uter t ry's exceptio n handler gets the chance to handle the exceptio n. Create a new
pro gram in the edito r windo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
""" Nested exception handling"""

def divide(a, b):


""" Return result of dividing a by b """
print("=" * 20)
print("a: ", a, "/ b: ", b)
try:
try:
return a/b
except TypeError:
print("Invalid types for division")
except ZeroDivisionError:
print("Divide by zero")

if __name__ == "__main__":
print(divide(1, "string"))
print(divide(2, 0))
print(divide(123, 4))

Save it in yo ur /pyt ho n1 fo lder as ne st e d.py, and run it:


INTERACTIVE SESSION:

cold1:~$ cd python1
cold1:~/python1$ ./nested.py
====================
a: 1 / b: string
Invalid types for division
None
====================
a: 2 / b: 0
Divide by zero
None
====================
a: 123 / b: 4
30.75

The statement print (divide (1, " st ring" )) raises a TypeErro r exceptio n because it isn't po ssible to divide a
number by a string. This exceptio n is caught by the inner handler and handled. The functio n then ends witho ut
returning a value, so its result is No ne . The statement print (divide (2, 0 )) also raises an exceptio n, but in
this case it isn't caught by the e xce pt o f the inner t ry because it isn't a TypeErro r. Co nsequently, the
exceptio n "bubbles up" to the next level, where there is a handler fo r the Zero Divisio nErro r that o ccurs. Finally,
the statement print (divide (123, 4 )) represents a legal arithmetic o peratio n and gets past bo th erro r
handlers and returns the appro priate result.

By nesting exceptio n handlers, yo u can catch erro rs that are thro wn at different levels and handle them
appro priately. Every additio nal level o f nesting remo ves so me readability fro m yo ur pro gram, tho ugh, so
avo id do ing it when yo u can. Fo rtunately, yo u can avo id so me o f that because Pytho n allo ws yo u to attach
several e xce pt clauses to a single t ry statement. Edit ne st e d.py belo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
""" Nested exception handling"""

def divide(a, b):


""" Return result of dividing a by b """
print("=" * 20)
print("a: ", a, "/ b: ", b)
try:
result = a/b
print("Sometimes executed")
return result
except TypeError:
print("Invalid types for division")
except ZeroDivisionError:
print("Divide by zero")

if __name__ == "__main__":
print(divide(1, "string"))
print(divide(2, 0))
print(divide(123, 4))

Save and run it. When the exceptio n is raised inside o f the t ry suite, the interpreter tries to match it against
each o f the e xce pt clauses, in turn. If it finds a matching clause, it executes the asso ciated handler suite. If
no ne o f the e xce pt clauses match the exceptio n, then no ne o f the handlers are run, and the interpreter starts
to examine the handlers o f any o uter t ry statements. The o utput fro m running this pro gram sho uld lo o k like
this:
INTERACTIVE SESSION:

cold1:~/python1$ ./nested.py
====================
a: 1 / b: string
Invalid types for division
None
====================
a: 2 / b: 0
Divide by zero
None
====================
a: 123 / b: 4
Sometimes executed
30.75

The print (" So m e t im e s e xe cut e d" ) statement and the fo llo wing re t urn aren't executed when an
exceptio n is raised. One particularly useful feature o f exceptio ns is that yo u can use them to change the flo w
o f yo ur pro gram's lo gic when co nditio ns are, well, exceptio nal.

Handling Multiple Exceptions with One Handler


So metimes yo u want to take the same actio n fo r several different exceptio ns. Yo u can do this by specifying
the exceptio ns as a tuple after the e xce pt keywo rd. Then the handler will be executed if any o f the exceptio ns
in the tuple o ccur during executio n o f the t ry clause.

Raising Exceptions
Yo u may want to be able to flag erro r co nditio ns fro m yo ur o wn co de. This is especially useful when yo u are
writing co de to be used by o ther peo ple. Yo u flag erro r co nditio ns with the raise statement; this is useful in
two co ntexts:

If yo u want to handle so me o f the co nsequences o f an exceptio n, but then re-raise it to be handled


by so me o uter handler, yo u can do so by executing a statement co nsisting o f o nly the keywo rd
raise . This will cause the same exceptio n to be presented to the o uter handlers.
If yo u detect so me co nditio n in yo ur co de that requires yo u to sto p running the pro gram, yo u can
raise a specific exceptio n o f yo ur cho ice by fo llo wing the raise keywo rd with an exceptio n. Yo u can
create that exceptio n by calling any o f the system exceptio ns with a string argument. Let's try o ut
so me o f these features in ne st e d.py. Type the co de belo w as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
""" Nested exception handling"""

def divide(a, b):


""" Return result of dividing a by b """
print("=" * 20)
print("a: ", a, "/ b: ", b)
try:
return a/b
except (ZeroDivisionError, TypeError):
print("Something went wrong!")
raise

if __name__ == "__main__":
for arg1, arg2 in ((1, "string"), (2, 0), (123, 4)):
try:
print(divide(arg1, arg2))
except Exception as msg:
print("Problem: {0}".format(msg))

Save and run it. Yo u sho uld see this:


OBSERVE:

====================
a: 1 / b: string
Something went wrong!
Problem: unsupported operand type(s) for /: 'int' and 'str'
====================
a: 2 / b: 0
Something went wrong!
Problem: int division or modulo by zero
====================
a: 123 / b: 4
30.75

The e xce pt statement in the divide() functio n no w specifies the same handler fo r bo th Zero Divisio nErro r and
TypeErro r exceptio ns. The handler prints an info rmative message ("So mething went wro ng!") and then re-
raises the same exceptio n. Since there are no further handlers in the functio n, the re-raised exceptio n is no w
caught by the e xce pt statement in the main pro gram.

In this case, the e xce pt statement catches pretty much any exceptio n, because all exceptio ns are direct o r
indirect subclasses o f Exce pt io n. Also , the exceptio n specificatio n can be fo llo wed by an as clause, which
specifies a name to bind to the exceptio n that is being handled. Yo u can see fro m the print () functio n call that
when an exceptio n is co nverted to a string, yo u get the message asso ciated with the exceptio n.

Specific and Generic Exceptions


Using specific exceptio ns is handy because do ing that allo ws yo u to ho ne in o n the exact exceptio n yo u want
to handle. But what happens when yo u have co de where exceptio ns might be raised in places yo u can't
anticipate? Pytho n will allo w yo u to o mit the exceptio n specificatio n alto gether. This clause must fo llo w all
e xce pt clauses with exceptio n specificatio ns, and will catch any exceptio n whatso ever. The next example
uses bo th specific and generic specificatio ns to catch exceptio ns fro m a Test class that po ssesses an add()
metho d specifically included to pro duce an AttributeErro r o r TypeErro r. Create a new pro gram as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
""" Named and generic exception handling"""

def add(a, b):


""" Print the results of adding a set and a value"""
try:
a.add(b)
print(a)
except AttributeError:
print("({0}) is not a set object".format(a))
except TypeError:
print("({0}) is not a hashable object".format(b))
except:
print("This is a generic exception")

class Test(object):
""" Just a simple test class """

def add(self, a):


""" Demonstrates how you need to be able to handle unpredictable results
. """
d = {'python':'fun'}
return d[a]

if __name__ == "__main__":
s = set((1,2,3))
add(s, 4)
add(1, 4)
add(s, [4, 5, 6])
t = Test()
add(t, 1)
Save it in yo ur /pyt ho n1 fo lder as e xce pt io ns.py, and run it. In o ur add() functio n, we plan fo r 'a' to thro w
either an AttributeErro r, TypeErro r, o r so mething we can't predict. Remember, the plain e xce pt clause must
fo llo w the named exceptio ns. In the last two lines, we attempt to use the add() metho d o f the T e st instance
to use the supplied parameter as an index to a dict with o nly o ne key. Co nsequently, the final call to add()
raises a KeyErro r exceptio n, which in turn causes the final e xce pt clause to be activated, because the
exceptio n raised is neither an AttributeErro r no r a TypeErro r.

After yo u run the pro gram, fo llo w the lo gic thro ugh to make sure yo u understand exactly why it behaves the
way it do es. If there's anything yo u do n't understand abo ut all o f this, talk it o ver with yo ur instructo r.

When to Use Exceptions


So me Pytho n o bjects are equipped with metho ds that remo ve the need fo r exceptio ns. The dict is a go o d
example o f this, as yo u'll see in the next co de sample—the dict .ge t () metho d tries to use the first argument
as a key into the dict, but if no such key exists, it returns the seco nd argument. Type the co mmands belo w as
sho wn:

INTERACTIVE SESSION:

>>> d = {1:'python'}
>>> d[1]
'python'
>>> try:
... d[10]
... except KeyError:
... print('no snake here')
...
no snake here
>>> d.get(10,'no snake here')
'no snake here'

Of co urse, dict .ge t () o nly wo rks if yo u kno w that d is o f type dict. If yo u do n't kno w that, yo u might want to
handle specific exceptio ns raised under tho se circumstances. Fo r example, yo u might try this:

INTERACTIVE SESSION:

>>> d = [1,2,3,4]
>>> try:
... d[10]
... except KeyError:
... print('no snake here')
... except IndexError:
... print('no snake here either')
...
no snake here either

Exceptional Work So Far!


Yo u need to be able to anticipate when things might go wro ng with yo ur pro grams, so yo u can catch and
handle the exceptio ns that are raised. This will make yo ur pro grams mo re ro bust, and capable o f handling
anything that users can thro w at them.

Ideally, yo u build pro grams that never terminate with an uncaught exceptio n. With yo ur new kno wledge o f
exceptio n handling, yo u are much clo ser to reaching that go al.

Yo u're almo st there, just o ne lesso n to go befo re yo ur final pro ject! Great wo rk so far, keep it up!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.
Building and Debugging Whole Programs
Lesson Objectives
When yo u co mplete this lesso n, yo u will be able to :

build and debug an entire pro gram.


do cument and test Pytho n co de.
co de in Pytho n.

Putting it All Together


No w that yo u've explo red the co re elements o f Pytho n, yo u kno w eno ugh to write so me pretty co mplex pro grams. But
there's still lo ts left to learn. In this lesso n, we'll go o ver a few mo re co ncepts that yo u can use to co mplete yo ur final
pro ject. We'll decipher the mo re advanced mysteries o f Pytho n in future co urses.

Fo r o ur last lesso n to gether in this co urse, we'll gather a bit mo re info rmatio n abo ut ho w to put pro grams to gether.

Yo u'll want to kno w abo ut testing and debugging (lo cating and fixing pro blems in yo ur co de). These to pics are kind o f
like icebergs: much o f their substance lies under the surface and will no t reveal itself immediately; yo u'll co ntinue
learning fo r as lo ng as yo u wo rk with Pytho n. In fact, I have been a practicing pro grammer myself fo r o ver fo rty years,
and I co ntinue to learn mo re and mo re abo ut testing and debugging.

T he Art of Computer Programming


The title o f this subsectio n is also the title o f a bo o k series being written by Do nald Knuth, a co mputer science
pro fesso r at Stanfo rd University. Tho ugh no t yet finished, it already fills fo ur massive vo lumes. Do n't be
disco uraged if yo u feel like yo u do n't have a handle o n all there is to kno w abo ut Pytho n yet! If yo u're go ing to
beco me really go o d at this, yo ur pro gramming educatio n will be o ngo ing.

As yo ur grasp o f the language increases, yo u'll inevitably find that when yo u review co de yo u wro te so me
time ago , yo u'll have fo und better ways to express the same algo rithms. It's go o d practice to reevaluate yo ur
co de o ccasio nally—even if it wo rks, it can pro bably be impro ved. On the flipside, as they say, "if it ain't bro ke,
do n't fix it." Unless there's a benefit to changing the co de (like increased speed o r reduced co mplexity), then
leave it alo ne.

It's all to o easy to intro duce subtle erro rs into yo ur pro grams by changing co de to o ther co de yo u think is
equivalent. Until yo u're a bit mo re experienced and co nfident in yo ur decisio ns, just be satisfied with
pro grams that wo rk.

Design T echniques
Two co mmo n terms flung abo ut by pro grammers are top-down and bottom-up design. In to p-do wn design,
yo u defer thinking abo ut the detail o f a pro blem until yo u have mapped o ut the o verall structure it will have.
Wo rking bo tto m-up, yo u begin by building a set o f primitive o peratio ns that yo u can then fo ld to gether with
glue logic to so lve yo ur pro blem.

The to p-do wn appro ach lets yo u avo id having to o much co nfusing detail to deal with early in the design cycle.
Go o d to p-do wn design fo cuses first o n the pro gram's large-scale architectural features.

The bo tto m-up appro ach is useful when yo u already understand yo ur data and the ways yo u need to
manipulate it. Using a t e st -drive n de ve lo pm e nt appro ach to pro gramming, yo u write tests first, and then
write yo ur pro gram to pass the tests. Each functio n and metho d is written to pass its tests, so yo u kno w that
yo ur lo wer-level co mpo nents do indeed behave as expected.

The to p-do wn and the bo tto m-up appro aches can also be used to gether o n the same pro ject. It's a little like
two teams bo ring a tunnel fro m o ppo site sides o f a mo untain: if the two do no t meet, they have no t been
wo rking harmo nio usly to gether.

By taking a to p-do wn appro ach initially, yo u can o perate a divide-and-co nquer scheme, and avo id being
o verwhelmed by detail early in the design. If yo ur co ding pro blem isn't to o co mplex, yo u might find that yo u
have already so lved it befo re yo u ever start wo rking bo tto m-up.

Agile Programming
Agile pro gramming techniques fo cus o n delivering the simplest co de that meets the requirements, o r as agile
practitio ners o ften say, "the simplest thing that co uld po ssibly wo rk." Agile metho ds place great emphasis o n
refactoring yo ur co de when it beco mes to o co mplex. Refacto ring means changing the way yo ur pro gram is
o rganized witho ut changing its behavio r. Refacto ring is generally used when handling large pro grams, but it
can be helpful whenever co mplexity starts to o verwhelm yo u. Refacto ring can help yo u to :

Re m o ve duplicat e co de : When two different functio ns pro vide the same result, o r o ne functio n
is a special case o f ano ther, we refacto r the two functio ns into o ne, and we'll have less co de to
maintain.
Iso lat e e xist ing lo gic f ro m a ne e de d change : If yo u have to change certain cases currently
handled by a single class, yo u might find it advantageo us to refacto r the class by turning it into two
subclasses o f a co mmo n base class. The changed behavio r can then be implemented in just o ne
o f the subclasses.
Make t he pro gram run f ast e r: When perfo rmance beco mes sluggish, it may be that yo ur
o riginal cho ice o f algo rithm o r data structure was inappro priate, so yo u refacto r to streamline yo ur
pro cess.

So me aspects o f agile develo pment are meant to be used by teams o f so ftware develo pers rather than
individuals. Let's go o ver a few key principles that apply to mo st agile techno lo gies:

De sign and co de are t e st -drive n: Whenever yo u add functio nality to yo ur pro gram, yo u first
write a test, fo r auto matic executio n, that checks to make sure that the functio nality is present and
perfo rms pro perly. Yo ur wo rk sho uld pro ceed in small increments—never add two features at the
same time.
Int e grat e co nt inuo usly: Each time yo u change o r fix a mo dule, after running its tests, integrate
the mo dule back into the system and run the system tests to make sure that yo ur change has no t
had any unintended co nsequences.
Re f act o r m e rcile ssly: To re f act o r m e rcile ssly means that if tasks are perfo rmed similarly in
two places, mo ve them aro und so they're do ne in o ne place instead, and then called o r inherited by
the two o riginal places. If yo u have co ding standards and they are vio lated, fix them. If yo u no tice
structural defects, fix them. After each change, rerun all o f yo ur tests to verify that yo ur co de has no t
been bro ken during the refacto ring pro cess.
Re le ase e arly and o f t e n: Release yo ur pro gram to the users befo re adding to o many features.
Yo u can use their feedback to guide further develo pment, and deliver the mo st impo rtant functio ns
o f yo ur pro gram faster.
Ke e p it sim ple : Do n't include co mplexity that yo u think might be handy later. Simplicity has many
benefits, and o ften "later" never arrives.
Co de is no t owned: Agile pro gramming is a team effo rt, so it is never "Jo e's co de" o r "Jim's
co de;" it's "o ur co de." Never fear changing co de created by so meo ne else—it's yo urs to use and
testing will help yo u make sure yo u do n't break it.

Documenting and T esting Python Code


Pytho n co mes with two testing framewo rks built-in. If yo u have been using the J Unit testing framewo rk,
co nsider using the unit t e st mo dule, which is based o n JUnit. Yo u'll pro bably find the do ct e st mo dule
easier to use, because it wo rks by embedding executable Pytho n statements and their expected o utco mes
into the do cstrings that are embedded into all Pytho n co de.

Because the do cstrings are available to the pro gram, testing framewo rk can use info rmatio n embedded in
them to verify that co de is functio ning co rrectly.

To see ho w do ct e st wo rks, create a new pro gram as sho wn:


CODE TO TYPE:

#!/usr/local/bin/python3
"""Demonstrates the doctest module in action."""

def square(x):
'''Returns the square of a numeric argument.

>>> square(3)
9
>>> square(1000)
1000000
>>> square("x")
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
'''
return x*2

def _test():
import doctest, testable
return doctest.testmod(testable)

if __name__ == "__main__":
_test()

Save it in yo ur /pyt ho n1 fo lder as t e st able .py, and run it. This pro gram co ntains a bug: instead o f
returning its argument raised to the seco nd po wer (squared), the square d() functio n returns its argument
multiplied by two . This is an easy mistake to make—we o nly left o ut a single asterisk—but it renders the
functio n inco rrect. Our o utput lo o ks like this:

OBSERVE:

**********************************************************************
File "/users/smiller/python1/testable.py", line 7, in testable.square
Failed example:
square(3)
Expected:
9
Got:
6
**********************************************************************
File "/users/smiller/python1/testable.py", line 9, in testable.square
Failed example:
square(1000)
Expected:
1000000
Got:
2000
**********************************************************************
File "/users/smiller/python1/testable.py", line 11, in testable.square
Failed example:
square("x")
Expected:
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
Got:
'xx'
**********************************************************************
1 items had failures:
3 of 3 in testable.square
***Test Failed*** 3 failures.

When yo u run the pro gram, it calls the _t e st () functio n, which in turn impo rts the do ct e st mo dule. It also
impo rts the pro gram itself, and then finally calls the do ct e st .t e st m o d() functio n with the mo dule as an
argument. This causes the examples in the square () functio n's do cstring to be run, and co mpared with the
o utput listed under each expressio n.

Because the results do n't agree with the predictio ns in the do cstring, the differences are repo rted as erro rs,
and the o utput makes it clear that so mething is wro ng with the pro gram.

Let's fix the erro r by changing the o peratio n in the square () functio n to an exponentiation (feel free to to ss the
wo rd exponentiation into co nversatio n as well, to impress yo ur friends), as sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Demonstrates the doctest module in action."""

def square(x):
'''Returns the effective length of a string
allowing for tabs of a given length tlen.

>>> square(3)
9
>>> square(1000)
1000000
>>> square("x")
Traceback (most recent call last):
...
TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'
'''
return x**2

def _test():
import doctest, testable
return doctest.testmod(testable)

if __name__ == "__main__":
_test()

Save and run it. Yo u get no o utput. That's go o d. The do ctest system is designed to help yo u to detect when
yo ur co de is wo rking inco rrectly and to ho ne in o n the tests that are failing. Yo u'll learn mo re abo ut testing in
o ther co urses, but fo r no w, do ctest is a great place to start. Yo ur do ctests can be integrated into o ther
schemes as yo u mo ve fo rward.

'Keep It Simple, Stupid' (KISS)


The KISS principle (albeit a tad harsh) is o ne that pro grammers find helpful. Of co urse, when yo u're first
learning a language, so metimes no thing seems simple. Breaking up o ur o peratio ns into smaller pieces
helps us understand the big picture. We can see, then, that every pro gram is made up o f a sequence o f
o peratio ns. Each o peratio n is either a basic statement, o r a cho ice between several alternatives, o r a lo o p.
When the user makes a cho ice, the actio n to be taken is a sequence o f o peratio ns—and each o peratio n can
be a basic statement, o r a cho ice between several alternatives, o r a lo o p.

Refactoring
The co ncept o f refacto ring co de can be co mpared to the editio ns o f a textbo o k o ver time. The first editio n
pro vides the main bo dy o f text, while in fo llo wing editio ns, edito rs clean up mistakes, make style changes, o r
add mo re info rmatio n. The co re co ntent o f the bo o k do esn't really change, but the details get better.

When yo u refacto r, yo u aren't adding new functio nality, yo u are making the co de better. Yo u exchange
duplicate co de fo r calls and inheritance where po ssible, fix structural defects, change co de to match co ding
standards (if yo u have them), and mo st impo rtantly, make sure that it passes all of your tests.

If yo u are go ing to refacto r yo ur co de mercilessly, you must have tests. Witho ut sufficient testing, yo u canno t
be certain that yo ur changes have no t bro ken yo ur pro gram.

Let's take so me co de and refacto r it mercilessly. It isn't o ften we strive to be merciless, so let's enjo y this rare
o ppo rtunity! In o ur sample pro gram, we have so me co de that is truly miserable to lo o k at, but it wo rks. Create
the file sho wn belo w:
CODE TO TYPE:

#!/usr/local/bin/python3
"""Demonstrates an opportunity for refactoring."""

def list_multiply(LIST_A, LIST_B):


""" Sums two lists of integers and multiplies them together

>>> list_multiply([3,4],[3,4])
49
>>> list_multiply([1,2,3,4],[10,20])
300
"""

TOTAL_A = 0
for i in LIST_A:
TOTAL_A += i
TOTAL_B = 0
counter = 0
while True:
if counter > len(LIST_B) - 1:
break
TOTAL_B = TOTAL_B + LIST_B[counter]
counter += 1
return TOTAL_A * TOTAL_B

def _test():
import doctest, refactor
return doctest.testmod(refactor)

if __name__ == "__main__":
_test()

Save it in yo ur /pyt ho n1 fo lder as re f act o r.py and run it. Yo u sho uld get no erro rs, but if this co de makes
yo u wince, then yo u are o n track to beco me a go o d Pytho n pro grammer! While the co de is technically co rrect,
it just plain smells. So me variables are upper-case and so me are lo wer-case. Two different lo o ps are used
to do the same actio n o f summing up the integers in two lists, when a simple built-in sum () functio n wo uld
suffice. Can yo u imagine making the necessary alteratio ns if yo u had to add the capability to handle a third o r
fo urth list to yo ur co de? Ouch.

Fo rtunately the co de co mes with do ctests, so yo u can do so me merciless refacto ring. Edit the pro gram as
sho wn:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Refactored version of previous example."""

def list_multiply(a, b):


""" Sums two lists of integers and multiplies them together

>>> list_multiply([3,4],[3,4])
49
>>> list_multiply([1,2,3,4],[10,20])
300
"""

return sum(a) * sum(b)

def _test():
import doctest, refactor
return doctest.testmod(refactor)

if __name__ == "__main__":
_test()

Huge difference! Save and run it again; the do ctest sho uld still wo rk. Refacto ring like this allo ws yo u to make
changes to impro ve yo ur co de witho ut the fear o f breaking it.

And if yo u need to add functio nality, refacto red co de makes it that much easier. Because the co de is generally
simpler (always remember KISS), it will be less difficult to extend it to wo rk with any number o f lists o f integers.
Try this versio n o f the co de, and make sure it passes the tests:

CODE TO TYPE:

#!/usr/local/bin/python3
"""Adding functionality, much easier with refactored code!"""

def list_multiply(*lists):
""" Sums any number of lists of integers and multiplies them together

>>> list_multiply([3,4],[3,4])
49
>>> list_multiply([1,2,3,4],[10,20])
300
>>> list_multiply([4,3,2,1],[50,50],[5,5,5])
15000
"""

total = 1
for l in lists:
total *= sum(l)

return total

def _test():
import doctest, refactor
return doctest.testmod(refactor)

if __name__ == "__main__":
_test()

Go Forth and Code in Python!


Save and run it again; the do ctest sho uld still wo rk. Wo w. Remember when yo u were a to tal Pytho n newbie?
Yo u've co me a lo ng way since Lesso n 1! No w yo u kno w almo st all o f Pytho n's syntax, and yo u're familiar
with the statements that make up the language. Yo u kno w ho w to structure pro grams as sets o f functio ns, and
ho w to deliver functio ns in mo dules that can be re-used by several different pro grams.

Yo u still do n't kno w all there is to kno w abo ut Pytho n (who do es?), but no w yo u're in po sitio n to understand
much o f the Pytho n co de yo u enco unter. Read lo ts o f Pytho n co de; it's a great way to learn mo re abo ut the
language and to increase yo ur understanding o f the library and third-party mo dules it uses. Yo u can practice
do ing just that and applying the Pytho n to o ls yo u've acquired here, in yo ur final pro ject. Thanks so much fo r
taking this Pytho n jo urney with us, it's been a real pleasure wo rking o n it with yo u. Go o d luck!

Copyright © 1998-2014 O'Reilly Media, Inc.

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
See http://creativecommons.org/licenses/by-sa/3.0/legalcode for more information.

You might also like