Vous êtes sur la page 1sur 209

An introduction to Python through

practical examples
Fletcher Heisler
Copyright 2012 RealPython.com
Python and the original Python logo are registered trademarks o the Python !ot"are #oundation$
modiied and used %y RealPython.com "ith permission rom the #oundation.
Real Python
RealPython.com
0) Introduction......................................5
0.1) Why Python?...........................................................5
0.2) Why this book?........................................................6
0.3) How to use this book................................................7
0.4) icense..................................................................!
1) "ettin# $t%rted...................................&
1.1) 'own(o%d Python.....................................................&
1.2) )*en I'+..............................................................&
1.3) Write % Python scri*t..............................................10
1.4) $crew thin#s u*.....................................................12
1.5) $tore % ,%ri%b(e.....................................................14
Inter(ude- e%,e yourse(. he(*.u( notes......16
2) /und%0ent%(s- $trin#s %nd 1ethods........1!
2.1) e%rn to s*e%k in Python..........................................1!
2.2) 1ess %round with your words....................................1&
2.3) 2se ob3ects %nd 0ethods.........................................23
4ssi#n0ent 2.3- Pick %*%rt your user5s in*ut.................................26
3) /und%0ent%(s- Workin# with $trin#s.......27
3.1) 1i6 %nd 0%tch di..erent ob3ects................................27
3.2) $tre%0(ine your *rint st%te0ents...............................2&
3.3) /ind % strin# in % strin#............................................31
4ssi#n0ent 3.3- 7urn your user into % (33t h460r...........................33
4) /und%0ent%(s- /unctions %nd oo*s.......34
4.1) 'o .uturistic %rith0etic...........................................34
4ssi#n0ent 4.1- Per.or0 c%(cu(%tions on user in*ut........................36
4.2) 8re%te your own .unctions........................................37
4ssi#n0ent 4.2- 8on,ert te0*er%tures........................................40
4.3) 9un in circ(es........................................................40
4ssi#n0ent 4.3- 7r%ck your in,est0ents.......................................44
2
Real Python
RealPython.com
Inter(ude- 'ebu# your code.....................46
5) /und%0ent%(s- 8ondition%( (o#ic............51
5.1) 8o0*%re ,%(ues.....................................................51
5.2) 4dd so0e (o#ic.......................................................53
5.3) 8ontro( the .(ow o. your *ro#r%0...............................5!
4ssi#n0ent 5.3- /ind the .%ctors o. % nu0ber................................61
5.4) :re%k out o. the *%ttern..........................................62
5.5) 9eco,er .ro0 errors................................................65
5.6) $i0u(%te e,ents %nd c%(cu(%te *rob%bi(ities..................6!
4ssi#n0ent 5.6.1- $i0u(%te %n e(ection.......................................70
4ssi#n0ent 5.6.2- $i0u(%te % coin toss e6*eri0ent.........................71
6) /und%0ent%(s- ists %nd 'iction%ries......72
6.1) 1%ke %nd u*d%te (ists..............................................72
4ssi#n0ent 6.1- W%6 *oetic......................................................77
6.2) 1%ke *er0%nent (ists..............................................7!
6.3) $tore re(%tionshi*s in diction%ries..............................!0
7) /i(e In*ut %nd )ut*ut.........................!6
7.1) 9e%d %nd write si0*(e .i(es.......................................!6
7.2) 2se 0ore co0*(ic%ted .o(der structures.......................&1
4ssi#n0ent 7.2- 2se *%ttern 0%tchin# to de(ete .i(es......................&7
7.3) 9e%d %nd write 8$; d%t%..........................................&!
4ssi#n0ent 7.3- 8re%te % hi#h scores (ist .ro0 8$; d%t%.................102
Inter(ude- Inst%(( *%ck%#es.....................103
!) Inter%ct with P'/ .i(es......................107
!.1) 9e%d %nd write P'/s..............................................107
!.2) 1%ni*u(%te P'/ .i(es..............................................111
4ssi#n0ent !.2- 4dd % co,er sheet to % P'/ .i(e...........................115
3
Real Python
RealPython.com
&) $< d%t%b%se connections..................116
&.1) 8o00unic%te with d%t%b%ses usin# $<ite..................116
&.2) 2se other $< ,%ri%nts...........................................122
10) Inter%ctin# with the web..................124
10.1) $cr%*e %nd *%rse te6t .ro0 websites........................124
10.2) 2se %n H71 *%rser to scr%*e websites....................131
10.3) Inter%ct with H71 .or0s......................................135
10.4) Inter%ct with websites in re%(=ti0e..........................142
11) $cienti.ic co0*utin# %nd #r%*hin#......145
11.1) 2se >u0Py .or 0%tri6 0%ni*u(%tion.........................145
11.2) 2se 0%t*(ot(ib .or *(ottin# #r%*hs...........................151
4ssi#n0ent 11.2- P(ot % #r%*h .ro0 8$; d%t%...............................164
12) "r%*hic%( 2ser Inter.%ces.................165
12.1) 4dd "2I e(e0ents with +%sy"2I..............................165
4ssi#n0ent 12.1- 2se "2I e(e0ents to he(* % user 0odi.y .i(es........172
12.2) 8re%te "2I %**(ic%tions with 7kinter........................172
4ssi#n0ent 12.2- 9eturn o. the *oet.........................................1!7
13) Web %**(ic%tions............................1!!
13.1) 8re%te % si0*(e web %**(ic%tion.............................1!!
13.2) 8re%te %n inter%cti,e web %**(ic%tion......................1&6
4ssi#n0ent 13.2- 7he *oet #%ins % web *resence.........................201
13.3) Put your web %**(ic%tion on(ine.............................202
/in%( 7hou#hts....................................204
4cknow(ed#e0ents..............................205
4
Real Python
RealPython.com
0) Introduction
hether you&re ne" to programming or a proessional code monkey looking to
di'e into a ne" language$ this %ook "ill teach you all o the practical Python
that you need to get started on pro(ects on your o"n.
)
Real Python emphasi*es real+"orld programming techni,ues$ "hich are illustrated
through interesting$ useul examples. -o matter "hat your ultimate goals may %e$ i you
"ork "ith computer at all$ you "ill soon %e inding endless "ays to impro'e your lie %y
automating tasks and sol'ing pro%lems through Python programs that you create.
0.1. )hy Python/
ython is open+source ree"are$ meaning you can do"nload it or ree and use it
or any purpose. 0t also has a great support community that has %uilt a num%er o
additional ree tools. -eed to "ork "ith P1# documents in Python/ 2here&s a ree
package or that. )ant to collect data rom "e%pages/ -o need to start rom scratch3
P
Python "as %uilt to %e easier to use than other programming languages. 0t&s usually much
easier to read Python code and 45C6 aster to "rite code in Python than in other
languages.
#or instance$ here&s some simple code "ritten in C$ another commonly used
programming language7
#include <stdio.h>
int main ()
{
printf ("Hello, world\n");
}
All the program does is print 6ello$ "orld on the screen. 2hat "as a lot o "ork to
print one phrase3 6ere&s the same code in Python7
print "Hello, world"
5
Real Python
RealPython.com
!imple$ right/ 8asy$ aster$ more reada%le.
At the same time$ Python has all the unctionality o other languages and more. 9ou
might %e surprised ho" many proessional products are %uilt on Python code7 :mail$
:oogle 4aps$ 9ou2u%e$ reddit$ !potiy$ turnta%le.m$ 9ahoo3 :roups$ and the list goes
on; And i it&s po"erul enough or %oth -A!A and the -!A$ it&s good enough or us.
0.2. )hy this %ook/
here are tons o %ooks and tutorials out there or learning Python already.
6o"e'er$ most o the resources out there generally ha'e t"o main pro%lems7 2
1. 2hey aren&t practical.
2. 2hey aren&t interesting.
4ost %ooks are so preoccupied "ith co'ering every last possi%le 'ariation o every
command that it&s easy to get lost in the details. 0n the end$ most o them end up
looking more like the Python documentation pages. 2his is great as reerence material$
%ut it&s a horri%le "ay to learn a programming language. -ot only do you spend most o
your time learning things you&ll ne'er use$ %ut it isn't any fun!
2his %ook is %uilt on the <0=20 principle. )e "ill co'er the commands and techni,ues
used in the vast ma(ority o cases and ocus on ho" to program real+"orld solutions to
pro%lems that ordinary people actually "ant to sol'e.
2his "ay$ 0 guarantee that you "ill7
>earn useul techni,ues much aster
!pend less time struggling "ith unimportant complications
#ind more practical uses or Python in your o"n lie
6a'e more un in the process3
0 you "ant to %ecome a serious$ proessional Python programmer$ this %ook "on&t %e
enough %y itsel ? %ut it "ill still %e the %est starting point. @nce you&'e mastered the
material in this %ook$ you "ill ha'e gained a strong enough oundation that 'enturing
6
Real Python
RealPython.com
out into more ad'anced territory on your o"n "ill %e a %ree*e.
!o di'e in3 >earn to program in a "idely used$ ree language that can do more than you
e'er thought "as possi%le.
0.A. 6o" to use this %ook
or the most part$ you should approach the topics in the irst hal o this %ook in
the same order as they are presented. 2his is less true o the second hal$ "hich
co'ers a num%er o mostly non+o'erlapping topics$ although the chapters are generally
increasing in diiculty throughout. 0 you are a more experienced programmer$ then you
may ind yoursel heading to"ard the %ack o the %ook right a"ay ? %ut don&t neglect
getting a strong oundation in the %asics irst3
#
8ach chapter section is ollo"ed %y re'ie" exercises to help you make sure that you&'e
mastered all the topics co'ered. 2here are also a num%er o assignments$ "hich are
more in'ol'ed and usually re,uire you to tie together a num%er o dierent concepts
rom pre'ious chapters. 2he practice iles that accompany this course also include
solution scripts to the assignments as "ell as some o the trickier exercises ? %ut to get
the most out o them$ you should try your %est to sol'e the assignment pro%lems on your
o"n %eore looking at the example solutions.
0 you get stuck$ you can al"ays log in at RealPython.com and ask or help on the
mem%ers& orumB it&s likely that someone else has already experienced the same
diiculty that you&re encountering and might %e a%le to guide you along.
2his %ook does mo'e ,uickly$ ho"e'er$ so i you&re completely ne" to programming$ you
may "ant to supplement the irst e" chapters "ith additional practice. 0 highly
recommend "orking through the %eginning Python lessons a'aila%le or ree at the
Codecademy site while you make your "ay through the %eginning o this material as the
%est "ay to make sure that you ha'e all the %asics do"n.
#inally$ i you ha'e any ,uestions or eed%ack a%out the course$ you&re al"ays "elcome
to contact me directly.
7
Real Python
RealPython.com
0.C. >icense
his e+%ook is copyrighted and licensed under a Creati'e Commons Attri%ution+
-onCommercial+-o1eri's A.0 5nported >icense. 2his means that you are "elcome
to share this %ook and use it or any non+commercial purposes so long as the entire %ook
remains intact and unaltered. 2hat %eing said$ i you ha'e recei'ed this copy or ree
and ha'e ound it helpul$ 0 "ould 'ery much appreciate i you purchased a copy o your
o"n.
2
2he example Python scripts associated "ith this %ook should %e considered open
content. 2his means that anyone is "elcome to use any portion o the code or any
purpose.
8
Real Python
RealPython.com
1) "ettin# $t%rted
1.1. 1o"nload Python
eore "e can do anything$ you ha'e to do"nload Python. 8'en i you already ha'e
Python on your computer$ make sure that you ha'e the correct 'ersion7 2.7.3 is
the 'ersion used in this %ook and %y most o the rest o the "orld.
D
7here5s % newer ,ersion? Python 3.3? but it c%n5t run code th%t w%s cre%ted with
*re,ious ,ersions o. Python @inc(udin# % (ot o. use.u( %nd i0*ort%nt *%ck%#es
th%t h%,en5t been u*d%ted). 4s % resu(t? Python 3 sti(( h%sn5t c%u#ht on yet.
$ince 0ost o. the code you5(( see e(sewhere wi(( be .ro0 Python 2.7? you shou(d
(e%rn th%t .irst. 7he two ,ersions %re sti(( very si0i(%r? %nd it wi(( t%ke you ,ery (itt(e
ti0e to #et used to the 0inor ch%n#es in Python 3 %.ter you5,e 0%stered Python 2.
A
1%c users- 9ou already ha'e a 'ersion o Python installed %y deault$ %ut it&s not quite
the same as the standard installation. 9ou should still do"nload Python 2.E.A as
directed %elo". @ther"ise$ you might run into pro%lems later "hen trying to install
some additional unctionality in Python or running code that in'ol'es graphics "indo"s.
inu6 users- 9ou might already ha'e Python 2.E.A installed %y deault. @pen your
2erminal application and type pthon !!"ersion to ind out. 0 you ha'e 2.E.1 or
2.E.2$ you should go ahead and update to the latest 'ersion.
0 you need to$ go to http7==""".python.org=do"nload= to do"nload Python 2.7.3 or
your operating system and install the program.
1.2. @pen 01>8
e&ll %e using 01>8 FInteracti'e 'e'eopment +n'ironment. to "rite our Python
code. 01>8 is a simple editing program that comes automatically installed "ith )
9
Real Python
RealPython.com
Python on )indo"s and 4ac$ and it "ill make our li'es much easier "hile "e&re coding.
9ou could "rite Python scripts in any program rom a %asic text editor to a 'ery complex
de'elopment en'ironment Fand many proessional coders use more ad'anced setups.$
%ut 01>8 is simple to use and "ill easily pro'ide all the unctionality "e need.
Windows- :o to your start menu and click on 01>8 FPython :50. rom the Python
2.E program older to open 01>8. 9ou can also type 01>8 into the search %ar.
)$ B- :o to your Applications older and click on 01>8 rom the Python 2.E older
to start running 01>8. Alternati'ely$ you can type #$%& F"ithout ,uotes. into your
2erminal "indo" to launch 01>8.
inu6- 0 recommend that you install 01>8 to ollo" along "ith this course. 9ou could use
Gim or 8macs$ %ut they "ill not ha'e the same %uilt+in de%ugging eatures. 2o install
01>8 "ith admin pri'ileges7
@n 5%untu=1e%ian$ type7 sudo apt!'et install idle
@n #edora=Red 6at=R68>=Cent@!$ type7 sudo um install pthon!tools
@n !5!8$ you can search or 01>8 'ia install sot"are through 9a!2.
@pening 01>8$ you "ill see a %rie description o Python$ ollo"ed %y a prompt7
>>>
)e&re ready to program3
1.A. )rite a Python script
he "indo" "e ha'e open at the moment is 01>8&s interactive windowB usually this
"indo" "ill (ust sho" us results "hen "e run programs that "e&'e "ritten$ %ut "e
can also enter Python code into this "indo" directly. :o ahead and try typing some
%asic math into the interacti'e "indo" at the prompt ? "hen you hit enter$ it should
e'aluate your calculation$ display the result and prompt you or more input7
2
>>> ()(
*
>>>
10
Real Python
RealPython.com
>et&s try out some actual code. 2he standard program to display 6ello$ "orld on the
screen is just that simple in Python. 2ell the interacti'e "indo" to print the phrase %y
using the print command like so7
>>> print "Hello, world"
Hello, world
>>>
I. you w%nt to #et to *re,ious (ines you5,e ty*ed into the inter%cti,e window
without ty*in# the0 out %#%in or co*yin# %nd *%stin#? you c%n use the *%ir o.
shortcut keys A>2HP @or on % 1%c? C2R>HP). +%ch ti0e you hit A>2HP? I'+ wi(( .i((
in the *re,ious (ine o. code .or you. Cou c%n then ty*e A>2H- @)$ B- C2R>H-) to
cyc(e b%ck to the ne6t 0ost recent (ine o. code.
A
-ormally "e "ill "ant to run more than one line o code at a time and sa'e our "ork so
that "e can return to it later. 2o do this$ "e need to create a ne" script.
#rom the menu %ar$ choose #ile -e" )indo" to generate a %lank script. 9ou should
rearrange this "indo" and your interacti'e results "indo" so that you can see them
%oth at the same time.
2ype the same line o code as %eore$ %ut put it in your ne" script7
print "Hello, world"
I. you 3ust co*y %nd *%ste .ro0 the inter%cti,e window into the scri*t? 0%ke
sure you ne,er inc(ude the DEEE F *%rt o. the (ine. 7h%t5s 3ust the window
%skin# .or your in*utG it isn5t *%rt o. the %ctu%( code. A
0n order to run this script$ "e need to sa'e it irst. Choose #ile !a'e As;$ name the
ile helloI"orld.py F"ithout the ,uotation marks. and sa'e it some"here you&ll %e
a%le to ind it later. 2he .py extension lets 01>8 kno" that it&s a Python script.
>otice th%t print %nd "Hello, world" %**e%r in di..erent co(ors to (et you
know th%t print is % co00%nd %nd "Hello, world" is % strin# o. ch%r%cters.
I. you s%,e the scri*t %s so0ethin# other th%n % D.pF .i(e @or i. you don5t
inc(ude the D.pF e6tension? this co(orin# wi(( dis%**e%r %nd e,erythin# wi(( turn
b(%ck? (ettin# you know th%t the .i(e is no (on#er reco#niHed %s % Python scri*t.
A
-o" that the script has %een sa'ed$ all "e ha'e to do in order to run the program is to
11
Real Python
RealPython.com
select Run Run 4odule rom the script "indo" For hit #J.$ and "e&ll see the result
appear in the interacti'e results "indo" (ust like it did %eore7
>>>
Hello, world
>>>
2o open and edit a program later on$ (ust open up 01>8 again and select #ile @pen;$
then %ro"se to and select the script to open it in a ne" script "indo".
inu6 users- Read this o'er'ie" irst Fespecially section 2.2.2. i you "ant to %e a%le to
run Python scripts outside o the editor.
Cou 0i#ht see so0ethin# (ike the .o((owin# (ine in the inter%cti,e window when
you run or re=run % scri*t-
>>> ++++++++++++++++++++++++++ ,&-./,. ++++++++++++++++++++++++++
7his is 3ust I'+5s w%y o. (ettin# you know th%t e,erythin# %.ter this (ine is the resu(t
o. the new scri*t th%t you %re 3ust %bout to run. )therwise? i. you r%n one scri*t
%.ter %nother @or one scri*t again %.ter itse(.)? it 0i#ht not be c(e%r wh%t out*ut
be(on#s to which run o. which scri*t.
A
1.C. !cre" things up
'ery%ody makes mistakes ? especially "hile programming. 0n case you ha'en&t
made any mistakes yet$ let&s get a head start on that and mess something up on
purpose to see "hat happens.
8
5sing 01>8$ there are t"o main types o errors you&ll experience. 2he most common is a
syntax error$ "hich usually means that you&'e typed something incorrectly.
>et&s try changing the contents o the script to7
print "Hello, world
6ere "e&'e (ust remo'ed the ending ,uotation mark$ "hich is o course a mistake ? no"
12
Real Python
RealPython.com
Python "on&t %e a%le to tell "here the string o text ends. !a'e your script and try
running it. )hat happens/
;9ou can&t run it3 01>8 is smart enough to reali*e there&s an error in your code$ and it
stops you rom e'en trying to run the %uggy program. 0n this case$ it says7 8@> "hile
scanning string literal. 8@> stands or 8nd @ >ine$ meaning that Python got all the
"ay to the end o the line and ne'er ound the end o your string o text.
01>8 e'en highlights the place "here the error occurred using a dierent color and
mo'es your cursor to the location o the error. 6andy3
2he other sort o error that you&ll experience is the type that 01>8 can't catch or you
until your code is already running. 2ry changing the code in your script to7
print Hello, world
-o" "e&'e entirely remo'ed the ,uotation marks rom the phrase. -otice ho" the text
changes color "hen "e do that/ 01>8 is letting us kno" that this is no longer a string o
text that "e "ill %e printing$ %ut something else. )hat is our code doing no"/ )ell$
sa'e the script and try to run it;
2he interacti'e "indo" "ill pop up "ith ugly red text that looks something like this7
>>>
.race0ac1 (most recent call last)2
3ile "4path to our script5\hello world.p", line (, in <module>
print Hello, world
6ame&rror2 name 7Hello7 is not defined
>>>
!o "hat happened/ Python is telling us a e" things7
An error occurred ? speciically$ Python calls it a 6ame&rror
2he error happened on line ( o the script
2he line that generated the error "as7 print Hello, world
2he speciic error "as7 name 7Hello7 is not defined
2his is called a run+time error since it only occurs once the programming is already
running. !ince "e didn&t put ,uotes around Hello, world$ Python didn&t kno" that this
13
Real Python
RealPython.com
"as text "e "anted to print. 0nstead$ it thought "e "ere reerring to t"o 'aria%les that
"e "anted to print. 2he irst 'aria%le it tried to print "as something named 6ello +
%ut since "e hadn&t deined a 'aria%le named 6ello$ our program crashed.
9e,iew e6ercises-
)rite a script that 01>8 "on&t let you run %ecause it has a syntax error
)rite a script that "ill only crash your program once it is already running
%ecause it has a run-time error
1.J. !tore a 'aria%le
>et&s try "riting a dierent 'ersion o the pre'ious script. 6ere "e&ll use a 'aria%le to
store our text %eore printing the text to the screen7
phrase + "Hello, world"
print phrase
-otice the dierence in "here the ,uotation marks go rom our pre'ious script. )e are
creating a 'aria%le named phrase and assigning it the 'alue o the string o text
"Hello, world". )e then print the phrase to the screen. 2ry sa'ing this script and
running these t"o linesB you should see the same output as %eore7
>>>
Hello, world
>>>
-otice that in our script "e didn&t say7
print "phrase"
5sing ,uotes here "ould (ust print the "ord phrase instead o printing the contents o
the 'aria%le named phrase.
Phr%ses th%t %**e%r in Iuot%tion 0%rks %re c%((ed strings. We c%(( the0 strin#s
bec%use they5re 3ust th%t J strin#s o. ch%r%cters. 4 strin# is one o. the 0ost b%sic
bui(din# b(ocks o. %ny *ro#r%00in# (%n#u%#e? %nd we5(( use strin#s % (ot o,er the
ne6t .ew ch%*ters.
A
14
Real Python
RealPython.com
)e also didn&t type our code like this7
8hrase + "Hello, world"
print phrase
Can you spot the dierence/ 0n this example$ the irst line deines the 'aria%le 8hrase
"ith a capital P at the %eginning$ %ut the second line prints out the 'aria%le phrase.
$ince Python is c%se=sensiti,e? the ,%ri%b(es 8hrase %nd phrase %re entire(y
di..erent thin#s. ikewise? co00%nds st%rt with (owerc%se (ettersG we c%n te((
Python to print? but it wou(dn5t know how to 8rint. Kee* this i0*ort%nt
distinction in 0indA
A
)hen you run into trou%le "ith the sample code$ %e sure to dou%le+check that e'ery
character in your code Foten including spaces. exactly matches the examples.
Computers don&t ha'e any common sense to interpret "hat you meant to say$ so %eing
almost correct still "on&t get a computer to do the right thing3
9e,iew e6ercises-
5sing the interacti'e "indo"$ display some text on the screen %y using print
5sing the interacti'e "indo"$ display a string o text %y sa'ing the string to a
'aria%le$ then printing the contents o that 'aria%le
1o each o the irst t"o exercises again %y irst sa'ing your code in a script
and then running the script
15
Real Python
RealPython.com
Interlude- e%,e yourse(. he(*.u( notes
s you start to "rite more complicated scripts$ you&ll start to ind yoursel going
%ack to parts o your code ater you&'e "ritten them and thinking$ "hat the heck
"as that supposed to do/
A
2o a'oid these moments$ you can lea'e yoursel notes in your codeB they don&t aect the
"ay the script runs at all$ %ut they help to document "hat&s supposed to %e happening.
2hese notes are reerred to as comments$ and in Python you start a comment "ith a
pound F#. sign.
1
@ur irst script could ha'e looked like this7
# .his is m first script9
phrase + "Hello, world."
print phrase # this line displas "Hello, world"
2he irst line doesn&t do anything$ %ecause it starts "ith a #. 2his tells Python to ignore
the line completely %ecause it&s (ust a note or you.
>ike"ise$ Python ignores the comment on the last lineB it "ill still print phrase$ %ut
e'erything starting "ith the # is simply a comment.
@ course$ you can still use a K sym%ol inside o a string. #or instance$ Python "on&t
mistake the ollo"ing or the start o a comment7
print "#("
0 you ha'e a lot to say$ you can also create comments that span o'er multiple lines %y
using a series o three single ,uotes F777. or three dou%le ,uotes F""". "ithout any
spaces %et"een them. @nce you do that$ everything ater the 777 or """ %ecomes a
comment until you close the comment "ith a matching 777 or """. #or instance$ i you
"ere eeling excessi'ely 'er%ose$ our irst script could ha'e looked like this7
777 .his is m first script.
#t prints the phrase "Hello, world."
.he comments are lon'er than the script9 777
phrase + "Hello, world."
print phrase
""" .he line a0o"e displas "Hello, world" """
1 2he # sym%ol is alternately reerred to as a num%er sign$ a hash$ a crosshatch$ or an octothorp. Really.
16
Real Python
RealPython.com
2he irst three lines are no" all one comment$ since they all %et"een pairs o 777. 9ou
can&t add a multi+line comment at the end o a line o code like "ith the K 'ersion$
"hich is "hy the last comment is on its o"n separate line. F)e&ll see "hy in the next
chapter..
Desides lea'ing yoursel notes$ another common use o comments is to comment out
code "hile you&re testing parts o a scripts to temporarily stop that part o the code
rom running. 0n other "ords$ adding a K at the %eginning o a line o code is an easy
"ay to make sure that you don&t actually use that line$ e'en though you might "ant to
keep it and use it later.
17
Real Python
RealPython.com
2) /und%0ent%(s- $trin#s %nd 1ethods
2.1. >earn to speak in Python
s "e&'e already seen$ you "rite strings in Python %y surrounding them "ith ,uotes.
9ou can use single ,uotes or dou%le ,uotes$ as long as you&re consistent or any
one string. All o the ollo"ing lines create string 'aria%les Fcalled string literals %ecause
"e&'e literally "ritten out exactly ho" they look.7
A
phrase + 7Hello, world.7
m-trin' + ":e7re #(9"
strin'6um0er + "(*;<"
con"ersation + 7# said, "8ut it o"er 0 the llama."7
!trings can include any characters + letters$ num%ers and sym%ols. 9ou can see the
%eneit o using either single or dou%le ,uotes in the last string exampleB since "e used
single ,uotes$ "e didn&t ha'e any trou%le putting dou%le ,uotes inside the string. F2here
are other "ays to do this$ %ut "e&ll get to those later in the chapter..
)e can also create really long strings that take up multiple lines %y using three single
,uotes For three dou%le ,uotes.$ like this7
lon'-trin' + 777.his is a
strin' that spans across multiple lines777
lon'-trin' + """.his is a new strin'
that spans across two lines"""
6ere "e assigned one 'alue to the 'aria%le lon'-trin'$ then "e o'er"rote that 'alue
"ith a ne" string literal. 2ry putting this in a script and then print the 'aria%le
lon'-trin'B you&ll see that it displays the string on t"o separate lines. 9ou can also
see no" "hy you can&t ha'e multi+line comments appear on the same line as actual
codeB Python "ouldn&t %e a%le to tell the dierence %et"een these and actual string
'aria%les3
@ne last thing a%out strings7 i you "ant to "rite out a really long string$ %ut you don't
18
Real Python
RealPython.com
"ant it to appear on multiple lines$ you can use a %ackslash like this "hen "riting it out7
m%on'-trin' + "Here7s a strin' that # want to write \
across multiple lines since it is lon'."
-ormally Python "ould get to the end o the irst line and get angry "ith you %ecause
you hadn&t closed the string "ith a matching single ,uote. Dut %ecause there&s a
%ackslash at the end$ you can (ust keep "riting the same string on the next line. 2his is
dierent rom the last example since the actual string isn&t stored on multiple lines this
time$ thereore the string gets displayed on a single line "ithout the %reak7
>>> print m%on'-trin'
Here7s a strin' that # want to write across multiple lines since it is lon'.
>>>
4s we5,e %(re%dy discussed? Python is c%se=sensiti,e. :y con,ention? Python5s
bui(t=in .unctions %nd 0ethods use e6c(usi,e(y (ower=c%se. $ince % sin#(e
,%ri%b(e n%0e c%n5t inc(ude %ny s*%ces or d%shes? when *ro#r%00ers w%nt to
#i,e descri*ti,e n%0es to ,%ri%b(es? one w%y o. 0%kin# the0 e%si(y re%d%b(e is to
use camelCase @i.e.? m%on'-trin')? so c%((ed bec%use o. the u**er=c%se Dhu0*sF
in the 0idd(e o. ter0s. We5(( 0ost(y stick to c%0e(8%se in this course? but %nother
*o*u(%r 0ethod is to se*%r%te words usin# underscores @i.e.? m=lon'=strin').
A
9e,iew e6ercises-
print a string that uses dou%le ,uotation marks inside the string
print a string that uses an apostrophe Fsingle ,uote. inside the string
print a string that spans across multiple lines
print a one+line string that you ha'e "ritten out on multiple lines
2.2. 4ess around "ith your "ords
ython has some %uilt+in unctionality that "e can use to modiy our strings or get
more inormation a%out them. #or instance$ there&s a length unction P
19
Real Python
RealPython.com
Fa%%re'iated as len in Python. that can tell you the length o all sorts o things$
including strings. 2ry typing these lines into the interacti'e "indo"7
>>> m-trin' + "a0c"
>>> len'th>f-trin' + len(m-trin')
>>> print len'th>f-trin'
;
>>>
#irst "e created a string named m-trin'. 2hen "e used the len() unction on
m-trin' to calculate its length$ "hich "e store in the ne" 'aria%le "e named
len'th>f-trin'. )e ha'e to gi'e the len() unction some input or its calculation$
"hich "e do %y placing m-trin' ater it in the parentheses ? you&ll see more on
exactly ho" this "orks later. 2he length o 7a0c7 is (ust the total num%er o characters
in it$ A$ "hich "e then print to the screen.
)e can com%ine strings together as "ell7
>>> strin'( + "a0ra"
>>> strin'* + "cada0ra"
>>> ma'ic-trin' + strin'( ) strin'*
>>> print ma'ic-trin'
a0racada0ra
>>>
@r e'en like this$ "ithout creating any ne" 'aria%les7
>>> print "a0ra" ) "ca" ) "da0ra"
a0racada0ra
>>>
0n programming$ "hen "e add strings together like this$ "e say that "e concatenate
them.
Cou5(( see % (ot o. it%(iciHed ter0s throu#hout the .irst .ew ch%*ters o. this book.
'on5t worry %bout 0e0oriHin# %(( o. the0 i. they5re un.%0i(i%rA Cou don5t need
%ny .%ncy 3%r#on to *ro#r%0 we((? but it5s #ood to be %w%re o. the correct
ter0ino(o#y. Pro#r%00ers tend to throw %round technic%( ter0s % (otG not on(y does
it %((ow .or 0ore *recise co00unic%tion? but it he(*s 0%ke si0*(e conce*ts sound
0ore i0*ressi,e.
A
)hen "e "ant to com%ine many strings at once$ "e can also use commas to separate
them. 2his "ill automatically add spaces %et"een the strings$ like so7
20
Real Python
RealPython.com
>>> print "a0ra", "ca", "da0ra"
a0ra ca da0ra
>>>
@ course$ the commas ha'e to go outside o the ,uotation marks$ since other"ise the
commas "ould %ecome part o the actual strings themsel'es.
!ince a string is (ust a se,uence o characters$ "e should %e a%le to access each
character indi'idually as "ell. )e can do this %y using s,uare %rackets ater the string$
like this7
>>> fla"or + "0irthda ca1e"
>>> print fla"or4;5
t
>>>
)ait$ %ut t is the ourth character3 )ell$ not in the programming "orld; 0n Python
Fand most other programming languages.$ we st%rt countin# %t 0. !o in this case$ % is
the *eroth character o the string 0irthda ca1e. 2his makes i the first
character$ r the second$ and t the third.
0 "e "anted to display "hat "e "ould normally tend to think o as the irst
character$ "e "ould actually need to print the 0
th
character7
>>> print fla"or4?5
0
>>>
:e c%re.u( when you5re usin#-
= *%rentheses- ( )
= sIu%re br%ckets- [ ]
= cur(y br%ces- { }
7hese all 0e%n di..erent thin#s to Python? so you c%n ne,er switch one .or %nother.
We5(( see 0ore e6%0*(es o. when e%ch one is used @%nd we h%,en5t seen {} yet)?
but kee* in 0ind th%t they5re %(( used di..erent(y.
A
2he num%er that "e assigned to each character&s position is called the index or subscript
num%er$ and Python thinks o the string like this7
@haracter2 b i r t h d ...
#ndeA B -u0script #2 ? ( * ; < C ...
21
Real Python
RealPython.com
)e can get a particular section out o the string as "ell$ %y using s,uare %rackets and
speciying the range o characters that "e "ant. )e do this %y putting a colon %et"een
the t"o su%script num%ers$ like so7
>>> fla"or + "0irthda ca1e"
>>> print fla"or4?2;5
0ir
>>>
6ere "e told Python to sho" us only the irst three characters o our string$ starting at
the 0
th
character and going up until F%ut not including. the A
rd
character. 2he num%er
%eore the colon tells Python the irst character "e "ant to include$ "hile the num%er
ater the colon says that "e "ant to stop just before that character.
0 "e use the colon in the %rackets %ut omit one o the num%ers in a range$ Python "ill
assume that "e meant to go all the "ay to the end o the string in that direction7
>>> fla"or + "0irthda ca1e"
>>> print fla"or42C5
0irth
>>> print fla"or4C25
da ca1e
>>> print fla"or425
0irthda ca1e
>>>
2he "ay "e&re using %rackets ater the string is reerred to as subscripting or indexing
since it uses the index num%ers o the string&s characters.
Python strin#s %re immutable? 0e%nin# th%t they c%n5t be ch%n#ed once you5,e
cre%ted the0. /or inst%nce? see wh%t h%**ens when you try to %ssi#n % new
(etter to one *%rticu(%r ch%r%cter o. % strin#-
m-trin' + "'oal"
m-trin'4?5 + "f" # this won7t wor19
Inste%d? we wou(d h%,e to cre%te %n entire(y new strin# @%(thou#h we c%n sti(( #i,e
m-trin' th%t new ,%(ue)-
m-trin' + "'oal"
m-trin' + "f" ) m-trin'4(25
In the .irst e6%0*(e? we were tryin# to ch%n#e part o. m-trin' %nd kee* the rest
o. it unch%n#ed? which doesn5t work. In the second e6%0*(e? we cre%ted % new
strin# by %ddin# two strin#s to#ether? one o. which w%s % *%rt o. m-trin'G then we
took th%t new strin# %nd co0*(ete(y re%ssi#ned m-trin' to this new ,%(ue.
A
22
Real Python
RealPython.com
9e,iew e6ercises-
Create a string and print its length using the len() unction
Create t"o strings$ concatenate them Fadd them next to each other. and
print the com%ination o the t"o strings
Create t"o string 'aria%les$ then print one o them ater the other F"ith a
space added in %et"een. using a comma in your print statement
print the string Din' %y using su%scripting and index num%ers on the
string 0aDin'a to speciy the correct range o characters
2.A. 5se o%(ects and methods
he Python programming language is an example o Object-Oriented Programming
FOOP.$ "hich means that "e store our inormation in objects. 0n Python$ a string
is an example o an o%(ect.
2
!trings are 'ery simple o%(ects + they only hold one piece o
inormation Ftheir 'alue. ? %ut a single o%(ect can %e 'ery complex. @%(ects can e'en
hold other o%(ects inside o them. 2his helps to gi'e structure and organi*ation to our
programming.
2
#or instance$ i "e "anted to model a car$ "e "ould Fhypothetically. create a Car o%(ect
that holds lots o descripti'e inormation a%out the car$ called its attributes. 0t "ould
ha'e a color attri%ute$ a model attri%ute$ etc.$ and each o these attri%utes "ould hold
one piece o descripti'e inormation a%out the car. 0t "ould also include dierent
o%(ects like 2ires$ 1oors$ and an 8ngine that all ha'e their o"n attri%utes as "ell.
1ierent o%(ects also ha'e dierent capa%ilities$ called methods. #or instance$ our Car
o%(ect might ha'e a dri"e() method and a par1() method. !ince these methods
belong to the car$ "e use them "ith dot notation %y putting them next to the o%(ect
2 !trings are actually called str o%(ects in Python$ %ecause programmers are la*y and don&t "ant to type
more than is a%solutely necessary. Dut you&ll al"ays hear string o%(ects reerred to as (ust strings.
23
Real Python
RealPython.com
and ater a period$ like this7
car.par1()
4ethods are ollo"ed %y parentheses$ %ecause sometimes methods use input. #or
instance$ i "e "anted to dri'e the car o%(ect a distance o J0$ "e "ould place that
input o J0 in the parentheses o the dri'e method7
car.dri"e(C?)
2here are certain methods that %elong to string o%(ects as "ell. #or instance$ there is a
string method called upper() that creates an upper+case 'ersion o the string.
F>ike"ise$ there is a corresponding method lower() that creates a lo"er+case 'ersion
o a string.. >et&s gi'e it a try in the interacti'e "indo"7
>>> loudEoice + "@an ou hear me etF"
>>> print loudEoice.upper()
@/6 G>H H&/, I& G&.F
>>>
)e created a string loudEoice$ then "e called its upper() method to return the
upper+case 'ersion o the string$ "hich "e print to the screen.
1ethods %re 3ust .unctions th%t belong to ob3ects. We %(re%dy s%w %n e6%0*(e
o. % #ener%(=*ur*ose .unction? the len() .unction? which c%n be used to te(( us
the (en#th o. 0%ny different ty*es o. ob3ects? inc(udin# strin#s. 7his is why we
use the (en#th .unction di..erent(y? by on(y s%yin#-
len(loudEoice)
1e%nwhi(e? we use dot not%tion to c%(( 0ethods th%t belong to %n ob3ect? (ike when
we c%(( the upper() 0ethod th%t be(on#s to the strin# loudEoice-
loudEoice.upper()
A
>et&s make things more interacti'e %y introducing one more general unction. )e&re
going to get some input rom the user o our program %y using the unction
raw=input(). 2he input that "e pass to this unction is the text that "e "ant it to
display as a promptB "hat the unction actually does is to recei'e additional input rom
the user. 2ry running the ollo"ing script7
24
Real Python
RealPython.com
user#nput + raw=input("He, what7s upF ")
print "Gou said2", user#nput
)hen you run this$ instead o the program ending and taking you %ack to the >>>
prompt$ you&ll (ust see7
>>>
He, what7s upF
..."ith a %linking cursor. 0t&s "aiting or you to ans"er3
A
8nter a response$ and it "ill
store that ans"er in the user#nput string and display it %ack7
>>>
He, what7s upF Iind our own 0usiness.
Gou said2 Iind our own 0usiness.
>>>
-o" "e&ll com%ine the unction raw=input() "ith the string method upper() in a
script to modiy the user&s input7
response + raw=input(":hat should # shoutF ")
response + response.upper()
print ":ell, if ou insist...", response
Calling response.upper() didn&t change anything a%out our response string. 2he
upper() method only returned the upper+case 'ersion o the string to us$ and it "as up
to us to do something "ith it. 2hat&s "hy "e had to set response +
response.upper() in order to reassign the 'alue o the string response to its o"n
upper+case e,ui'alent.
In I'+? i. you w%nt to see %(( the 0ethods c%n %**(y to % *%rticu(%r kind o.
ob3ect? you c%n ty*e th%t ob3ect out .o((owed by % *eriod %nd then hit
C2R>H!PAC8. /or inst%nce? .irst de.ine % strin# ob3ect in the inter%cti,e window-
>>> m-trin' + "1erfuffle"
>ow ty*e the n%0e o. your strin# in %#%in? .o((owed by % *eriod @without hittin#
enter)-
>>> m-trin'.
When you hit C2R>H!PAC8? you5(( see % (ist o. 0ethod o*tions th%t you c%n scro((
throu#h with the %rrow keys. $trin#s h%,e (ots o. 0ethodsA
A
A -otice that "e added a space at the end o the string "e supplied to raw=input(). 2his isn&t
mandatory$ %ut that "ay the user&s input doesn&t sho" up on the screen right next to our prompt.
25
Real Python
RealPython.com
4 re(%ted shortcut in I'+ is the %bi(ity to .i(( in te6t %uto0%tic%((y without h%,in# to
ty*e in (on# n%0es by hittin# ./J. /or inst%nce? i. you on(y ty*e in Dm-trin'.uF
%nd then hit the ./J key? I'+ wi(( %uto0%tic%((y .i(( in Dm-trin'.upperF bec%use
there is on(y one 0ethod be(on#in# to m-trin' th%t be#ins with % DuF. In .%ct? this
e,en works with ,%ri%b(e n%0esG try ty*in# in 3ust the .irst .ew (etters o.
Dm-trin'F %nd? %ssu0in# you don5t h%,e %ny other n%0es %(re%dy de.ined th%t
sh%re those .irst (etters? I'+ wi(( %uto0%tic%((y co0*(ete the n%0e Dm-trin'F .or
you when you hit the ./J key.
9e,iew e6ercises-
)rite a script that takes input rom the user and displays that input %ack
5se C2R>H!PAC8 to 'ie" all the methods o a string o%(ect$ then "rite a
script that returns the lo"er+case 'ersion o a string
Assignment 2.3: Pick apart your user's input
Write % scri*t n%0ed D.irstL(etter.*yF th%t .irst *ro0*ts the user .or in*ut by
usin# the strin#-
.ell me our password2
7he scri*t shou(d then deter0ine the .irst (etter o. the user5s in*ut? con,ert th%t
(etter to u**er=c%se? %nd dis*(%y it b%ck. 4s %n e6%0*(e? i. the user in*ut w%s DnoF
then the *ro#r%0 shou(d res*ond (ike this-
.he first letter ou entered was2 6
/or now? it5s ok%y i. your *ro#r%0 cr%shes when the user enters nothin# %s in*ut
@3ust hittin# 8-28R inste%d). We5(( .ind out % cou*(e w%ys you cou(d de%( with this
situ%tion in ch%*ter 5.
?
26
Real Python
RealPython.com
3) /und%0ent%(s- Workin# with $trin#s
A.1. 4ix and match dierent o%(ects
e&'e seen that string o%(ects can hold any characters$ including num%ers.
6o"e'er$ don&t conuse string num%ers "ith actual num%ers3 #or instance$ try
this %it o code out in the interacti'e "indo"7
)
>>> m6um0er + "*"
>>> print m6um0er ) m6um0er
**
>>>
)e can add strings together$ %ut "e&re (ust concatenating them ? "e&re not actually
adding the t"o ,uantities together. Python "ill e'en let us multiply strings as "ell7
>>> m6um0er + "(*"
>>> print m6um0er K ;
(*(*(*
>>>
0 "e "ant to change a string o%(ect into a num%er$ there are t"o general unctions "e
commonly use7 int() and float().
int() stands or integer and con'erts o%(ects into "hole num%ers$ "hile loat()
stands or loating+point num%er and con'erts o%(ects into num%ers that ha'e decimal
points. #or instance$ "e could change the string m6um0er into an integer or a loat
like so7
>>> m6um0er + "(*"
>>> print int(m6um0er)
(*
>>> print float(m6um0er)
(*.?
>>>
-otice ho" the second 'ersion added a decimal point$ %ecause the loating+point
num%er has more precision Fmore decimal places.. #or this reason$ "e couldn&t change a
27
Real Python
RealPython.com
string that looks like a loating+point num%er into an integer %ecause "e "ould ha'e to
lose e'erything ater the decimal7
>>> m6um0er + "(*.?"
>>> print int(m6um0er)
.race0ac1 (most recent call last)2
3ile "<pshell#(>", line (, in <module>
print int(m6um0er)
Ealue&rror2 in"alid literal for int() with 0ase (?2 7(*.?7
>>>
8'en though the extra 0 ater the decimal place doesn&t actually add any 'alue to our
num%er$ Python is telling us that "e can&t (ust change 12.0 into 12 ? %ecause "e might
lose part o the num%er.
0 you "ant to turn a num%er into a string$ o course there&s a unction or that$ too ? the
str() unction. @ne place "here this %ecomes important to do is "hen "e "ant to add
string and num%ers together. #or instance$ "e can&t (ust concatenate the t"o dierent
types o o%(ects like this7
>>> print "(" ) (
.race0ac1 (most recent call last)2
3ile "<pshell#(>", line (, in <module>
print "(" ) (
.pe&rror2 cannot concatenate 7str7 and 7int7 o0Lects
>>>
Python doesn&t kno" ho" to add dierent types o o%(ects together ? "e could ha'e
meant the ans"er to %e 2 or 11 depending on "hether "e had strings or integers. 0
"e "anted to put the t"o num%ers side+%y+side as one string$ "e "ould ha'e to convert
the integer into a string7
>>> print "(" ) str(()
((
>>>
0nteger and string are called types o o%(ects. Al"ays keep in mind that you might
get unexpected results i you mix types incorrectly or i you use one type o o%(ect "hen
you really meant to use another.
28
Real Python
RealPython.com
9e,iew e6ercises-
Create a string o%(ect that stores an integer as its 'alue$ then con'ert that
string into an actual integer o%(ect using int()B test that your ne" o%(ect is
really a num%er %y multiplying it %y another num%er and displaying the result
Repeat the pre'ious exercise$ %ut use a loating+point num%er and float()
Create a string o%(ect and an integer o%(ect$ then display them side+%y+side
"ith a single print statement %y using the str() unction
A.2. !treamline your print statements
uppose "e ha'e a string o%(ect$ name + "Maphod"$ and t"o integer o%(ects$
numHeads + * and num/rms + ;. )e "ant to display them in the ollo"ing line7 !
Maphod has * heads and ; arms
)e&'e already seen t"o "ays o doing this. 2he irst "ould in'ol'e using commas to
insert spaces %et"een each piece o our statement7
print name, "has", str(numHeads), "heads and", str(num/rms), "arms"
Another "ay "e could do this is %y concatenating the strings "ith the ) operator7
print name)" has ")str(numHeads))" heads and ")str(num/rms))" arms"
0 didn&t use spaces around all the ) signs (ust so that the t"o expressions "ould line up$
%ut it&s pretty diicult to read either "ay. 2rying to keep track o "hat goes inside or
outside o the ,uotes can %e a huge pain$ "hich is "hy there&s a third "ay o com%ining
strings together7 using the string format() method.
2he simplest 'ersion o the format() method "ould look like this or our example7
print "{} has {} heads and {} arms".format(name, numHeads, num/rms)
2he pairs o empty curly %races F{} "ithout any space in %et"een the t"o. ser'e as
29
Real Python
RealPython.com
place+holders or the 'aria%les that "e "ant to place inside the string. )e then pass
these 'aria%les into our string as inputs o the string&s format() method$ in order. 2he
really great part a%out this techni,ue is that "e didn&t e'en ha'e to change our integers
into string types irst ? the format() method did that or us automatically.
Although it&s less re,uently used$ "e can also use index num%ers inside the curly %races
to do the same thing7
print "{?} has {(} heads and {*} arms".format(name, numHeads, num/rms)
6ere "e&'e inserted name into the {?} place+holder %ecause it is the 0
th
input listed$
and so on. !ince "e num%ered our place+holders$ "e don&t e'en ha'e to pro'ide the
inputs in the same order. #or instance$ this line "ould also do the exact same thing7
print "{*} has {(} heads and {?} arms".format(num/rms, numHeads, name)
2his style o ormatting can %e helpul i you "ant to repeat an input multiple times
"ithin a string$ i.e.7
>>> print "{?} has {?} heads and {?} arms".format(name)
Maphod has Maphod heads and Maphod arms.
>>>
#inally$ i "e didn&t "ant to create three separate o%(ects ahead o time$ one last "ay o
using format() "ould %e to name and assign ne" o%(ects inside the format()
method$ like so7
print "{name} has {numHeads} heads and {num/rms} arms".format(name+"Maphod",
numHeads+*, num/rms+;)
2hese input 'aria%les don&t necessarily ha'e to %e listed in the same order since "e&'e
called on each o them %y name inside the string.
7here is %(so %nother w%y to print .or0%tted strin#s- usin# the N o*er%tor. Cou
0i#ht see this in code th%t you .ind e(sewhere? %nd you c%n re%d %bout how it
works here i. you5re curious? but 3ust be %w%re th%t this sty(e is bein# *h%sed
out co0*(ete(y in Python 3 @%nd the DnewF format() sty(e works 3ust .ine in
Python 2.7)? so there5s not 0uch *oint in (e%rnin# to 0%ster this outd%ted 0ethod.
A
9e,iew e6ercises-
30
Real Python
RealPython.com
Create a loat o%(ect Fa decimal num%er. named wei'ht that holds the
'alue ?.*$ and create a string o%(ect named animal that holds the 'alue
newt$ then use these o%(ects to print the ollo"ing line without using
the format() string method7
?.* 1' is the wei'ht of the newt.
1isplay the same line using format() and empty {} place+holders
1isplay the same line using {} place+holders that use the index num%ers o
the inputs pro'ided to the format() method
1isplay the same line %y creating ne" string and loat o%(ects inside o the
format() method
A.A. #ind a string in a string
ne o the most useul string methods is find(). As its name implies$ "e can use
this method to ind the location o one string in another string. )e use dot
notation %ecause this method belongs to a string$ and the input "e supply in
parentheses is the string "e&re searching or7
@
>>> phrase + "the surprise is in here somewhere"
>>> print phrase.find("surprise")
<
>>>
)e&re searching or the location o the string surprise in our phrase string. 2he
'alue that find() returns is the index o the irst occurrence o that string. 0n this
case$ surprise starts at the C
th
character into the phrase Fremem%er to start
counting at 0.$ so "e displayed <.
0 find() doesn't ind the string "e&re looking or$ it "ill return !( instead7
>>> phrase + "the surprise is in here somewhere"
>>> print phrase.find("eLafLallaLO1ull")
!(
31
Real Python
RealPython.com
>>>
)e can e'en call string methods on a string literal directly$ so in this case "e didn&t
e'en need to create a ne" string o%(ect7
>>> print "the surprise is in here somewhere".find("surprise")
<
>>>
Leep in mind that this matching is done exactly$ character %y character. 0 "e had tried
to ind -H,8,#-&$ "e "ould ha'e gotten a !(.
2he part o the string "e are searching or For any part o a string. is called a substring.
0 a su%string appears more than once in our string$ find() "ill (ust return the irst
appearance$ starting rom the %eginning o the string. #or instance$ try out7
>>> "# put a strin' in our strin'".find("strin'")
P
>>>
Leep in mind that "e still can&t mix o%(ect typesB find() "ill only accept a string as its
input. 0 "e "ere looking or an integer inside in a string$ "e "ould still ha'e to put that
integer 'alue in a string o its o"n7
>>> "I num0er is CCC!CCC!CCCC".find("C")
(;
>>>
A similar string method is replace()$ "hich "ill replace all occurrences o one
su%string "ith a dierent string. #or instance$ let&s replace e'ery instance o the
truth "ith the string lies in the ollo"ing7
>>> m-tor + "#7m tellin' ou the truth; he spo1e nothin' 0ut the truth9"
>>> print m-tor.replace("the truth", "lies")
#7m tellin' ou lies; he spo1e nothin' 0ut lies9
>>>
Leep in mind that calling replace() did not actually change m-torB in order to
aect this string$ "e "ould still ha'e to reassign it to a ne" 'alue$ as in7
>>> m-tor + m-tor.replace("the truth", "lies")
>>>
32
Real Python
RealPython.com
9e,iew e6ercises-
0n one line$ display the result o trying to find() the su%string a in the
string ///B the result should %e !(
Create a string o%(ect that contains the 'alue "ersion *.?B find() the
irst occurrence o the num%er *.? inside o this string %y irst creating a
loat o%(ect that stores the 'alue *.? as a loating+point num%er$ then
con'erting that o%(ect to a string using the str() unction
)rite and test a script that accepts user input using raw=input()$ then
displays the result o trying to find() a particular letter in that input
Assignment 3.3: Turn your user into a l33t h4x0r
Write % scri*t Dtr%ns(%te.*yF th%t %sks the user .or so0e in*ut with the
.o((owin# *ro0*t-
&nter some teAt2
Cou shou(d then use the replace() 0ethod to con,ert the te6t entered by the user
into D(eets*e%kF by 0%kin# the .o((owin# ch%n#es to (ower=c%se (etters-
7he (etter- a beco0es- <
7he (etter- 0 beco0es- P
7he (etter- e beco0es- ;
7he (etter- l beco0es- (
7he (etter- o beco0es- ?
7he (etter- s beco0es- C
7he (etter- t beco0es- Q
Cour *ro#r%0 shou(d then dis*(%y the resu(tin# out*ut. 4 s%0*(e run o. the *ro#r%0?
with the user in*ut in bo(d? is shown be(ow-
>>> &nter some teAt2 I like to eat eggs and spam.
# (i1; Q? ;<Q ;''C <nd Cp<m.
>>>
?
33
Real Python
RealPython.com
4) /und%0ent%(s- /unctions %nd oo*s
C.1. 1o uturistic arithmetic
e already did some %asic math using 01>8&s interacti'e "indo". #or instance$ "e
sa" that "e could e'aluate simple expressions (ust %y typing them in at the
prompt$ "hich "ould display the ans"er7
)
>>> R K (()R)
<*
>>>
6o"e'er$ (ust putting that line into a script7
R K (()R)
"ould %e useless since "e ha'en&t actually told the program to do anything. 0 "e "ant
to display the result rom a program$ "e ha'e to rely on the print command again.
:o ahead and open a ne" script$ sa'e it as arithmetic.py and try displaying the results
o some %asic calculations7
print "( ) ( +", ( ) (
print "* K (* ) ;) +", * K (*);)
print "(.* B ?.; +", (.* B ?.;
print "C B * +", C B *
6ere "e&'e used a single print statement on each line to com%ined t"o pieces o
inormation %y separating the 'alues "ith a comma. 2he results o the numerical
expressions on the right "ill automatically %e calculated "hen "e display it.
4(( o. the s*%ces we inc(uded %bo,e were entire(y o*tion%(? but they he(* to
0%kes thin#s e%sier to re%d. A
)hen you sa'e and run this script$ it displays the results o your print commands as
ollo"s7
>>>
34
Real Python
RealPython.com
( ) ( + *
* K (* ) ;) + (?
(.* B ?.; + <.?
C B * + *
>>>
)ait a second... J = 2 M 2/ #or a computer$ that doesn&t sound 'ery accurate3
5nortunately$ the mathematics aicionados Fread7 N%er+nerds. "ho de'eloped Python
made di'ision a little counter+intuiti'e at the cost o %eing technically correct. !ince
"e&re di'iding t"o integers Fi.e.$ "hole num%ers.$ Python is doing integer di'ision and
ignoring the remainder.
!ince this is an annoying ,uirk that "e usually don&t "ant$ "e ha'e to change ho"
Python treats di'ision %y adding this %i*arre line once at the 'ery %eginning o our
script7
from ==future== import di"ision
2hat&s ==future== "ith double underscore characters Ft"o I&s on each side.. I *ro0ise
th%t this is the (e%st sensib(e (ine o. code I wi(( e,er h%,e you write. Oust remem%er
to add it to the top o any script "here you might "ant to di'ide one integer %y another$
and all "ill %e "ell. Coincidentally$ normal di'ision %y deault is one o the e" useul
changes in Python A$ hence "hy "e need to import this unctionality rom the
uture.
I. you really w%nted to do inte#er di,ision? 3ust use the // o*er%tor inste%d. /or
inst%nce? C BB * + *$ e,en i. you5,e %(re%dy i0*orted .uturistic di,ision.
7his on(y %**(ies to the BB o*er%tor. 7he KK o*er%tor is so0ethin# di..erent
entire(y? %nd %ctu%((y c%(cu(%tes one nu0ber r%ised to the *ower o. %nother nu0ber.
/or inst%nce? C KK * + *C.
A
-o" that "e&'e imported the a%ility to di'ide integers correctly$ "e can run a script like
this7
from ==future== import di"ision
print "(B* +", (B*
And "e&ll get the expected result o (B* + ?.C instead o ?.
35
Real Python
RealPython.com
6o"e'er$ notice that i "e try to e'aluate (B* in the interacti'e "indo"$ "e still get ?
as our ans"er ? e'en ater running our ne" script. 2his is %ecause "e ha'en&t actually
added this ne" di'ision unctionality to the interacti'e "indo". Dut "e can al"ays do
that separately as "ell7
>>> from ==future== import di"ision
>>> (B*
?.C
>>>
And no" our interacti'e "indo" "ill also di'ide num%ers the "ay "e "ould expect.
9e,iew e6ercises-
0n a script$ print the result o di'iding one integer %y a second$ larger
integerB this is integer division
0mport di'ision rom the uture into the same script$ then sa'e and rerun
the scriptB compare these results to the pre'ious 'ersion
Assignment 4.1: Perform calculations on user input
Write % scri*t De6*onent.*yF th%t recei,es two nu0bers .ro0 the user %nd
dis*(%ys the resu(t o. t%kin# the .irst nu0ber to the *ower o. the second
nu0ber. 4 s%0*(e run o. the *ro#r%0 shou(d (ook (ike this @with e6%0*(e in*ut
th%t h%s been *ro,ided by the user hi#h(i#hted in bo(d)-
>>>
&nter a 0ase2 1.
&nter an eAponent2 !
(.* to the power of ; + (.Q*P
>>>
Kee* the .o((owin# in 0ind-
= In Python? 6
y
is c%(cu(%ted by usin# the e6*ression A KK
= :e.ore you c%n do %nythin# with the user5s in*ut? you wi(( h%,e to store
the resu(ts o. both c%((s to raw=input() in new ob3ects
= 7he raw=input() .unction returns % strin# ob3ect? so you wi(( need to
con,ert the user5s in*ut into nu0bers in order to do %rith0etic on the0
= Cou shou(d use the strin# format() 0ethod to print the resu(t
= Cou c%n %ssu0e th%t the user wi(( enter %ctu%( nu0bers %s in*ut
?
36
Real Python
RealPython.com
C.2. Create your o"n unctions
ne o the main %eneits o programming in Python is the ease "ith "hich
dierent parts and pieces o code can %e put together in ne" "ays. 2hink o it
like %uilding "ith >ego %ricks instead o ha'ing to crat e'erything %y hand each time
you start a pro(ect.
@
2he >ego %rick o programming is called a function. A unction is %asically a miniature
programB it accepts input and produces output. )e&'e already seen some examples o
unctions such as the find() string method ? "hen called on a string$ it takes some
input and returns the location o that input "ithin the string as its output.
)e could create our o"n unction that takes a num%er as its input and produces the
s,uare o that num%er as its output. 0n Python$ this "ould look like7
def sSuare(num0er)2
sSr=num + num0er K num0er
return sSr=num
2he def is short or deine and lets Python kno" that "e are a%out to deine a ne"
unction. 0n this case$ "e called the unction sSuare and ga'e it one input 'aria%le Fthe
part in parentheses. named num0er. A unction&s input is called an argument o the
unction$ and a unction can take more than one argument.
2he irst line "ithin our unction multiplies num0er %y itsel and stores the result in a
ne" 'aria%le named sSr=num. 2hen the last line o our unction returns the 'alue o
sSr=num$ "hich is the output o our unction.
0 you (ust type these three lines into a script$ sa'e it and run it$ nothing "ill happen.
2he unction doesn&t do anything %y itsel.
6o"e'er$ no" "e can use the unction later on rom the main section o the script. #or
instance$ try running this script7
def sSuare(num0er)2
sSr=num + num0er KK *
return sSr=num
input=num + C
37
Real Python
RealPython.com
output=num + sSuare(input=num)
print output=num
Dy saying output=num + sSuare(input=num)$ "e are calling up the unction
sSuare and pro'iding this unction "ith the input 'aria%le input=num$ "hich in this
case has a 'alue o C. @ur unction then calculates J
2
and returns the 'alue o the
'aria%le sSr=num$ "hich gets stored in our ne" 'aria%le output=num.
>otice the co(on %nd the indent%tion %.ter we de.ined our .unction. 7hese
%ren5t o*tion%(A 7his is how Python knows th%t we %re sti(( inside o. the
.unction. 4s soon %s Python sees % (ine th%t isn5t indented? th%t5s the end o. the
.unction. Every line inside the function must be indented!
A
9ou can deine many unctions in one script$ and unctions can e'en reer to each other.
6o"e'er$ it&s important that a unction has %een deined before you try to use it. #or
instance$ try running this code instead7
input=num + C
output=num + sSuare(input=num)
print output=num
def sSuare(num0er)2
sSr=num + num0er K num0er
return sSr=num
6ere "e&'e (ust reordered the t"o parts o our script so that the main section comes
%eore the unction. 2he pro%lem here is that Python runs through our code rom the top
to the %ottom ? so "hen "e call the sSuare unction on the second line$ Python has no
idea "hat "e mean yet %ecause "e don&t actually deine the sSuare unction until later
on in the script$ and it hasn&t gotten there yet. 0nstead "e see an error7
6ame&rror2 name 7sSuare7 is not defined
2o create a unction that uses more than one input$ all "e need to do is separate each
argument o the unction "ith a comma. #or instance$ the ollo"ing unction takes t"o
arguments as input and returns the dierence$ su%tracting the second num%er rom the
irst7
def return$ifference(num(, num*)2
return num( T num*
38
Real Python
RealPython.com
2o call this unction$ "e need to supply it "ith t"o inputs7
print return$ifference(;, C)
2his line "ill call our ne" return$ifference() unction$ then display the result o !*
that the unction returns.
)nce % .unction returns % ,%(ue with the return co00%nd? the .unction is done
runnin#G i. %ny code %**e%rs inside the .unction after the return st%te0ent? it
wi(( ne,er be run bec%use the .unction h%s %(re%dy returned its .in%( resu(t. A
@ne last helpul thing a%out unctions is that Python allo"s you to add special comments
called docstrings. A docstring ser'es as documentation$ helping to explain "hat a
unction does and ho" to use it. 2hey&re completely optional$ %ut can %e helpul i
there&s any chance that you&ll either share your code "ith someone else or i you e'er
come %ack to your code later$ once you&'e orgotten "hat it&s supposed to do ? "hich is
"hy you should lea'e comments in the irst place3 A docstring looks (ust like a multi+line
comment "ith three ,uotation marks$ %ut it has to come at the 'ery %eginning o a
unction$ right ater the irst deinition line7
def return$ifference(n(, n*)2
""",eturn the difference 0etween two num0ers.
-u0tracts n* from n(."""
return n( ! n*
2he %eneit o this F%esides lea'ing a helpul comment in the code. is that "e can no"
use the help() unction to get inormation a%out this unction. Assuming "e deined
this unction %y typing it in the interacti'e "indo" or "e already ran a script "here it
"as deined$ "e can no" type help(return$ifference) and see7
>>> help(return$ifference)
Help on function return$ifference in module ==main==2
return$ifference(n(, n*)
,eturn the difference 0etween two num0ers.
-u0tracts n* from n(.
>>>
@ course$ you can also call help() on the many other Python unctions "e&ll see to get
39
Real Python
RealPython.com
a ,uick reerence on ho" they are used.
9e,iew e6ercise-
)rite a cu0e() unction that takes a num%er and multiplies that num%er %y
itsel t"ice o'er$ returning the ne" 'alueB test the unction %y displaying the
result o calling your cu0e() unction on a e" dierent num%ers
)rite a unction multipl() that takes t"o num%ers as inputs and multiples
them together$ returning the resultB test your unction %y sa'ing the result o
multipl(*, C) in a ne" integer o%(ect and printing that integer&s 'alue
Assignment 4.2: on!ert temperatures
Write % scri*t Dte0*er%ture.*yF th%t inc(udes two .unctions. )ne .unction
t%kes % 8e(sius te0*er%ture %s its in*ut? con,erts th%t nu0ber into the
eIui,%(ent /%hrenheit te0*er%ture %nd returns th%t ,%(ue. 7he second .unction
t%kes % /%hrenheit te0*er%ture %nd returns the eIui,%(ent 8e(sius te0*er%ture.
7est your .unctions by *%ssin# in*ut ,%(ues to the0 %nd *rintin# the out*ut resu(ts.
/or testin# your .unctions? e6%0*(e out*ut shou(d (ook (ike-
Q* de'rees 3 + **.********** de'rees @
;Q de'rees @ + UP.R de'rees 3
In c%se you didn5t w%nt to s*end % 0inute se%rchin# the web or doin# %(#ebr% @the
horrorA)? the re(e,%nt con,ersion .or0u(%s %re-
/ M 8 N &O5 P 32
8 M @/ J 32) N 5O&
?
C.A. Run in circles
ne ma(or %eneit o computers is that "e can make them do the same exact thing
o'er and o'er again$ and they rarely complain or get tired. 2he easiest "ay to
program your computer to repeat itsel is "ith a loop.
@
2here are t"o kinds o loops in Python7 for loops and while loops. 2he %asic idea
%ehind any kind o loop is to run a section o code repeatedly as long as a speciic
statement Fcalled the test condition. is true. #or instance$ try running this script that
40
Real Python
RealPython.com
uses a while loop7
n + (
while (n < C)2
print "n +", n
n + n ) (
print "%oop finished9"
6ere "e create a 'aria%le n and assign it a 'alue o (. 2hen "e start the while loop$
"hich is organi*ed in a similar "ay to ho" "e deined a unction. 2he statement that "e
are testing comes in parentheses ater the while commandB in this case "e "ant to
kno" i the statement n < C is true or alse. !ince 1 P J$ the statement is true and "e
enter into the loop ater the colon.
>otice the indent%tion on the (ines %.ter the co(on. Qust (ike when we de.ined %
.unction? this s*%cin# is i0*ort%ntA 7he co(on %nd indentin# (et Python know
th%t the ne6t (ines %re inside the while (oo*. 4s soon %s Python sees % (ine th%t
isn5t indented? th%t (ine %nd the rest o. the code %.ter it wi(( be considered outside
o. the (oo*.
A
@nce "e&'e entered the loop$ "e print the 'alue o the 'aria%le n$ then "e add ( to its
'alue. -o" n is 2$ and "e go bac to test our "hile statement. 2his is still true$ since 2 P
J$ so "e run through the next t"o lines o code again; And "e keep on "ith this pattern
while the statement n < C is true.
As soon as this statement %ecomes alse$ "e&re completely done "ith the loopB "e (ump
straight to the end and continue on "ith the rest o the script$ in this case printing out
%oop finished9
:o ahead and test out dierent 'ariations o this code + and try to guess "hat your
output "ill %e %eore you run each script. Oust %e careul7 it&s easy to create "hat&s
called an infinite loop! i you test a statement that&s al"ays going to %e true$ you "ill
ne'er %reak out o the loop$ and your code "ill (ust keep running .ore,er.
4
It5s i0*ort%nt to be consistent with indent%tion? too. >otice how you c%n hit t%b
%nd b%cks*%ce to ch%n#e indent%tion? %nd I'+ %uto0%tic%((y inserts .our s*%ce
ch%r%cters? 7h%t5s bec%use you c%n5t 0i6 t%bs %nd s*%ces %s indent%tion.
4(thou#h I'+ won5t (et you 0%ke this 0ist%ke? i. you were to o*en your scri*t in %
di..erent te6t editor %nd re*(%ce so0e o. the s*%ce indent%tion with t%bs? Python
A
C ...or at least until you manage to orci%ly ,uit out o 01>8 using your panic key com%ination o choice.
41
Real Python
RealPython.com
wou(d #et con.used J e,en thou#h the s*%cin# looks the s%0e to youA
@Cou could use t%b ch%r%cters e,erywhere %s indent%tion J or e,en use % di..erent
nu0ber o. s*%ce ch%r%cters J %s (on# %s you %(w%ys use the same ty*e o. indent%tion
.or % *%rticu(%r section o. indented te6t.)
2he second type o loop$ a for loop$ is slightly dierent in Python. )e typically use for
loops in Python in order to loop o'er e'ery indi'idual item in a set o similar things ?
these things could %e num%ers$ 'aria%les$ lines rom an input ile$ etc.
#or instance$ the ollo"ing code does the exact same thing as our pre'ious script %y
using a for loop to repeatedly run code or a ran'e o num%ers7
for n in ran'e((, C)2
print "n +", n
print "%oop finished9"
6ere "e are using the ran'e() unction$ "hich is a unction that is %uilt into Python$ to
return a list o num%ers.
J
2he ran'e() unction takes t"o input 'alues$ a starting
num%er and a stopping num%er. !o in the irst line$ "e create a 'aria%le n e,ual to ($
then "e run through the code inside o our loop or n + (.
)e then run through the loop again or n + *$ etc.$ all the "ay through our range o
num%ers. @nce "e get to the end o the ran'e$ "e (ump out o the loop. 9es$ it&s
slightly counter+intuiti'e$ %ut in Python a ran'e(A, ) starts at A %ut ends right
before .
When we use % "or (oo*? we don5t need to de.ine the ,%ri%b(e we5(( be (oo*in#
o,er .irst. 7his is bec%use the "or (oo* re%ssi#ns % new ,%(ue to the ,%ri%b(e
e%ch ti0e we run throu#h the (oo*. In the %bo,e e6%0*(e? we %ssi#ned the
,%(ue 1 to the ob3ect n %s soon %s we st%rted the (oo*. 7his is di..erent .ro0 %
while (oo*? where the .irst thin# we do is to test so0e condition J which is why we
need to h%,e #i,en % ,%(ue to %ny ,%ri%b(e th%t %**e%rs in the while (oo* before we
enter the (oo*.
A
Play around "ith some 'ariations o this script to make sure you understand ho" the for
J 0 you ha'e a 'ery large ran'e() o integers and memory considerations are an issue$ then you should
use the unction Aran'e()$ "hich "orks the exact same "ay as ran'e() and is more eicient. 2his is
%ecause Aran'e() looks through the integers one at a time$ "hile ran'e() creates the ull list o
num%ers irst. F0n Python A$ ran'e() "orks like Aran'e()$ "hich in turn no longer exists..
42
Real Python
RealPython.com
loop is structured. Again$ %e sure to use the exact same syntax$ including the in
key"ord$ the colon$ and the proper indentation inside the loop.
'on5t 3ust co*y %nd *%ste the s%0*(e code into % scri*t = ty*e it out yourse(.A
>ot on(y wi(( th%t he(* you (e%rn the conce*ts? but the *ro*er indent%tion won5t
co*y o,er correct(y %nyw%yR A
As long as "e indent the code correctly$ "e can e'en put loops inside loops3 2ry this out7
for n in ran'e((, <)2
for L in 4"a", "0", "c"52
print "n +", n, "and L +", L
6ere L is looping o'er a list o stringsB "e&ll see ho" lists "ork in a later chapter$ %ut this
example is only to sho" that you don&t have to use the ran'e() unction "ith a for
loop. !ince the L loop is inside the n loop$ "e run through the entire L loop FL+"a",
L+"0", L+"c". or each 'alue that gets assigned to n in the outer loop.
)e "ill use for loops in uture chapters as an easy "ay to loop o'er all the items stored
in many dierent types o o%(ects ? or instance$ all the lines in a ile.
)nce your code is runnin# in the inter%cti,e window? so0eti0es you 0i#ht
%ccident%((y end u* enterin# % (oo* th%t t%kes 0uch (on#er th%n you e6*ected.
I. th%t5s the c%se @or i. your code see0s D.roHenF bec%use o. %nythin# e(se th%t5s
t%kin# (on#er th%n e6*ected)? you c%n usu%((y bre%k out o. the code by ty*in#
@.,%)@ in the inter%cti,e window. 7his shou(d i00edi%te(y sto* the rest o. your
scri*t .ro0 runnin# %nd t%ke you b%ck to % *ro0*t in the inter%cti,e window.
I. th%t doesn5t see0 to h%,e %ny e..ect @bec%use you so0ehow 0%n%#ed to .reeHe
the I'+ window)? you c%n usu%((y ty*e @.,%)V to Iuit out o. I'+ entire(y? 0uch
(ike D+nd 7%skF in Windows or D/orce <uitF on % 1%c.
A
9e,iew e6ercises-
)rite a for loop that prints out the integers 2 through 10$ each on a ne"
line$ %y using the ran'e() unction
5se a while loop that prints out the integers 2 through 10
F6int7 you&ll need to create a ne" integer firstB there&s no good reason to use
43
Real Python
RealPython.com
a while loop instead o a for loop in this case$ %ut it&s good practice;.
)rite a unction dou0les() that takes one num%er as its input and dou%les
that num%er three times using a loop$ displaying each result on a separate
lineB test your unction %y calling dou0les(*) to display <$ P$ and (R
Assignment 4.3: Track your in!estments
Write % scri*t Din,est.*yF th%t wi(( tr%ck the #rowin# %0ount o. %n in,est0ent
o,er ti0e. 7his scri*t inc(udes %n in"est() .unction th%t t%kes three in*uts-
the initi%( in,est0ent %0ount? the %nnu%( co0*oundin# r%te? %nd the tot%(
nu0ber o. ye%rs to in,est. $o? the .irst (ine o. the .unction wi(( (ook (ike this-
def in"est(amount, rate, time)2
7he .unction then *rints out the %0ount o. the in,est0ent .or e,ery ye%r o. the
ti0e *eriod.
6
In the 0%in body o. the scri*t @%.ter de.inin# the .unction)? use the
.o((owin# code to test your .unction-
in"est((??, .?C, P)
in"est(*???, .?*C, C)
9unnin# this test code shou(d *roduce the .o((owin# out*ut exactly-
principal amount2 W(??
annual rate of return2 ?.?C
ear (2 W(?C.?
ear *2 W((?.*C
ear ;2 W((C.QR*C
ear <2 W(*(.CC?R*C
ear C2 W(*Q.R*P(CR*C
ear R2 W(;<.??UCR<?R;
ear Q2 W(<?.Q(??<**RR
ear P2 W(<Q.Q<CC<<;QU
principal amount2 W*???
annual rate of return2 ?.?*C
ear (2 W*?C?.?
ear *2 W*(?(.*C
ear ;2 W*(C;.QP(*C
ear <2 W**?Q.R*CQP(*C
ear C2 W**R*.P(R<*CQP
?
Q 2he only math in'ol'ed here is that the initial Fprincipal. in'estment amount is multiplied %y 1 H the
annual return rate e'ery year. #or instance$ ater one year at a 0.0J rate$ R100 R100 x 1.0J M R10J.
44
Real Python
RealPython.com
Hint- 4(thou#h .unctions usu%((y return out*ut ,%(ues? this is entire(y o*tion%( in
Python. /unctions the0se(,es c%n print out*ut direct(y %s we((. Cou c%n print %s
0uch %s you (ike .ro0 inside % .unction? %nd the .unction wi(( continue runnin# unti(
you re%ch its end.
$o0e %ddition%( *ointers i. you5re stuck-
= Cou wi(( need to use % for (oo* o,er % ran'e th%t5s b%sed on
the .unction5s time in*ut.
= Within your (oo*? you wi(( need to re%ssi#n % new ,%(ue to the
amount e,ery ye%r b%sed on how it #rows %t ( ) rate.
= 9e0e0ber th%t you need to use either the strin# format() 0ethod or
str() to con,ert nu0bers to strin#s .irst i. you w%nt to print both
strin#s %nd nu0bers in % sin#(e st%te0ent.
= 2sin# the print st%te0ent by itse(. wi(( *rint % b(%nk (ine.
45
Real Python
RealPython.com
Interlude- 'ebu# your code
ou&'e pro%a%ly already disco'ered ho" easy it is to make mistakes that 01>8 can&t
automatically catch or you. As your code %ecomes longer and more complicated$ it
can %ecome a lot more diicult to track do"n the sources o these errors.
9
)hen "e learned a%out syntax and run-time errors$ 0 actually let out a third$ most
diicult type o error that you&'e pro%a%ly already experienced7 the logic error. >ogic
errors occur "hen you&'e "ritten a program that$ as ar as your computer is concerned$
is a completely 'alid program that it has no trou%le running ? %ut the program doesn&t
do "hat you intended it to do %ecause you made a mistake some"here.
Programmers use debuggers to help get these %ugs out o their programs F"e&re cle'er
"ith names like that.$ and there&s already a simple de%ugger %uilt into 01>8 that you
should learn to use + %eore you need to use it.
4(thou#h debu##in# is the (e%st #(%0orous %nd 0ost borin# *%rt o. *ro#r%00in#?
(e%rnin# to 0%ke #ood use o. % debu##er c%n s%,e you % (ot o. ti0e in the end.
We %(( 0%ke 0ist%kesG it5s % #ood ide% to (e%rn how to .ind %nd .i6 the0. A
#rom the ile menu o the interacti'e "indo" o 01>8 Fnot in a script "indo".$ click on
1e%ug 1e%ugger to open the 1e%ug Control "indo".
-otice ho" the interacti'e "indo" no" sho"s 4$&JHX >65 at the prompt to let you
kno" that the de%ugger is open. )e ha'e a e" main options a'aila%le to us$ all o
"hich "ill %e explained shortly7 "o$ $te*$ ),er$ )ut$ and <uit.
Leep %oth the de%ugger "indo" and the interacti'e "indo" open$ %ut let&s also start a
ne" script so that "e can see ho" the de%ugger "orks7
for i in ran'e((,<)2
L + iK*
print "i is", i, "and L is", L
0 you run this script "hile you ha'e the de%ugger open$ you&ll notice that it doesn&t get
'ery ar. Actually$ it pauses %eore running anything at all$ and the !tack "indo" at
the top o the de%ugger says7
46
Real Python
RealPython.com
> 7==main==7.<module>(), line (2 for i in ran'e((,<)2
All this is telling us is that line 1 F"hich contains the code for i in ran'e((,<)2.
is a%out to %e run. 2he %eginning o the !tack line in the de%ugger reers to the act
that "e&re currently in the main section o the script ? or instance$ as opposed to
%eing in a unction deinition %eore the main %lock o code has %een reached.
2he de%ugger allo"s us to step through the code line %y line$ keeping track o all our
'aria%les as "e go. !o$ let&s go ahead and click once on $te* in the de%ugger in order
to do that. )atch careully "hat happens to the de%ugger "indo" "hen you do that;
-o" the !tack "indo" in the de%ugger says that "e&re a%out to run line 2 o the code$
"hich means that line 1 has %een executed. Delo" that$ the :lo%als and >ocals
"indo" includes a ne" 'aria%le i that&s %een assigned the 'alue (. 2his is %ecause the
for loop in the irst line o our code created this integer i and ga'e it that starting
'alue. F2here are also a e" internal system 'aria%les listed a%o'e it$ %ut "e can ignore
those..
Continue hitting the $te* %utton to "alk through your code line %y line$ "atching
"hat happens in the de%ugger "indo". 9ou can track the gro"ing 'alues o i and L as
you loop through the for statement$ and output is displayed in the interacti'e "indo"
as usual "hen the print statements are run.
5sually$ "e only "ant to de%ug a particular section o the code$ so spending all day
clicking the $te* %utton is less than ideal. 2his is the idea %ehind setting a
breapoint.
Dreakpoints tell the de%ugger "hen to start pausing your code. 2hey don&t actually brea
anythingB they&re more like hang on a second$ let me take a look at things irst+points.
>et&s learn to use %reakpoints %y "orking "ith the ollo"ing example code$ "hich isn&t
,uite doing "hat "e "ant it to do yet7
def addHnderscores(word)2
new=word + "="
for i in ran'e(?, len(word))2
new=word + word4i5 ) "="
return new=word
47
Real Python
RealPython.com
phrase + "hello9"
print addHnderscores(phrase)
)hat "e meant or the unction addHnderscores() to do "as to add underscores
around e'ery character in the "ord passed to it$ so that "e could gi'e 0t the input
hello9 and it "ould return the output7
=h=e=l=l=o=9=
0nstead$ all "e see right no" is7
9=
0t might already %e o%'ious to you "hat our error "as$ %ut let&s use the de%ugger to
"ork through the pro%lem. )e kno" that the pro%lem is occurring some"here inside in
the unction ? speciically$ "ithin the for loop$ since "e said that new=word should
start "ith a = %ut it clearly doesn&t. !o let&s put a %reakpoint at the start o the for
loop so that "e can trace out exactly "hat&s happening inside.
2o set a %reakpoint on a line$ right+click F4ac7 control+click. on that line and select $et
:re%k*oint$ "hich should highlight the line to let you kno" that the %reakpoint is
acti'e.
-o" "e can run the script "ith the de%ugger open. 0t "ill still pause on the 'ery irst
line it sees F"hich is deining the unction.$ %ut "e can select "o to run through the
code normally. 2his "ill sa'e the unction in Python&s memory$ sa'e the 'aria%le phrase
as hello3$ call up our unction rom the print statement; and then pause at our
%reakpoint$ right %eore entering the for loop.
At this point$ "e see that "e ha'e t"o local 'aria%les deined Fthey&re local %ecause
they %elong to the unction.. As expected$ "e ha'e new=word$ "hich is a string "ith
(ust the underscore character$ and "e ha'e word$ the 'aria%le "e passed to the
unction$ "ith hello3 as its contents.
Click $te* once and you&ll see that "e&'e entered the for loop. 2he counter "e&re
using$ i$ has %een gi'en its irst 'alue o ?.
Click $te* one more time$ and it might %ecome clearer "hat&s happening in our code.
2he 'aria%le new=word has taken on the 'alue h=; 0t got rid o our irst underscore
48
Real Python
RealPython.com
character already3 0 you click $te* a e" more times$ you&ll see that new=word gets
set to e=$ then l=$ etc. )e&'e %een o'er"riting the contents o new=word instead
o adding to it$ and so "e correct the line to7
new=word + new=word ) word4i5 ) "="
@ course$ the de%ugger couldn&t tell us exactly how to ix the pro%lem$ %ut it helped us
identiy where the pro%lem occurred and "hat exactly the unexpected %eha'ior "as.
9ou can remo'e a %reakpoint at any time %y right+clicking F4ac7 control+clicking. and
selecting 8(e%r :re%k*oint.
0n the de%ugger$ <uit does (ust that ? immediately ,uits out o the program entirely$
regardless o "here you "ere in the script. 2he option ),er is sort o a com%ination o
$te* and "o + it "ill step over a unction or loop. 0n other "ords$ i you&re a%out to
$te* into a unction "ith the de%ugger$ you can still run that unction&s code "ithout
ha'ing to $te* all the "ay through each line o it + ),er "ill take you directly to
the end result o running that unction. >ike"ise$ i you&re already inside o a unction$
)ut "ill take you directly to the end result o that unction.
When tryin# to reo*en the debu##er? you 0i#ht see this error-
You can only toggle the deugger !hen idle
It5s 0ost (ike(y bec%use you c(osed out o. the debu##er whi(e your scri*t w%s sti((
runnin#. 4(w%ys be sure to hit D"oF or D<uitF when you5re .inished with %
debu##in# session inste%d o. 3ust c(osin# the debu##er? or you 0i#ht h%,e troub(e
reo*enin# it. 7he I'+ debu##er isn5t the 0ost c%re.u((y cr%.ted *iece o. so.tw%re J
so0eti0es you5(( 3ust h%,e to e6it out o. I'+ %nd reo*en your scri*t to 0%ke this
error #o %w%y.
A
1e%ugging can %e tricky and time+consuming$ %ut sometimes it&s the only relia%le "ay to
ix errors that you&'e o'erlooked. 6o"e'er$ %eore turning to the de%ugger$ in some
cases you can (ust use print statements to your ad'antage to igure out your mistakes
much more easily.
2he easiest "ay to do this is to print out the contents o 'aria%les at speciic points
throughout your script. 0 your code %reaks at some point$ you can also print out the
contents o 'aria%les using the interacti'e "indo" to compare ho" they appear to ho"
49
Real Python
RealPython.com
you thought they should look at that point.
#or instance$ in the pre'ious example "e could ha'e added the statement print
new=word inside o our for loop. 2hen "hen "e run the script$ "e&d %e a%le to see
ho" new=word actually gro"s For in this case$ ho" it doesn&t gro" properly.. Oust %e
careul "hen using print statements this "ay$ especially inside o loops ? i you don&t
plan out the process "ell$ it&s easy to end up displaying thousands o lines that aren&t
inormati'e and only end up slo"ing do"n or ree*ing your program.
@r you could al"ays try ru%%er ducking.
50
Real Python
RealPython.com
5) /und%0ent%(s- 8ondition%( (o#ic
J.1. Compare 'alues
omputers understand our "orld in %inary$ %reaking e'ery pro%lem do"n into 0&s
and 1&s. 0n order to make comparisons %et"een 'alues$ "e ha'e to learn ho" to
communicate in this 1 or 0 language using boolean logic. Doolean reers to anything
that can only take on one o t"o 'alues7 true or alse.
C
2o help make this more intuiti'e$ Python has t"o special key"ords that are con'eniently
named .rue and 3alse. 2he capitali*ation is important ? these key"ords are not
ordinary 'aria%les or strings$ %ut are essentially synonyms or 1 and 0$ respecti'ely. 2ry
doing some arithmetic in the interacti'e "indo" using .rue and 3alse inside o your
expressions$ and you&ll see that they %eha'e (ust like 1 and 07
>>> <* K .rue ) 3alse
<*
>>> 3alse K * ! ;
!;
>>> .rue ) ?.* B .rue
(.*
>>>
Deore "e can e'aluate expressions to determine "hether or not they are .rue or
3alse$ "e need a "ay to compare 'alues to each other. )e use a standard set o
sym%ols Fcalled boolean comparators. to do this$ and most o them are pro%a%ly already
amiliar to you7
a > 0 a greater than 0
a < 0 a less than 0
a >+ 0 a greater than or e#$al to 0
a <+ 0 a less than or e#$al to 0
a 9+ 0 a not e#$al to 0
a ++ 0 a e#$al to 0
51
Real Python
RealPython.com
2he last t"o sym%ols might re,uire some explanation. 2he sym%ol 9+ is a sort o
short+cut notation or saying not e,ual to. 2ry it out on a e" expressions$ like these7
>>> ( 9+ *
.rue
>>> ( 9+ (
3alse
>>>
0n the irst case$ since 1 does not e,ual 2$ "e see the result .rue. 2hen$ in the second
example$ 1 does e,ual 1$ so our test expression ( 9+ ( returns 3alse.
)hen "e "ant to test i a e,uals 0$ "e can&t (ust use the expression a + 0 %ecause
in programming$ that "ould mean "e "ant to assign the 'alue o 0 to a. )e use the
sym%ol ++ as a test expression "hen "e "ant to see if a is e,ual to 0. #or instance$
take a look at the t"o 'ersions o e,uals here7
>>> a + (
>>> 0 + *
>>> a ++ 0
3alse
>>> a + 0
>>> a ++ 0
.rue
>>>
#irst "e assigned a and 0 t"o dierent 'alues. )hen "e check "hether they are e,ual
%y using the a ++ 0 expression$ "e get the result 3alse. 2hen$ "e reassign a the
'alue o 0 %y saying a + 0. -o"$ since a and 0 are %oth e,ual to *$ "e can test this
relationship again %y saying a ++ 0 F"hich is more o a ,uestion that "e&re asking.$
"hich returns the result o .rue. >ike"ise$ "e could ask7
>>> a 9+ 0
3alse
>>>
0t&s .rue that * ++ *. !o the opposite expression$ a 9+ 0$ is 3alse. 0n other "ords$
it&s not .rue that * does not e,ual *.
)e can compare strings in the same "ay that "e compare num%ers. !aying that one
"ord is less than another doesn&t really mean anything$ %ut "e can test "hether t"o
52
Real Python
RealPython.com
strings are the same %y using the ++ or 9+ comparators7
>>> "do'" ++ "cat"
3alse
>>> "do'" ++ "do'"
.rue
>>> "do'" 9+ "cat"
.rue
>>>
Leep in mind that t"o strings ha'e to ha'e exactly the same 'alue them to %e e,ual. #or
instance$ i one string has an extra space character at the end or i the t"o strings ha'e
dierent capitali*ation$ comparing "hether or not they are e,ual "ill return 3alse.
9e,iew e6ercises-
#igure out "hat the result "ill %e F.rue or 3alse. "hen e'aluating the
ollo"ing expressions$ then type them into the interacti'e "indo" to check
your ans"ers7
( <+ (
( 9+ (
( 9+ *
"'ood" 9+ "0ad"
"'ood" 9+ "Xood"
(*; ++ "(*;"
J.2. Add some logic
ython also has special key"ords Fcalled logical operators. or comparing t"o
expressions$ "hich are7 and$ or$ and not. 2hese key"ords "ork much the same
"ay as "e use them in 8nglish.
P
>et&s start "ith the and key"ord. !aying and means that both statements must %e
true. #or instance$ take the ollo"ing t"o simple phrases Fand assume they&re %oth
true.7
53
Real Python
RealPython.com
cats ha'e our legs
cats ha'e tails
0 "e use these phrases in com%ination$ the phrase cats ha'e our legs and cats ha'e
tails is true$ o course. 0 "e negate %oth o these phrases$ cats do not ha'e our legs
and cats do not ha'e tails is alse. Dut e'en i "e make one o these phrases alse$ the
com%ination also %ecomes alse7 cats ha'e our legs and cats do not ha'e tails is a
alse phrase. >ike"ise$ cats do not ha'e our legs and cats ha'e tails is still alse.
>et&s try this same concept out in Python %y using some numerical expressions7
>>> ( < * and ; < < # 0oth are .rue
.rue
>>> * < ( and < < ; # 0oth are 3alse
3alse
>>> ( < * and < < ; # second statement is 3alse
3alse
>>> * < ( and ; < < # first statement is 3alse
3alse
>>>
1 % and ! % &7 both statements are .rue$ so the com%ination is also .rue
% 1 and & % !7 %oth statements are 3alse$ so their com%ination is also
3alse
1 % and & % !7 the irst statement F( < *. is .rue$ "hile the second
statement F< < ;. is 3alseB since both statements ha'e to %e .rue$ com%ining
them "ith the and key"ord gi'es us 3alse
% 1 and ! % &7 the irst statement F* < (. is 3alse$ "hile the second
statement F; < <. is .rueB again$ since both statements ha'e to %e .rue$
com%ining them "ith the and key"ord gi'es us 3alse
)e can summari*e these results in a ta%le7
Com%ination using and7 Result is7
.rue and .rue .rue
.rue and 3alse 3alse
3alse and .rue 3alse
54
Real Python
RealPython.com
3alse and 3alse 3alse
0t might seem counter+intuiti'e that .rue and 3alse is 3alse$ %ut think %ack to
ho" "e use this term in 8nglishB the ollo"ing phrase$ taken in its entirety$ is o course
alse7 cats ha'e tails and the moon is made o cheese.
2he or key"ord means that at least one 'alue must %e true. )hen "e say the "ord or
in e'eryday con'ersation$ sometimes "e mean an exclusive or + this means that only
the irst option or the second option can %e true. )e use an exclusive or "hen "e say
a phrase such as$ 0 can stay or 0 can go. 0 can&t do %oth ? only one o these options can
%e true.
6o"e'er$ in programming "e use an inclusive or since "e also "ant to include the
possi%ility that both 'alues are true. #or instance$ i "e said the phrase$ "e can ha'e
ice cream or "e can ha'e cake$ "e also "ant the possi%ility o ice cream and cake$ so
"e use an "inclusive or to mean either ice cream$ or cake$ or both ice cream and
cake.
Again$ "e can try this concept out in Python %y using some numerical expressions7
>>> ( < * or ; < < # 0oth are .rue
.rue
>>> * < ( or < < ; # 0oth are 3alse
3alse
>>> ( < * or < < ; # second statement is 3alse
.rue
>>> * < ( or ; < < # first statement is 3alse
.rue
SSS
0 any part o our expression is .rue$ e'en i %oth parts are .rue$ the result "ill also %e
.rue. )e can summari*e these results in a ta%le7
Com%ination using or7 Result is7
.rue or .rue .rue
.rue or 3alse .rue
3alse or .rue .rue
3alse or 3alse 3alse
55
Real Python
RealPython.com
)e can also com%ine the and and or key"ords using parentheses to create more
complicated statements to e'aluate$ such as the ollo"ing7
>>> 3alse or (3alse and .rue)
3alse
>>> .rue and (3alse or .rue)
.rue
>>>
#inally$ as you "ould expect$ the not key"ord simply re'erses the truth o a single
statement7
8ect o using not7 Result is7
not .rue 3alse
not 3alse .rue
5sing parentheses or grouping statements together$ "e can com%ine these key"ords
"ith .rue and 3alse to create more complex expressions. #or instance7
>>> (not 3alse) or .rue
.rue
>>> 3alse or (not 3alse)
.rue
>>>
)e can no" com%ine these key"ords "ith the %oolean comparators that "e learned in
the pre'ious section to compare much more complicated expressions. #or instance$
here&s a some"hat more in'ol'ed example7
.rue and not (( 9+ ()
)e can %reak this statement do"n %y starting on the ar right side$ as ollo"s7
)e kno" that ( ++ ( is .rue$ thereore;
( 9+ ( is 3alse$ thereore;
not (( 9+ () can %e simpliied to not (3alse)
not 3alse is .rue
-o" "e can use this partial result to sol'e the ull expression;
56
Real Python
RealPython.com
.rue and not (( 9+ () can %e simpliied to .rue and .rue
.rue and .rue e'aluates to %e .rue
)hen "orking through complicated expressions$ the %est strategy is to start "ith the
most complicated part For parts. o the expression and %uild out"ard rom there. #or
instance$ try e'aluating this example7
("/" 9+ "/") or not (* >+ ;)
)e can %reak this expression do"n into t"o sections$ then com%ine them7
)e&ll start "ith the expression on the let side o the or key"ord
)e kno" that "/" ++ "/" is .rue$ thereore;
"/" 9+ "/" is 3alse$ and the let side o our expression is 3alse
-o" on the right side o the or$ * >+ ; is 3alse$ thereore;
not (* >+ ;) is .rue
!o our entire expression simpliies to 3alse or .rue
3alse or .rue e'aluates to %e .rue
-ote that "e didn&t have to use parentheses to express either o these examples.
6o"e'er$ it&s usually %est to include parentheses as long as they help to make a
statement more easily reada%le.
Cou shou(d .ee( ,ery co0.ort%b(e usin# ,%rious co0bin%tions o. these keywords
%nd boo(e%n co0*%risons. P(%y %round in the inter%cti,e window? cre%tin# 0ore
co0*(ic%ted e6*ressions %nd tryin# to .i#ure out wh%t the %nswer wi(( be be.ore
checkin# yourse(.? unti( you %re con.ident th%t you c%n deci*her boo(e%n (o#ic.
A
9e,iew e6ercises-
#igure out "hat the result "ill %e F.rue or 3alse. "hen e'aluating the
ollo"ing expressions$ then type them into the interacti'e "indo" to check
your ans"ers7
(( <+ () and (( 9+ ()
57
Real Python
RealPython.com
not (( 9+ *)
("'ood" 9+ "0ad") or 3alse
("'ood" 9+ "Xood") and not (( ++ ()
J.A. Control the lo" o your program
o ar$ "e ha'en&t really let our programs make any decisions on their o"n ? "e&'e
%een supplying a series o instructions$ "hich our scripts ollo" in a speciic order
regardless o the inputs recei'ed.
!
6o"e'er$ no" that "e ha'e precise "ays to compare 'alues to each other$ "e can start
to %uild logic into our programsB this "ill let our code decide to go in one direction or
another %ased on the results o our comparisons.
)e can do this %y using if statements to test "hen certain conditions are .rue. 6ere&s
a simple example o an if statement7
if * ) * ++ <2
print "* and * is <"
print "/rithmetic wor1s."
Oust like "hen "e created for and while loops$ "hen "e use an if statement$ "e
ha'e a test condition and an indented %lock o text that "ill run or not %ased on the
results o that test condition. 6ere$ our test condition F"hich comes ater the if
key"ord. is * ) * ++ <. !ince this expression is .rue$ our if statement e'aluates to
%e .rue and all o the code inside o our if statement is run$ displaying the t"o lines.
)e happened to use t"o print statements$ %ut "e could really put any code inside the
if statement.
0 our test condition had %een 3alse For instance$ * ) * 9+ <.$ nothing "ould ha'e
%een displayed %ecause our program "ould ha'e (umped past all o the code inside this
i %lock ater inding that the if statement "as 3alse.
2here are t"o other related key"ords that "e can use in com%ination "ith the if
58
Real Python
RealPython.com
key"ord7 else and elif. )e can add an else statement ater an if statement like so7
if * ) * ++ <2
print "* and * is <"
print "/rithmetic wor1s."
else2
print "* and * is not <"
print "Ji' Jrother wins."
2he else statement doesn&t ha'e a test condition o its o"n %ecause it is a catch+all
%lock o codeB our else is (ust a synonym or other"ise. !o i the test condition o the
if statement had %een 3alse$ the t"o lines inside o the else %lock "ould ha'e run
instead. 6o"e'er$ since our test condition F* ) * ++ <. is .rue$ the section o code
inside the else %lock is not run.
2he elif key"ord is short or else i and can %e used to add more possi%le options
ater an if statement. #or instance$ "e could com%ine an if$ and elif$ and an else
in a single script like this7
num + (C
if num < (?2
print "num0er is less than (?"
elif num > (?2
print "num0er is 'reater than (?"
else2
print "num0er is eSual to (?"
Ater creating an integer o%(ect named num "ith a 'alue o 1J$ "e irst test "hether or
not our num is less than 10B since this condition is 3alse$ "e (ump o'er the irst print
statement "ithout running it. )e land at the elif statement$ "hich Fbecause the test
condition o the if statement "as 3alse. oers us an alternati'e testB since 1J S 10$
this condition is .rue$ and "e display the second print statement&s text. !ince one o
our test conditions "as .rue$ "e skip o'er the else statement entirelyB i %oth the if
and the elif had %een 3alse$ ho"e'er$ "e "ould ha'e displayed the last line in the
else statement.
2his is called branching %ecause "e are deciding "hich %ranch o the code to go
do"nB "e ha'e gi'en our code dierent paths to take %ased on the results o the test
conditions. 2ry running the script a%o'e and changing num to %e a e" dierent 'alues
59
Real Python
RealPython.com
to make sure you understand ho" if$ elif and else are "orking together.
9ou can also try getting rid o the else %lock entirelyB "e don&t have to gi'e our code a
path to go do"n$ so it&s completely accepta%le i "e skip o'er the entire set o if=elif
statements "ithout taking any action. #or instance$ get rid o the last t"o lines in the
script a%o'e and try running it again "ith num + (?.
0t&s important to note that elif can only %e used ater an if statement and that else
can only %e used at the end o a set o if=elif statements For ater a single if.$ since
using one o these key"ords "ithout an if "ouldn&t make any sense. >ike"ise$ i "e
"ant to do t"o separate tests in a ro"$ "e should use t"o separate if statements. #or
instance$ try out this short script7
if ( < *2
print "( is less than *"
elif ; < <2
print "; is less than <"
else2
print ":ho mo"ed m cheeseF"
2he irst test condition F( < *. is .rue$ so "e print the irst line inside the if %lock.
!ince "e already sa" one .rue statement$ ho"e'er$ the program doesn&t e'en %other to
check "hether the elif or the else %locks should %e runB these are only alternative
options. !o$ e'en though it&s .rue that A is less than C$ "e only e'er run the irst print
statement.
Oust like "ith for and while loops$ "e can nest if statements inside o each other to
create more complicated paths7
want=ca1e + "es"
ha"e=ca1e + "no"
if want=ca1e ++ "es"2
print ":e want ca1e..."
if ha"e=ca1e + "no"2
print "Jut we don7t ha"e an ca1e9"
elif ha"e=ca1e ++ "es"2
print "/nd it7s our luc1 da9"
else2
print ".he ca1e is a lie."
0n this example$ irst "e check i "e "ant cake ? and since "e do$ "e enter the irst if
60
Real Python
RealPython.com
%lock. Ater displaying our desire or cake$ "e enter the inside set o if=elif
statements. )e check and display that "e don&t ha'e any cake. 0 it had %een the case
that ha"e=ca1e "as es then it "ould ha'e %een our luc1 da. @n the other
hand$ i ha"e=ca1e had %een any 'alue other than es or no then "e "ouldn&t
ha'e displayed a second line at all$ since "e used elif rather than else. 0 For
"hate'er t"isted reason. "e had set the 'alue o want=ca1e to anything other than
es$ "e "ould ha'e (umped do"n to the %ottom else and only displayed the last
print statement.
9e,iew e6ercises-
)rite a script that prompts the user to enter a "ord using the raw=input()
unction$ stores that input in a string o%(ect$ and then displays "hether the
length o that string is less than J characters$ greater than J characters$ or
e,ual to J characters %y using a set o if$ elif and else statements.
Assignment ".3: #in$ the factors of a num%er
Write % scri*t D.%ctors.*yF th%t inc(udes % .unction to .ind %(( o. the inte#ers
th%t di,ide e,en(y into %n inte#er *ro,ided by the user. 4 s%0*(e run o. the
*ro#r%0 shou(d (ook (ike this @with the user5s in*ut hi#h(i#hted in bo(d)-
>>>
&nter an inte'er2 1
( is a di"isor of (*
* is a di"isor of (*
; is a di"isor of (*
< is a di"isor of (*
R is a di"isor of (*
(* is a di"isor of (*
>>>
Cou shou(d use the N o*er%tor to check di,isibi(ity. 7his is c%((ed the D0odu(us
o*er%torF %nd is re*resented by % *ercent sy0bo( in Python. It returns the
remainder o. %ny di,ision. /or inst%nce? 3 #oes into 16 % tot%( o. 5 ti0es with %
re0%inder o. 1? there.ore (R N ; returns (. 1e%nwhi(e? since 15 is di,isib(e by 3?
(C N ; returns ?.
4(so kee* in 0ind th%t raw=input() returns % strin#? so you wi(( need to con,ert
this ,%(ue to %n inte#er be.ore usin# it in %ny c%(cu(%tions.
?
61
Real Python
RealPython.com
J.C. Dreak out o the pattern
here are t"o main key"ords that help to control the lo" o programs in Python7
0rea1 and continue. 2hese key"ords can %e used in com%ination "ith for and
while loops and "ith if statements to allo" us more control o'er "here "e are in a
loop.
2
>et&s start "ith 0rea1$ "hich does (ust that7 it allo"s you to brea out o a loop. 0 "e
"anted to %reak out o a for loop at a particular point$ our script might look like this7
for i in ran'e(?, <)2
if i ++ *2
0rea1
print i
print "3inished with i +", str(i)
#ithout the if statement that includes the 0rea1 command$ our code "ould normally
(ust print out the ollo"ing output7
>>>
?
(
*
;
3inished with i + ;
>>>
0nstead$ each time "e run through the loop$ "e are checking "hether i ++ *. )hen
this is .rue$ "e 0rea1 out o the loopB this means that "e ,uit the for loop entirely as
soon as "e reach the 0rea1 key"ord. 2hereore$ this code "ill only display7
>>>
?
(
3inished with i + *
>>>
-otice that "e still displayed the last line since this "asn&t part o the loop. >ike"ise$ i
"e "ere in a loop inside another loop$ 0rea1 "ould only %reak out o the inner loopB
the outer loop "ould continue to run Fpotentially landing us %ack inside the inner loop
62
Real Python
RealPython.com
again..
4uch like 0rea1$ the continue key"ord (umps to the end o a loopB ho"e'er$ instead
o exiting a loop entirely$ continue says to go %ack to the top o the loop and continue
"ith the next item o the loop. #or instance$ i "e had used continue instead o
0rea1 in our last example7
for i in ran'e(?, <)2
if i ++ *2
continue
print i
print "3inished with i +", str(i)
)e&re no" skipping o'er the print i command "hen our if statement is .rue$ and
so our output includes e'erything rom the loop except displaying i "hen i ++ *7
>>>
?
(
;
3inished with i + ;
>>>
It5s %(w%ys % #ood ide% to #i,e short but descri*ti,e n%0es to your ,%ri%b(es th%t
0%ke it e%sy to te(( wh%t they %re su**osed to re*resent. 7he (etters i? ' %nd k
%re e6ce*tions bec%use they %re so co00on in *ro#r%00in#G these (etters %re
%(0ost %(w%ys used when we need % Dthrow%w%yF nu0ber so(e(y .or the *ur*ose o.
kee*in# count whi(e workin# throu#h % (oo*.
A
>oops can ha'e their o"n else statements in Python as "ell$ although this structure
isn&t used 'ery re,uently. 2acking an else onto the end o a loop "ill make sure that
your else %lock always runs ater the loop unless the loop "as exited %y using the
0rea1 key"ord. #or instance$ let&s use a for loop to look through e'ery character in a
string$ searching or the upper+case letter Y7
phrase + "it mar1s the spot"
for letter in phrase2
if letter ++ "Y"2
0rea1
else2
print ".here was no 7Y7 in the phrase"
63
Real Python
RealPython.com
6ere$ our program attempted to ind Y in the string phrase$ and "ould 0rea1 out o
the for loop i it had. !ince "e ne'er %roke out o the loop$ ho"e'er$ "e reached the
else statement and displayed that Y "asn&t ound. 0 you try running the same
program on the phrase it mar1s Ythe spot or some other string that includes an
Y$ ho"e'er$ there "ill %e no output at all %ecause the %lock o code in the else "ill
not %e run.
E
>ike"ise$ an else placed ater a while loop "ill always %e run unless the while
loop has %een exited using a 0rea1 statement. #or instance$ try out the ollo"ing
script7
tries + ?
while tries < ;2
password + raw=input("8assword2 ")
if password ++ "#<;Jie0er"2
0rea1
else2
tries + tries ) (
else2
print "-uspicious acti"it. .he authorities ha"e 0een alerted."
6ere$ "e&'e gi'en the user three chances to enter the correct pass"ord. 0 the pass"ord
matches$ "e %reak out o the loop. @ther"ise Fthe irst else.$ "e add one to the
tries counter. 2he second else %lock belongs to the loop Fhence "hy it&s less
indented than the irst else.$ and "ill only %e run i "e don't 0rea1 out o the loop.
!o "hen the user enters a correct pass"ord$ "e do not run the last line o code$ %ut i
"e exit the loop %ecause the test condition "as no longer .rue Fi.e.$ the user tried
three incorrect pass"ords.$ then it&s time to alert the authorities.
4 co00on(y used shortcut in Python is the D)+F o*er%tor? which is shorth%nd
.or s%yin# Dincre%se % nu0ber by so0e %0ountF. /or inst%nce? in our (%st code
e6%0*(e %bo,e? inste%d o. the (ine-
tries + tries ) (
We cou(d h%,e done the e6%ct s%0e thin# @%ddin# ( to tries) by s%yin#-
tries )+ (
A
E @ course$ it "ould ha'e %een easier to use the result o phrase.find("Y")$ %ut you can&t expect all
these examples to %e sensi%le;
64
Real Python
RealPython.com
In .%ct? this works with the other b%sic o*er%tors %s we((G !+ 0e%ns Ddecre%seF? K+
0e%ns D0u(ti*(y byF? %nd B+ 0e%ns Ddi,ide byF. /or inst%nce? i. we w%nted to
ch%n#e the ,%ri%b(e tries .ro0 its ori#in%( ,%(ue to th%t ,%(ue 0u(ti*(ied by 3? we
cou(d shorten the st%te0ent to s%y-
trials K+ ;
9e,iew e6ercises-
5se a 0rea1 statement to "rite a script that prompts the users or input
repeatedly$ only ending "hen the user types S or V to ,uit the programB
a common "ay o creating an ininite loop is to "rite while .rue2
Com%ine a for loop o'er a ran'e() o num%ers "ith the continue key"ord
to print e'ery num%er rom 1 through J0 except or multiples o AB you "ill
need to use the N operator as explained in Assignment J.A
J.J. Reco'er rom errors
ou&'e pro%a%ly already "ritten lots o scripts that generated errors in Python. Run+
time errors Fso+called %ecause they happen once a program is already running. are
called exceptions. Congratulations ? you&'e made the code do something exceptional3
9
2here are dierent types o exceptions that occur "hen dierent rules are %roken. #or
instance$ try to get the 'alue o ( B ? at the interacti'e "indo"$ and you&ll see a
Mero$i"ision&rror exception. 6ere&s another example o an exception$ a
Ealue&rror$ that occurs "hen "e try Fand ail. to turn a string into an integer7
>>> int("not a num0er")
.race0ac1 (most recent call last)2
3ile "<pshell#(>", line (, in <module>
int("not a num0er")
Ealue&rror2 in"alid literal for int() with 0ase (?2 7not a num0er7
>>>
65
Real Python
RealPython.com
2he name o the exception is displayed on the last line$ ollo"ed %y a description o the
speciic pro%lem that occurred.
)hen "e can predict that a certain type o exception might occur$ "e might not %e a%le
to pre'ent the error$ %ut there are "ays that "e can reco'er rom the pro%lem more
graceully than ha'ing our program %reak and display lots o angry red text.
0n order to stop our code rom %reaking %ecause o a particular exception$ "e use a
tr=eAcept pair$ as in the ollo"ing7
tr2
num0er + int(raw=input("&nter an inte'er2 "))
eAcept Ealue&rror2
print ".hat was not an inte'er."
2he irst thing that happens in a tr=eAcept pair is that e'erything inside o the tr
%lock is run normally. 0 no error occurs$ the code skips o'er the eAcept %lock and
continues running normally. !ince "e said eAcept Ealue&rror$ ho"e'er$ i the
program encounters a Ealue&rror F"hen the user enters something that isn&t an
integer.$ "e (ump do"n to the eAcept %lock and run e'erything there. 2his a'oids
Python&s automatic error display and doesn&t %reak the script since "e ha'e caught the
Ealue&rror.
0 a different kind o exception had occurred$ then the program still "ould ha'e %rokenB
"e only handled one type o exception Fa Ealue&rror. "ith our eAcept %lock.
A single eAcept %lock can handle multiple types o exceptions %y separating the
exception names "ith commas and putting the list o names in parentheses7
from ==future== import di"ision
def di"ide(num(, num*)2
tr2
print num( B num*
eAcept (.pe&rror, Mero$i"ision&rror)2
print "encountered a pro0lem"
2his isn&t used 'ery re,uently since "e usually "ant our code to react speciically to
each type o exception dierently. 0n this case$ "e created a di"ide() unction that
tries to di'ide t"o num%ers. 0 one or %oth o the num%ers aren&t actually num%ers$ a
66
Real Python
RealPython.com
.pe&rror exception "ill occur %ecause "e can&t use something that isn&t a num%er or
di'ision. And i "e pro'ide ? as the second num%er$ a Mero$i"ision&rror "ill occur
since "e can&t di'ide %y *ero. $oth o these exceptions "ill %e caught %y our eAcept
%lock$ "hich "ill (ust let the user kno" that "e encountered a pro0lem and
continue on "ith anything else that might %e let in our script outside o the
tr=eAcept pair.
4ore eAcept error handling %locks can %e added ater the irst eAcept to catch
dierent types o exceptions$ like so7
tr2
num0er + int(raw=input("&nter an non!Dero inte'er2 "))
print "(? B {} + {}".format(num0er, (?.?Bnum0er)
eAcept Ealue&rror2
print "Gou did not enter an inte'er."
eAcept Mero$i"ision&rror2
print "Gou cannot enter ?."
6ere$ "e might ha'e encountered t"o dierent types o errors. #irst$ the user might not
ha'e input an integerB "hen "e try to con'ert the string input using int()$ "e raise an
exception and (ump to the eAcept Ealue&rror2 %lock$ displaying the pro%lem.
>ike"ise$ "e could ha'e tried to di'ide 10 %y the user+supplied num%er and$ i the user
ga'e us an input o 0$ "e "ould ha'e ended up "ith a Mero$i"ision&rror exceptionB
instead$ "e (ump to the second eAcept %lock and display this pro%lem to the user.
<
A list o Python&s %uilt+in exceptions can %e ound here. 0t&s usually easiest to igure out
the name o an exception %y purposeully causing the error to occur yoursel$ although
you should then read the documentation on that particular type o exception to make
sure that your code "ill actually handle all o the errors that you expect and F(ust as
importantly. that your program "ill still %reak i it encounters a dierent$ unexpected
type o exception.
)e can also use an eAcept %lock %y itsel "ithout naming speciic exceptions to
catch7
tr2
# do lots of haDardous thin's that mi'ht 0rea1
< -otice ho" "e used 10.0 in the actual di'ision/ 2his "as (ust an easy "ay to a'oid importing integer
di'ision %y using a loat F10.0. instead o another integer F10. in the di'ision.
67
Real Python
RealPython.com
eAcept2
print ".he user must ha"e screwed somethin' up."
6o"e'er$ this is dangerous to do and is usually not a good idea at all. 0t&s easy to hide a
poorly "ritten section o code %ehind a tr=eAcept and think that e'erything "as
"orking ine$ only to disco'er later that you "ere silencing all sorts o unexpected
pro%lems that should ne'er ha'e occurred.
9e,iew e6ercises-
)rite a script that repeatedly asks the user to input an integer$ displaying a
message to tr a'ain %y catching the Ealue&rror that is raised i the
user did not enter an integerB once the user enters an integer$ the program
should display the num%er %ack to the user and end "ithout crashing
J.Q. !imulate e'ents and calculate pro%a%ilities
ou&ll pro%a%ly ind the assignments in this section to %e airly diicult$ especially i
you&re not 'ery mathematically inclined. At the 'ery least$ 0 encourage you to read
through this section or the inormation and try the assignments out ? i they&re too
tricky or no"$ mo'e on and come %ack to them later.
9
)e "ill %e running a simple simulation kno"n as a 4onte Carlo experiment. 0n order to
do this$ "e need to add a real+"orld element o chance to our code. Python has %uilt+
in unctionality or (ust that purpose$ and it&s suita%ly called the random module.
A module is (ust a collection o related unctions. #or no"$ all "e "ill need rom the
random module is the randint() unction. Calling randint(A, ) on t"o integers A
and returns a random Fe'enly distri%uted. integer that "ill ha'e a 'alue %et"een A
and + including %oth A and $ unlike the ran'e() unction.
)e can import this unction into our program like so7
from random import randint
68
Real Python
RealPython.com
-o" "e can use the randint() unction in our code7
print randint(?, ()
0 you try this "ithin the interacti'e "indo"$ you should see something like this7
>>> from random import randint
>>> print randint(?, ()
?
>>>
@ course$ %ecause the output is random$ you ha'e a J0T chance o getting a ( instead.
@kay$ let&s take e'erything "e&'e learned so ar and put it all together to sol'e a real
pro%lem. )e&ll start "ith a %asic pro%a%ility ,uestion %y simulating the outcome o an
e'ent.
>et&s say "e lip a air coin FJ0=J0 chance o heads or tails.$ and "e keep lipping it until
"e get it to land on heads. 0 "e keep doing this$ "e&ll end up "ith a %unch o indi'idual
trials that might include getting heads on the irst lip$ tails on one lip and heads on the
second$ or e'en occasionally tails$ tails$ tails$ tails$ tails and inally heads. @n a'erage$
"hat&s our expected ratio o heads to tails or an indi'idual trial/
2o get an accurate idea o the long+term outcome$ "e&ll need to do this lots o times ? so
let&s use a for loop7
for trials in ran'e(?, (????)2
)e can use the randint() unction to simulate a J0=J0 coin toss %y considering ? to
represent tails and ( to %e a heads lip. 2he logic o the pro%lem is that "e "ill
continue to toss the coin as long as "e get tails$ "hich sounds like a while loop7
while randint(?, () ++ ?2
-o" all "e ha'e to do is keep track o our counts o heads and tails. !ince "e only
"ant the a'erage$ "e can sum them all up o'er all our trials$ so our ull script ends up
looking like the ollo"ing7
from ==future== import di"ision
from random import randint
heads + ?
tails + ?
69
Real Python
RealPython.com
for trial in ran'e(?, (????)2
while randint(?, () ++ ?2
tails + tails ) (
heads + heads ) (
print "heads B tails +", headsBtails
8ach time "e toss tails$ "e add one to our total tails tally. 2hen "e go %ack to the top
o our while loop and generate a ne" random num%er to test. @nce it&s not true that
randint(?, () ++ ?$ this means that "e must ha'e tossed heads$ so "e exit out o
the while loop F%ecause the test condition isn&t true that time. and add one to the
total heads tally.
#inally$ "e (ust print out the result o our heads+to+tails ratio. 0 you use a large enough
sample si*e and try this out a e" times$ you should %e a%le to igure out Fi you hadn&t
already. that the ratio approaches 171.
@ course$ you pro%a%ly could ha'e calculated this ans"er aster (ust %y "orking out the
actual pro%a%ilities$ %ut this same method can %e applied to much more complicated
scenarios. #or instance$ one popular application o this sort o 4onte Carlo simulation is
to predict the outcome o an election %ased on current polling percentages.
9e,iew e6ercises-
)rite a script that uses the randint() unction to simulate the toss o a
die$ returning a random num%er %et"een 1 and Q
)rite a script that simulates 10$000 thro"s o dice and displays the a'erage
num%er resulting rom these tosses
Assignment ".&.1: 'imulate an election
Write % scri*t De(ection.*yF th%t wi(( si0u(%te %n e(ection between two
c%ndid%tes? 4 %nd :. )ne o. the c%ndid%tes wins the o,er%(( e(ection by %
0%3ority b%sed on the outco0es o. three re#ion%( e(ections. @In other words? %
c%ndid%te wins the o,er%(( e(ection by winnin# %t (e%st two re#ion%( e(ections.)
8%ndid%te 4 h%s the .o((owin# odds-
= !7S ch%nce o. winnin# re#ion 1
= 65S ch%nce o. winnin# re#ion 2
= 17S ch%nce o. winnin# re#ion 3
?
70
Real Python
RealPython.com
I0*ort %nd use the random() .unction .ro0 the random 0odu(e to si0u(%te e,ents
b%sed on *rob%bi(itiesG this .unction doesn5t t%ke %ny %r#u0ents @0e%nin# you don5t
*%ss it %ny in*ut ,%ri%b(es) %nd returns % r%ndo0 ,%(ue so0ewhere between 0 %nd
1.
$i0u(%te 10?000 such e(ections? then @b%sed on the %,er%#e resu(ts) dis*(%y the
*rob%bi(ity th%t 8%ndid%te 4 wi(( win %nd the *rob%bi(ity th%t 8%ndid%te : wi(( win.
I. you w%nt to check your work without (ookin# %t the s%0*(e scri*t? the %nswer is
in this .ootnote.
&
Hint- 7o do this? you5(( *rob%b(y need to use % "or (oo* with % (ot o. i"Oelse
st%te0ents to check the resu(ts o. e%ch re#ion%( e(ection.
Assignment ".&.2: 'imulate a coin toss experiment
Write % scri*t DcoinLtoss.*yF th%t uses coin toss si0u(%tions to deter0ine the
%nswer to this s(i#ht(y 0ore co0*(e6 *rob%bi(ity *uHH(e-
I kee* .(i**in# % .%ir coin unti( I5,e seen it (%nd on both he%ds %nd t%i(s %t (e%st
once e%ch J in other words? %.ter I .(i* the coin the .irst ti0e? I continue to .(i* it
unti( I #et % different resu(t. )n %,er%#e? how 0%ny ti0es wi(( I h%,e to .(i* the coin
tot%(?
4#%in? the %ctu%( *rob%bi(ity cou(d be worked out? but the *oint here is to si0u(%te
the e,ent usin# randint(). 7o #et the e6*ected %,er%#e nu0ber o. tosses? you
shou(d set % ,%ri%b(e trials ( 1)))) %nd % ,%ri%b(e "lip ( )? then %dd 1 to
your "lips ,%ri%b(e e,ery ti0e % coin toss is 0%de. 7hen you c%n print "lips /
trials %t the end o. the code to see wh%t the %,er%#e nu0ber o. .(i*s w%s.
7his one is tricky to structure correct(y. 7ry writin# out the (o#ic before you st%rt
codin#. $o0e %ddition%( *ointers i. you5re stuck-
= Cou wi(( need to use % "or (oo* o,er % range o. trials.
= /or e%ch tri%(? first you shou(d check the outco0e o. the .irst .(i*.
= 1%ke sure you %dd the .irst .(i* to the tot%( nu0ber o. "lips.
= 4.ter the .irst toss? you5(( need %nother (oo* to kee* .(i**in#
while you #et the s%0e resu(t %s the .irst .(i*.
= I. you 3ust w%nt to check whether or not your .in%( %nswer is
correct without (ookin# %t the s%0*(e code? c(ick here.
?
U Candidate A has approximately a QAT chance o "inningB Candidate D has roughly a AET chance.
71
Real Python
RealPython.com
6) /und%0ent%(s- ists %nd 'iction%ries
Q.1. 4ake and update lists
ists are extremely useul ? in lie and in Python. 2here are so many things that
naturally lend themsel'es to %eing put into lists that it&s oten a 'ery intuiti'e "ay
to store and order data. 0n Python$ a list is a type o o%(ect F(ust like a string or an
integer.$ except a list o%(ect is a%le to hold other o%(ects inside o it. )e create a list
%y simply listing all the items "e "ant in list$ separated %y commas$ and enclosing
e'erything inside s,uare %rackets. 2hese are all examples o simple list o%(ects7
>
colors + 4"red", "'reen", "0urnt sienna", "0lue"5
scores + 4(?, P, U, !*, U5
m%ist + 4"one", *, ;.?5
2he irst o%(ect$ colors$ holds a list o our strings. @ur scores list holds i'e integers.
And the last o%(ect$ m%ist$ holds three dierent o%(ects ? a string$ an integer and a
loating+point num%er. !ince "e usually "ant to track a set o similar items$ it&s not 'ery
common to see a list that holds dierent types o o%(ects like our last example$ %ut it&s
possi%le.
:etting a single item out o a list is as easy as getting a single character out o a string ?
in act$ it&s the exact same process o reerring to the item %y its index num%er7
>>> colors + 4"red", "'reen", "0urnt sienna", "0lue"5
>>> print colors4*5
0urnt sienna
>>>
Remem%er$ since "e start counting at 0 in Python$ "e asked or colors4*5 in order to
get "hat "e think o as the third o%(ect in the list. )e can also get a range o o%(ects
rom a list in the same "ay that "e got su%strings out o strings7
>>> colors + 4"red", "'reen", "0urnt sienna", "0lue"5
>>> print colors
47red7, 7'reen7, 70urnt sienna7, 70lue75
>>> print colors4?2*5
72
Real Python
RealPython.com
47red7, 7'reen75
>>>
#irst "e printed the entire list o colors$ "hich displayed almost exactly the same "ay
as "e typed it in originally. 2hen "e printed the o%(ects in the list "ithin the range
4?2*5 ? this includes the o%(ects at positions 0 and 1$ "hich are returned as a smaller
list. F)e can tell they&re still in a list %ecause o the s,uare %rackets..
5nlike strings$ lists are mutable o%(ects$ meaning that "e can change indi'idual items
"ithin a list. #or instance7
>>> colors + 4"red", "'reen", "0urnt sienna", "0lue"5
>>> colors4?5 + "0ur'und"
>>> colors4;5 + "electric indi'o"
>>> print colors
470ur'und7, 7'reen7, 70urnt sienna7, 7electric indi'o75
>>>
!ince "e can change the items in lists$ "e can also create ne" lists and add o%(ects to
them$ item %y item. )e create an empty list using an empty pair o s,uare %rackets$
and "e can add an o%(ect to the list using the append() method o the list7
>>> animals + 45
>>> animals.append("lion")
>>> animals.append("ti'er")
>>> animals.append("frumious Jandersnatch")
>>> print animals
47lion7, 7ti'er7, 7frumious Jandersnatch75
>>>
>ike"ise$ "e can remo'e o%(ects rom the list using the remo"e() method o the list7
>>> animals.remo"e("lion")
>>> animals.remo"e("ti'er")
>>> print animals
47frumious Jandersnatch75
>>>
)e can also use the list&s indeA() method to get the index num%er o a particular item
in a list in order to determine its position. #or instance7
>>> colors + 4"red", "'reen", "0urnt sienna", "0lue"5
>>> print colors.indeA("0urnt sienna")
*
>>>
73
Real Python
RealPython.com
Copying one list into another list$ ho"e'er$ is some"hat unintuiti'e. 9ou can&t (ust
reassign one list o%(ect to another list o%(ect$ %ecause you&ll get this Fpossi%ly surprising.
result7
>>> animals + 4"lion", "ti'er", "frumious Jandersnatch"5
>>> lar'e=cats + animals
>>> lar'e=cats.append(".i''er")
>>> print animals
47lion7, 7ti'er7, 7frumious Jandersnatch7, 7.i''er75
>>>
)e tried to assign the strings in the list animals to the list lar'e=cats$ then "e
added another string into lar'e=cats. Dut "hen "e display the contents o animals$
"e see that "e&'e changed our original list ? e'en though "e meant to assign in the
other direction$ gi'ing lar'e=cats the 'alues in animals.
2his is a ,uirk o o%(ect+oriented programming$ %ut it&s %y designB "hen "e say
lar'e=cats + animals$ "e make the lists lar'e=cats and animals %oth refer
to the same object. )hen "e created our irst list$ the name animals "as only a "ay
to point us to a list o%(ect ? in other "ords$ the name animals is (ust a "ay to
reerence the actual list o%(ect that is some"here in the computer&s memory. 0nstead o
copying all the contents o the list o%(ect$ saying lar'e=cats + animals assigns
the same object reference to lar'e=catsB %oth o our list names no" reer to the
same o%(ect$ and any changes made to one "ill aect the other since %oth names point
to the same o%(ect.
10
0 "e actually "anted to copy the contents o one list o%(ect into a ne" list o%(ect$ "e
ha'e to retrie'e all the indi'idual items rom the list and copy them o'er indi'idually.
)e don&t ha'e to use a loop to do this$ ho"e'erB "e can simply say7
lar'e=cats + animals425
2he 425 is the same techni,ue that "e used to retrie'e a su%set o the list o'er some
range$ %ut since "e didn&t speciy an index num%er on either side o the colon$ "e
gra%%ed e'erything rom the irst item through the last item.
10 -ote that this "asn&t a pro%lem "ith simple o%(ects like strings %ecause they&re immuta%leB since "e
ha'e to completely reassign these o%(ects$ "e can't aect one reerence %y changing another o%(ect.
74
Real Python
RealPython.com
Leep in mind that %ecause lists are muta%le$ there is no need to reassign a list to itsel
"hen "e use one o its methods. 0n other "ords$ "e only need to say
animals.append("Lu0Lu0") to add the Lu0Lu0 to the animals list. 0 "e had said
animals + animals.append("Lu0Lu0")$ "e "ould ha'e sa'ed the result returned
%y the append() method F"hich is nothing. into animals$ "iping out our list entirely.
2his is true o all the methods that %elong to muta%le o%(ects. #or instance$ lists also
ha'e a sort() method that sorts all o the items in ascending order Fusually
alpha%etical or numerical$ depending on the o%(ects in the list.B all "e ha'e to say i "e
"ant to sort the animals list is animals.sort()$ "hich alpha%eti*es the list7
>>> animals.sort()
>>> print animals
47frumious Jandersnatch7, 7Lu0Lu07, 7lion7, 7ti'er7, 7.i''er75
>>>
0 "e had instead assigned the 'alue returned %y the sort() method to our list$ "e
"ould ha'e lost the list entirely7
>>> animals + animals.sort()
>>> print animals
6one
>>>
!ince lists can hold any o%(ects$ "e can e'en put lists inside o lists. )e sometimes
make a list o lists in order to create a simple matrix. 2o do this$ "e simply nest one
set o s,uare %rackets inside o another$ like so7
>>> two=0=two + 44(, *5, 4;, <55
)e ha'e a single list "ith t"o o%(ects in it$ %oth o "hich are also lists o t"o o%(ects
each. )e no" ha'e to stack the index 'alues "e "ant in order to reach a particular
item$ or instance7
>>> two=0=two4(54?5
;
>>>
!ince saying two=0=two4(5 %y itsel "ould return the list 4;, <5$ "e then had to
speciy an additional index in order to get a single num%er out o this su%+list.
75
Real Python
RealPython.com
!ince a list is (ust a se,uence o o%(ects$ nested lists don&t ha'e to %e symmetrical7
>>> list + 4"# heard ou li1e lists", 4"so # put a list", "in our list"55
>>> print list
47# heard ou li1e lists7, 47so # put a list7, 7in our list755
>>>
#inally$ i "e "ant to create a list rom a single string$ "e can use the string split()
method as an easy "ay o splitting one string up into indi'idual list items %y pro'iding
the character For characters. occurring %et"een these items. #or instance$ i "e had a
single string o grocery items$ each separated %y commas and spaces$ "e could turn
them into a list o items like so7
>>> 'roceries + "e''s, spam, pop roc1s, cheese"
>>> 'rocer%ist + 'roceries.split(", ")
>>> print 'rocer%ist
47e''s7, 7spam7, 7pop roc1s7, 7cheese75
>>>
9e,iew e6ercises-
Create a list named desserts that holds the t"o string 'alues ice cream
and coo1ies
!ort the desserts in alpha%etical order$ then display the contents o the list
1isplay the index num%er o ice cream in the desserts list
Copy the contents o the desserts list into a ne" list o%(ect named food
Add the strings 0roccoli and turnips to the food list
1isplay the contents o %oth lists to make sure that 0roccoli and
turnips ha'en&t %een added to desserts
Remo'e coo1ies rom the food list
1isplay the irst t"o items in the food list %y speciying an index range
Create a list named 0rea1fast that holds three strings$ each "ith the 'alue
o coo1ies$ %y splitting up the string coo1ies, coo1ies, coo1ies
76
Real Python
RealPython.com
Assignment &.1: (ax poetic
Write % scri*t D*oetry.*yF th%t wi(( #ener%te % *oe0 b%sed on r%ndo0(y chosen
words %nd % *re=deter0ined structure. When you %re done? you wi(( be %b(e to
#ener%te *oetic 0%ster*ieces such %s the .o((owin# in 0ere 0i((iseconds-
/ furr horse
/ furr horse curdles within the fra'rant man'o
eAtra"a'antl, the horse slurps
the man'o meows 0eneath a 0aldin' eAtro"ert
4(( o. the *oe0s wi(( h%,e this s%0e #ener%( structure? ins*ired by 8(i..ord Picko,er-
{/B/n} {adLecti"e(} {noun(}
{/B/n} {adLecti"e(} {noun(} {"er0(} {preposition(} the {adLecti"e*} {noun*}
{ad"er0(}, the {noun(} {"er0*}
the {noun*} {"er0;} {preposition*} a {adLecti"e;} {noun;}
Cour scri*t shou(d inc(ude % .unction ma1e8oem() th%t returns % 0u(ti=(ine strin#
re*resentin# % co0*(ete *oe0. 7he 0%in section o. the code shou(d si0*(y print
ma1e8oem() to dis*(%y % sin#(e *oe0. In order to #et there? use the .o((owin# ste*s
%s % #uide-
= /irst? youT(( need % ,oc%bu(%ry .ro0 which to cre%te the *oe0. 8re%te se,er%(
(ists? e%ch cont%inin# words *ert%inin# to one *%rt o. s*eech @0ore or (ess)G i.e.?
cre%te se*%r%te (ists .or nouns? ,erbs? %d3ecti,es? %d,erbs? %nd *re*ositions. Cou
wi(( need to inc(ude %t (e%st three di..erent nouns? three ,erbs? three %d3ecti,es?
two *re*ositions %nd one %d,erb. Cou c%n use the s%0*(e word (ists be(ow? but .ee(
.ree to %dd your own-
>ouns- VossilV$ VhorseV$ Vaard'arkV$ V(udgeV$ VcheV$ VmangoV$ Vextro'ertV$ VgorillaV
;erbs- VkicksV$ V(inglesV$ V%ouncesV$ VslurpsV$ Vmeo"sV$ VexplodesV$ VcurdlesV
4d3ecti,es- VurryV$ V%aldingV$ VincredulousV$ VragrantV$ Vexu%erantV$ VglisteningV
Pre*ositions- VagainstV$ VaterV$ VintoV$ V%eneathV$ VuponV$ VorV$ VinV$ VlikeV$ Vo'erV$ V"ithinV
4d,erbs- VcuriouslyV$ Vextra'agantlyV$ Vtantali*inglyV$ VuriouslyV$ VsensuouslyV
= 8hoose r%ndo0 words .ro0 the %**ro*ri%te (ist usin# the random.choice()
.unction? storin# e%ch choice in % new strin#. $e(ect three nouns? three ,erbs? three
%d3ecti,es? one %d,erb? %nd two *re*ositions. 1%ke sure th%t none o. the words %re
re*e%ted. @Hint- 2se % while (oo* to re*e%t the se(ection *rocess unti( you #et %
new word.)
= P(u# the words you se(ected into the structure %bo,e to cre%te % *oe0 strin# by
usin# the format() strin# 0ethod
= :onus- 1%ke sure th%t the D/F in the tit(e %nd the .irst (ine is %d3usted to beco0e
%n D/nF %uto0%tic%((y i. the .irst %d3ecti,e be#ins with % ,owe(.
?
77
Real Python
RealPython.com
Q.2. 4ake permanent lists
uples are 'ery close cousins o the list o%(ect. 2he only real dierence %et"een
lists and tuples is that tuple o%(ects are immutable ? they can&t %e changed at all
once they ha'e %een created. 2uples can hold any list o o%(ects$ and they e'en look
nearly identical to lists$ except that "e use parentheses instead o s,uare %rackets to
create them7
2
>>> m.uple + ("ou7ll", "ne"er", "chan'e", "me")
>>> print m.uple
("ou7ll", 7ne"er7, 7chan'e7, 7me7)
>>>
!ince tuples are immuta%le$ they don&t ha'e methods like append() and sort().
6o"e'er$ "e can reerence the o%(ects in tuples using index num%ers in the same "ay as
"e did "ith lists7
>>> m.uple4*5
7chan'e7
>>> m.uple.indeA("me")
;
>>>
9ou pro%a%ly "on&t create your o"n tuples 'ery re,uently$ although "e&ll see some
instances later on "hen they %ecome necessary. @ne place "here "e tend to see tuples
is "hen a unction returns multiple 'aluesB in this case$ "e "ouldn&t "ant to accidentally
change anything a%out those 'alues or their ordering$ so the unction pro'ides them to
us as a permanent list.
Parentheses are actually optional "hen "e are creating a tupleB "e can also (ust list out
a set o o%(ects to assign to a ne" o%(ect$ and Python "ill assume %y deault that "e
mean to create a tuple7
>>> coordinates + <.*(, U.*U
>>> print coordinates
(<.*(, U.*U)
>>>
2his process is called tuple pacing %ecause "e are packing a num%er o o%(ects into a
78
Real Python
RealPython.com
single immuta%le tuple o%(ect. 0 "e "ere to recei'e the a%o'e coordinates tuple
rom a unction and "e then "ant to retrie'e the indi'idual 'alues rom this tuple$ "e
can perorm the re'erse process$ suita%ly called tuple unpacing7
>>> A, + coordinates
>>> print A
<.*(
>>> print
U.*U
>>>
)e assigned %oth ne" 'aria%les to the tuple coordinates$ separating the names "ith
commas$ and Python automatically kne" ho" to hand out the items in the tuple. 0n act$
"e can al"ays make multiple assignments in a single line %y separating the names "ith
commas$ "hether or not "e use a tuple7
>>> str(, str*, str; + "a", "0", "c"
>>> print str(
a
>>> print str*
0
>>> print str;
c
>>>
2his "orks %ecause Python is %asically doing tuple packing and tuple unpacking on its
o"n in the %ackground. 6o"e'er$ "e don&t use this 'ery re,uently %ecause it usually
only makes code harder to read and more diicult to update "hen changes are needed.
9e,iew e6ercises-
Create a tuple named cardinal=nums that holds the strings irst$
second and third in order
1isplay the string at position 2 in cardinal=nums %y using an index num%er
Copy the tuple 'alues into three ne" strings named pos($ pos* and pos; in
a single line o code %y using tuple unpacking$ then print those string 'alues
79
Real Python
RealPython.com
Q.A. !tore relationships in dictionaries
ne o the most useul structures in Python is a dictionary.
11
>ike lists and tuples$
dictionaries are used as a "ay to store a collection o o%(ects. 6o"e'er$ the order
o the o%(ects in a dictionary is unimportant. 0nstead$ dictionaries hold inormation in
pairs o data$ called key+'alue pairs. 8'ery ey in a dictionary is associated "ith a single
value. >et&s take a look at an example in "hich "e create a dictionary that represents
entries in a phone%ook7
@
>>> phone0oo1 + {"Zenn"2 "PRQ!C;?U", "Ii1e Zones"2 "*P(!;;?!P??<",
"$estin"2 "U??!QP;!;;RU"}
>>> print phone0oo1
{7Ii1e Zones72 7*P(!;;?!P??<7, 7Zenn72 7PRQ!C;?U7, 7$estin72 7U??!QP;!
;;RU7}
>>>
2he eys in our example phone%ook are names o people. Leys are (oined to their values
"ith colons$ "here each 'alue is a phone num%er. 2he key+'alue pairs are each
separated %y commas$ (ust like the items in a list or tuple. )hile lists use s,uare
%rackets and tuples use parentheses$ dictionaries are enclosed in curly %races$ {}. Oust
as "ith empty lists$ "e could ha'e created an empty dictionary %y using only a pair o
curly %races.
-otice ho"$ "hen "e displayed the contents o the dictionary "e had (ust created$ the
key+'alue pairs appeared in a dierent order. Python sorts the contents o the dictionary
in a "ay that makes it 'ery ast to get inormation out o the dictionary F%y a process
called hashing.$ %ut this ordering changes randomly e'ery time the contents o the
dictionary change.
0nstead o the order o the items$ "hat "e really care a%out is which value belongs to
which ey. 2his is a 'ery natural "ay to represent many dierent types o inormation.
#or instance$ 0 pro%a%ly don&t care "hich num%er 0 happen to put into my phone%ook
irstB 0 only "ant to kno" "hich num%er %elongs to "hich person. )e can retrie'e this
inormation the same "ay as "e did "ith lists$ using s,uare %rackets$ except that "e
speciy a key instead o an index num%er7
11 0n act$ Python calls them dict o%(ects$ and sometimes people reer to them as dicts or short.
80
Real Python
RealPython.com
>>> phone0oo14"Zenn"5
7PRQ!C;?U7
>>>
)e can add entries to a dictionary %y speciying the ne" key in s,uare %rackets and
assigning it a 'alue7
>>> phone0oo14">0ama"5 + "*?*!<CR!(<(<"
>>> print phone0oo1
{7Ii1e Zones72 7*P(!;;?!P??<7, 7>0ama72 7*?*!<CR!(<(<7, 7Zenn72 7PRQ!C;?U7,
7$estin72 7U??!QP;!;;RU}
>>>
)e&re not allo"ed to ha'e duplicates keys in a Python dictionaryB in other "ords$ each
key can only %e assigned a single 'alue. 2his is %ecause ha'ing duplicate keys "ould
make it impossi%le to identiy which key "e mean "hen "e&re trying to ind the key&s
associated 'alue. 0 a key is gi'en a ne" 'alue$ Python (ust o'er"rites the old 'alue. #or
instance$ perhaps Zenn got a ne" num%er7
>>> phone0oo14"Zenn"5 + "CCC!?(UU"
>>> print phone0oo1
{7Ii1e Zones72 7*P(!;;?!P??<7, 7>0ama72 7*?*!<CR!(<(<7, 7Zenn72 7CCC!?(UU7,
7$estin72 7U??!QP;!;;RU7}
>>>
2o remo'e an indi'idual key+'alue pair rom a dictionary$ "e use the del() unction
Fshort or delete.7
>>> del(phone0oo14"$estin"5)
>>> print phone0oo1
{7Ii1e Zones72 7*P(!;;?!P??<7, 7>0ama72 7*?*!<CR!(<(<7, 7Zenn72 7CCC!?(UU7}
>>>
@ten "e "ill "ant to loop o'er all o the keys in a dictionary. )e can get all o the keys
out o a dictionary in the orm o a list %y using the 1es() method7
>>> print phone0oo1.1es()
47Ii1e Zones7, 7Zenn7, 7>0ama75
>>>
0 "e "anted to do something speciic "ith each o the dictionary&s keys$ though$ "hat&s
usually e'en easier to do is to use a for loop to get each key indi'idually. !aying for
A in dictionar automatically gi'es us each key in the dictionary. )e can then use
81
Real Python
RealPython.com
the 'aria%le name in our for loop to get each corresponding 'alue out o our
dictionary7
12
>>> for contact6ame in phone0oo12
print contact6ame, phone0oo14contact6ame5
Ii1e Zones *P(!;;?!P??<
Zenn CCC!?(UU
>0ama *?*!<CR!(<(<
>>>
)e can also use the in key"ord to check "hether or not a particular key exists in a
dictionary7
>>> "Zenn" in phone0oo1
.rue
>>> "-anta" in phone0oo1
3alse
>>>
2his expression FA in dictionar. is usually used in an if statement$ or instance
%eore deciding "hether or not to try to get the corresponding 'alue or that key. 2his is
important %ecause it&s an error to attempt to get a 'alue or a key that doesn&t exist in a
dictionary7
>>> phone0oo14"-anta"5
.race0ac1 (most recent call last)2
3ile "<pshell#(>", line (, in <module>
phone0oo14"-anta"5
[e&rror2 7-anta7
>>>
0 "e do "ant to access a dictionary&s keys in their sorted order$ "e can use Python&s
sorted() unction to loop o'er the keys alpha%etically7
>>> for contact6ame in sorted(phone0oo1)2
print contact6ame, phone0oo14contact6ame5
Zenn CCC!?(UU
Ii1e Zones *P(!;;?!P??<
>0ama *?*!<CR!(<(<
>>>
12 6ere "e&'e "ritten a loop in the interacti'e "indo"B the %lank line is %ecause "e had to hit %ackspace
in order to make this line unindented so that Python kno"s "here "e "ant to end the loop.
82
Real Python
RealPython.com
Leep in mind that sorted() doesn&t re+sort the order o the actual dictionaryB Python
has to keep the apparently hapha*ard ordering o keys in the dictionary in order to %e
a%le to access the dictionary keys ,uickly using its o"n complicated hash unction.
1ictionaries are 'ery lexi%le and can hold a "ide 'ariety o inormation %eyond the
strings that "e&'e experimented "ith here. Although it&s usually the case$ dictionaries
don&t e'en have to hold keys or 'alues that are all same types o o%(ects. 1ictionary
'alues can %e anything$ "hile keys must %e immuta%le o%(ects. #or instance$ "e could
ha'e added a key to our phone0oo1 that "as an integer o%(ect. 6o"e'er$ "e couldn&t
ha'e added a list as a key$ since that list could %e modiied while it&s in the dictionary$
%reaking the o'erall structure o the dictionary.
1ictionary 'alues can e'en %e other dictionaries$ "hich is more common than it pro%a%ly
sounds. #or instance$ "e could imagine a more complicated phone%ook in "hich e'ery
key is a uni,ue contact name that is associated "ith a dictionary o its o"nB these
indi'idual contact dictionaries could then include keys descri%ing the phone num%er
Fhome$ "ork$ custom supplied type$ etc.. that are each associated "ith a phone
num%er 'alue. 2his is much like creating a list o lists7
>>> contacts + {"Zenn"2 {"cell"2 "CCC!?(UU", "home"2 "PRQ!C;?U"}, "Ii1e
Zones"2 {"home"2 "*P(!;;?!P??<"}, "$estin"2 {"wor1"2 "U??!QP;!;;RU"}}
>>> print contacts
{7Ii1e Zones72 {7home72 7*P(!;;?!P??<7}, 7Zenn72 {7cell72 7CCC!?(UU7,
7home72 7PRQ!C;?U7}, 7$estin72 {7wor172 7U??!QP;!;;RU7}}
>>> print contacts4"Zenn"5
{7cell72 7CCC!?(UU7, 7home72 7PRQ!C;?U7}
>>> print contacts4"Zenn"54"cell"5
CCC!?(UU
>>>
)hen "e "anted to retrie'e a speciic 'alue inside the dictionary+'alue associated "ith
the key or Zenn$ "e had to say contacts4"Zenn"54"cell"5. 2his is %ecause
saying contacts4"Zenn"5 no" returns the dictionary o num%ers or Zenn$ rom
"hich "e ha'e to speciy a key or a speciic type o phone num%er.
#inally$ there are t"o alternati'e "ays to create dictionaries that can come in useul in
certain speciic contexts. 9ou shouldn&t "orry a%out learning the details o ho" to use
them right no"$ %ut (ust %e a"are that they are a possi%ility.
83
Real Python
RealPython.com
)hen you "ant to use keys that are strings that only include letters and num%ers Fi.e.$
strings that could stand or 'aria%le names.$ you can use dict() to create a dictionary
like so7
>>> simple$ictionar + dict(strin'(+""alue(", strin'*+*, strin';+;.?)
>>> print simple$ictionar
{7strin'*72 *, 7strin';72 ;.?, 7strin'(72 7"alue(7}
>>>
6ere "e created a ne" dictionary named simple$ictionar that has three string
keys$ %ut without putting ,uotes around the key names this time %ecause Python kno"s
to expect strings "hen "e use dict() in this "ay. )e&ll see an example o this use o
dict() later in the course.
2he second "ay to use dict() in'ol'es pro'iding a list o key+'alue pairs represented as
tuples$ like so7
>>> simple$ictionar + dict(4("strin'(",""alue("), ("strin'*",*),
("strin';",;.?)5)
>>> print simple$ictionar
{7strin'*72 *, 7strin';72 ;.?, 7strin'(72 7"alue(7}
>>>
)ithin dict()$ "e include a list Fthe s,uare %rackets.$ and separated %y commas inside
that list are tuples Fin the pairs o parentheses. that hold each o our key+'alue pairs. 0n
this case$ "e aren&t limited to simple string keysB "e can again assign any sort o keys
"e "ant as long as they are all the same type o o%(ect.
Kee* in 0ind th%t? e,en thou#h diction%ries 0i#ht see0 0ore co0*(ic%ted to
use? their 0%in %d,%nt%#e is th%t they %re very .%st. When you5re workin# with
(on# (ists o. d%t%? re*e%ted(y cyc(in# throu#h %n entire (ist to .ind % sin#(e *iece
o. in.or0%tion c%n t%ke % (on# ti0eG by contr%st? (ookin# u* the in.or0%tion
%ssoci%ted with % diction%ry key is %(0ost inst%nt%neous. I. you e,er .ind yourse(.
w%ntin# to cre%te 0u(ti*(e (ists where ite0s 0%tch u* %cross (ists b%sed on their
orderin#? you shou(d *rob%b(y be usin# % diction%ry inste%dA
A
9e,iew e6ercises-
Create an empty dictionary named 0irthdas
8nter the ollo"ing data into the dictionary7
1A
84
Real Python
RealPython.com
&>uke !ky"alker&7 &J=2C=1U&
&@%i+)an Leno%i&7 &A=11=JE&
&1arth Gader&7 &C=1=C1&
)rite if statements that test to check i &9oda& and &1arth Gader& exist as keys
in the dictionary$ then enter each o them "ith %irthday 'alue &unkno"n& i
their name does not exist as a key
1isplay all the key+'alue pairs in the dictionary$ one per line "ith a space
%et"een the name and the %irthday$ %y looping o'er the dictionary&s keys
1elete &1arth Gader& rom the dictionary
Donus7 4ake the same dictionary %y using dict() and passing in the initial
'alues "hen you irst create the dictionary
1A All %irth dates are rough approximations %ased on the :alactic !tandard Calendar.
85
Real Python
RealPython.com
7) /i(e In*ut %nd )ut*ut
E.1. Read and "rite simple iles
o ar$ "e&'e allo"ed the user to type input into our program and displayed output
on the screen. Dut "hat i "e "ant to "ork "ith a lot o data/ 0t&s time to learn
ho" to use Python to "ork "ith iles.
!
2o read or "rite ra" text iles Fi.e.$ the sort o ile that you could use in a %asic text
editor %ecause it contains no ormatting or extra inormation.$ "e use the general+
purpose open() unction. )hen "e open() a ile$ the irst thing "e ha'e to determine
is i "e "ant to read rom it or write to it. >et&s start %y creating a ne" text ile and
"riting some data into it7
m>utput3ile + open("hello.tAt", "w")
)e passed t"o pieces o inormation Fcalled arguments. to the open() unction. 2he
irst argument "as a string that represents the actual name o the ile "e "ant to
create7 hello.tAt. 2he second argument speciies our purpose or opening the ileB in
this case$ "e said "w" %ecause "e "ant to write to the ile.
2he open() unction returns a 3ile o%(ect that has %een sa'ed in the 'aria%le
m>utput3ile. >et&s "rite a line o text into the ile "ith the writelines() method.
@ur ull script should look like this7
m>utput3ile + open("hello.tAt", "w")
m>utput3ile.writelines(".his is m first file.")
m>utput3ile.close()
4ake sure you kno" "here you are sa'ing this script %eore you run itB since "e didn&t
speciy a directory path or the ile$ right no" hello.tAt "ill %e created in the same
older as the script.
Cou shou(d %(w%ys use the close() 0ethod to c(ose %ny .i(e th%t you h%,e
open() once you5re co0*(ete(y done with the .i(e. Python wi(( e,entu%((y c(ose
%ny o*en .i(es when you e6it the *ro#r%0? but not c(osin# .i(es yourse(. c%n sti(( A
86
Real Python
RealPython.com
c%use sur*risin# *rob(e0s. 7his is bec%use Python o.ten buffers .i(e out*ut? 0e%nin#
th%t it 0i#ht s%,e % bunch o. co00%nds you5,e written @without runnin# the0 ri#ht
%w%y)? then run the0 %(( in % bi# b%tch (%ter on to 0%ke the *rocess run .%ster. 7his
cou(d resu(t in so0ethin# (ike the .o((owin# unw%nted situ%tion- you write out*ut to
% .i(e? then o*en th%t .i(e u* in % te6t editor to ,iew the out*ut? but since you didn5t
close() the .i(e in Python @%nd I'+ is sti(( runnin#)? the .i(e is co0*(ete(y b(%nk
even though Python is *(%nnin# to write out*ut to the .i(e be.ore it is c(osed.
Ater running this script$ you should see a ne" ile named hello.tAt appear in the
same older as your scriptB open the output ile up yoursel to check that it contains the
line "e "rote.
2he writelines() method can also take a list o lines to %e "ritten all at once. 2he
lines "ill %e "ritten one ater the other "ithout a ne" line$ so "e ha'e to speciy the
special ne"line character \n i "e actually "ant the lines to appear on separate lines.
>et&s modiy the script to "rite a couple lines rom a list7
m>utput3ile + open("hello.tAt", "w")
lines.o:rite + 4".his is m file.", "\n.here are man li1e it,", "\n0ut this
one is mine."5
m>utput3ile.writelines(lines.o:rite)
m>utput3ile.close()
)ithout deleting the pre'ious hello.tAt ile$ try running this 'ersion o the script$
then check the contents o the ile. 2his is an important lesson that&s easy to orget7
4s soon %s you open() % .i(e in "w" @write) 0ode? i. the .i(e %(re%dy e6ists then
the .i(e5s current contents %re completely deleted. It5s % co00on 0ist%ke to
%ccident%((y o,erwrite or de(ete the contents o. %n i0*ort%nt .i(e this w%y. A
0 "e "ant to add inormation to a ile instead o o'er"riting its contents$ "e can use
the "a" mode to append to the end o the ile. 2he rest o the process is identical to
"riting in "w" modeB the only dierence is that "e start "riting at the end o the ile.
Again$ i "e "ant the ne" output to appear on a ne" line$ "e ha'e to speciy the \n
character to mo'e to a ne" line. >et&s append one additional line onto our current ile
hello.tAt7
m>utput3ile + open("hello.tAt", "a")
neAt%ine + 4"\n6>6 -&VH#.H,9"5
m>utput3ile.writelines(neAt%ine)
m>utput3ile.close()
87
Real Python
RealPython.com
-o" that "e ha'e a ile "ritten$ let&s read the data rom it. 9ou can pro%a%ly guess ho"
this goes %y no"7
m#nput3ile + open("hello.tAt", "r")
print m#nput3ile.readlines()
m#nput3ile.close()
2his time$ "e used the "r" mode to read input rom the ile. )e then used the
readlines() method to return e'ery line o the ile$ "hich are displayed like so7
>>>
47.his is m file.\n7, 7.here are man li1e it,\n7, 70ut this one is
mine.\n7, 76>6 -&VH#.H,975
>>>
2he output is returned in the orm o a list$ and all o the line %reaks "ere 'isi%le to us
as printed ne"line characters. @ne common "ay o "orking "ith a ile in its entirety is
to use a for loop7
m#nput3ile + open("hello.tAt", "r")
for line in m#nput3ile.readlines()2
print line,
m#nput3ile.close()
>otice how we ended our print st%te0ent with % co00%G this is bec%use %ny
print st%te0ent wi(( usu%((y %dd % new (ine to the end o. the (ine o. out*ut.
7he e6tr% co00% sto*s the print st%te0ent .ro0 %ddin# this %uto0%tic \n so
th%t the ne6t print st%te0ent wi(( continue to dis*(%y on the s%0e (ine. $ince our
.i(e already has new (ine ch%r%cters? %ddin# extra new (ines wou(d h%,e 0%de the
.i(e out*ut dis*(%y incorrect(y? with % b(%nk (ine %**e%rin# in between e%ch %ctu%(
(ine o. the .i(e.
3
)e can also read lines rom the ile one at a time using the readline() method.
Python "ill keep track o "here "e are in the ile or as long as "e ha'e it open$
returning the next a'aila%le line in the ile each time readline() is called7
m#nput3ile + open("hello.tAt", "r")
line + m#nput3ile.readline()
while line 9+ ""2
print line,
line + m#nput3ile.readline()
m#nput3ile.close()
2here is an additional short+cut that can %e helpul in organi*ing code "hen "orking
88
Real Python
RealPython.com
"ith iles7 using Python&s with key"ord. 5sing with to read our ile$ "e could say7
with open("hello.tAt", "r") as m#nput3ile2
for line in m#nput3ile.readlines()2
print line,
Compare this code careully to the t"o pre'ious examples. )hen "e say with Y as
G "e are deining the 'aria%le G to %e the result o running Y. 2his %egins a %lock o
code "here "e can use our ne" 'aria%le as usual Fin this case$ m#nput3ile.. 2he
added %eneit "ith using the with key"ord is that "e no longer ha'e to "orry a%out
closing the ileB once our with %lock is inished$ this clean+up "ork "ill %e managed
or us automatically.
0n act$ "e can name multiple 'aria%les in a with statement i "e "ant to open
multiple iles at once. #or instance$ i "e "anted to read hello.tAt in and "rite its
contents out into a ne" ile hi.tAt line+%y+line$ "e could simply say7
with open("hello.tAt", "r") as m#nput, open("hi.tAt", "w") as m>utput2
for line in m#nput.readlines()2
m>utput.write(line)
2his "ill take care o all the clean+up "ork or us$ closing %oth iles once "e exit the
%lock o code inside the with statement. F@ course$ practically speaking there&s an
easier "ay to accomplish this particular taskB the shutil module includes many helpul
unctions including cop()$ "hich can %e used to copy an entire ile into a ne"
location..
7he rest o. the 0%teri%( in this section is conce*tu%((y 0ore co0*(ic%ted %nd
usu%((y isn5t necess%ry .or 0ost b%sic .i(e re%din#Owritin# t%sks. /ee( .ree to ski0
this re0%inin# 0%teri%( .or now %nd co0e b%ck to it i. you e,er .ind th%t you
need to re%d or write to % .i(e in % w%y th%t in,o(,e s*eci.ic parts o. (ines r%ther
th%n t%kin# entire (ines .ro0 % .i(e one by one.
A
0 "e "ant to 'isit a speciic part o the ile$ "e can use the see1() method to (ump a
particular num%er o characters into the ile. #or instance7
m#nput3ile + open("hello.tAt", "r")
print "%ine ? (first line)2", m#nput3ile.readline()
m#nput3ile.see1(?) # Lump 0ac1 to 0e'innin'
89
Real Python
RealPython.com
print "%ine ? a'ain2", m#nput3ile.readline()
print "%ine (2", m#nput3ile.readline()
m#nput3ile.see1(P) # Lump to character at indeA P
print "%ine ? (startin' at Uth character)2", m#nput3ile.readline()
m#nput3ile.see1((?, () # relati"e Lump forward (? characters
print "%ine ( (startin' at ((th character)2", m#nput3ile.readline()
m#nput3ile.close()
Run this script$ then ollo" along "ith the output as you read the description$ since it&s
not the most intuiti'e method to use. )hen "e pro'ide a single num%er to see1()$ it
"ill go to the character in the ile "ith that index num%er$ regardless o "here "e
currently are in the ile. 2hus$ see1(?) al"ays gets us %ack to the %eginning o the ile$
and see1(P) "ill al"ays place us at the character at index position <$ regardless o
"hat "e ha'e done pre'iously. )hen "e pro'ide a second argument o ( to see1()$
as in the last example$ "e are mo'ing or"ard For %ack"ard$ i "e use a negati'e
num%er. relative to "here "e currently are in the ile.
1C
0n this case$ ater "e displayed
line 0 starting at its U
th
character$ "e "ere currently at the %eginning o line 1. Calling
see1((?, () then mo'ed us 10 characters ahead in line 1. Clearly$ this sort o seeking
%eha'iour is only useul in 'ery speciic cases3
1J
Although it&s less commonly used$ it is possi%le to open a ile or %oth reading and
"riting. 9ou may ha'e already guessed "hy this is usually not a good idea$ thoughB it&s
typically 'ery diicult to keep track o "here you are in a particular ile using see1()
in order to decide "hich pieces you "ant to read or "rite. )e can speciy the mode
r) to allo" or %oth reading and "riting$ or ra) to %oth read and append to an
existing ile. !ince "riting or appending "ill change the characters in the ile$ ho"e'er$
you "ill need to perorm a ne" see1() "hene'er s"itching modes rom "riting to
reading.
9e,iew e6ercises-
Read in the ra" text ile poem.txt rom the chapter E practice iles and
display each line %y looping o'er them indi'idually$ then close the ileB "e&ll
1C 0 "e had passed a 0 as the second argument$ see1() "ould act exactly as i "e had only pro'ided the
irst num%erB since 0 is passed as the deault 'alue$ "e usually don&t %other to pro'ide it explicitly.
1J #or instance$ seeking is great i you need to read or modiy particular entries in a ixed+"idth ile.
90
Real Python
RealPython.com
discuss using ile paths in the next section$ %ut or no" you can sa'e your
script in the same older as the text ile
Repeat the pre'ious exercise using the with key"ord so that the ile is
closed automatically ater you&re done looping through the lines
)rite a text ile output.txt that contains the same lines as poem.txt %y
opening %oth iles at the same time Fin dierent modes. and copying the
original ile o'er line+%y+lineB do this using a loop and closing %oth iles$ then
repeat this exercise using the with key"ord
Re+open output.txt and append an additional line o your choice to the end
o the ile on a ne" line
E.2. 5se more complicated older structures
hances are that you don&t "ant to limit yoursel to using the same older as your
script or all your iles all the time. 0n order to get access to dierent directories$
"e can (ust add them to the ile name to speciy a ull path. #or instance$ "e could
ha'e pointed our script to the ollo"ing ictitious path7
C
m#nput3ile + open("@2BI $ocumentsBuseless teAt filesBhello.tAt", "r")
>otice how we used on(y .orw%rd s(%shes in the *%th J not b%cks(%shes. 7his
0ethod o. substitutin# .orw%rd s(%shes works .ine e,en in Windows? where the
o*er%tin# syste05s de.%u(t is to use b%cks(%shes to se*%r%te directories. We do
this to %,oid the Desc%*e ch%r%cterF *rob(e0 where Python wou(d h%,e tre%ted %
b%cks(%sh %nd the ch%r%cter .o((owin# it %s % *%ir o. s*eci%( ch%r%cters inste%d o.
re%din# the0 %(on# with the rest o. the strin# nor0%((y. 7he b%cks(%sh is c%((ed %n
Desc%*e ch%r%cterF bec%use it (ets Python know th%t the b%cks(%sh %nd the
ch%r%cter .o((owin# it shou(d be re%d as a pair to re*resent % di..erent ch%r%cter.
/or inst%nce? D\nF wou(d be inter*reted %s % new(ine ch%r%cter %nd D\tF
re*resents % Dt%bF ch%r%cter.
4nother w%y to #et %round this *rob(e0 is to *ut % (owerc%se DrF 3ust be.ore %
strin#? without % s*%ce? (ike so-
m6ame + r"@2\I $ocuments\useless teAt files\hello.tAt"
A
91
Real Python
RealPython.com
7his cre%tes % Dr%wF strin# th%t is re%d in e6%ct(y %s it is ty*ed? 0e%nin# th%t
b%cks(%shes %re on(y e,er re%d %s %ctu%( b%cks(%sh ch%r%cters %nd won5t be
co0bined with %ny other ch%r%cters to cre%te s*eci%( ch%r%cters.
0n order to do anything more ad'anced "ith ile structures$ "e need to rely on a %uilt+in
set o Python code called the os module$ "hich gi'es us access to 'arious unctions
related to the operating system. !o the irst thing that "e "ill need to do is import os
into our code.
0 you are used to "orking in the command line$ the os module gi'es you much o the
same %asic unctionality that "ill pro%a%ly already %e some"hat amiliar ? or instance$
the rmdir() unction to delete a directory and the m1dir() unction to create a ne"
directory.
!oon "e&ll see ho" to manipulate and interact "ith the included example iles in 'arious
"ays. Although there are a num%er o dierent "ays to set your scripts up correctly or
accessing iles$ or simplicity "e "ill do the ollo"ing7 "hene'er "e need to "rite a
script that makes use o an example ile in the course older$ "e "ill start "ith
something like the ollo"ing code7
import os
m8ath + "@2B,eal 8thonB@ourse materials"
9ou should replace the string that gets assigned to the 'aria%le path "ith a string that
actually represents the location at "hich you&'e sa'ed the main course materials older
F"hich is named ,eal 8thonB@ourse materials %y deault$ %ut might not %e
sa'ed directly onto your @2 dri'e..
1Q
2his "ay$ you "ill only e'er ha'e to speciy "hich
olders inside o the course older you "ant to access instead o typing it out each time
you "ant to access a sample ile. )e "ill then (oin this path to the rest o each ile
location using the os.path.Loin() unction$ as "e&ll see %elo".
#or instance$ i you "anted to display the ull contents o the example text ile named
eAample.tAt in the chapter E practice iles older$ the sample code "ould look like
the ollo"ing7
import os
1Q -on+)indo"s users "ill pro%a%ly need to replace @2B "ith BhomeBourusernameB.
92
Real Python
RealPython.com
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice files"
input3ile6ame + os.path.Loin(m8ath, "eAample.tAt")
with open(input3ile6ame, "r") as m#nput3ile2
for line in m#nput3ile.readlines()2
print line
Again$ the string on the second line that represents the path to the 8ractice files
older might need to %e changed i you sa'ed the course iles in a dierent location.
-otice ho" "e used os.path.Loin() as a "ay o adding the ull ile path onto the
main directory %y passing the t"o parts o the path as arguments to this unction. 2his
(ust com%ines the t"o strings together$ making sure that the right num%er o slashes is
included in %et"een the t"o parts. 0nstead o using os.path.Loin()$ "e could ha'e
simply added Fconcatenated. the string path to the rest o the ile path %y using a plus
sign and adding an extra or"ard slash %et"een the t"o strings like this7
input3ile6ame + m8ath ) "BeAample.tAt"
6o"e'er$ os.path.Loin() comes "ith the added %eneit o Python automatically
adding any slashes %et"een the t"o path strings necessary to create a 'alid path. 2his is
"hy it&s a good idea to get into the ha%it o using this unction to (oin path names
togetherB sometimes "e "ill retrie'e part o a path names through our code and not
now ahead o time i it includes an extra slash or not$ and in these cases
os.path.Loin() "ill %e a necessity.
>et&s start modiying iles using a %asic practical example7 "e "ant to rename e'ery
.X#3 ile in a particular older to %e a .Z8X ile o the same name. 0n order to get a list
o the iles in the older$ "e can use the os.listdir() unction$ "hich returns a list o
ile names ound in the pro'ided directory. )e can use the string method endswith()
to check the ile extension o each ile name. #inally$ "e&ll use os.rename() to rename
each ile7
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesBima'es"
# 'et a list of all files and folders
file6ames%ist + os.listdir(m8ath)
# loop o"er e"er file in the main folder
for file6ame in file6ames%ist2
if file6ame.lower().endswith(".'if")2 # eAtension matches a X#3 file
93
Real Python
RealPython.com
print 7@on"ertin' "{}" to Z8X...7.format(file6ame)
# 'et full path name and chan'e the ".'if" to ".Lp'"
full3ile6ame + os.path.Loin(m8ath, file6ame)
new3ile6ame + full3ile6ame4?2len(full3ile6ame)!<5 ) ".Lp'"
os.rename(full3ile6ame, new3ile6ame)
!ince endswith() is case+sensiti'e$ "e had to con'ert file6ame to lo"ercase using
the lower() methodB since this method returns a string as "ell$ "e (ust stacked one
method on top o another in the same line. )e used su%scripting to replace the ile
extension in the line new3ile6ame + full3ile6ame4?2len(full3ile6ame)!<5
%y trimming the last our characters Fthe .'if. o o the ull ile name$ then "e
added the ne" .Lp' extension instead. @ur os.rename() unction took t"o
arguments$ the irst %eing the ull original ile name and the second %eing the ne" ile
name.
A more eicient "ay o perorming this same task "ould %e to import and use the 'lo0
module$ "hich ser'es the purpose o helping to match patterns in ile names. 2he
'lo0.'lo0() unction takes a string that uses "ildcard characters$ then returns a
list o all possi%le matches. 0n this case$ i "e pro'ide the ile name pattern K.'if
then "e "ill %e a%le to ind any ile names that match the .'if extension at the
end7
1E
import 'lo0
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesBima'es"
possi0le3iles + os.path.Loin(m8ath, "K.'if")
for file6ame in 'lo0.'lo0(possi0le3iles)2
print 7@on"ertin' "{}" to Z8X...7.format(file6ame)
full3ile6ame + os.path.Loin(m8ath, file6ame)
new3ile6ame + full3ile6ame4?2len(full3ile6ame)!<5 ) ".Lp'"
os.rename(full3ile6ame, new3ile6ame)
Dy pro'iding a string "ith the ull ile path and a K$ "e "ere a%le to return a 'lo0 list
o all possi%le :0# images in that particular directory. )e can also use 'lo0() to search
through su%olders ? or instance$ i "e "anted to search or all o the P-: iles that are
in olders inside of our images older$ "e could search using the string pattern7
1E 0nstead o using indexing to get the ile extension$ "e also could ha'e used the os.path.spliteAt()
unction$ "hich takes a ile path and returns a tuple "here the irst item in the tuple is e'erything
%eore the extension and the second item in the tuple is the ile extension.
94
Real Python
RealPython.com
import 'lo0
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesBima'es"
possi0le3iles + os.path.Loin(m8ath, "KBK.pn'")
for file6ame in 'lo0.'lo0(possi0le3iles)2
print file6ame
Adding the string KBK.pn' to the path means that "e are searching or any iles
ending in .pn' that are inside o olders that can ha'e any name Fthe irst K.. !ince
"e used the or"ard slash to separate the last older$ ho"e'er$ "e "ill only %e searching
in su%olders o the ima'es directory.
When you print .i(e *%ths #ener%ted by Python? you 0%y notice th%t so0e o.
the0 inc(ude b%cks(%shes. In .%ct? Python is %uto0%tic%((y %ddin# two
b%cks(%shes e,erywhere? but on(y the second b%cks(%sh o. e%ch *%ir is
dis*(%yed. 7his is bec%use the .irst b%cks(%sh is sti(( %ctin# %s %n Desc%*eF ch%r%cter?
then the second b%cks(%sh te((s Python th%t we do in .%ct w%nt just % b%cks(%sh
ch%r%cter. We cou(d %(so h%,e s*eci.ied our own *%ths this w%y? .or inst%nce-
m8ath + "@2\\,eal 8thon\\@ourse materials\\@hapter Q\\8ractice files\\ima'es"
4(thou#h this wou(d then display the strin# correct(y @try it out)? i. we e,er use the
strin# in % w%y th%t c%uses Python to reinter*ret e%ch o. the b%cks(%shes in the .i(e
*%th %s % doub(e b%cks(%sh? we5(( end u* with %n in,%(id *%th .u(( o. doubled doub(e
b%cks(%shesA 7his is why it5s % #ood ide% to stick with usin# either .orw%rd s(%shes or
Dr%wF strin#s .or *%th n%0es.
A
Another special pattern+matching character that can %e included in a 'lo0 pattern is a
F to stand or any one single characterB or instance$ searching or anything matching
FF.'if "ould only return :0# iles that ha'e a name that is t"o characters long. )e
can also include ranges to search o'er %y putting them in s,uare %racketsB the pattern
4?!U5 "ill match any single num%er rom 0 through U$ and the pattern Wa!DX "ill
match any single letter. #or instance$ i "e "anted to search or any :0# iles that ha'e
the name ima'e ollo"ed speciically %y t"o digits$ "e could pass the pattern
ima'e4?!U54?!U5.'if to 'lo0.
1<
Leep in mind that listdir() returns a list o all iles and olders in a gi'en older.
1< 2hese pattern matching rules ollo" a 5nix shell standard or path expansionsB they are not the same
as regular expressions$ "hich are a much more in'ol'ed pattern matching system that "ill %e
introduced in the chapter on "e% scraping.
95
Real Python
RealPython.com
2hereore$ i "e had "anted to aect e'ery ile in the ima'e older$ then "e "ould
"ant to %e careul not to aect older names as "ell. )e can check this easily %y using
either os.path.isfile() or os.path.isdir()$ %oth o "hich return .rue or
3alse. #or instance$ i "e "anted to add the string folder to the end o each
older name inside the ima'es older %ut not aect any o the iles in ima'es$ "e
could do the ollo"ing7
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesBima'es"
files/nd3olders + os.listdir(m8ath)
for folder6ame in files/nd3olders2
full8ath + os.path.Loin(m8ath, folder6ame)
if os.path.isdir(full8ath)2
os.rename(full8ath, full8ath ) " folder")
2o rename a older For ile.$ "e simply passed the original ull path string and the ne"
ull path string to the os.rename() unction. 6ere "e used os.path.isdir() to
decide "hether folder6ame is actually a older or notB in this case it&s either a 'alid
path to a older or a 'alid path to a ile$ %ut passing any string that isn&t a 'alid older
path to os.path.isdir() "ill return 3alse. Another related unction that can %e
especially useul or deciding "hether or not a particular ile needs to %e created or the
irst time is os.path.eAists()$ "hich returns .rue or 3alse depending on "hether
the ile or older speciied already exists or not.
!ometimes "e need to deal "ith more complicated older structures + or instance$ i "e
"anted to get all the iles in all su%olders o a particular older. #or this$ "e can use
os.wal1(). 2his unction "ill return all the possi%le com%inations o Ffolder$
subfolders$ file names. as tuples that represent the paths to reach e'ery ile any"here
in a named root older. #or instance$ i "e "anted to display e'ery ile "ithin the
ima'es older and any o its su%olders$ "e could do the ollo"ing7
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesBima'es"
for current3older, su0folders, file6ames in os.wal1(m8ath)2
for file6ame in file6ames2
print os.path.Loin(current3older, file6ame)
2he call to os.wal1() created an o%(ect that Python could loop o'er$ each time
96
Real Python
RealPython.com
returning a dierent tuple that includes F1. a particular older$ F2. a list o the
su%olders "ithin that older$ and FA. a list o iles "ithin that older. )e used tuple
unpacking in the outer for loop in order to get e'ery possi%le com%ination o
(current3older, su0folders, file6ames) to loop o'er$ "here current3older
might actually represent the ima'es older or a su%older o ima'es. 0n this case$ "e
don&t care a%out any o the results rom su0folders since looping through each o the
file6ames and (oining them to current3older "ill gi'e us the ull path to e'ery ile.
Although "e&'e co'ered the most common cases$ there are many additional unctions
%elonging to %oth the os module and the os.path module that can %e used in 'arious
"ays or accessing and modiying iles and olders. 0n the assignment %elo"$ "e&ll
practice a couple more o these unctions7 deleting iles and olders %y passing them to
the os.remo"e() unction and getting the si*e o a ile in %ytes %y passing it to the
os.path.'etsiDe() unction.
9e,iew e6ercises-
1isplay the ull paths o all o the iles and olders in the ima'es older %y
using os.listdir()
1isplay the ull paths o any P-: iles in the ima'es older %y using
'lo0.'lo0()
Rename any P-: iles in the ima'es older and its su%olders to %e OP: iles
%y using os.wal1()B in case you mess things up %eyond repair$ there is a
copy o the ima'es older in the 0ac1up older
4ake sure that your last script "orked %y using os.path.eAists() to check
that the iles pn' file T not a 'if.Lp' and Badditional
filesBone last ima'e.Lp' no" exists F%y pro'iding
os.path.eAists() "ith the ull path to each o these iles.
97
Real Python
RealPython.com
Assignment ).2: *se pattern matching to $elete files
Write % scri*t Dre0o,eL.i(es.*yF th%t wi(( (ook in the ch%*ter 7 *r%ctices .i(es
.o(der n%0ed Dlittle picsF %s we(( %(( o. its sub.o(ders. 7he scri*t shou(d
use os.remo"e() to de(ete %ny QP" .i(e .ound in %ny o. these .o(ders if the .i(e
is (ess th%n 2 Kb @2?000 bytes) in siHe.
Cou c%n su**(y the os.path.'etsiDe() .unction with % .u(( .i(e *%th to return the
.i(e5s siHe in bytes. 8heck the contents o. the .o(ders be.ore runnin# your scri*t to
0%ke sure th%t you de(ete the correct .i(esG you shou(d on(y end u* re0o,in# the
.i(es n%0ed Dto 0e deleted.Lp'F %nd Ddefinitel has to 'o.Lp'F =
%(thou#h you shou(d on(y use the .i(e e6tensions %nd .i(e siHes to deter0ine this.
I. you 0ess u* %nd de(ete the wron# .i(es? there is % .o(der n%0ed D0ac1upF th%t
cont%ins %n e6%ct co*y o. the Dlittle picsF .o(der %nd %(( its contents so th%t you
c%n co*y these contents b%ck %nd try %#%in.
?
E.A. Read and "rite C!G data
he types o iles "e ha'e to deal "ith in our e'eryday li'es are usually more
complicated than plain text iles. 0 "e "ant to %e a%le to modiy the contents o
these iles Frather than (ust copy$ rename or delete them.$ "e "ill need more complex
systems or %eing a%le to read this inormation.
2
@ne common "ay o storing text data is in C!G iles. C!G stands or Comma+!eparated
Galue$ %ecause each entry in a ro" o data is usually separated rom other entries %y a
comma. #or example$ the contents o the ile named won1a.cs" in the chapter E
practice materials older look like this7
3irst name,%ast name,,eward
@harlie,Juc1et,"'olden tic1et, chocolate factor"
Eeruca,-alt,sSuirrel re"olution
Eiolet,Jeaure'arde,fruit chew
)e ha'e three columns o 'aria%les7 3irst name$ %ast name$ and ,eward. 8ach line
represents another ro" o data$ including the irst ro"$ "hich is a header ro" that
tells us "hat each entry represents. @ur entries ha'e to appear in the same order or
each ro"$ "ith each entry separated rom others %y commas. -otice ho" "'olden
98
Real Python
RealPython.com
tic1et, chocolate factor" is in ,uotes ? this is %ecause it contains a comma$ %ut
this comma isn&t meant to separate one entry rom another. 2here is no set standard or
ho" to "rite out C!G iles$ %ut this particular ile "as created "ith 4icrosot 8xcel$
"hich added the ,uotation marks around the entry containing a comma.
I. you o*en the Dwon1a.cs"F *r%ctice .i(e? it wi(( 0ost (ike(y be o*ened
%uto0%tic%((y by +6ce(? )*en)..ice 8%(c? ibre)..ice 8%(c? or % si0i(%r *ro#r%0G
%(( o. these *ro#r%0s h%,e the %bi(ity to re%d %nd write 8$; d%t%? which is one
re%son why this .or0%t is so use.u(. 4s (on# %s you don5t need to tr%ck
ch%r%cteristics o. % d%t% .i(e such %s .or0%ttin# %nd co(ors? it5s usu%((y e%siest to
e6*ort d%t% to % 8$; .i(e be.ore workin# with the d%t% in PythonG the 8$; c%n %(w%ys
be o*ened in the %**ro*ri%te *ro#r%0 %nd re=s%,ed %s the *ro*er .or0%t %#%in
(%ter. 8$; .i(es c%n %(so be use.u( .or i0*ortin# or e6*ortin# d%t% .ro0 syste0s such
%s $< d%t%b%ses th%t we wi(( (e%rn %bout in ch%*ter &.
A
Python has a %uilt+in cs" module that makes it nearly as easy to read and "rite C!G iles
as any other sort o text ile. >et&s start "ith a %asic example and read in our
won1a.cs" ile$ then display its contents7
import cs"
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice files"
with open(os.path.Loin(m8ath, "won1a.cs""), "r0") as m3ile2
m3ile,eader + cs".reader(m3ile)
for row in m3ile,eader2
print row
)e opened a ile (ust as "e&'e done %eore$ %ut this time "e chose r0 mode$ "hich
stands or read binary. 2he additional %inary part is important here$ %ecause C!G iles
Fdespite their appearance. aren&t sa'ed in the same "ay as ra" text iles. F!peciically$
on )indo"s "e "ill end up sa'ing extra ne"line characters ater e'ery line i "e only
speciy r mode..
)e then created a C!G ile reader using cs".reader() and passed it the ile. -otice
that "e had to pass the actual opened ile o%(ect to cs".reader()$ not (ust the ile
name3 #rom there$ "e can easily loop o'er the ro"s o data in this C!G reader o%(ect$
"hich are each displayed as a list o strings7
>>>
473irst name7, 7%ast name7, 7,eward75
99
Real Python
RealPython.com
47@harlie7, 7Juc1et7, 7'olden tic1et, chocolate factor75
47Eeruca7, 7-alt7, 7sSuirrel re"olution75
47Eiolet7, 7Jeaure'arde7, 7fruit chew75
>>>
4uch like "ith readline() 'ersus readlines()$ there is also a neAt() method that
gets only the next ro" o data rom a C!G reader o%(ect. 2his method is usually used as
a simple method o skipping o'er a ro" o header dataB or instance$ i "e "anted to
read in and store all the inormation except the irst line o our C!G ile$ "e could add
the line m3ile,eader.neAt() ater opening the C!G ile to skip o'er the irst line$
then loop through the remaining ro"s as usual.
0 "e kno" "hat ields to expect rom the C!G ahead o time$ "e can e'en unpack them
rom each ro" into ne" 'aria%les in a single step7
import cs"
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice files"
with open(os.path.Loin(m8ath, "won1a.cs""), "r0") as m3ile2
m3ile,eader + cs".reader(m3ile)
m3ile,eader.neAt()
for first6ame, last6ame, reward in m3ile,eader2
print "{} {} 'ot2 {}".format(first6ame, last6ame, reward)
Ater skipping the irst header ro"$ "e assigned the three 'alues in each ro" to the
three separate strings first6ame$ last6ame and reward$ "hich "e then used inside
o the for loop$ generating this output7
>>>
@harlie Juc1et 'ot2 'olden tic1et, chocolate factor
Eeruca -alt 'ot2 sSuirrel re"olution
Eiolet Jeaure'arde 'ot2 fruit chew
>>>
2he commas in C!G iles are called delimiters %ecause they are the character used to
separate dierent pieces o the data. !ometimes a C!G ile "ill use a dierent
character as a delimiter$ especially i there are a lot o commas already contained in the
data. #or instance$ let&s read in the ile ta00ed won1a.cs"$ "hich uses ta%s instead
o commas to separate entries and looks like this7
3irst name %ast name ,eward
@harlie Juc1et 'olden tic1et, chocolate factor
100
Real Python
RealPython.com
Eeruca -alt sSuirrel re"olution
Eiolet Jeaure'arde fruit chew
)e can read iles like this using the cs" module (ust as easily as %eore$ %ut "e need to
speciy "hat character has %een used as the delimiter7
import cs"
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice files"
with open(os.path.Loin(m8ath, "ta00ed won1a.cs""), "r0") as m3ile2
m3ile,eader + cs".reader(m3ile, delimiter+"\t")
m3ile,eader.neAt()
for row in m3ile,eader2
print row
6ere "e used the special character \t to mean the ta% character and assigned it to
the argument delimiter "hen "e created m3ile,eader.
)riting C!G iles is accomplished using the cs".writer() method in much the same
"ay. Oust as ro"s o data read rom C!G iles appeared as lists o strings$ "e irst need
to structure the ro"s "e "ant to "rite as lists o strings7
import cs"
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesB>utput"
with open(os.path.Loin(m8ath, "mo"ies.cs""), "w0") as m3ile2
m3ile:riter + cs".writer(m3ile)
m3ile:riter.writerow(4"Io"ie", ",atin'"5)
m3ile:riter.writerow(4",e0el :ithout a @ause", ";"5)
m3ile:riter.writerow(4"Iont 8thon7s %ife of Jrian", "C"5)
m3ile:riter.writerow(4"-anta @laus @onSuers the Iartians", "?"5)
)e opened a ne" ile in w0 mode this time so that "e could write binary data. )e
then "rote out indi'idual ro"s to the C!G ile "riter o%(ect using its writerow()
method. )e also could ha'e used the writerows() method$ "hich takes a list o ro"s$
to "rite all the ro"s in a single line7
import cs"
import os
m8ath + "@2B,eal 8thonB@ourse materialsB@hapter QB8ractice filesB>utput"
m,atin's + 4 4"Io"ie", ",atin'"5,
4",e0el :ithout a @ause", ";"5,
4"Iont 8thon7s %ife of Jrian", "C"5,
4"-anta @laus @onSuers the Iartians", "?"5 5
with open(os.path.Loin(m8ath, "mo"ies.cs""), "w0") as m3ile2
101
Real Python
RealPython.com
m3ile:riter + cs".writer(m3ile)
m3ile:riter.writerows(m,atin's)
0 "e "anted to export data created %y a Python script to For instance. an 8xcel
"ork%ook ile$ although it&s possible to do this directly$ it&s usually suicient and much
easier to create a C!G ile that "e can then open later in 8xcel and$ i needed$ con'ert
to the desired ormat.
9e,iew e6ercises-
)rite a script that reads in the data rom the C!G ile pastimes.cs"
located in the chapter E practice iles older$ skipping o'er the header ro"
1isplay each ro" o data Fexcept or the header ro". as a list o strings
Add code to your script to determine "hether or not the second entry in each
ro" Fthe 3a"orite 8astime. con'erted to lo"er+case includes the "ord
fi'htin' using the string methods find() and lower()
5se the list append() method to add a third column o data to each ro"
that takes the 'alue @om0at i the "ord fi'htin' is ound and takes
the 'alue >ther i neither "ord appears
)rite out a ne" C!G ile cate'oriDed pastimes.cs" to the @utput
older "ith the updated data that includes a ne" header ro" "ith the ields
6ame$ 3a"orite 8astime$ and .pe of 8astime
Assignment ).3: reate a high scores list from '+ $ata
Write % scri*t Dhi#hLscores.*yF th%t wi(( re%d in % 8$; .i(e o. users5 scores %nd
dis*(%y the hi#hest score .or e%ch *erson. 7he .i(e you wi(( re%d in is n%0ed
Dscores.cs"F %nd is (oc%ted in the ch%*ter 7 *r%ctice .i(es .o(der. Cou shou(d
store the hi#h scores %s ,%(ues in % diction%ry with the %ssoci%ted n%0es %s
diction%ry keys. 7his w%y? %s you re%d in e%ch row o. d%t%? i. the n%0e %(re%dy h%s %
score %ssoci%ted with it in the diction%ry? you c%n co0*%re these two scores %nd
decide whether or not to re*(%ce the DcurrentF hi#h score in the diction%ry.
2se the sorted() .unction on the diction%ry5s keys in order to dis*(%y %n ordered
(ist o. hi#h scores? which shou(d 0%tch this out*ut-
&mpiro *;
?
102
Real Python
RealPython.com
%;;tH<A <*
%%@ool$a"e *Q
IaAA. *C
Iisha<R *C
>=> **
Lohnsmith ;?
red (*
tom(*; *R
103
Real Python
RealPython.com
Inter(ude- Inst%(( *%ck%#es
he remaining hal o this course relies on unctionality ound in 'arious toolkits
that are not packaged "ith Python %y deault. 2here are o'er 2C$000 o these
extra packages registered "ith Python and a'aila%le or do"nload. Although all o the
add+on eatures that "e&ll co'er are "idely used and reely a'aila%le$ you "ill irst need
to do"nload and install each o these packages in order to %e a%le to import ne"
unctionality into your o"n code.
2
Python packages and toolkits are usually (ust another "ay o reerring to a module
or set o modules that can %e imported into other Python code$ although sometimes
these modules rely on other code outside o Python$ "hich is "hy it can sometimes %e
tricky to get e'erything installed correctly.
!ome Python packages Fespecially or )indo"s. oer automated installers that you can
do"nload and run "ithout an extra hassle. 5sually in >inux$ installing a Python package
is only a matter o searching or the correct package name Fe.g.$ in the 1e%ian package
directory.$ then running the command7
sudo apt!'et pthon!pac1a'e!name
6o"e'er$ e'entually you "ill come across a Python package that is not as simple to
install or your particular operating system. #or this reason$ 0 recommend that you
install a tool called eas=install no"$ before you "ant to use a diicult+to+install
package. 0ronically$ eas=install can %e diicult to install. Dut once it&s set up
properly$ your uture "ith Python "ill %e much more hassle+ree.
Deore installing anything$ you irst need to make sure that your operating system can
ind PythonB this "ay$ you&ll %e a%le to run Python scripts outside o 01>8.
Windows- @n your desktop$ right+click on 1y 8o0*uter and click Pro*erties.
1U
Click on
the 4d,%nced ta%$ then click on +n,iron0ent%( ;%ri%b(es. Click to highlight the P%th
'aria%le$ then click +dit. 9ou can no" edit the system directories listedB each o these
1U 0 you don&t ha'e a 1y 8o0*uter shortcut$ go to $t%rt 8ontro( P%ne( $yste0 4d,%nced syste0
settin#s.
104
Real Python
RealPython.com
olders is separated rom the pre'ious older %y a comma. 1@ -@2 delete any o the
current paths. :o to the 'ery end o this string and Fassuming you installed Python into
the deault directory. add the t"o Python paths as ollo"s$ starting "ith a semicolon to
separate the ne" paths rom the pre'ious entries in your PA26 'aria%le7
;@2\8thon*Q\;@2\8thon*Q\-cripts
)$ B- 9ou should %e ine as long as you&'e separately do"nloaded the correct 'ersion o
Python 2.E.A and are not relying on the %uilt+in @! Y 'ersion o Python. 2ype pthon
into your 2erminal to make sure it is recogni*ed and loads as 'ersion 2.E.A Fsee %elo"..
inu6- 9ou should %e ine. 2ype pthon into your 2erminal to make sure it is
recogni*ed and loads as 'ersion 2.E.A Fsee %elo"..
1ou%le+check that Python is recogni*ed %y your system %y opening a ne" command
prompt
20
F)indo"s. or 2erminal F@! Y and >inux. "indo" and simply typing the name
pthon as a command. @nce you hit enter$ Python should load (ust the same "ay as i
you "ere in the 01>8 interacti'e "indo"$ gi'ing you a >>> prompt as usual. 9ou can
exit out o Python in this "indo" %y typing eAit().
-o" that your operating system kno"s ho" to access Python$ you can get
eas=install installed and set up7
Windows- 0 you are running A2+%it )indo"s$ do"nload and run the installer ound here
to set up eas=install automatically. 0 you ha'e QC+%it )indo"s$ do"nload and run
the script e*Isetup.pyB you may need to copy the code into a ne" script manually.
)$ B- 0 you ha'e YCode installed$ you may already ha'e a 'ersion o eas=install as
"ell. 0 not$ do"nload the 8:: ile a'aila%le here into your user home directory$ then
install it %y typing the ollo"ing command into your 2erminal7
sh setuptools!?.Rc((!p*.Q.e''
'ebi%nOinu6- 5se the ollo"ing command to install eas=install7
sudo apt!'et install pthon!setuptools
20 Click -tart Fthe )indo"s %utton. and type cmd to ind and start the command prompt.
105
Real Python
RealPython.com
9P1=b%sed o*er%tin# syste0s should do"nload and install the RP4 ile here.
9ou can no" Fgenerally. install most packages %y typing eas=install
pac1a'e=name at the command prompt For )indo"s. or sudo eas=install
pac1a'e=name at the 2erminal For non+)indo"s..
!ince eas=install isn&t al"ays that easy to install$ there is an alternati'e.
Cou don5t need to #o throu#h the .o((owin# *rocess in det%i( yet? but re.er b%ck to
this section %s needed i. you h%,e di..icu(ty inst%((in# % *%ck%#e- A
4ost packages "ill come "ith a setup.p script that "ill help you to install them into
Python. 0 this is the case$ you can ollo" these steps to install the package7
Windows-
1o"nload the .Dip ile or the package and un*ip it into a older in your user
directory Fi.e.$ @2\Hsers\ourname.
1ou%le+check that there is a script named setup.p in the package older
@pen up a command prompt F"hich should display @2\Hsers\ourname>.
and type the command cd ollo"ed %y the package older nameB or instance$ i
you "anted to install a package in the older named 0eautifulsoup<!
<.(.? then you "ould enter7
cd 0eautifulsoup<!<.(.?
2o install the package$ enter the command7
pthon setup.p install
>on=Windows-
1o"nload the .tar.'D ile or the package and decompress it into a older in
your users directory Fi.e.$ BhomeBourname.
1ou%le+check that there is a script named setup.p in the package older
0n 2erminal$ type the command cd ollo"ed %y the package older nameB or
106
Real Python
RealPython.com
instance$ i you "anted to install a package in the older named
0eautifulsoup<!<.(.? then you "ould enter7
cd 0eautifulsoup<!<.(.?
2o install the package$ enter the command7
sudo pthon setup.p install
0 all else ails$ you can al"ays do"nload Fand un*ip. the entire set o iles or a gi'en
package and copy its older into the same directory as the script "here it is used. !ince
the package iles "ill %e in the same current location as the script$ you "ill %e a%le to
ind and import them automatically.
@ course$ there are a num%er o pro%lems "ith this approach ? mainly$ the package may
take up a lot o memory i it&s large$ and you&ll ha'e to copy the entire li%rary o'er into a
ne" directory e'ery time you "rite a script in a ne" older. 0 it&s a small package Fand
the license allo"s you to copy the entire set o source iles.$ ho"e'er$ one %eneit is
that you can then send this entire older$ complete "ith your script and the needed
li%rary iles$ to someone else$ "ho "ould then %e a%le to run your script "ithout ha'ing
to install the package as "ell. 1espite this minor possi%le con'enience$ this approach
should usually only %e used as a last+ditch eort i all other proper attempts to install a
package ha'e ailed.
107
Real Python
RealPython.com
!) Inter%ct with P'/ .i(es
<.1. Read and "rite P1#s
1# iles ha'e %ecome a sort o necessary e'il these days. 1espite their re,uent
use$ P1#s are some o the most diicult iles to "ork "ith in terms o making
modiications$ com%ining iles$ and especially or extracting text inormation.
P
#ortunately$ there are a e" options in Python or "orking speciically "ith P1# iles.
-one o these options are perect solutions$ %ut oten you can use Python to completely
automate or at least ease some o the pain o perorming certain tasks using P1#s.
2he most re,uently used package or "orking "ith P1# iles in Python is named pyPd
and can %e ound here. 9ou "ill need to do"nload and install this package %eore
continuing "ith the chapter.
Windows- 1o"nload and run the automated installer FpyPd+1.1A."inA2.exe..
)$ B- i you ha'e eas=install installed$ you can type the ollo"ing command into
your 2erminal to install pyPd7
sudo eas=install ppdf
@ther"ise$ you "ill need to do"nload and un*ip the .tar.'D ile and install the
module using the setup.p script as explained in the section on installing packages.
'ebi%nOinu6- Oust type the command7
sudo apt!'et install pthon!ppdf
2he pyPd package includes a 8df3ile,eader and a 8df3ile:riterB (ust like "hen
perorming other types o ile input=output$ reading and "riting are t"o entirely
separate processes.
#irst$ let&s get started %y reading in some %asic inormation rom a sample P1# ile$ the
108
Real Python
RealPython.com
irst couple chapters o Oane Austen&s Pride and Prejudice 'ia Pro(ect :uten%erg7
import os
from p8df import 8df3ile,eader
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, "8ride and 8reLudice.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
print "6um0er of pa'es2", input3ile.'et6um8a'es()
print ".itle2", input3ile.'et$ocument#nfo().title
)e created a 8df3ile,eader o%(ected named input3ile %y passing a file() o%(ect
"ith r0 Fread binary. mode and gi'ing the ull path o the ile. 2he additional
%inary part is necessary or reading P1# iles %ecause "e aren&t (ust reading %asic text
data. P1#s include much more complicated inormation$ and saying r0 here instead o
(ust r tells Python that "e might encounter and ha'e to interpret characters that
can&t %e represented as standard reada%le text.
)e can then return the num%er o pages included in the P1# input ile. )e also ha'e
access to certain attri%utes through the 'et$ocument#nfo() methodB in act$ i "e
display the result o simply calling this method$ "e "ill see a dictionary "ith all o the
a'aila%le document ino7
21
>>> print input3ile.'et$ocument#nfo()
{7B@reation$ate72 u7$2*?((?P(*(Q<*?P7, 7B/uthor72 u7@huc17, 7B8roducer72
u7Iicrosoft\Aae >ffice :ord *??Q7, 7B@reator72 u7Iicrosoft\Aae >ffice :ord
*??Q7, 7BIod$ate72 u7$2*?((?P(*(Q<*?P7, 7B.itle72 u78ride and 8reLudice, 0
Zane /usten7}
>>>
)e can also retrie'e indi'idual pages rom the P1# document using the 'et8a'e()
method and speciying the index num%er o the page Fas al"ays$ starting at 0.. 6o"e'er$
since P1# pages include much more than simple text$ displaying the text data on a P1#
page is more in'ol'ed. #ortunately$ pyPd has made the process o parsing out text
some"hat easier$ and "e can use the eAtract.eAt() method on each page7
>>> print input3ile.'et8a'e(?).eAtract.eAt()
.he 8roLect Xuten0er' &Joo1 of 8ride and 8reLudice, 0 Zane /usten .his
eJoo1 is for the use of anone anwhere at no cost and with almost no
restrictions whatsoe"er. Gou ma cop it, 'i"e it awa or re!use it under
the terms of the 8roLect Xuten0er' %icense included with this eJoo1 or online
21 !ometimes this inormation Fcalled meta-data. gets illed in automatically or in unexpected "aysB or
instance$ @huc1 Fmost likely a helpul %ut un"itting 'olunteer. appears to %e the author o this ile;
109
Real Python
RealPython.com
at www.'uten0er'.or' .itle2 8ride and 8reLudice /uthor2 Zane /usten
,elease $ate2 /u'ust *R, *??P 4&Joo1 #(;<*5 4%ast updated2 /u'ust ((, *?((5
%an'ua'e2 &n'lish @haracter set encodin'2 /-@## KKK -./,. >3 .H#- 8,>Z&@.
XH.&6J&,X &J>>[ 8,#$& /6$ 8,&ZH$#@& KKK 8roduced 0 /nonmous Eolunteers,
and $a"id :id'er 8,#$& /6$ 8,&ZH$#@& J Zane /usten @ontents
>>>
#ormatting standards in P1#s are inconsistent at %est$ and it&s usually necessary to take
a look at the P1# iles you "ant to use on a case+%y+case %asis. 0n this instance$ notice
ho" "e don&t actually see ne"line characters in the outputB instead$ it appears that ne"
lines are %eing represented as multiple spaces in the text extracted %y pyPd. )e can
use this kno"ledge to "rite out a roughly ormatted 'ersion o the %ook to a plain text
ile For instance$ i "e only had the P1# a'aila%le and "anted to make it reada%le on an
untalented mo%ile de'ice.7
import os
from p8df import 8df3ile,eader
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, "8ride and 8reLudice.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output3ile6ame + os.path.Loin(path, ">utputB8ride and 8reLudice.tAt")
output3ile + open(output3ile6ame, "w")
title + input3ile.'et$ocument#nfo().title # 'et the file title
total8a'es + input3ile.'et6um8a'es() # 'et the total pa'e count
output3ile.write(title ) "\n")
output3ile.write("6um0er of pa'es2 {}\n\n".format(total8a'es))
for pa'e6um in ran'e(?, total8a'es)2
teAt + input3ile.'et8a'e(pa'e6um).eAtract.eAt()
teAt + teAt.replace(" ", "\n")
output3ile.write(teAt)
output3ile.close()
!ince "e&re "riting out %asic text$ "e chose the plain w mode and created a ile
0oo1.tAt in the >utput older. 4ean"hile$ "e still use r0 mode to read data
rom the P1# ile since$ %eore "e can extract the plain text rom each page$ "e are in
act reading much more complicated data. )e loop o'er e'ery page num%er in the P1#
ile$ extracting the text rom that page. !ince "e kno" that ne" lines "ill sho" up as
additional spaces$ "e can approximate %etter ormatting %y replacing e'ery instance o
dou%le spaces F . "ith a ne"line character.
110
Real Python
RealPython.com
Cou 0%y .ind th%t % P'/ docu0ent inc(udes unusu%( ch%r%cters th%t c%nnot be
written into % *(%in te6t .i(e J .or inst%nce? % tr%de0%rk sy0bo(. 7hese
ch%r%cters %re not in the 4$8II ch%r%cter set? 0e%nin# th%t they c%n5t be
re*resented usin# %ny o. the 12! st%nd%rd co0*uter ch%r%cters. :ec%use o. this?
your code wi(( not be %b(e to write out % r%w te6t .i(e in DwF 0ode. 2su%((y the w%y
to #et %round this is by usin# the encode() 0ethod? (ike so-
teAt + teAt.encode("utf!P")
I. we h%,e % strin# te*t th%t h%s unusu%( ch%r%cters in it? this (ine wi(( %((ow us to
ch%n#e how e%ch ch%r%cter is re*resented @usin# 27/=! encodin#) so th%t we c%n
now store these sy0bo(s in % r%w te6t .i(e. 7hese unusu%( ch%r%cters 0i#ht not
%**e%r the s%0e w%y %s in the ori#in%( .i(e? since the te6t .i(e h%s % 0uch 0ore
(i0ited set o. ch%r%cters %,%i(%b(e? but i. you do not ch%n#e the encodin# then you
wi(( not be %b(e to out*ut the te6t %t %((.
@I. you really w%nt to #et % h%nd(e on te6t encodin# %nd wh%t5s re%((y h%**enin#?
t%ke % (ook %t this t%(k.)
A
0nstead o extracting text$ "e might "ant to modiy the P1# ile itsel$ sa'ing out a ne"
'ersion o the P1#. )e&ll see more examples o "hy and ho" this might occur in the next
section$ %ut or no" create the simplest modiied ile %y sa'ing out only a section o
the original ile. 6ere "e copy o'er the irst three pages o the P1# Fnot including the
co'er page. into a ne" P1# ile7
import os
from p8df import 8df3ile,eader, 8df3ile:riter
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, "8ride and 8reLudice.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output8$3 + 8df3ile:riter()
for pa'e6um in ran'e((, <)2
output8$3.add8a'e(input3ile.'et8a'e(pa'e6um))
output3ile6ame + os.path.Loin(path, ">utputBportion.pdf")
output3ile + file(output3ile6ame, "w0")
output8$3.write(output3ile)
output3ile.close()
)e imported %oth 8df3ile,eader and 8df3ile:riter rom pyPd so that "e can
"rite out a P1# ile o our o"n. 8df3ile:riter doesn&t take any arguments$ "hich
might %e surprisingB "e can start adding P1# pages to our output8$3 before "e&'e
111
Real Python
RealPython.com
speciied "hat ile it "ill %ecome. 6o"e'er$ in order to sa'e the output to an actual P1#
ile$ at the end o our code "e create an output3ile as usual and then call
output8$3.write(output3ile) in order to "rite the P1# contents into this ile.
9e,iew e6ercises-
)rite a script that opens the ile named 2he )histling :ypsy.pd rom the
Chapter < practice iles$ then displays the title$ author$ and total num%er o
pages in the ile
8xtract the ull contents o 2he )histling :ypsy.pd into a .2Y2 ileB you
"ill need to encode the text as 52#+< %eore you can output it
!a'e a ne" 'ersion o 2he )histling :ypsy.pd that does not include the
co'er page into the @utput older
<.2. 4anipulate P1# iles
ten the reason "e "ant to modiy a P1# ile is more complicated than (ust
sa'ing a portion o the ile. )e might "ant to rotate some pages$ crop pages$ or
e'en merge inormation rom dierent pages together. )hen manually editing the iles
in Ado%e Acro%at isn&t a practical or easi%le solution$ "e can automate any o these
tasks using pyPd.
@
>et&s start "ith a surprisingly common pro%lem7 rotated P1# pages. :o ahead and open
up the ile u'l.pdf in the @hapter PB8ractice filesB older. 9ou&ll see that
it&s a lo'ely P1# ile o 6ans Christian Andersen&s %he &gly 'ucling$ except that e'ery
odd+num%ered page is rotated counterclock"ise %y ninety degrees. 2his is simple enough
to correct %y using the rotate@loc1wise() method on e'ery other P1# page and
speciying the num%er o degrees to rotate7
22
import os
from p8df import 8df3ile,eader, 8df3ile:riter
22 >ike"ise$ there is a rotate@ounter@loc1wise() method or the unimaginati'e. 5nortunately or
the imaginati'e$ you can only rotate %y a multiple o ninety degrees.
112
Real Python
RealPython.com
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, "u'l.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output8$3 + 8df3ile:riter()
for pa'e6um in ran'e(?, input3ile.'et6um8a'es())2
pa'e + input3ile.'et8a'e(pa'e6um)
if pa'e6um N * ++ ?2
pa'e.rotate@loc1wise(U?)
output8$3.add8a'e(pa'e)
output3ile6ame + os.path.Loin(path, ">utputB.he @onformed $uc1lin'.pdf")
output3ile + file(output3ile6ame, "w0")
output8$3.write(output3ile)
output3ile.close()
Another useul eature o pyPd is the a%ility to crop pages$ "hich in turn "ill allo" us
to split up P1# pages into multiple parts or sa'e out partial sections o pages. #or
instance$ open up the ile half and half.pdf rom the chapter < practice iles
older to see an example o "here this might %e useul. 2his time$ "e ha'e a P1# that&s
presented in t"o rames per page$ "hich again is not an ideal layout in many
situations. 0n order to split these pages up$ "e "ill ha'e to reer to the IediaJoA
%elonging to each P1# page$ "hich is a rectangle representing the %oundaries o the
page. >et&s take a look at the IediaJoA o a P1# page in the interacti'e "indo" to get
an idea o "hat it looks like7
>>> from p8df import 8df3ile,eader
>>> input3ile + 8df3ile,eader(file("@2B,eal 8thonB@ourse materialsB@hapter
PB8ractice filesBhalf and half.pdf", "r0"))
>>> pa'e + input3ile.'et8a'e(?)
>>> print pa'e.mediaJoA
,ectan'le>0Lect(4?, ?, QU*, R(*5)
>>>
A mediaJoA is a type o o%(ect called a ,ectan'le>0Lect. Conse,uently$ "e can get
the coordinates o the rectangle&s corners7
>>> print pa'e.mediaJoA.lower%eft
(?, ?)
>>> print pa'e.mediaJoA.lower,i'ht
(QU*, ?)
>>> print pa'e.mediaJoA.upper,i'ht
(QU*, R(*)
>>> print pa'e.mediaJoA.upper,i'ht4?5
113
Real Python
RealPython.com
QU*.?
>>> print pa'e.mediaJoA.upper,i'ht4(5
R(*.?
>>>
2hese locations are returned to us as tuples that include the x and y coordinate pairs.
-otice ho" "e didn&t include parentheses any"here %ecause mediaJoA and its corners
are unchangea%le attributes$ not methods o the P1# page.
)e "ill ha'e to do a little math in order to crop each o our P1# pages. Dasically$ "e
need to set the corners o each hal+page so that "e crop out the side o the page that
"e don&t "ant. 2o do this$ "e di'ide the "idth o the landscape page into t"o hal'esB "e
set the right corner o the let+side page to %e hal o the total "idth$ and "e set the
let corner o the right+side page to start hal"ay across the "idth o the page.
!ince "e ha'e to crop the hal+pages in order to "rite them out to our ne" P1# ile$ "e
"ill also ha'e to create a copy o each page. 2his is %ecause the P1# pages are muta%le
o%(ectsB i "e change something a%out a page$ "e also change the same things a%out
any 'aria%le that reerences that o%(ect. 2his is exactly the same pro%lem that "e ran
into "hen ha'ing to copy an entire list into a ne" list %eore making changes. 0n this
case$ "e import the %uilt+in cop module$ "hich creates and returns a copy o an
o%(ect %y using the cop.cop() unction. F0n act$ this unction "orks (ust as "ell or
making copies o entire lists instead o the shorthand list* + list(425 notation..
2his is tricky code$ so take a "hile to "ork through it and play "ith dierent 'ariations
o the copying and cropping to make sure you understand the underlying math7
import os
import cop
from p8df import 8df3ile,eader, 8df3ile:riter
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, "half and half.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output8$3 + 8df3ile:riter()
for pa'e6um in ran'e(?, input3ile.'et6um8a'es())2
pa'e%eft + input3ile.'et8a'e(pa'e6um)
pa'e,i'ht + cop.cop(pa'e%eft)
upper,i'ht + pa'e%eft.mediaJoA.upper,i'ht # 'et ori'inal pa'e corner
# crop and add left!side pa'e
pa'e%eft.mediaJoA.upper,i'ht + (upper,i'ht4?5B*, upper,i'ht4(5)
114
Real Python
RealPython.com
output8$3.add8a'e(pa'e%eft)
# crop and add ri'ht!side pa'e
pa'e,i'ht.mediaJoA.upper%eft + (upper,i'ht4?5B*, upper,i'ht4(5)
output8$3.add8a'e(pa'e,i'ht)
output3ile6ame + os.path.Loin(path, ">utputB.he %ittle Iermaid.pdf")
output3ile + file(output3ile6ame, "w0")
output8$3.write(output3ile)
output3ile.close()
P'/ .i(es %re % bit unusu%( in how they s%,e *%#e orient%tion. 'e*endin# on how
the P'/ w%s ori#in%((y cre%ted? it 0i#ht be the c%se th%t your %6es %re switched
J .or inst%nce? % st%nd%rd D*ortr%itF docu0ent th%t5s been con,erted into %
(%ndsc%*e P'/ might h%,e the 6=%6is re*resented ,ertic%((y whi(e the y=%6is is
horiHont%(. ikewise? the corners wou(d %(( be rot%ted by &0 de#reesG the
upper%eft corner wou(d %**e%r on the u**er ri#ht or the (ower (e.t? de*endin# on
the .i(e5s rot%tion. +s*eci%((y i. you5re workin# with % (%ndsc%*e P'/ .i(e? it5s best to
do so0e initi%( testin# to 0%ke sure th%t you %re usin# the correct corners %nd %6es.
A
Deyond manipulating an already existing P1#$ "e can also add our own inormation %y
merging one P1# page "ith another. #or instance$ perhaps "e "ant to automatically add
a header or a "atermark to e'ery page in a ile. 0&'e sa'ed an image "ith a transparent
%ackground into a one+page P1# ile or this purpose$ "hich "e can use as a "atermark$
com%ining this image "ith e'ery page in a P1# ile %y using the mer'e8a'e() method7
import os
from p8df import 8df3ile,eader, 8df3ile:riter
path + "@2B,eal 8thonB@ourse materialsB@hapter PB8ractice files"
input3ile6ame + os.path.Loin(path, ".he &mperor.pdf")
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output8$3 + 8df3ile:riter()
watermar13ile6ame + os.path.Loin(path, "top secret.pdf")
watermar13ile + 8df3ile,eader(file(watermar13ile6ame, "r0"))
for pa'e6um in ran'e(?, input3ile.'et6um8a'es())2
pa'e + input3ile.'et8a'e(pa'e6um)
pa'e.mer'e8a'e(watermar13ile.'et8a'e(?)) # add watermar1 ima'e
output8$3.add8a'e(pa'e)
output8$3.encrpt("'ood*J1in'") # add a password to the 8$3 file
output3ile6ame + os.path.Loin(path, ">utputB6ew -uit.pdf")
output3ile + file(output3ile6ame, "w0")
output8$3.write(output3ile)
output3ile.close()
115
Real Python
RealPython.com
)hile "e "ere securing the ile$ notice that "e also added %asic encryption %y supplying
the pass"ord 'ood*J1in' through the 8df3ile:riter&s encrpt() method. 0 you
kno" the pass"ord used to protect a P1# ile$ there is also a matching decrpt()
method to decrypt an input ile that is pass"ord protectedB this can %e incredi%ly useul
as an automation tool i you ha'e many identically encrypted P1#s and don&t "ant to
ha'e to type out a pass"ord each time you open one o the iles.
Although pyPd is one o the %est and most re,uently relied+upon packages or
interacting "ith P1#s in Python$ it does ha'e some "eaknesses. #or instance$ there is no
"ay to generate your o"n P1# iles rom scratchB instead$ you must start "ith at least a
template document. #or P1# generation in particular$ 0 suggest researching the
Report>a% toolkit$ "hich is also ree and open+source. Another popular choice or
manipulation o existing P1# iles in Python is P1#4iner$ "hich oers slightly dierent
unctionality rom pyPd.
2here is also a PyP1#2 in the "orks that aims to handle more diicult P1# iles and
make some P1# manipulation tasks e'en easier than in pyPd. 6o"e'er$ as o this "riting
F!eptem%er 2012. there is not yet any documentation a'aila%le on ho" to use it.
9e,iew e6ercises-
)rite a script that opens the ile named )alrus.pd rom the Chapter <
practice ilesB you "ill need to decrypt the ile using the pass"ord
#amthe:alrus
Rotate e'ery page in this input ile counter+clock"ise %y U0 degrees
!plit each page in hal 'ertically$ such that e'ery column appears on its o"n
separate page$ and output the results as a ne" P1# ile in the @utput older
Assignment ,.2: A$$ a co!er sheet to a P-# file
Write % scri*t Dco,erLtheLe0*eror.*yF th%t %**ends the ch%*ter ! *r%ctice .i(e
n%0ed D.he &mperor.pdfF to the end o. the ch%*ter ! *r%ctice .i(e n%0ed
D&mperor co"er sheet.pdfF %nd out*uts the .u(( resu(tin# P'/ to the .i(e
D.he @o"ered &mperor.pdfF in the ch%*ter ! *r%ctice .i(es )ut*ut .o(der.
?
116
Real Python
RealPython.com
&) $< d%t%b%se connections
U.1. Communicate "ith data%ases using !Z>ite
you&re interested in this chapter$ 0&m assuming that you ha'e at least a %asic
kno"ledge o !Z> and the concept o ,uerying a data%ase. 0 not$ you might "ant to
take a moment to read through this article introducing data%ases and %ro"se through
these lessons introducing %asic !Z> code.
0
2here are many dierent 'ariations o !Z>$ and some are suited to certain purposes
%etter than others. 2he simplest$ most light"eight 'ersion o !Z> is !Z>ite$ "hich runs
directly on your machine and comes %undled "ith Python automatically.
!Z>ite is usually used "ithin applications or small internal storage tasks$ %ut it can also
%e useul or testing !Z> code %eore setting an application up to use a larger data%ase.
0n order to communicate "ith !Z>ite$ "e need to import the module and connect to a
data%ase7
import sSlite;
connection + sSlite;.connect("test=data0ase.d0")
6ere "e&'e created a ne" data%ase named test=data0ase.d0$ %ut connecting to an
existing data%ase "orks exactly the same "ay. -o" "e need a "ay to communicate
across the connection7
c + connection.cursor()
2his line creates a (ursor o%(ect$ "hich "ill let us execute commands on the !Z>
data%ase and return the results. )e&ll %e using the cursor a lot$ so "e can (ust call it c
or short. -o" "e easily execute regular !Z> statements on the data%ase through the
cursor like so7
c.eAecute("@,&/.& ./J%& 8eople(3irst6ame .&Y., %ast6ame .&Y., /'e #6.)")
2his line creates a ne" ta%le named 8eople and inserts three ne" columns into the
117
Real Python
RealPython.com
ta%le7 text to store each person&s 3irst6ame$ another text ield to store the
%ast6ame$ and an integer to store /'e. )e can insert data into this ne" ta%le like this7
c.eAecute("#6-&,. #6.> 8eople E/%H&-(7,on7, 7>0"ious7, <*)")
connection.commit()
6ere "e&'e inserted a ne" ro"$ "ith a 3irstname o ,on$ a %ast6ame o >0"ious$
and an /'e e,ual to <*. 0n the second line$ "e had to commit the change "e made to
the ta%le to say that "e really meant to change the ta%le&s contents ? other"ise our
change "ouldn&t actually %e sa'ed.
We used doub(e Iuot%tion 0%rks in the strin# %bo,e? with sin#(e Iuotes
denotin# strin#s inside o. the $< st%te0ent. 4(thou#h Python doesn5t
di..erenti%te between usin# sin#(e %nd doub(e Iuotes? so0e ,ersions o. $<
@inc(udin# $<ite) only %((ow strin#s to be enc(osed in sin#(e Iuot%tion 0%rks? so it5s
i0*ort%nt not to switch these %round.
A
At this point$ you could close and restart 01>8 completely$ and i you then reconnect to
test=data0ase.d0$ your 8eople ta%le "ill still exists there$ storing ,on >0"ious
and his /'eB this is "hy !Z>ite can %e useul or internal storage or those times "hen it
makes sense to structure your data as a data%ase o ta%les rather than "riting output to
indi'idual iles. 2he most common example o this is to store inormation a%out users o
an application.
I. you 3ust w%nt to cre%te % one=ti0e=use d%t%b%se whi(e you5re testin# code or
*(%yin# %round with t%b(e structures? you c%n use the s*eci%( n%0e 2memor2 to
cre%te the d%t%b%se in te0*or%ry 941 (ike so-
connection + sSlite;.connect(72memor27)
A
0 "e "ant to delete the 8eople ta%le$ it&s as easy as executing a $,>8 ./J%&
statement7
c.eAecute("$,>8 ./J%& #3 &Y#-.- 8eople")
F6ere "e also checked i the ta%le exists %eore trying to drop it$ "hich is usually a good
ideaB it helps to a'oid errors i "e happened to try deleting a ta%le that&s already %een
deleted or ne'er actually existed in the irst place..
@nce "e&re done "ith a data%ase connection$ "e should close() the connectionB (ust
118
Real Python
RealPython.com
like closing iles$ this pushes any changes out to the data%ase and rees up any resources
currently in memory that are no longer needed. 9ou close the data%ase connection in
the same "ay as "ith iles7
connection.close()
)hen "orking "ith a data%ase connection$ it&s also a good idea to use the with key"ord
to simpliy your code Fand your lie.$ similar to ho" "e used with to open iles7
with sSlite;.connect("test=data0ase.d0") as connection2
# perform an -V% operations usin' connection here
Desides making your code more compact$ this "ill %eneit you in a e" important "ays.
#irstly$ you no longer need to commit() changes you makeB they&re automatically sa'ed.
5sing with also helps "ith handling potential errors and reeing up resources that are
no longer needed$ much like ho" "e can open Fand automatically close. iles using the
with key"ord. Leep in mind$ ho"e'er$ that you "ill still need to commit() a change i
you "ant to see the result o that change immediately F%eore closing the connection.B
"e&ll see an example o this later in the section.
0 you "ant to run more than one line o !Z> code at a time$ there are a couple possi%le
options. @ne simple option is to use the eAecutescript() method and gi'e it a string
that represents a ull scriptB although lines o !Z> code "ill %e separated %y semicolons$
it&s common to pass a multi+line string or reada%ility. @ur ull code might look like so7
import sSlite;
with sSlite;.connect(7test=data0ase.d07) as connection2
c + connection.cursor()
c.eAecutescript("""
$,>8 ./J%& #3 &Y#-.- 8eople;
@,&/.& ./J%& 8eople(3irst6ame .&Y., %ast6ame .&Y., /'e #6.);
#6-&,. #6.> 8eople E/%H&-(7,on7, 7>0"ious7, <*);
""")
)e can also execute many similar statements %y using the eAecuteman() method and
supplying a tuple o tuples$ "here each inner tuple supplies the inormation or a single
command. #or instance$ i "e ha'e a lot o people&s inormation to insert into our
8eople ta%le$ "e could sa'e this inormation in the ollo"ing tuple o tuples7
peopleEalues + (
119
Real Python
RealPython.com
(7,on7, 7>0"ious7, <*),
(7%ui'i7, 7Eercotti7, <;),
(7/rthur7, 7Jellin'7, *P)
)
)e could then insert all o these people at once Fater preparing our connection and our
8eople ta%le. %y using the single line7
c.eAecuteman("#6-&,. #6.> 8eople E/%H&-(F, F, F)", peopleEalues)
6ere$ the ,uestion marks act as place+holders or the tuples in peopleEaluesB this is
called a parameteri)ed statement. 2he dierence %et"een parameteri*ed and non+
parameteri*ed code is 'ery similar to ho" "e can "rite out strings %y concatenating
many parts together 'ersus using the string format() method to insert speciic pieces
into a string ater creating it.
#or security reasons$ especially "hen you need to interact "ith a !Z> ta%le %ased on
user+supplied input$ you should al"ays use parameteri*ed !Z> statements. 2his is
%ecause the user could potentially supply a 'alue that loos like !Z> code and causes
your !Z> statement to %eha'e in unexpected "ays. 2his is called a !Z> in(ection
attack and$ e'en i you aren&t dealing "ith a malicious user$ it can happen completely %y
accident.
#or instance$ suppose "e "ant to insert a person into our 8eople ta%le %ased on user+
supplied inormation. )e might initially try something like the ollo"ing Fassuming "e
already ha'e our 8eople ta%le set up.7
import sSlite;
# 'et person data from user
first6ame + raw=input("&nter our first name2 ")
last6ame + raw=input("&nter our last name2 ")
a'e + int(raw=input("&nter our a'e2 "))
# eAecute insert statement for supplied person data
with sSlite;.connect(7test=data0ase.d07) as connection2
c + connection.cursor()
line + "#6-&,. #6.> 8eople Ealues(7" ) first6ame ) "7,7" ) last6ame )
"7," ) str(a'e) ) ")"
c.eAecute(line)
-otice ho" "e had to change a'e into an integer to make sure that it "as a 'alid age$
120
Real Python
RealPython.com
%ut then "e had to change it %ack into a string in order to concatenate it "ith the rest
o the lineB this is %ecause "e created the line %y adding a %unch o strings together$
including using single ,uotation marks to denote strings "ithin our string. 0 you&re still
not clear ho" this "orks$ try inserting a person into the ta%le and then print line to
see ho" the ull line o !Z> code looks.
Dut "hat i the user&s name included an apostrophe/ 2ry adding 3lanner >7@onnor to
the ta%le$ and you&ll see that she %reaks the codeB this is %ecause the apostrophe gets
mixed up "ith the single ,uotes in the line$ making it appear that the !Z> code ends
earlier than expected.
0n this case$ our code only causes an error F"hich is %ad. instead o corrupting the entire
ta%le F"hich "ould %e very %ad.$ %ut there are many other hard+to+predict cases that
can %reak !Z> ta%les "hen not parameteri*ing your statements. 2o a'oid this$ "e should
ha'e used place+holders in our !Z> code and inserted the person data as a tuple7
import sSlite;
# 'et person data from user and insert into a tuple
first6ame + raw=input("&nter our first name2 ")
last6ame + raw=input("&nter our last name2 ")
a'e + int(raw=input("&nter our a'e2 "))
person$ata + (first6ame, last6ame, a'e)
# eAecute insert statement for supplied person data
with sSlite;.connect(7test=data0ase.d07) as connection2
c + connection.cursor()
c.eAecute("#6-&,. #6.> 8eople E/%H&-(F, F, F)", person$ata)
)e can also update the content o a ro" %y using a !Z> H8$/.& statement. #or
instance$ i "e "anted to change the /'e associated "ith someone already in our
8eople ta%le$ "e could say the ollo"ing For a cursor "ithin a connection.7
c.eAecute("H8$/.& 8eople -&. /'e+F :H&,& 3irst6ame+F /6$ %ast6ame+F", (<C,
7%ui'i7, 7Eercotti7))
@ course$ inserting and updating inormation in a data%ase isn&t all that helpul i "e
can&t etch that inormation %ack out. Oust like "ith readline() and readlines()
"hen reading iles$ there are t"o a'aila%le optionsB "e can either retrie'e all the
results o a !Z> ,uery$ using fetchall()$ or retrie'e a single result at a time$ using
121
Real Python
RealPython.com
fetchone(). #irst$ let&s insert some people into a ta%le and then ask !Z> to retrie'e
inormation rom some o them7
import sSlite;
peopleEalues + (
(7,on7, 7>0"ious7, <*),
(7%ui'i7, 7Eercotti7, <;),
(7/rthur7, 7Jellin'7, *P)
)
with sSlite;.connect(7test=data0ase.d07) as connection2
c + connection.cursor()
c.eAecute("$,>8 ./J%& #3 &Y#-.- 8eople")
c.eAecute("@,&/.& ./J%& 8eople(3irst6ame .&Y., %ast6ame .&Y., /'e #6.)")
c.eAecuteman("#6-&,. #6.> 8eople E/%H&-(F, F, F)", peopleEalues)
# select all first and last names from people o"er a'e ;?
c.eAecute("-&%&@. 3irst6ame, %ast6ame 3,>I 8eople :H&,& /'e > ;?")
for row in c.fetchall()2
print row
)e executed a -&%&@. statement that returned the irst and last names o all people
o'er the age o A0$ then called fetchall() on our cursor to retrie'e the results o this
,uery$ "hich are stored as a list o tuples. >ooping o'er the ro"s in this list to 'ie" the
indi'idual tuples$ "e see7
>>>
(u7,on7, u7>0"ious7)
(u7%ui'i7, u7Eercotti7)
>>>
2he u %eore each string stands or unicode Fas opposed to A!C00. and %asically means
that the string might contain complicated characters that can&t %e represented %y the
usual %asic set o characters "e normally see in 8nglish text.
0 "e "anted to loop o'er our result ro"s one at a time instead o etching them all at
once$ "e "ould usually use a loop such as the ollo"ing7
c.eAecute("-&%&@. 3irst6ame, %ast6ame 3,>I 8eople :H&,& /'e > ;?")
while .rue2
row + c.fetchone()
if row ++ 6one2
0rea1
print row
122
Real Python
RealPython.com
2his checks each time "hether our fetchone() returned another ro" rom the cursor$
displaying the ro" i so and %reaking out o the loop once "e run out o results.
7he 6one keyword is the w%y th%t Python re*resents the %bsence o. %ny ,%(ue
.or %n ob3ect. When we w%nted to co0*%re % strin# to % 0issin# ,%(ue? we used
e0*ty Iuotes to check th%t the strin# ob3ect h%d no in.or0%tion inside-
strin'6ame ++ ""
When we w%nt to co0*%re other ob3ects to 0issin# ,%(ues to see i. those ob3ects
ho(d %ny in.or0%tion? we co0*%re the0 to >one? (ike so-
o0Lect6ame ++ 6one
7his co0*%rison wi(( return .rue i. o0Lect6ame e6ists but is e0*ty %nd 3alse i.
o0Lect6ame ho(ds %ny ,%(ue.
A
9e,iew e6ercises-
Create a data%ase ta%le in RA4 named ,oster that includes the ields
76ame7$ 7-pecies7 and 7#V7
Populate your ne" ta%le "ith the ollo"ing 'alues7
Zean!Japtiste Mor'$ Human$ (**
[or0en $allas$ Ieat 8opsicle$ (??
/17not$ Ian'alore$ !C
5pdate the -pecies o [or0en $allas to %e Human
1isplay the names and 0Zs o e'eryone in the ta%le "ho is classiied as Human
U.2. 5se other !Z> 'ariants
you ha'e a particular type o !Z> data%ase that you&d like to access through
Python$ most o the %asic syntax is likely to %e identical to "hat you (ust learned or
!Z>ite. 6o"e'er$ you&ll need to install an additional package in order to interact "ith
your data%ase since !Z>ite is the only %uilt+in option. 2here are many !Z> 'ariants and
corresponding Python packages a'aila%le. A e" o the most commonly used and relia%le
0
123
Real Python
RealPython.com
open+source alternati'es are7
2he pyod%c module allo"s connections to most types o data%ases.
!peciically or use "ith Postgre!Z>7 Psycopg is one o the most re,uently used
package to interace %et"een Python and Postgre!Z>. A )indo"s 'ersion$ "in+
psycopg$ is also a'aila%le.
!peciically or use "ith 4y!Z>7 4y!Z>d% oers 4y!Z> support or Python.
)indo"s users might "ant to try the myPy!Z> extension instead$ made
speciically or )indo"s.
@ne dierence rom !Z>ite F%esides the actual syntax o the !Z> code$ "hich changes
slightly "ith e'ery dierent la'or o !Z>. is that "hen you connect to any other !Z>
data%ase$ you&ll need to supply the user and password Fas "ell as your host$ i the
data%ase is hosted on an external ser'er.. Check the documentation or the particular
package you "ant to use to igure out the exact syntax or ho" to make a data%ase
connection.
124
Real Python
RealPython.com
10) Inter%ctin# with the web
10.1. !crape and parse text rom "e%sites
i'en the hundreds o millions o "e%sites out there$ chances are that you might
at some point %e interested in gathering data rom a "e%page ? or perhaps rom
thousands o "e%pages. 0n this chapter "e "ill explore 'arious options or interacting
"ith and gathering data rom the 0nternet through Python.
:
8o((ectin# d%t% .ro0 websites usin# %n %uto0%ted *rocess is known %s web
scraping. $o0e websites e6*(icit(y .orbid users .ro0 scr%*in# their d%t% with
%uto0%ted too(s (ike the ones we wi(( cre%te. Websites do this .or either o. two
*ossib(e re%sons-
= 7he site h%s % #ood re%son to *rotect its d%t%G .or inst%nce? "oo#(e 1%*s
wi(( not %((ow you to reIuest too 0%ny resu(ts too Iuick(y
= 1%kin# 0%ny re*e%ted reIuests to % website5s ser,er 0%y use u*
b%ndwidth? s(owin# down the website .or other users %nd *otenti%((y
o,er(o%din# the ser,er such th%t the website sto*s res*ondin# entire(y
Cou shou(d %(w%ys check % website5s %cce*t%b(e use *o(icy be.ore scr%*in# its d%t%
to see i. %ccessin# the website by usin# %uto0%ted too(s is % ,io(%tion o. its ter0s o.
use. e#%((y? web scr%*in# %#%inst the wishes o. % website is ,ery 0uch % #r%y %re%?
but I 3ust w%nt to 0%ke it c(e%r th%t the .o((owin# techniIues 0%y be i((e#%( when
used on websites th%t *rohibit web scr%*in#.
A
2he primary language o inormation on the 0nternet is 624> FHyper7ext 1arkup
anguage.$ "hich is ho" most "e%pages are displayed in %ro"sers. #or instance$ i you
%ro"se to a particular "e%site and choose to 'ie" page source in your %ro"ser$ you
"ill most likely %e presented "ith 624> code underlying that "e%pageB this is the
inormation that your %ro"ser recei'es and translates into the page you actually see.
0 you are not amiliar "ith the %asics o *%+, tags$ you should take a little "hile to
read through the irst do*en chapters o this %rie 624> introduction. -one o the 624>
used in this chapter "ill %e 'ery complicated$ %ut ha'ing a solid understanding o 624>
elements is an important prere,uisite or de'eloping good techni,ues or "e% scraping.
125
Real Python
RealPython.com
>et&s start %y gra%%ing all o the 624> code rom a single "e%page. )e&ll take a 'ery
simple page that&s %een set up (ust or practice7
import urlli0*
m/ddress + "http2BB,eal8thon.comBpracticeBaphrodite.html"
html8a'e + urlli0*.urlopen(m/ddress)
html.eAt + html8a'e.read()
print html.eAt
2his displays the ollo"ing result or us$ "hich represents the ull 624> o the page (ust
as a "e% %ro"ser "ould see it7
>>>
<html>
<head>
<title>8rofile2 /phrodite<Btitle>
<Bhead>
<0od 0'color+"ellow">
<center>
<0r><0r>
<im' src+"aphrodite.'if" B>
<h*>6ame2 /phrodite<Bh*>
<0r><0r>
3a"orite animal2 $o"e
<0r><0r>
3a"orite color2 ,ed
<0r><0r>
Hometown2 Iount >lmpus
<Bcenter>
<B0od>
<Bhtml>
>>>
8%((in# urlopen() wi(( c%use the .o((owin# error i. Python c%nnot connect to
the Internet-
H,%&rror2 <urlopen error 4&rrno ((??(5 'etaddrinfo failed>
I. you *ro,ide %n in,%(id web %ddress th%t c%n5t be .ound? you wi(( see the .o((owin#
error? which is eIui,%(ent to the D404F *%#e th%t % browser wou(d (o%d-
H..8&rror2 H..8 &rror <?<2 6ot 3ound
A
-o" "e can scrape speciic inormation rom the "e%page using text parsing$ i.e.$
looking through the ull string o text and gra%%ing only the pieces that are rele'ant to
us. #or instance$ i "e "anted to get the title o the "e%page Fin this case$ 8rofile2
/phrodite.$ "e could use the string find() method to search through the text o the
126
Real Python
RealPython.com
624> or the <title> tags and parse out the actual title using index num%ers7
import urlli0*
m/ddress + "http2BB,eal8thon.comBpracticeBaphrodite.html"
html8a'e + urlli0*.urlopen(m/ddress)
html.eAt + html8a'e.read()
start.a' + "<title>"
end.a' + "<Btitle>"
start#ndeA + html.eAt.find(start.a') ) len(start.a')
end#ndeA + html.eAt.find(end.a')
print html.eAt4start#ndeA2end#ndeA5
Running this script correctly displays the 624> code limited to only the text in the title7
>>>
8rofile2 /phrodite
>>>
@ course$ this "orked or a 'ery simple example$ %ut 624> in the real "orld can %e
much more complicated and ar less predicta%le. #or a small taste o the expectations
'ersus reality o text parsing$ 'isit poseidon.html and 'ie" the 624> source code. 0t
loos like the same layout as %eore$ %ut let&s try running the same script as %eore on
m/ddress + "http2BB,eal8thon.comBpracticeBposeidon.html"7
>>>
<head>
<title >8rofile2 8oseidon
>>>
)e didn&t manage to ind the %eginning o the <title> tag correctly this time %ecause
there "as a space %eore the closing >$ like so7 <title >. 0nstead$ our find()
method returned !( F%ecause the exact string <title> "asn&t ound any"here. and
then added the length o the tag string$ making us think that the %eginning o the title
"as six characters into the 624> code.
Decause these sorts o pro%lems can occur in countless unpredicta%le "ays$ a more
relia%le alternati'e than using find() is to use regular expressions. Regular expressions
Fshortened to re'eA in Python. are strings that can %e used to determine "hether or
not text matches a particular pattern.
Regular expressions are not particular to PythonB they are a general programming
127
Real Python
RealPython.com
concept that can %e used "ith a "ide 'ariety o programming languages. Regular
expressions use a language all o their o"n that is notoriously diicult to learn %ut
incredi%ly useul once mastered. Although a ull o'er'ie" o regular expressions is
outside the scope o this %ook$ 0&ll co'er (ust a e" couple examples to get started.
Python allo"s us to use regular expressions through the re module. Oust as Python uses
the %ackslash character as an escape character or representing special characters
that can&t simply %e typed into strings$ regular expressions use a num%er o dierent
special characters Fcalled meta-characters. that are interpreted as "ays to signiy
dierent types o patterns. #or instance$ the asterisk character$ K$ stands or *ero or
more o "hate'er came (ust %eore the asterisk. >et&s see this in an example$ "here "e
use the re.findall() unction to ind any text "ithin a string that matches a gi'en
regular expression. 2he irst argument "e pass to re.findall() is the regular
expression that "e "ant to match$ and the second argument is the string to test7
>>> import re
>>> re.findall("a0Kc", "ac")
47ac75
>>> re.findall("a0Kc", "a0cd")
47a0c75
>>> re.findall("a0Kc", "acc")
47ac75
>>> re.findall("a0Kc", "a0cac")
47a0c7, 7ac75
>>> re.findall("a0Kc", "a0dc")
45
>>>
@ur regular expression$ a0Kc$ matches any part o the string that %egins "ith an a$
ends "ith a c$ and has )ero or more o 0 in %et"een the t"o. 2his unction returns
a list o all matches. -ote that this is case+sensiti'eB i "e "anted to match this pattern
regardless o upper+case or lo"er+case dierences$ "e could pass a third argument "ith
the 'alue re.#X6>,&@/-&$ "hich is a speciic 'aria%le stored in the re module7
>>> re.findall("a0Kc", "/J@")
45
>>> re.findall("a0Kc", "/J@", re.#X6>,&@/-&)
47/J@75
>>>
128
Real Python
RealPython.com
)e can use a period to stand or any single character in a regular expression. #or
instance$ "e could ind all the strings that contains the letters a and c separated %y
a single character as ollo"s7
>>> re.findall("a.c", "a0c")
47a0c75
>>> re.findall("a.c", "a00c")
45
>>> re.findall("a.c", "ac")
45
>>> re.findall("a.c", "acc")
47acc75
>>>
2hereore$ putting the term .K inside o a regular expression stands or any character
%eing repeated any num%er o times. #or instance$ i "e "anted to ind e'ery string
inside o a particular string that starts "ith the letter a and ends "ith the letter c$
regardless o "hat occurs in %et"een these t"o letters$ "e could say7
>>> re.findall("a.Kc", "a0c")
47a0c75
>>> re.findall("a.Kc", "a00c")
47a00c75
>>> re.findall("a.Kc", "ac")
47ac75
>>> re.findall("a.Kc", "acc")
47acc75
>>>
5sually "e "ill "ant to use the re.search() unction to search or a particular
pattern inside a string. 2his unction is some"hat more complicated %ecause it returns
an o%(ect called a Iatch>0Lect that stores dierent groups o dataB this is %ecause
there might %e matches inside o other matches$ and re.search() "ants to return
e'ery possi%le result. 2he details o Iatch>0Lect are irrele'ant here$ %ut or our
purposes$ calling the 'roup() method on a Iatch>0Lect "ill return the irst and most
inclusi'e result$ "hich in most instances is all "e care to ind. #or instance7
>>> match,esults + re.search("a0Kc", "/J@", re.#X6>,&@/-&)
>>> print match,esults.'roup()
/J@
>>>
129
Real Python
RealPython.com
2here is one more re unction that "ill come in handy "hen parsing out text. 2he
su0() unction$ "hich is short or su%stitute$ allo"s us to replace text in a string that
matches a regular expression "ith ne" text Fmuch like the string replace() method..
2he arguments passed to re.su0() are the regular expression$ ollo"ed %y the
replacement text$ then ollo"ed %y the string. #or instance7
>>> m-trin' + "&"erthin' is <replaced> if it7s in <ta's>."
>>> m-trin' + re.su0("<.K>", "&%&8H/6.-", m-trin')
>>> print m-trin'
&"erthin' is &%&8H/6.-.
>>>
Perhaps that "asn&t ,uite "hat "e expected to happen; )e ound and replaced
everything in %et"een the irst < and last >$ "hich ended up %eing most o the
string. 2his is %ecause Python&s regular expressions are greedy
2A
$ meaning that they try
to ind the longest possi%le match "hen characters like K are used. 0nstead$ "e should
ha'e used the non-greedy matching pattern KF$ "hich "orks the same "ay as K
except that it tries to match the shortest possi%le string o text7
>>> m-trin' + "&"erthin' is <replaced> if it7s in <ta's>."
>>> m-trin' + re.su0("<.KF>", "&%&8H/6.-", m-trin')
>>> print m-trin'
&"erthin' is &%&8H/6.- if it7s in &%&8H/6.-.
>>>
Armed "ith all this kno"ledge$ let&s no" try to parse out the title rom dionysus.html$
"hich includes this rather carelessly "ritten line o 624>7
<.#.%& >8rofile2 $ionsus<Btitle B >
@ur find() method "ould ha'e a diicult time dealing "ith the inconsistencies here$
%ut "ith the cle'er use o regular expressions$ "e "ill %e a%le to handle this code
easily7
2C
import re
import urlli0*
m/ddress + "http2BB,eal8thon.comBpracticeBdionsus.html"
html8a'e + urlli0*.urlopen(m/ddress)
html.eAt + html8a'e.read()
2A 9es$ that&s a legitimate term.
2C Actually$ this code "ould also remo'e any <> tags that appear inside o the title&s text$ %ut "e&ll
assume here that "e "ould "ant to remo'e such tags in the unlikely e'ent that they do appear there.
130
Real Python
RealPython.com
match,esults + re.search("<title .KF>.K<Btitle .KF>", html.eAt,
re.#X6>,&@/-&)
title + match,esults.'roup()
title + re.su0("<.KF>", "", title) # remo"e H.I% ta's
print title
>et&s take the irst regular expression "e used and %reak it do"n into three parts7
<title .KF> #irst "e check or the opening tag$ "here there must %e a space
ater the "ord title and the tag must %e closed$ %ut any
characters can appear in the rest o the tagB "e use the non+greedy
.KF %ecause "e "ant the first closing S to match the tag&s end
.K Any characters can appear in %et"een the <title> tags
<Btitle .KF> 2his expression is the same as the irst part$ except that "e also
re,uire the or"ard slash %eore title %ecause this is a closing
624> tag
>ike"ise$ "e then use the non+greedy .KF placed inside o an 624> tag to match any
624> tags and remo'e them rom the parsed+out title.
Regular expressions are an incredi%ly po"erul tool "hen used correctly. )e&'e only
scratched the surace o their potential here$ although you&re encouraged to take some
time to study the 'ery thorough Python Regular 8xpression 6@)2@ document.
/%ir w%rnin#- web scr%*in# in *r%ctice c%n be ,ery tedious work. :eyond the
.%ct th%t no two websites %re or#%niHed the s%0e w%y? usu%((y web*%#es %re
0essy %nd inconsistent in their .or0%ttin#. 7his (e%ds to % (ot o. ti0e s*ent
h%nd(in# une6*ected e6ce*tions to e,ery ru(e? which is (ess th%n ide%( when you
w%nt to %uto0%te % t%sk.
A
9e,iew e6ercises-
)rite a script that gra%s the ull 624> rom the page dionysus.html
5se the string find() method to display the text ollo"ing 6ame2 and
3a"orite @olor2 Fnot including any leading spaces or trailing 624> tags
that might appear on the same line.
131
Real Python
RealPython.com
Repeat the pre'ious exercise using regular expressionsB the end o each
pattern should %e a < Fi.e.$ the start o an 624> tag. or a ne"line
character$ and you should remo'e any extra spaces or ne"line characters
rom the resulting text
10.2. 5se an 624> parser to scrape "e%sites
lthough regular expressions are great or pattern matching in general$ sometimes
it&s easier to use an *%+, parser that is designed speciically or piecing apart
624> pages. 2here are a num%er o Python tools "ritten or this purpose$ %ut the most
popular Fand easiest to learn. is named Deautiul !oup.
A
2o set up Deautiul !oup or Windows or )$ B$ i you ha'e eas=install set up then
you can type the ollo"ing command into your command prompt or 2erminal7
eas=install 0eautifulsoup<
@ther"ise$ do"nload the compressed .tar.'D ile$ un*ip it$ then install Deautiul
!oup using the setup.p script rom the command line or 2erminal as descri%ed in the
chapter on installing packages.
#or 'ebi%nOinu6$ (ust type7
sudo apt!'et install pthon!0s<
@nce you ha'e Deautiul !oup installed$ you can no" import the 0s< module and pass a
string o 624> to Jeautiful-oup to %egin parsing7
from 0s< import Jeautiful-oup
import urlli0*
m/ddress + "http2BB,eal8thon.comBpracticeBdionsus.html"
html8a'e + urlli0*.urlopen(m/ddress)
html.eAt + html8a'e.read()
m-oup + Jeautiful-oup(html.eAt)
#rom here$ "e can parse data out o m-oup in 'arious useul "ays depending on "hat
132
Real Python
RealPython.com
inormation "e "ant. #or instance$ Jeautiful-oup includes a 'et=teAt() method
or extracting (ust the text rom a document$ remo'ing any 624> tags automatically7
>>> print m-oup.'et=teAt()
8rofile2 $ionsus
6ame2 $ionsus
Hometown2 Iount >lmpus
3a"orite animal2 %eopard
3a"orite @olor2 :ine
>>>
2here are a lot o extra %lank lines let$ %ut these can al"ays %e taken out using the
string replace() method. 0 "e only "ant to get speciic text rom an 624> document$
using Jeautiful-oup to extract the text irst and then using find() is sometimes
easier than "orking "ith regular expressions.
6o"e'er$ sometimes the 624> tags are actually the elements that point out the data "e
"ant to retrie'e. #or instance$ perhaps "e "ant to retrie'e links or all the images on
the page$ "hich "ill appear in <im'> 624> tags. 0n this case$ "e can use the
find=all() method to return a list o all instances o that particular tag7
>>> print m-oup.find=all("im'")
4<im' src+"dionsus.Lp'"B>, <im' src+"'rapes.pn'"><0r><0r>
Hometown2 Iount >lmpus
<0r><0r>
3a"orite animal2 %eopard <0r>
<0r>
3a"orite @olor2 :ine
<B0r><B0r><B0r><B0r><B0r><B0r><Bim'>5
>>>
2his "asn&t exactly "hat "e expected to see$ %ut it happens ,uite oten in the real
133
Real Python
RealPython.com
"orldB the irst element o the list$ <im' src+"dionsus.Lp'"B>$ is a sel+closing
624> image tag that doesn&t re,uire a closing <Bim'> tag. 5nortunately$ "hoe'er
"rote the sloppy 624> or this page ne'er added a closing or"ard slash to the second
624> image tag$ <im' src+"'rapes.pn'">$ and didn&t include a <Bim'> tag either.
!o Jeautiful-oup ended up gra%%ing a air amount o 624> after the image tag as
"ell %eore inserting a <Bim'> on its o"n to correct the 624>.
#ortunately$ this still doesn&t ha'e much %earing on ho" "e can parse inormation out o
the image tags "ith Deautiul !oup. 2his is %ecause these 624> tags are stored as .a'
o%(ects$ and "e can easily extract certain inormation out o each .a'. 0n our example$
assume or simplicity that "e kno" to expect t"o images in our list so that "e can pull
t"o .a' o%(ects out o the list7
>>> ima'e(, ima'e* + m-oup.find=all("im'")
>>>
)e no" ha'e t"o .a' o%(ects$ ima'e( and ima'e*. 2hese .a' o%(ects each ha'e a
name$ "hich is (ust the type o 624> tag that to "hich they correspond7
>>> print ima'e(.name
im'
>>>
2hese .a' o%(ects also ha'e 'arious attributes$ "hich can %e accessed in the same "ay
as a dictionary. 2he 624> tag <im' src+"dionsus.Lp'"B> has a single attri%ute
src that takes on the 'alue dionsus.Lp' Fmuch like a 1e2 "alue pair in a
dictionary.. >ike"ise$ an 624> tag such as <a href+"http2BB,eal8thon.com"
tar'et+"=0lan1"> "ould ha'e two attri%utes$ a href attri%ute that is assigned the
'alue http2BB,eal8thon.com and a tar'et attri%ute that has the 'alue
=0lan1.
)e can thereore pull the image source Fthe link that "e "anted to parse. out o each
image tag using standard dictionary notation to get the 'alue that the src attri%ute
o the image has %een assigned7
>>> print ima'e(4"src"5
dionsus.Lp'
134
Real Python
RealPython.com
>>> print ima'e*4"src"5
'rapes.pn'
>>>
8'en though the second image tag had a lot o extra 624> code associated "ith it$ "e
could still pull out the 'alue o the image src "ithout any trou%le %ecause o the "ay
Deautiul !oup organi*es 624> tags into .a' o%(ects.
0n act$ i "e only "ant to gra% a particular tag$ "e can identiy it %y the corresponding
name o the .a' o%(ect in our soup7
>>> print m-oup.title
<title>8rofile2 $ionsus<Btitle>
>>>
-otice ho" the 624> <title> tags ha'e automatically %een cleaned up %y Deautiul
!oup. #urthermore$ i "e "ant to extract only the string o text out o the <title>
tags F"ithout including the tags themsel'es.$ "e can use the strin' attri%ute stored %y
the title7
>>> print m-oup.title.strin'
8rofile2 $ionsus
>>>
)e can e'en search or speciic kinds o tags "hose attri%utes match certain 'alues. #or
instance$ i "e "anted to ind all o the <im'> tags that had a src attri%ute e,ual to
the 'alue dionsus.Lp'$ "e could pro'ide the ollo"ing additional argument to the
find=all() method7
>>> m-oup.find=all("im'", src+"dionsus.Lp'")
4<im' src+"dionsus.Lp'"B>5
>>>
0n this case$ the example is some"hat ar%itrary since "e only returned a list that
contained a single image tag$ %ut "e "ill use this techni,ue in a later section in order to
help us ind a speciic 624> tag %uried in a 'ast sea o other 624> tags.
Although Deautiul !oup is still used re,uently today$ the code is no longer %eing
maintained and updated %y its creator. A similar toolkit$ lxml$ is some"hat trickier to
get started using$ %ut oers all o the same unctionality as Deautiul !oup and more.
135
Real Python
RealPython.com
@nce you are comorta%le "ith the %asics o Deautiul !oup$ you should mo'e on to
learning ho" to use lxml or more complicated 624> parsing tasks.
H71 *%rsers (ike :e%uti.u( $ou* c%n @%nd o.ten do) s%,e % lot o. ti0e %nd e..ort
when it co0es to (oc%tin# s*eci.ic d%t% in web*%#es. Howe,er? so0eti0es H71
is so *oor(y written %nd disor#%niHed th%t e,en % so*histic%ted *%rser (ike
:e%uti.u( $ou* doesn5t re%((y know how to inter*ret the H71 t%#s *ro*er(y. In this
c%se? you5re o.ten (e.t to your own de,ices @n%0e(y? find() %nd re#e6) to try to
*iece out the in.or0%tion you need.
A
9e,iew e6ercises-
)rite a script that gra%s the ull 624> rom the page proiles.html
Parse out a list o all the links on the page using Deautiul !oup %y looking or
624> tags "ith the name a and retrie'ing the 'alue taken on %y the
href attri%ute o each tag
:et the 624> rom each o the pages in the list %y adding the ull path to the
ile name$ and display the text F"ithout 624> tags. on each page using
Deautiul !oup&s 'et=teAt() method
10.A. 0nteract "ith 624> orms
e usually retrie'e inormation rom the 0nternet %y sending re,uests or
"e%pages. A module like urlli%2 ser'es us "ell or this purpose$ since it oers a
'ery simple "ay o returning the 624> rom indi'idual "e%pages. !ometimes$ ho"e'er$
"e need to send inormation bac to a page + or instance$ su%mitting our inormation
on a login orm. #or this$ "e need an actual %ro"ser. 2here are a num%er o "e%
%ro"sers %uilt or Python$ and one o the most popular and easiest to use is in a module
called mechaniDe.
)
8ssentially$ mechani*e is an alternati'e to urlli0* that can do all o the same things
%ut has much more added unctionality that "ill allo" us to tal bac to "e%pages.
136
Real Python
RealPython.com
Windows- 0 you ha'e eas=install set up$ you can type eas=install
mechaniDe into your command prompt. @ther"ise$ do"nload the .Dip ile$
decompress it$ and install the package %y running the setup.p script rom the
command line as descri%ed in the section on installing packages.
)$ B- 0 you ha'e eas=install set up$ you can type sudo eas=install
mechaniDe into your 2erminal. @ther"ise$ do"nload the .tar.'D ile$ decompress
it$ and install the package %y running the setup.p script rom your 2erminal as
descri%ed in the section on installing packages.
'ebi%nOinu6- As usual7
sudo apt!'et install pthon!mechaniDe
9ou may need to close and restart your 01>8 session or mechani*e to load and %e
recogni*ed ater it&s %een installed.
:etting mechani*e to create a ne" Dro"ser o%(ect and use it to open a "e%page is as
easy as saying7
import mechaniDe
mJrowser + mechaniDe.Jrowser()
mJrowser.open("http2BB,eal8thon.comBpracticeBaphrodite.html")
)e no" ha'e 'arious inormation that the "e%site returned to us stored in our
mechani*e %ro"ser as a response "hich "e can return %y calling the response()
method. 2his response also has 'arious methods that help us piece out inormation
returned rom the "e%site7
>>> print mJrowser.response().'eturl()
http2BBwww.,eal8thon.comBpracticeBaphrodite.html
>>> print mJrowser.response().'et=data()
<html>
<head>
<title>8rofile2 /phrodite<Btitle>
<Bhead>
<0od 0'color+"ellow">
<center>
<0r><0r>
<im' src+"aphrodite.'if" B>
<h*>6ame2 /phrodite<Bh*>
137
Real Python
RealPython.com
<0r><0r>
3a"orite animal2 $o"e
<0r><0r>
3a"orite color2 ,ed
<0r><0r>
Hometown2 Iount >lmpus
<Bcenter>
<B0od>
<Bhtml>
>>>
6ere "e used the 'eturl() method to return the 5R> Fi.e.$ the ull address. o the
"e%page and the 'et=data() method to return the actual 624> code in the same "ay
that "e used read() "ith urlli0*. )e could then use Deautiul !oup or regular
expressions to parse out the inormation "e "ant rom the string returned %y the
'et=data() method.
Dut "hat i "e ha'e to su%mit inormation to the "e%site/ #or instance$ "hat i the
inormation "e "ant is %ehind a login page such as login.php/ 0 "e are trying to do
things automatically$ then "e "ill need a "ay to automate the login process as "ell.
#irst$ let&s take a look at the 624> response pro'ided %y login.php7
import mechaniDe
mJrowser + mechaniDe.Jrowser()
mJrowser.open("http2BB,eal8thon.comBpracticeBlo'in.php")
m,esponse + mJrowser.response()
print m,esponse.'et=data()
2his returns the ollo"ing orm F"hich you should take a look at in a regular %ro"ser as
"ell to see ho" it appears.7
>>>
<html>
<head>
<title>%o' #n<Btitle>
<Bhead>
<0od 0'color+"ellow">
<center>
<0r><0r>
<h*>8lease lo' in to access Iount >lmpus2<Bh*>
<0r><0r>
<form name+"lo'in" action+"lo'in.php" method+"post">
Hsername2 <input tpe+"teAt" name+"user"><0r>
8assword2 <input tpe+"password" name+"pwd"><0r><0r>
138
Real Python
RealPython.com
<input tpe+"su0mit" "alue+"-u0mit">
<Bform>
<Bcenter>
<B0od>
<Bhtml>
>>>
2he code "e see is 624>$ %ut the page itsel is "ritten in another language called P6P.
2J

0n this case$ the P6P is creating the 624> that "e see %ased on the inormation "e
pro'ide. #or instance$ try logging into the page "ith an incorrect username and
pass"ord$ and you "ill see that the same page no" includes a line o text to let you
kno"7 :ron' username or password9 6o"e'er$ i you pro'ide the correct login
inormation Fusername o Deus and pass"ord o .hunder$ude.$ you "ill %e
redirected to the proiles.html page.
#or our purposes$ the important section o 624> code is the login orm$ i.e.$ e'erything
inside the <form> tags. )e can see that there is a su%mission <form> named lo'in
that includes t"o <input> tags$ one named user and the other named pwd. 2he
third <input> is the actual -u0mit %utton. -o" that "e kno" the underlying
structure o the orm$ "e can return to mechani*e to automate the login process.
import mechaniDe
mJrowser + mechaniDe.Jrowser()
mJrowser.open("http2BB,eal8thon.comBpracticeBlo'in.php")
# select the form and fill in its fields
mJrowser.select=form("lo'in")
mJrowser4"user"5 + "Deus"
mJrowser4"pwd"5 + ".hunder$ude"
m,esponse + mJrowser.su0mit() # su0mit form
print m,esponse.'eturl() # ma1e sure we were redirected
)e used the %ro"ser&s select=form() method to select the orm$ passing in the name
lo'in that "e disco'ered %y reading the 624> o the page. @nce "e had that orm
selected in the %ro"ser$ "e could then assign 'alues to the dierent ields the same "ay
"e "ould assign dictionary 'aluesB "e passed the 'alue Deus to the ield named
2J P6P stands or P6P7 Hypertext Prepocessor; 9eah$ 0 kno"$ that&s super helpul. P6P used to stand or
Personal Home Page.
139
Real Python
RealPython.com
user and the 'alue .hunder$ude to the ield named pwdB once again$ "e kne"
"hat to call these ields %y reading the name attri%ute assigned "ithin each <input>
624> tag.
@nce "e illed in the orm$ "e could su%mit this inormation to the "e%page %y using
the %ro"ser&s su0mit() method$ "hich returns a response in the same "ay that calling
open() on a "e%page "ould do. )e displayed the 5R> o this response to make sure
that our login su%mission "orkedB i "e had pro'ided an incorrect username or pass"ord
then "e "ould ha'e %een sent %ack to login.php$ %ut "e see that "e "ere successully
redirected to proiles.html as planned.
We %re %(w%ys bein# encour%#ed to use (on# *%sswords with 0%ny di..erent
ty*es o. ch%r%cters in the0? %nd now you know the 0%in re%son- %uto0%ted
scri*ts (ike the one we 3ust desi#ned c%n be used by h%ckers to Dbrute .orceF
(o#ins by r%*id(y tryin# to (o# in with 0%ny di..erent usern%0es %nd *%sswords unti(
they .ind % workin# co0bin%tion. :esides this bein# highly illegal? %(0ost %((
websites these d%ys @inc(udin# 0y *r%ctice .or0) wi(( (ock you out %nd re*ort your
IP %ddress i. they see you 0%kin# too 0%ny .%i(ed reIuests? so don5t try itA
A
)e "ere a%le to retrie'e the "e%page orm %y name %ecause mechani*e includes its
o"n 624> parser. )e can use this parser through 'arious %ro"ser methods as "ell to
easily o%tain other types o 624> elements. 2he lin1s() method "ill return all the
links appearing on the %ro"ser&s current page as %in1 o%(ects$ "hich "e can then loop
o'er to o%tain their addresses. #or instance$ i our %ro"ser is still on the proiles.html
page$ "e could say7
>>> for lin1 in mJrowser.lin1s()2
print "/ddress2", lin1.a0solute=url
print ".eAt2", lin1.teAt
/ddress2 http2BB,eal8thon.comBpracticeBaphrodite.html
.eAt2 /phrodite
/ddress2 http2BB,eal8thon.comBpracticeBposeidon.html
.eAt2 8oseidon
/ddress2 http2BB,eal8thon.comBpracticeBdionsus.html
.eAt2 $ionsus
>>>
8ach %in1 o%(ect has a num%er o attri%utes$ including an a0solute=url attri%ute
that represents the address o the "e%page Fi.e.$ the href 'alue. and a teAt
140
Real Python
RealPython.com
attri%ute that represents the actual text that appears as a link on the "e%page.
2he mechani*e %ro"ser pro'ides many other methods to oer us the ull unctionality o
a standard "e% %ro"ser. #or instance$ the %ro"ser&s 0ac1() method simply takes us
%ack one page$ similar to hitting the Dack %utton in an ordinary %ro"ser. )e can also
click on links in a page to ollo" them using the %ro"ser&s follow=lin1() method.
>et&s ollo" each o the links on the proiles.html page using the %ro"ser&s
follow=lin1() and 0ac1() methods$ displaying the title o each "e%page "e 'isit %y
using the %ro"ser&s title() method7
import mechaniDe
mJrowser + mechaniDe.Jrowser()
mJrowser.open("http2BB,eal8thon.comBpracticeBprofiles.html")
for neAt%in1 in mJrowser.lin1s()2 # follow each lin1 on profiles.html
mJrowser.follow=lin1(neAt%in1)
print "8a'e title2", mJrowser.title() # displa current pa'e title
mJrowser.0ac1() # return to profiles.html
print "8a'e title2", mJrowser.title() # 0ac1 to profiles.html
Dy using the follow=lin1() method to open links$ "e a'oid the trou%le o ha'ing to
add the rest o the 5R> path to each link. #or instance$ the irst link on the page simply
links to a page named aphrodite.html "ithout including the rest o the 5R>B this is
a relative 5R>$ and mechani*e "ouldn&t kno" ho" to load this "e%page i "e passed it
to the open() method. 2o open() this address$ "e "ould ha'e to create an absolute
5R> %y adding the rest o the "e% address$ i.e.$
http2BB,eal8thon.comBpracticeBaphrodite.html.
2he follow=lin1() method takes care o this pro%lem or us since the %in1 o%(ects
all store a%solute 5R> paths. @ course$ in this case it still may ha'e %een more sensi%le
to open() each o these links directly since this "ouldn&t re,uire loading as many pages.
6o"e'er$ sometimes "e need the a%ility to mo'e %ack and orth %et"een pages.
Dut ho" did our code do/ 2he output appears as ollo"s7
>>>
8a'e title2 8rofile2 /phrodite
8a'e title2 8rofile2 8oseidon
141
Real Python
RealPython.com
8a'e title2 8rofile2 $ionsus<Btitle B> <Bhead> <0od 0'color+"ellow">
<center> <0r><0r> <im' src+"dionsus.Lp'"> <h*>6ame2 $ionsus<Bh*> <im'
src+"'rapes.pn'"><0r><0r> Hometown2 Iount >lmpus <0r><0r> 3a"orite animal2
%eopard <0r> <0r> 3a"orite @olor2 :ine <Bcenter> <B0od> <Bhtml>
8a'e title2 /ll 8rofiles
>>>
5nortunately$ mechani*e&s 624> parser couldn&t ind the closing title tag or 1ionysus
%ecause o the errant or"ard slash at the end$ and "e ended up gathering the rest o
the page. )hen one parsing method ails us Fin this case$ the mechani*e %ro"ser&s
title() method. %ecause o poorly "ritten 624>$ the %est course o action is to turn
to another parsing method ? in this case$ creating a Jeautiful-oup o%(ect and
extracting the "e%page&s title rom it. #or instance7
import mechaniDe
from 0s< import Jeautiful-oup
mJrowser + mechaniDe.Jrowser()
html8a'e + mJrowser.open("http2BBwww.,eal8thon.comBpracticeBdionsus.html")
html.eAt + html8a'e.'et=data()
m-oup + Jeautiful-oup(html.eAt)
print m-oup.title.strin'
-otice that "e didn&t ha'e to re'isit using urlli0* since mechani*e already pro'ides
the unctionality o opening "e%pages and retrie'ing their 624> or us.
9e,iew e6ercises-
5se mechani*e to pro'ide the correct username Deus and pass"ord
.hunder$ude to the login page su%mission orm located at7
http7==RealPython.com=practice=login.php
5sing Deautiul !oup$ display the title o the current page to determine that
you ha'e %een redirected to proiles.html
5se mechani*e to return to login.php %y going %ack to the pre'ious page
Pro'ide an incorrect username and pass"ord to the login orm$ then search
the 624> o the returned "e%page or the text :ron' username or
password9 to determine that the login process ailed
142
Real Python
RealPython.com
10.C. 0nteract "ith "e%sites in real+time
ometimes "e "ant to %e a%le to etch real+time data rom a "e%site that oers
continually updated inormation. 0n the dark days %eore you learned Python
programming$ you "ould ha'e %een orced to sit in ront o a %ro"ser$ clicking the
Reresh %utton to reload the page each time you "ant to check i updated content is
a'aila%le. 0nstead$ "e can easily automate this process using the reload() method o
the mechani*e %ro"ser.
!
As an example$ let&s create a script that periodically checks 9ahoo3 #inance or a current
stock ,uote or the 96@@ sym%ol. 2he irst step "ith any "e% scraping task is to
igure out exactly "hat inormation "e&re seeking. 0n this case$ the "e%page 5R> is
http7==inance.yahoo.com=,/sMyhoo. Currently$ the stock price Fas 0 see it. is 1J.E2$ and
so "e 'ie" the page&s 624> source code and search or this num%er. #ortunately$ it only
occurs once in the code7
<span class+"time=rtS=tic1er"><span id+"fs=lP<=hoo">1+.,<Bspan><Bspan>
-ext$ "e check that the tag <span id+"fs=lP<=hoo"> also only occurs once in the
"e%page$ since "e "ill need a "ay to uni,uely identiy the location o the current
price.
2Q
0 this is the only <span> tag "ith an id attri%ute e,ual to fs=lP<=hoo$
then "e kno" "e&ll %e a%le to ind it on the "e%page later and extract the inormation
"e need rom this particular pair o <span> tags.
)e&re in luck Fthis is the only <span> tag "ith this id.$ so "e can use mechani*e and
Deautiul !oup to ind and display the current price$ like so7
import mechaniDe
from 0s< import Jeautiful-oup
mJrowser + mechaniDe.Jrowser()
html8a'e + mJrowser.open("http2BBfinance.ahoo.comBSFs+hoo")
html.eAt + html8a'e.'et=data()
m-oup + Jeautiful-oup(html.eAt)
# return a list of all the <span> ta's where id+"fs=lP<=hoo"
m.a's + m-oup.find=all("span", id+"fs=lP<=hoo")
2Q -ote that there&s a lo"er+case > %eore the <C in the tag$ not the num%er 1.
143
Real Python
RealPython.com
# ta1e the Jeautiful-oup strin' out of the first (and onl) <span> ta'
m8rice + m.a's4?5.strin'
print ".he current price of GH>> is2 {}".format(m8rice)
)e needed to use format() to print the price %ecause m8rice is not (ust an ordinary
stringB it&s actually a more complex Jeautiful-oup string that has other inormation
associated "ith it$ and Deautiul !oup "ould try to display this other inormation as "ell
i "e had only said print m8rice.
-o"$ in order to repeatedly get the ne"est stock ,uote a'aila%le$ "e&ll need to create a
loop that uses the reload() method. Dut irst$ "e should check the 9ahoo3 #inance
terms o use to make sure that this isn&t in 'iolation o their accepta%le use policy.
2E
2he
terms state that "e should not use the 9ahoo3 #inance 4odules in a manner that
exceeds reasona%le re,uest 'olume WorX constitutes excessi'e or a%usi'e usage$ "hich
seems reasona%le enough. @ course$ reasonable and excessive are entirely su%(ecti'e
terms$ %ut the general rules o 0nternet eti,uette suggest that you don5t %sk .or 0ore
d%t% th%n you need. !ometimes$ the amount o data you need or a particular use
might still %e considered excessi'e$ %ut ollo"ing this rule is a good place to start.
0n our case$ an ininite loop that gra%s stock ,uotes as ,uickly as possi%le is definitely
more than "e need$ especially since it appears that 9ahoo3 only updates its stock ,uotes
once per minute. !ince "e&ll only %e using this script to make a e" "e%page re,uests as
a test$ let&s "ait one minute in %et"een each re,uest. )e can pause the unctioning o a
script %y passing a num%er o seconds to the sleep() method o Python&s time module$
like so7
from time import sleep
print "#7m a0out to wait for fi"e seconds..."
sleep(C)
print "$one waitin'9"
Although "e "on&t explore them here$ Python&s time module also includes 'arious "ays
to get the current time in case "e "ished to add a time stamp to each price.
2E 2here is nothing in the general 9ahoo3 2erms o !er'ice to suggest that using automated tools to scrape
pages isn&t allo"ed$ and a num%er o third+party products ha'e %een kno"n to scrape 9ahoo3 #inance
data or years$ so "e should %e in the clear as ar as using mechani*e to access these "e%pages.
144
Real Python
RealPython.com
5sing the sleep() method$ "e can no" repeatedly o%tain real+time stock ,uotes7
from time import sleep
import mechaniDe
from 0s< import Jeautiful-oup
# create a Jrowser o0Lect
mJrowser + mechaniDe.Jrowser()
# o0tain ( stoc1 Suote per minute for the neAt ; minutes
for i in ran'e(?, ;)2
html8a'e + mJrowser.open("http2BBfinance.ahoo.comBSFs+hoo")
html.eAt + html8a'e.'et=data()
m-oup + Jeautiful-oup(html.eAt)
m.a's + m-oup.find=all("span", id+"fs=lP<=hoo")
m8rice + m.a's4?5.strin'
print ".he current price of GH>> is2 {}".format(m8rice)
if i<*2 # wait a minute if this isn7t the last reSuest
sleep(R?)
9e,iew e6ercises-
Repeat the example in this section to scrape 96@@ stock ,uotes$ %ut
additionally include the current time o the ,uote as o%tained rom the
9ahoo3 #inance "e%pageB this time can %e taken rom part o a string inside
another span tag that appears shortly ater the actual stock price in the
"e%page&s 624>
145
Real Python
RealPython.com
11) $cienti.ic co0*utin# %nd #r%*hin#
11.1. 5se -umPy or matrix manipulation
you are a scientist$ an engineer$ or the sort o person "ho couldn&t sur'i'e a "eek
"ithout using 4A2>AD$ chances are high that you "ill "ant to make use o the
-umPy and !ciPy packages to increase your Python coding a%ilities. 8'en i you don&t all
into one o those categories$ these tools can still %e ,uite useul. 2his section "ill
introduce you to a Python package that lets you store and manipulate matrices o data$
and the next section "ill introduce an additional package that makes it possi%le to
'isuali*e data through endless 'arieties o graphs and charts.
0
2he main package or scientiic computing in Python is -umPyB there are a num%er o
additional speciali*ed packages$ %ut most o these are %ased on the unctionality
oered %y -umPy. 2o install -umPy$ do"nload the latest 'ersion here or )indo"s or
here or 4ac$ then run the automated installer.
2<
1e%ian=5%untu users can get -umPy %y
typing7
sudo apt!'et install pthon!nump
Among many other possi%ilities$ -umPy primarily oers an easy "ay to manipulate data
stored in many dimensions. #or instance$ "e usually think o a t"o+dimensional list as a
matrix or a ta%le that could %e created %y orming a list o lists in Python7
>>> matriA + 44(,*,;5, 4<,C,R5, 4Q,P,U55
>>> print matriA
44(, *, ;5, 4<, C, R5, 4Q, P, U55
>>>
)e could then reer to the num%ers at 'arious ro"=column locations using index
num%ers. #or instance7
>>> matriA4?54(5
*
2< @! Y users may encounter pro%lems using -umPy i YCode is already installed. 2he %est "ork+around so
ar appears to %e uninstalling YCode or using 0Python$ "hich is mentioned at the end o this chapter.
146
Real Python
RealPython.com
>>>
2hings get much more complicated$ ho"e'er$ i "e "ant to do anything more
complicated "ith this t"o+dimensional list. #or instance$ "hat i "e "anted to multiply
e'ery entry in our matrix %y 2/ 2hat "ould re,uire looping o'er e'ery entry in e'ery list
inside the main list.
>et&s create this same list using -umPy7
>>> from nump import arra
>>> matriA + arra(44(,*,;5, 4<,C,R5, 4Q,P,U55)
>>> print matriA
44( * ;5
4< C R5
4Q P U55
>>> matriA4?54(5
*
>>> matriA4?,(5
*
>>>
0n this case$ our matrix is reerred to as a t"o+dimensional array. An array is dierent
rom a list %ecause it can only hold similar entries For instance$ all num%ers. "hereas
"e could thro" any sort o o%(ects together into a list. 6o"e'er$ there are many more
"ays "e can create and control -umPy arrays.
In >u0Py? e%ch di0ension in %n arra is c%((ed %n axis. )ur e6%0*(e %rr%y h%s
two axes. 7he tot%( nu0ber o. di0ensions or %6es is c%((ed the Dr%nkF o. %
0%tri6? but these %re re%((y %(( ter0s .or describin# the s%0e thin#G 3ust kee* in
0ind th%t >u0Py o.ten re.ers to the ter0 D%6isF to 0e%n % di0ension o. %n %rr%y.
A
Another %eneit$ as "e can already see$ is that -umPy automatically kno"s to display
our t"o+dimensional Ft"o axis. array in t"o dimensions so that "e can easily read its
contents. )e also ha'e t"o options or accessing an entry$ either %y the usual indexing
or %y speciying the index num%er or each axis$ separated %y commas.
9e0e0ber to inc(ude the 0%in set o. sIu%re br%ckets when cre%tin# % >u0Py
%rr%yG e,en thou#h the arra() h%s *%rentheses? inc(udin# sIu%re br%ckets is
necess%ry when you w%nt to ty*e out the %rr%y entries direct(y. /or inst%nce?
this is correct-
matriA + arra(44(,*5,4;,<55)
A
147
Real Python
RealPython.com
1e%nwhi(e? this wou(d be I>8)99+87 bec%use it is 0issin# outer br%ckets-
matriA + arra(4(,*5,4;,<5)
We h%,e to ty*e out the %rr%y this w%y bec%use we cou(d %(so h%,e #i,en % di..erent
in*ut to cre%te the arra() = .or inst%nce? we cou(d h%,e su**(ied % (ist th%t is
%(re%dy enc(osed in its own set o. sIu%re br%ckets-
list + 44(,*5, 4;,<55
matriA + arra(list)
In this c%se? inc(udin# the sIu%re br%ckets %round list wou(d be nonsensic%(.
-o"$ multiplying e'ery entry in our matrix is as simple as "orking "ith an actual matrix7
>>> print matriAK*
44 * < R5
4 P (? (*5
4(< (R (P55
>>>
+,en i. you h%,e no interest in usin# 0%trices .or scienti.ic co0*utin#? you sti((
0i#ht .ind it he(*.u( %t so0e *oint to store in.or0%tion in % >u0Py arra
bec%use o. its 0%ny he(*.u( *ro*erties. /or inst%nce? *erh%*s you %re desi#nin#
% #%0e %nd need %n e%sy w%y to store? ,iew %nd 0%ni*u(%te % #rid o. ,%(ues with
rows %nd co(u0ns. 9%ther th%n cre%tin# % (ist o. (ists or so0e other co0*(ic%ted
structure? usin# % >u0Py arra is % si0*(e w%y to store your two=di0ension%( d%t%.
A
)e can (ust as easily perorm arithmetic using multi+dimensional arrays as "ell7
>>> secondIatriA + arra(44C,<,;5, 4Q,R,C5, 4U,P,Q55)
>>> print secondIatriA ! matriA
44 < * ?5
4 ; ( !(5
4 * ? !*55
>>>
0 you "ant to perorm matrix multiplication$ using the standard K sym%ol "ill perorm
%asic multiplication %y matching corresponding entries7
>>> print secondIatriA K matriA
44 C P U5
4*P ;? ;?5
4R; R< R;55
>>>
2o calculate an actual matrix dot product$ "e need to import and use the dot()
148
Real Python
RealPython.com
unction7
>>> from nump import dot
>>> print dot(secondIatriA, matriA)
44 <* C< RR5
4 RR P< (?*5
4 U? ((< (;P55
>>>
2"o matrices can also %e stacked 'ertically using 'stackF. or hori*ontally using hstackF.
i their axis si*es match7
>>> from nump import "stac1, hstac1
>>> print "stac1(4matriA, secondIatriA5) # add secondIatriA 0elow matriA
44( * ;5
4< C R5
4Q P U5
4C < ;5
4Q R C5
4U P Q55
>>> print hstac1(4matriA, secondIatriA5) # add secondIatriA neAt to matriA
44( * ; C < ;5
4< C R Q R C5
4Q P U U P Q55
>>>
#or %asic linear alge%ra purposes$ a e" o the most commonly used -umPy arra
properties are also sho"n here %riely$ as they are all airly sel+explanatory7
>>> print matriA.shape # a tuple of the aAis len'ths (; A ;)
(;, ;)
>>> print matriA.dia'onal() # arra of the main dia'onal entries
4( C U5
>>> print matriA.flatten() # a flat arra of all entries
4( * ; < C R Q P U5
>>> print matriA.transpose() # mirror!ima'e alon' the dia'onal
44( < Q5
4* C P5
4; R U55
>>> print matriA.min() # the minimum entr
(
>>> print matriA.maA() # the maAimum entr
U
>>> print matriA.mean() # the a"era'e "alue of all entries
C.?
>>> print matriA.sum() # the total of all entries
<C
>>>
149
Real Python
RealPython.com
)e can also reshape arrays "ith the reshape() unction to shit entries around7
>>> print matriA.reshape(U,()
44(5
4*5
4;5
4<5
4C5
4R5
4Q5
4P5
4U55
>>>
@ course$ the total si*e o the reshaped array must match the original array&s si*e. #or
instance$ "e couldn&t ha'e said matriA.reshape(*,C) %ecause there "ould ha'e
%een one extra entry created "ith nothing let to ill it.
2he reshape() unction can %e particularly helpul in com%ination "ith aran'e()$
"hich is -umPy&s e,ui'alent to ran'e() except that a -umPy arra is returned. #or
instance$ instead o typing out our se,uential list o num%ers into a matrix$ "e could
ha'e imported aran'e() and then reshaped the se,uence into a t"o+dimensional
matrix7
>>> from nump import aran'e
>>> matriA + aran'e((,(?) # an arra of num0ers ( throu'h U
>>> print matriA
4( * ; < C R Q P U5
>>> matriA + matriA.reshape(;,;)
>>> print matriA
44( * ;5
4< C R5
4Q P U55
>>>
Again$ (ust like "ith ran'e()$ using aran'e((,(?) "ill return the num%ers 1 through
U %ecause "e stop just before getting to the last num%er in the range.
)e ha'e %een "orking entirely "ith t"o+dimensional arrays since they are %oth the most
commonly used and the easiest to grasp. 6o"e'er$ (ust as "e can create a list o lists
o lists$ -umPy allo"s us to create arrays o higher dimensions as "ell. #or instance$
"e could create a simple three+dimensional array "ith the ollo"ing7
150
Real Python
RealPython.com
>>> arra;d + arra(444(,*5,4;,<55, 44C,R5,4Q,P55, 44U,(?5,4((,(*555)
>>> print arra;d
444 ( *5
4 ; <55
44 C R5
4 Q P55
44 U (?5
4(( (*555
>>>
An easier and saer "ay to create this particular array "ould %e to reshape() an
aran'e()7
>>> arra;d + aran'e((,(;)
>>> arra;d + arra;d.reshape(;,*,*)
>>>
8'en i a multi+dimensional array doesn&t use a se,uential list o num%ers$ sometimes it&s
easier to create the lat$ one+dimensional list o entries and then reshape() the array
into the desired shape instead o struggling "ith many nested sets o s,uare %rackets.
-umPy also has its o"n set o random unctionality$ "hich is particularly useul or
creating multi+dimensional arrays o random num%ers. #or instance$ "e can easily create
a AxA matrix o random num%ers like so7
>>> from nump import random
>>> print random.random(4;,;5)
44 ?.Q;PRUC ?.C*(C;;RQ ?.CPR(UR?(5
4 ?.;P*;*RQQ ?.(CU<(CQ; ?.RR?P?U(R5
4 ?.R(QC*QQU ?.R?*;R(PQ ?.CU(<RR* 55
>>>
-umPy oers much more unctionality than the %asics sho"n here$ although e'erything
co'ered should %e suicient or most tasks in'ol'ing %asic array storage and
manipulation. #or an incredi%ly thorough and mathematical introduction$ see the :uide
to -umPy. 2here is also a good %ut incomplete 2entati'e -umPy 2utorial a'aila%le and a
-umPy "ork in progress 5ser :uide.
#or scientists and engineers$ another indispensa%le tool is !ciPy$ "hich "orks on top o
-umPy to oer a mind+num%ingly 'ast set o tools or data manipulation and
'isuali*ation. !ciPy is a 'ery po"erul and very extensi'e collection o unctions and
151
Real Python
RealPython.com
algorithms that are too ad'anced to co'er in an introductory course$ %ut it&s "orth
researching i you ha'e a particular ad'anced topic already in mind. !ome o the tools
a'aila%le include unctionality or tasks in'ol'ing optimi*ation$ integration$ statistical
tests$ signal processing$ #ourier transorms$ image processing and more. #or a thorough
introduction to additional unctionality a'aila%le in !ciPy$ there is a drat reerence
guide that co'ers most ma(or topics. !ciPy is a'aila%le or do"nload here.
9e,iew e6ercises-
Create a A x A -umPy array named firstIatriA that includes the num%ers
A through 11 %y using aran'e() and reshape()
1isplay the minimum$ maximum and mean o all entries in firstIatriA
!,uare e'ery entry in firstIatriA using the KK operator$ and sa'e the
results in an array named secondIatriA
5se "stac1() to stack firstIatriA on top o secondIatriA and sa'e
the results in an array named thirdIatriA
5se dot() to calculate the dot product o thirdIatriA %y firstIatriA
Reshape thirdIatriA into an array o dimensions A x A x 2
11.2. 5se matplotli% or plotting graphs
he matplotli% li%rary "orks "ith -umPy to pro'ide tools or creating a "ide
'ariety o t"o+dimensional igures or 'isuali*ing data. 0 you ha'e e'er created
graphs in 4A2>AD$ matplotli% in many "ays directly recreates this experience "ithin
Python. #igures can then %e exported to 'arious ormats in order to sa'e out pictures or
documents.
2
9ou "ill irst need to do"nload and install %oth -umPy Fsee the pre'ious section. and
matplotli%. )indo"s and @! Y users can do"nload an automated matplotli% installer
152
Real Python
RealPython.com
here. 1e%ian=>inux users can get matplotli% %y typing the command7
2U
sudo apt!'et install pthon!matplotli0
2here are a e" modules included in the matplotli% package$ %ut "e "ill only "ork "ith
the %asic plotting module$ pplot. )e can import this unctionality as ollo"s7
from matplotli0 import pplot as plt
2his part o the code might take a little time to run ? there is a lot o code %eing
imported "ith this line3 )e decided to rename pplot to the name plt to sa'e a
little space and eort since "e&ll %e typing it a lot. Plotting a simple graph is in act
,uite simple to do. 2ry out this short script7
from matplotli0 import pplot as plt
plt.plot(4(,*,;,<,C5, 4*,<,R,P,(?5)
plt.show()
)e created a plot$ supplying a list o x+coordinate points and a matching list o y+
coordinate points. )hen "e call plt.show()$ a ne" "indo" appears$ displaying a
graph o our i'e Fx$y. points. @ur interacti'e "indo" is essentially locked "hile this plot
"indo" is open$ and "e can only end the script and return to a ne" prompt in the
interacti'e "indo" once "e&'e closed the graph.
2U !ome >inux users might separately need to install code to support the graphical interace Fsee section
12.2. %y typing the command sudo apt!'et install pthon!t1.
153
Real Python
RealPython.com
We5(( stick to usin# scri*ts to *(ot r%ther th%n ty*in# co00%nds into the
inter%cti,e window. 2sin# Windows? you shou(d %(so h%,e no *rob(e0s co*yin#
this code (ine=by=(ine into the inter%cti,e window. Howe,er? newer ,ersions o.
)$ B h%,e di..icu(ty res*ondin# to show(). 1e%nwhi(e? I'+ in inu6 c%n correct(y
show() % *(ot .ro0 %n inter%cti,e window? but then I'+ wi(( need to be rest%rted.
We5(( discuss other o*tions %nd %(tern%ti,es .or dis*(%yin# %nd inter%ctin# with *(ots
%t the end o. this section.
A
)hen plotting$ "e don&t e'en ha'e to speciy the hori*ontal axis pointsB i "e don&t
include any$ matplotli% "ill assume that "e "ant to graph our y 'alues against a
se,uential x axis increasing %y one7
from matplotli0 import pplot as plt
plt.plot(4*,<,R,P,(?5)
plt.show()
6o"e'er$ this isn&t exactly the same graph %ecause$ as al"ays$ Python %egins counting at
0 instead o 1$ "hich is "hat "e no" see or the hori*ontal axis 'alues as "ell.
2here is a optional ormatting argument that can %e inserted into plot() ater
speciying the points to %e plotted. 2his argument speciies the color and style o lines
or points to dra". 5nortunately$ the standard is %orro"ed rom 4A2>AD and Fcompared
to most Python. the ormatting is not 'ery intuiti'e to read or remem%er. 2he deault
'alue is solid %lue line$ "hich "ould %e represented %y the ormat string 0!. 0 "e
"anted to plot green circular dots connected %y solid lines instead$ "e "ould use the
ormat string '!o like so7
from matplotli0 import pplot as plt
154
Real Python
RealPython.com
plt.plot(4*,<,R,P,(?5, "'!o")
plt.show()
#or reerence$ the ull list o possi%le ormatting com%inations can %e ound here.
Plotting "ouldn&t %e 'ery con'enient i "e had to organi*e e'erything into lists oursel'es
irstB matplotli% "orks "ith -umPy to accept arrays as "ell. F8'en i you can get a"ay
"ith using a %asic list$ it&s a good idea to stick "ith arrays in case you later disco'er that
you do need to modiy the num%ers in some "ay.. #or instance$ to create our pre'ious
graph$ "e could use aran'e() to return an array o the same num%ers7
from matplotli0 import pplot as plt
from nump import aran'e
plt.plot(aran'e(*,(*,*), "'!o")
plt.show() # displas the same 'raph as the pre"ious eAample
6ere$ "e used the optional third argument o aran'e()$ "hich speciies the step. 2he
step is the amount %y "hich to increase each su%se,uent num%er$ so saying
aran'e(*,(*,*) gi'es us an array o num%ers %eginning at 2$ increasing %y 2 e'ery
step$ and ending %eore 12. F0n act$ this third step argument "orks exactly the same
"ay or the %uilt+in ran'e() unction as "ell..
2o plot multiple sets o points$ "e add them to plot() as additional arguments7
from matplotli0 import pplot as plt
from nump import aran'e
A8oints + aran'e((,*()
0aseline + aran'e(?,*?)
plt.plot(A8oints, 0aselineKK*, "'!o", A8oints, 0aseline, "r!\")
plt.show()
155
Real Python
RealPython.com
)e plotted t"o sets o pointsB the green dots plot the 'alues in A8oints "ith the
s,uare o the 0aseline y 'alues$ "hile the red triangles (ust plot the 'alues in
A8oints "ith the original 0aseline 'alues.
2his isn&t a 'ery pretty graph$ though. #ortunately$ there are plenty o things "e can do
to impro'e the layout and ormatting. #irst o all$ let&s change the axes so that our
points don&t go o the corners o the graph7
from matplotli0 import pplot as plt
from nump import aran'e
A8oints + aran'e((,*()
0aseline + aran'e(?,*?)
plt.plot(A8oints, 0aselineKK*, "'!o", A8oints, 0aseline, "r!\")
plt.aAis(4?, *(, ?, <??5)
plt.show()
156
Real Python
RealPython.com
)e deine the %oundaries o the displayed axes "ith a list o the our points in the order
4min Y, maA Y, min G, maA G5 + in this case$ "e increased the maximum 'alue
that the x+axis extended rom 20 to 21 so that the last t"o points don&t appear hal"ay
o the graph.
-o" "e&re starting to get some"here useul$ %ut nothing is la%eled yet. >et&s add a title$
a legend and some titles or the axes7
from matplotli0 import pplot as plt
from nump import aran'e
A8oints + aran'e((,*()
0aseline + aran'e(?,*?)
plt.plot(A8oints, 0aselineKK*, "'!o", A8oints, 0aseline, "r!\")
plt.aAis(4?, *(, ?, <??5)
plt.title("/mount of 8thon learned o"er time")
plt.Ala0el("$as")
plt.la0el("-tandardiDed 1nowled'e indeA score")
plt.le'end((",eal 8thon", ">ther course"), loc+*)
plt.show()
2here are many more complicated "ays to create a legend$ %ut the simplest is to supply
a tuple that lists the la%els to %e applied to all the plotted points in order. )e speciied
loc+* in the legend %ecause "e "ant the legend to appear in the top let corner$ "hile
the deault is or the legend to appear in the top right corner. 5nless you&re making
graphs 'ery re,uently$ it&s near impossi%le to remem%er the particular detail that
loc+* corresponds to the top let corner along "ith so many other cryptic ormatting
detailsB the %est thing to do in this situation is to search the "e% or a rele'ant term like
157
Real Python
RealPython.com
matplotli% legend. 0n this case$ you&ll ,uickly %e directed to the matplotli% legend
guide that oers$ among many other details$ a ta%le pro'iding legend location codes.
Another re,uently used type o plot in %asic data 'isuali*ation is a %ar chart. >et&s start
"ith a 'ery simple example o a %ar chart$ "hich uses the 0ar() plotting unction7
from matplotli0 import pplot as plt
from nump import aran'e
plt.0ar(aran'e(?,(?), aran'e((,*(,*))
plt.show()
2he irst argument takes a list or an array o the x+axis locations or each %ar&s let edgeB
in this case$ "e placed the let sides o our %ars along the num%ers rom 0 through U.
2he second argument o 0ar() is a list or an array o the ordered %ar 'aluesB here "e
supplied the odd num%ers 1 through 1U or our %ar heights. 2he %ars automatically ha'e
"idths o 1$ although this can also %e changed %y setting the optional "idth argument7
from matplotli0 import pplot as plt
from nump import aran'e
plt.0ar(aran'e(?,(?), aran'e((,*(,*), width+.C)
plt.show()
158
Real Python
RealPython.com
@ten "e "ill "ant to compare t"o or more sets o %ars on a single plot. 2o do this$ "e
ha'e to space them out along the x+axis so that each set o %ars appears next to each
other. )e can multiply an aran'e() %y some actor in order to lea'e space$ since in
this case "e care more a%out placing our %ars in the correct order rather than speciying
where on the x+axis our %ars are located7
from matplotli0 import pplot as plt
from nump import aran'e
plt.0ar(aran'e(?,(?)K*, aran'e((,*(,*))
plt.0ar(aran'e(?,(?)K* ) (, aran'e((,;(,;), color+"red")
plt.show()
#or the x+axis o the irst set o %ars$ "e supplied the e'en num%ers 0 through 1< %y
multiplying e'ery num%er in our aran'e() %y 2. 2his allo"s us to lea'e some space or
159
Real Python
RealPython.com
the second set o %ars$ "hich "e place along each o the e'en num%ers 1 through 1U.
6o"e'er$ the automatic num%ering pro'ided along the x+axis is meaningless no". )e can
change this %y gi'ing locations to la%el along the x+axis "ith the Atic1s() unction.
)hile "e&re at it$ let&s also space out each pair o %ars$ lea'ing a %lank space %et"een
each grouping so that the pairs are more apparent7
from matplotli0 import pplot as plt
from nump import aran'e
plt.0ar(aran'e(?,(?)K;, aran'e((,*(,*))
plt.0ar(aran'e(?,(?)K; ) (, aran'e((,;(,;), color+"red")
plt.Atic1s(aran'e(?,(?)K; ) (, aran'e((,((), fontsiDe+*?)
plt.show()
!ince "e "anted to sho" the x+axis la%els in %et"een each o our pairs o %ars$ "e
speciied the let side o the second Fred. set o %ars as the position to sho" the la%el.
)e then ga'e the num%ers 1 through 10 as the actual la%els to displayB "e could (ust as
easily ha'e used a list o strings as la%els as "ell. #inally$ "e also speciied a larger ont
si*e or %etter reada%ility.
Again$ "e can also add axis la%els$ a graph title$ a legend$ etc. in the same "ay as "ith
any other plot7
from matplotli0 import pplot as plt
from nump import aran'e
plt.0ar(aran'e(?,(?)K;, aran'e((,*(,*))
plt.0ar(aran'e(?,(?)K; ) (, aran'e((,;(,;), color+"red")
plt.Atic1s(aran'e(?,(?)K; ) (, aran'e((,((), fontsiDe+*?)
plt.title("@offee consumption due to sleep depri"ation")
plt.Ala0el("Xroup num0er")
160
Real Python
RealPython.com
plt.la0el("@ups of coffee consumed")
plt.le'end(("@ontrol 'roup", ".est 'roup"), loc+*)
plt.show()
Another commonly used type o graph is the histogram$ "hich is notoriously diicult to
create in other programs like 4icrosot 8xcel. )e can make simple histograms 'ery
easily using matplotli% "ith the hist() unction$ "hich "e supply "ith a list For array.
o 'alues and the num%er o %ins to use. #or instance$ "e can create a histogram o
10$000 normally distri%uted F:aussian. random num%ers %inned across 20 possi%le %ars
"ith the ollo"ing$ "hich uses -umPy&s random.randn() unction to generate an array
o normal random num%ers7
from matplotli0 import pplot as plt
from nump import random
plt.hist(random.randn((????), *?)
plt.show()
161
Real Python
RealPython.com
@ten "e "ant to add some text to a graph or chart. 2here are a num%er o "ays to do
this$ %ut adding graph annotations is a 'ery detailed topic that can ,uickly %ecome case+
speciic. #or one short example$ let&s point out the expected a'erage 'alue on our
histogram$ complete "ith an arro"7
from matplotli0 import pplot as plt
from nump import random
plt.hist(random.randn((????), *?)
plt.annotate("eApected mean", A+(?, ?), AteAt+(?, ;??), ha+"center",
arrowprops+dict(facecolor+70lac17), fontsiDe+*?)
plt.show()
)hen "e call annotate()$ irst "e pro'ide the string o text that "e "ant to appear.
2his is ollo"ed %y the location to %e annotated Fi.e.$ "here the arro" points. and the
location o the text. )e optionally say that the text should %e centered in terms o
hori*ontal alignment using ha+"center"$ and then "e add an arro" prop that "ill
point rom the text Fcentered at the point AteAt. to the annotation point Fcentered at
the point A.. 2his arro" takes a dictionary o deinitions$ although "e only pro'ide one
? namely that the arro" should %e colored %lack. #inally$ "e speciy a large ont si*e o
20.
)e can e'en include mathematical expressions in our text %y using a "riting style called
%e- marup language. 2his "ill %e amiliar to you i you&'e e'er used >a2eY$ although a
%rie introduction or use in matplotli% can %e ound here. As a simple example$ let&s
make out annotation a little more scientiic %y adding the sym%ol [ "ith a hat o'er+
line to sho" the predicted mean 'alue7
162
Real Python
RealPython.com
from matplotli0 import pplot as plt
from nump import random
plt.hist(random.randn((????), *?)
plt.annotate(r"W\hat \mu + ?W", A+(?, ?), AteAt+(?, ;??), ha+"center",
arrowprops+dict(facecolor+70lac17), fontsiDe+*?)
plt.show()
2he text expression is preaced "ith an r to let Python kno" that it&s a raw string$
meaning that the %ackslashes should not %e interpreted as special characters. 2hen the
ull 2eY string is enclosed in dollar signs. Again$ a ull o'er'ie" o 2eY expressions is
%eyond the scope o this course$ %ut it&s usually a airly simple matter to ind a similar
example to "hat you "ant to create and then modiy it to suit your needs.
@nce "e ha'e a chart created$ chances are that "e&ll "ant to %e a%le to sa'e it
some"here. 0t turns out that this process is e'en easier than "riting other kinds o iles$
%ecause matplotli% allo"s us to sa'e P-: images$ !G: images$ P1# documents and
Post!cript iles %y simply speciying the type o ile to use and then calling the
sa"efi'() unction. #or instance$ instead o displaying out histogram on the screen$
let&s sa'e it out as %oth a P-: image and a P1# ile to our chapter 11 output older7
from matplotli0 import pplot as plt
from nump import random
plt.hist(random.randn((????), *?)
path + "@2B,eal 8thonB@ourse materialsB@hapter ((B8ractice filesB>utputB"
plt.sa"efi'(path)"histo'ram.pn'")
plt.sa"efi'(path)"histo'ram.pdf")
163
Real Python
RealPython.com
When usin# pplot? i. you w%nt to both s%,e % .i#ure %nd dis*(%y it on the
screen? 0%ke sure th%t you s%,e it first be.ore dis*(%yin# itA :ec%use show()
*%uses your code %nd bec%use c(osin# the dis*(%y window destroys the #r%*h?
tryin# to s%,e the .i#ure after c%((in# show() wi(( on(y resu(t in %n e0*ty .i(e.
A
#inally$ "hen you&re initially t"eaking the layout and ormatting o a particular graph$
you might "ant to change parts o the graph "ithout re+running an entire script to re+
display the graph. 5nortunately$ on some systems matplotli% doesn&t "ork "ell "ith
01>8 "hen it comes to creating an interacti'e process$ %ut there are a couple options
a'aila%le i you do "ant this unctionality. @ne simple "ork+around is simply to sa'e out
a script speciically to create the graph$ then continually modiy and rerun this script.
Another possi%ility is to install the 0Python package$ "hich creates an interacti'e
'ersion o Python that "ill allo" you to "ork "ith a graphics "indo" that&s already
open. A simpler %ut less user+riendly solution is to run Python rom the )indo"s
command line or 4ac=>inux 2erminal Fsee the .nterlude/ .nstall Pacages section or
instructions on ho" to do this.. 0n either case$ you "ill then %e a%le to turn on
matplotli%&s interacti'e mode or a gi'en plot using the ion() unction$ like so7
>>> from matplotli0 import pplot as plt
>>> plt.ion()
>>>
9ou can then create a plot as usual$ without ha'ing to call the show() unction to
display it$ and then make changes to the plot "hile it is still %eing displayed %y typing
commands into the interacti'e "indo".
Although "e&'e co'ered the most commonly used %asics or creating plots$ the
unctionality oered in matplotli% is incredi%ly extensi'e. 0 you ha'e an idea in mind
or a particular type o data 'isuali*ation$ no matter ho" complex$ the %est "ay to get
started is usually to %ro"se the matplotli% gallery or something that looks similar and
then make the necessary modiications to the example code.
9e,iew e6ercises-
Recreate all the graphs sho"n in this section %y "riting your o"n scripts
"ithout reerring to the pro'ided code
164
Real Python
RealPython.com
Assignment 11.2: Plot a graph from '+ $ata
It is % we((=docu0ented .%ct th%t the nu0ber o. *ir%tes in the wor(d is
corre(%ted with % rise in #(ob%( te0*er%tures. Write % scri*t Dpirates.pyF th%t
,isu%((y e6%0ines this re(%tionshi*-
= 9e%d in the .i(e Dpirates.cs'F .ro0 the 8h%*ter 11 *r%ctice .i(es .o(der.
= 8re%te % (ine #r%*h o. the %,er%#e wor(d te0*er%ture in de#rees 8e(sius
%s % .unction o. the nu0ber o. *ir%tes in the wor(d? i.e.? #r%*h 8irates
%(on# the 6=%6is %nd .emperature %(on# the y=%6is.
= 4dd % #r%*h tit(e %nd (%be( your #r%*h5s %6es.
= $%,e the resu(tin# #r%*h out %s % P>" i0%#e .i(e.
= :onus- %be( e%ch *oint on the #r%*h with the %**ro*ri%te GearG you
shou(d do this D*ro#r%00%tic%((yF by (oo*in# throu#h the %ctu%( d%t%
*oints r%ther th%n s*eci.yin# the indi,idu%( *osition o. e%ch %nnot%tion.
/
165
Real Python
RealPython.com
12) "r%*hic%( 2ser Inter.%ces
12.1. Add :50 elements "ith 8asy:50
e&'e made a e" pretty pictures "ith matplotli% and manipulated some iles$ %ut
other"ise "e ha'e limited oursel'es to programs that are generally in'isi%le and
occasionally spit out text. )hile this might %e good enough or most purposes$ there are
some programs that could really %eneit rom letting the user point and click ? say$ a
script you "rote to rename a older&s "orth o iles that your technologically impaired
riend no" "ants to use. #or this$ "e need to design a graphical user interace Freerred
to as a 0&. and pronounced gooey ? really..
)
)hen "e talk a%out :50s$ "e usually mean a ull 0&. application "here e'erything
a%out the program happens inside a "indo" ull o 'isual elements Fas opposed to a
text+%ased program.. 1esigning good :50 applications can %e incredi%ly diicult %ecause
there are so many mo'ing parts to manageB all the pieces o an application constantly
ha'e to %e listening to each other and to the user$ and you ha'e to keep updating all the
'isual elements so that the user only sees the most recent 'ersion o e'erything.
0nstead o di'ing right into the complicated "orld o making :50 applications$ let&s irst
add some indi'idual :50 elements to our code. 2hat "ay$ "e can still impro'e the
experience or the person using our program "ithout ha'ing to spend endless hours
designing and coding it.
)e&ll start out in :50 programming "ith a module named 8asy:50. #irst$ you&ll need to
do"nload this package7
Windows- 0 you ha'e eas=install set up$ then you can install the package %y
typing eas=install eas'ui at a command prompt. @ther"ise$ do"nload the
compressed .Dip ile$ un*ip it$ and install the package %y running Python on
setup.p rom the command prompt as descri%ed in the installation section.
)$ B- 0 you ha'e eas=install set up$ then you can install the package %y typing
sudo eas=install eas'ui into the 2erminal. @ther"ise$ do"nload the
compressed .tar.'D ile$ decompress it$ then install the package %y running Python
166
Real Python
RealPython.com
on setup.p rom 2erminal as descri%ed in the installation section.
'ebi%nOinu6- 2ype sudo apt!'et install pthon!eas'ui.
8asy:50 is dierent rom other :50 modules %ecause it doesn&t rely on events. 4ost :50
applications are event-driven$ meaning that the lo" o the program depends on actions
taken %y the userB this is usually "hat makes :50 programming so complicated$ %ecause
any o%(ect that might change in response to the user has to listen or dierent
e'ents to occur. Dy contrast$ 8asy:50 is structured linearly like any unctionB at some
point in our code$ "e display some 'isual element on the screen$ use it to take input
rom the user$ then return that user&s input to our code and proceed as usual.
>et&s start %y importing the unctionality rom 8asy:50 into the interacti'e "indo" and
displaying a simple message %ox7
>>> from eas'ui import K
>>> ms'0oA("Hello, &asXH#9", ".his is a messa'e 0oA", "Hi there")
7Hi there7
>>>
)hen you run the second line o code$ something like the "indo" a%o'e should ha'e
appeared. @n 4ac$ it "ill look more like this7
167
Real Python
RealPython.com
And in 5%untu7
0 nothing appears$ see the %ox %elo". #or the sake o the ma(ority$ 0&ll %e sticking to
screenshots rom a )indo"s :50 perspecti'e only.
)e used the ms'0oA() to generate a ne" %ox that includes a message$ a "indo" title$
and %utton text that "e pro'ided$ in that order. F2he deault 'alue or the %utton text
"ould %e >[ i "e hadn&t pro'ided a third argument.. )hen the user clicks the %utton$
8asy:50 returns the 'alue o the %utton&s text$ and "e&re %ack to the interacti'e prompt.
+%sy"2I uses % too(kit c%((ed 7kinter? which we wi(( #et to use in the ne6t
section. I'+ uses 7kinter to run %s we((. Cou might run into *rob(e0s with
.reeHin# windows? etc.? bec%use o. dis%#ree0ents between the new windows
you cre%te %nd the I'+ window itse(.. I. you think this 0i#ht be h%**enin#? you c%n
%(w%ys try runnin# your code or scri*t by runnin# Python .ro0 the co00%nd *ro0*t
@Windows) or 7er0in%( @1%cOinu6).
A
-otice that "hen "e ran the pre'ious code$ clicking the %utton returned the 'alue that
"as in the %utton text %ack to the interacti'e "indo". 0n this case$ returning the text o
the %utton clicked %y the user "asn&t that inormati'e$ %ut "e can also pro'ide more
than one choice %y using a 0utton0oA() and pro'iding a tuple o %utton 'alues7
>>> choices + ("Jlue", "Gellow", "/uuu'h9")
>>> 0utton0oA(":hat is our fa"orite colorF", "@hoose wisel...", choices)
7/uuu'h97
>>>
168
Real Python
RealPython.com
-o" "e "ere a%le to tell that our user chose Auuugh3 as the a'orite color$ and "e
could set that return 'alue e,ual to a 'aria%le to %e used later in our code.
2here are a num%er o other "ays to recei'e input rom the user through easy:50 to suit
your needs. #or starters$ try out the ollo"ing lines a e" times each and see "hat
'alues they return %ased on the dierent choices you select7
>>> choices + ("Jlue", "Gellow", "/uuu'h9") # tuple of choices
>>> title + "@hoose wisel..." # window title
>>> indeA0oA(":hat is our fa"orite colorF", title, choices)
>>> choice0oA(":hat is our fa"orite colorF", title, choices)
>>> multchoice0oA(":hat are our fa"orite colorsF", title, choices)
>>> enter0oA(":hat is our fa"orite colorF", title)
>>> password0oA(":hat is our fa"orite colorF (# won7t tell.)", title)
>>> teAt0oA("8lease descri0e our fa"orite color2")
Another useul eature pro'ided %y 8asy:50 is a simple "ay or the user to select a ile
through a standard ile dialog %ox7
>>> fileopen0oA("messa'e", "title", "K.tAt")
2he third argument "e passed to fileopen0oA() "as the type o ile "e "ant the user
to open$ "hich "e speciy in a string %y using a "ildcard K sym%ol ollo"ed %y the
name o the ile extension. 2his automatically ilters the 'ie"a%le iles to those that
match the .tAt extension$ although the user still has the option to change this %ox to
/ll files (K.K) and select any type o ile.
-otice ho" "e still pro'ided a message and a title e'en though they %oth appeared
in the title %arB typically you "ill (ust "ant to pass an empty string to one o these$
169
Real Python
RealPython.com
since a single title is enough. 0 "e look up the easy:50 documentation to ind out the
names o the 'aria%les used %y the unction fileopen0oA()$ "e can also pro'ide only
speciic arguments %y directly assigning 'alues to the 'aria%le names$ like so7
>>> fileopen0oA(title+">pen a file...", default+"K.tAt")
)ithin a ile open dialog %ox$ try typing in the name o a ile that doesn&t exist and
opening itB the dialog %ox "on&t let you3 2his is one less thing that "e ha'e to "orry
a%out programming into our code. 2he user can still hit cancel$ in "hich case 6one is
returned to represent a lack o any o%(ect. F!ee the call+out %ox at the 'ery end o
section U.1 or a more complete explanation o the 6one key"ord.. @ther"ise$
fileopen0oA() gi'es us a string representing the ull path to the selected ile. Leep in
mind that "e aren&t actually opening this ile in any "ayB "e&re simply presenting the
user "ith the a%ility to select a ile or opening$ %ut the rest o the code is still up to us.
2here is also a diropen0oA() unction or letting the user choose a older rather than
an indi'idual ileB in this case$ the optional third argument can tell the dialog %ox "hich
directory to ha'e open %y deault.
#inally$ there is a filesa"e0oA() that "orks similarly to fileopen0oA() except that
it allo"s the user to select a ile to %e sa'ed rather than opened. 2his dialog %ox also
conirms that the user "ants to o'er"rite the ile i the chosen name is the same as a
ile that already exists. Again$ no actual sa'ing o iles is happening ? that&s still up to us
to program once "e recei'e the ile name rom easy:50.
0n practice$ one o the most diicult pro%lems "hen it comes to letting the user select
iles is "hat to do i the user cancels out o the "indo" "hen you need to ha'e selected
a ile. @ne simple solution is to display the dialog in a loop until the user inally does
select a ile$ %ut that&s not 'ery nice ? ater all$ may%e your user had a change o heart
and really doesn&t "ant to run "hate'er code comes next.
0nstead$ you should plan to handle re(ection graceully. 1epending on "hat exactly
you&re asking o the user$ most o the time you should use eAit() to end the program
"ithout a uss "hen the user cancels. F0 you&re running the script in 01>8$ eAit() "ill
also close the current interacti'e "indo". 0t&s 'ery thorough..
170
Real Python
RealPython.com
>et&s get some practice "ith ho" to handle ile dialogs %y "riting a simple$ usa%le
program. )e "ill guide the user F"ith :50 elements. through the process o opening a
P1# ile$ rotating its pages in some "ay$ and then sa'ing the rotated ile as a ne" P1#7
from eas'ui import K
from p8df import 8df3ile,eader, 8df3ile:riter
# let the user choose an input file
input3ile6ame + fileopen0oA("", "-elect a 8$3 to rotate...", "K.pdf")
if input3ile6ame ++ 6one2 # eAit on "@ancel"
eAit()
# let the user choose an amount of rotation
rotate@hoices + (U?, (P?, *Q?)
messa'e + ",otate the 8$3 cloc1wise 0 how man de'reesF"
de'rees + 0utton0oA(messa'e, "@hoose rotation...", rotate@hoices)
# let the user choose an output file
output3ile6ame + filesa"e0oA("", "-a"e the rotated 8$3 as...", "K.pdf")
while input3ile6ame ++ output3ile6ame2 # cannot use same file as input
ms'0oA("@annot o"erwrite ori'inal file9", "8lease choose another
file...")
output3ile6ame + filesa"e0oA("", "-a"e the rotated 8$3 as...", "K.pdf")
if output3ile6ame ++ 6one2
eAit() # eAit on "@ancel"
# read in file, perform rotation and sa"e out new file
input3ile + 8df3ile,eader(file(input3ile6ame, "r0"))
output8$3 + 8df3ile:riter()
for pa'e6um in ran'e(?, input3ile.'et6um8a'es())2
pa'e + input3ile.'et8a'e(pa'e6um)
pa'e + pa'e.rotate@loc1wise(int(de'rees))
output8$3.add8a'e(pa'e)
output3ile + file(output3ile6ame, "w0")
output8$3.write(output3ile)
output3ile.close()
Desides the use o eAit()$ you should already %e amiliar "ith all the code in this
script. 2he tricky part is the logic ? i.e.$ ho" to put all the dierent pieces together to
create a seamless experience or the user. #or longer programs$ it can %e helpul to
dra" out diagrams %y hand using %oxes and arro"s to represent ho" "e "ant the user to
experience the dierent parts o our programB it&s a good idea to do this e'en before
you start "riting any code at all. >et&s represent ho" this script "orks in an outline orm
in terms o "hat "e display to the user7
171
Real Python
RealPython.com
1. >et the user select an input ile
2. 0 the user canceled the open ile dialog F6one "as returned.$ exit the program
A. >et the user select a rotation amount
+ W-o alternati'e choice hereB the user must click a %uttonX
C. >et the user select an output ile
J. 0 the user tries to sa'e a ile "ith the same name as the input ile7
+ Alert the user o the pro%lem "ith a message %ox
+ Return to step C
Q. 0 the user canceled the sa'e ile dialog F6one "as returned.$ exit the program
2he inal steps are the hardest to plan out. Ater step C$ since "e already kno" From
step 2. that the input ile isn&t 6one$ "e can check "hether the output ile and input
ile match before checking or the canceled dialog. 2hen$ %ased on the return 'alue
rom the dialog$ "e can check or "hether or not the user canceled the dialog %ox ater
the act.
9e,iew e6ercises-
Recreate the three dierent :50 elements pictured in this section %y "riting
your o"n scripts "ithout reerring to the pro'ided code
!a'e each o the 'alues returned rom these :50 elements into ne" 'aria%les$
then print each o them
2est out indeA0oA()$ choice0oA()$ multchoice0oA()$ enter0oA()$
password0oA() and teAt0oA() to see "hat :50 elements they produceB
you can use the help() unction to read more a%out each unction in the
interacti'e "indo" ? or instance$ type import eas'ui then
help(eas'ui.indeA0oA)
172
Real Python
RealPython.com
Assignment 12.1: *se .*/ elements to help a user mo$ify files
Write % scri*t D*%rti%(LP'/.*yF th%t e6tr%ct % s*eci.ic r%n#e o. *%#es .ro0 %
P'/ .i(e b%sed on .i(e n%0es %nd % *%#e r%n#e su**(ied by the user. 7he
*ro#r%0 shou(d run %s .o((ows-
= et the user choose % .i(e usin# % fileopen0oA
= et the user choose % be#innin# *%#e to se(ect usin# %n enter0oA
= I. the user enters in,%(id in*ut? use % ms'0oA to (et the user
know th%t there w%s % *rob(e0? then %sk .or % be#innin# *%#e
%#%in usin# %n enter0oA
= et the user choose %n endin# *%#e usin# %nother enter0oA
= I. the user enters %n in,%(id endin# *%#e? use % ms'0oA to (et the
user know th%t there w%s % *rob(e0? then %sk .or % be#innin#
*%#e %#%in usin# %n enter0oA
= et the user choose %n out*ut .i(e n%0e usin# % sa"efile0oA
= I. the user chooses the s%0e .i(e %s the in*ut .i(e? (et the user
know the *rob(e0 usin# % ms'0oA? then %sk %#%in .or % .i(e n%0e
usin# % sa"efile0oA
= )ut*ut the new .i(e %s % section o. the in*ut .i(e b%sed on the
user=su**(ied *%#e r%n#e
7he user shou(d be %b(e to su**(y D1F to 0e%n the .irst *%#e o. the docu0ent.
7here %re % nu0ber o. *otenti%( issues th%t your scri*t shou(d be %b(e to h%nd(e.
7hese inc(ude-
= I. the user c%nce(s out o. % bo6? the *ro#r%0 shou(d e6it without
%ny errors
= 8heck th%t *%#es su**(ied %re ,%(id nu0bersG you c%n use the
strin# 0ethod isdi'it() to check whether or not % strin# is %
,%(id positive inte#er. @7he isdi'it() 0ethod wi(( return .%(se
.or the strin# D0F %s we((.)
= 8heck th%t the *%#e r%n#e itse(. is ,%(id @i.e.? the end U the st%rt)
?
12.2. Create :50 applications "ith 2kinter
or many %asic tasks "here :50 elements are needed one at a time$ 8asy:50 can
sa'e a lot o eort compared to creating an entire :50 program. 0 you do "ant to
%uild a complete :50 application "ith many interacting elements$ it "ill take
signiicantly more code Fand time spent programming.$ %ut this section "ill help get you
started.
#
2here are a lot o dierent tools a'aila%le or :50 application design in Python. 2he
173
Real Python
RealPython.com
simplest and most commonly used rame"ork is the 2kinter module$ "hich comes "ith
Python %y deault. F0n act$ easy:50 is really (ust a simpliied "ay o accessing 2kinter in
small$ managea%le pieces.. 2here are more ad'anced toolkits that can %e used to
produce more complicated Fand e'entually %etter+looking. :50s$ and "e "ill touch on
these at the end o the chapter. 6o"e'er$ 2kinter is still the module o choice or many
:50 pro(ects %ecause it is so light"eight and relati'ely easy to use or simple tasks
compared to other toolkits. 0n act$ 01>8 itsel uses 2kinter3
4s 0entioned in the (%st section? bec%use I'+ is %(so bui(t with 7kinter? you
0i#ht encounter di..icu(ties when runnin# your own "2I *ro#r%0s within I'+. I.
you .ind th%t the "2I window you %re tryin# to cre%te is une6*ected(y .reeHin#
or %**e%rs to be 0%kin# I'+ 0isbeh%,e in so0e une6*ected w%y? try runnin# your
scri*t in Python ,i% your co00%nd *ro0*t @Windows) or 7er0in%( @1%cOinu6) to
check i. I'+ is the re%( cu(*rit.
A
:50 applications exist as windows$ "hich are (ust the application %oxes you&re used to
using e'ery"here$ each one "ith its o"n title$ minimi*e %utton$ close %utton$ and
usually the a%ility to %e resi*ed. )ithin a "indo" "e can ha'e one or more frames that
contain the actual contentB the rames help to separate the "indo"&s content into
dierent sections. #rames$ and all the dierent o%(ects inside o them Fmenus$ text
la%els$ %uttons$ etc.. are all called widgets.
>et&s start "ith a "indo" that only contains a single "idget. 0n this case$ "e&ll use a
%a0el to sho" a single string o text7
from .1inter import K
m/pplication + .1() # create a new window
'reetin' + %a0el(teAt+"Hello, .1inter") # create a teAt la0el
'reetin'.pac1() # add the la0el to the window
m/pplication.mainloop() # run the application
2his is already signiicantly more complicated than easy:503 #irst$ "e had to import
unctionality rom the .1inter module. 2hen "e created a ne" 2kinter "indo" %y
calling .1() and made a %a0el o%(ect containing some text. 2o actually add the %a0el
to our app "indo" and make it 'isi%le$ "e had to call the pac1() method on the
%a0el$ "hich packs it into the "indo". #inally$ "e called the mainloop() method to
174
Real Python
RealPython.com
make our m/pplication "indo" and its contents 'isi%le and %egin the processing o
running the :50 application. Although it can&t do anything interesting yet$ it does
unctionB the application can %e resi*ed$ minimi*ed$ and closed.
0 you run this script$ a "indo" should appear that "ill look something like one o the
ollo"ing$ depending on your operating system7
Again$ or the sake o the ma(ority$ 0&ll stick to displaying only the resulting )indo"s
application 'ersion or the remained o this section.
5sually$ the layout o e'en a 'ery %asic complete :50 application "ill %e much more
complicated than our last example. Although it may look intimidating "hen starting out$
keep in mind that all o the initial "ork is helpul to make it much easier once "e "ant
to add additional eatures to the application. A more typical setup or a Fstill %lank. :50
application might look something more like this7
from .1inter import K
# define the XH# application
class /pp(3rame)2
def ==init==(self, master)2
3rame.==init==(self, master)
# create the application window
window + .1()
window.'eometr("<??A*??") # default window siDe
m/pplication + /pp(window)
m/pplication.master.title("# made a window9")
m/pplication.mainloop() # start the application
Although this type o setup is necessary or expanding :50 applications to more complex
unctionality$ the code in'ol'ed is %eyond the scope o this %rie introduction. 0nstead$
"e "ill restrict oursel'es to a simpler setup that is still completely unctional %ut less
eicient or %uilding ad'anced user interaces.
175
Real Python
RealPython.com
>et&s start "ith a simple "indo" again$ %ut this time add a single rame into it. )e&ll set
a deault "indo" si*e$ and the one rame "ill take up the entire "indo". )e can then
add "idgets to the rame as "ell$ such as a %a0el "ith text. 2his time$ "e&ll speciy
%ackground F0'. and oreground Ff'. colors or the %a0el text as "ell as a ont7
from .1inter import K
window + .1()
window.title("Here7s a window")
window.'eometr("*C?A(??") # default window siDe
m3rame + 3rame()
m3rame.pac1()
la0el.eAt + %a0el(m3rame, teAt+"#7"e 0een framed9", 0'+"red", f'+"ellow",
font+"/rial")
la0el.eAt.pac1()
window.mainloop()
2he result is 'ery similar to our irst "indo"$ since the rame itsel isn&t a 'isi%le o%(ect7
)hen "e created the la%el$ "e had to assign the la%el to the rame %y passing the name
o our rame Fm3rame. as the irst argument o this %a0el "idget. 2his is important to
do %ecause "e&re other"ise packing the la%el into the window$ and anything "e do to
modiy the rame&s ormatting "on&t %e applied to "idgets that don&t speciically name
the rame to "hich they %elong. 2he rame is called the parent "idget o the la%el since
the la%el is placed inside o it. 2his %ecomes especially important once "e ha'e multiple
rames and ha'e to tell 2kinter "hich "idgets "ill appear in "hich rames.
2here are a e" dierent "ays "e can organi*ing the packing o "idgets into a rame.
#or instance$ running the same script as a%o'e %ut packing our la%el "ith
la0el.eAt.pac1(fill+Y) "ill make the la%el span across the entire "idth o the
176
Real Python
RealPython.com
rame. )idgets stack 'ertically on top o each other %y deault$ %ut "e can pack them
side+%y+side as "ell7
from .1inter import K
window + .1()
m3rame + 3rame()
m3rame.pac1()
# a 0ar to span across the entire top
la0el.eAt( + %a0el(m3rame, teAt+"top 0ar", 0'+"red")
la0el.eAt(.pac1(fill+Y)
# three side!0!side la0els
la0el%eft + %a0el(m3rame, teAt+"left", 0'+"ellow")
la0el%eft.pac1(side+%&3.) # place la0el to the left of the neAt wid'et
la0elIid + %a0el(m3rame, teAt+"middle", 0'+"'reen")
la0elIid.pac1(side+%&3.) # place la0el to the left of the neAt wid'et
la0el,i'ht + %a0el(m3rame, teAt+"ri'ht", 0'+"0lue")
la0el,i'ht.pac1()
window.mainloop()
0t can ,uickly get diicult to igure out ho" to arrange things using pac1()$ %ut there
are t"o other options a'aila%le as "ell or getting your "idgets organi*ed. 2he place()
method can %e used to place a "idget in an exact location "ithin a rame %ased on
speciic x and y coordinates$ "here the point F0$ 0. is the upper let corner o the
rame. At the same time$ "e can also speciy each "idget&s "idth and height in pixels.
#or instance$ let&s place() a couple %uttons in a rame7
from .1inter import K
window + .1()
window.'eometr("*??A*??") # default window siDe
m3rame + 3rame()
m3rame.pac1()
0utton( + Jutton(m3rame, teAt+"#7m at ((??, (C?)")
0utton(.place(A+(??, +(C?)
177
Real Python
RealPython.com
0utton* + Jutton(m3rame, teAt+"#7m at (?, ?)")
0utton*.place(A+?, +?, width+(??, hei'ht+C?)
window.mainloop()
#irst "e set a speciic "indo" si*e$ "hich is 200 pixels "ide and 200 pixels tall. )e
created 0utton( using Jutton() and placed it at the location F100$ 1J0.$ "hich is
hal"ay across the "indo" and \ o the "ay do"n the "indo". )e then placed
0utton* at the location F0$ 0.$ "hich is (ust the upper let corner o the "indo"$ and
ga'e it a "idth o 100 pixels Fhal the "idth o the "indo". and a height o J0 pixels F]
the height o the "indo"..
@ther than speciying absolute placement and si*e Fmeaning that "e gi'e exact amounts
o pixels to use.$ "e can instead pro'ide relative placement and si*e o a "idget. #or
instance$ since rames are also "idgets$ let&s add two rames to a "indo" and place
them %ased on relati'e positions and si*es7
from .1inter import K
window + .1()
window.'eometr("*??AC?") # window is *?? piAels wide 0 C? piAels tall
# create side!0!side frames
frame%eft + 3rame(0d+;, relief+-H6[&6) # 'i"e the frame an outline
frame%eft.place(relA+?, relwidth+?.C, relhei'ht+()
frame,i'ht + 3rame(0d+;, relief+-H6[&6) # 'i"e the frame an outline
frame,i'ht.place(relA+?.Q, relwidth+?.;)
# add a la0el to each frame
left%a0el + %a0el(frame%eft, teAt+"#7"e 0een framed9")
left%a0el.pac1()
178
Real Python
RealPython.com
ri'ht%a0el + %a0el(frame,i'ht, teAt+"-o ha"e #9")
ri'ht%a0el.pac1()
window.mainloop()
2he extra parameters "e passed to each rame pro'ided a %order F0d. and set that
%order in sunken relie so that "e could actually see the edges o the rames$ since %y
deault the rames "ouldn&t ha'e %een 'isi%le %y themsel'es.
2his time "e used relA to pro'ide a relative x placement$ "hich takes a 'alue rom 0
to 1 to represent a raction o the "indo"&s "idth. 2he irst la%el has relA+?$ so it
appears all the "ay at the let o the "indo". !ince "e ga'e the second la%el a
relA+.Q and relwidth+.;$ it appears E0T o the "ay across the "indo" and takes up
the remaining A0T o the space "ithout running o the end o the "indo". )e speciied
a relhei'ht+( or the irst la%el so that it took up the entire height o the "indo".
!ince "e didn't name a relhei'ht 'alue Fand didn&t e'en pro'ide a rel 'alue. or the
second la%el$ it deaulted to appear at the top o the "indo" "ith only the height
necessary to display the text inside o it. 2ry modiying all these 'alues one %y one to
see ho" they change the appearance o the rames.
>otice how we h%d to *%ss the n%0e o. e%ch .r%0e %s the .irst %r#u0ent o. e%ch
(%be(. 7his is how 7kinter tr%cks which wid#et be(on#s in which .r%0e.
)therwise? we wou(dn5t know which .r%0e our (%be( be(on#s to %nd cou(dn5t te((
where to *%ck %nd dis*(%y it. +,en i. you on(y h%,e % sin#(e .r%0e? howe,er? since
re(%ti,e *(%ce0entOsiHin# is done inside o. the *%rent wid#et? you shou(d %(w%ys be
sure to n%0e the .r%0e to which e%ch wid#et be(on#s.
A
Although it oers more detailed control than pac1() does$ using place() to arrange
"idgets usually isn&t an ideal strategy$ since it can %e diicult to update the speciic
placements o e'erything i one "idget gets added or deleted. Deyond this$ dierent
screen resolutions can make a "indo" appear some"hat dierently$ making your careul
placements less eecti'e i you "ant to share the program to %e run on dierent
computers.
179
Real Python
RealPython.com
2he last and usually the easiest "ay to make clean$ simple :50 layouts "ithout too much
hassle is %y using 'rid() to place "idgets in a t"o+dimensional grid. 2o do this$ "e can
imagine a grid "ith num%ered ro"s and columns$ "here "e can then speciy "hich cell
For cells. o our grid "e "ant to %e taken up %y each particular "idget.
from .1inter import K
window + .1()
m3rame + 3rame()
m3rame.'rid() # add frame to ta1e up the whole window usin' 'rid()
la0el.op%eft + %a0el(m3rame, teAt+"#7m at ((,()")
la0el.op%eft.'rid(row+(, column+()
la0elJottom%eft + %a0el(m3rame, teAt+"#7m at (*,()")
la0elJottom%eft.'rid(row+*, column+()
0uttonJottom,i'ht + Jutton(m3rame, teAt+"#7m at (;,*)")
0uttonJottom,i'ht.'rid(row+;, column+*)
mainloop() # start the application
0nstead o calling pac1() on our rame "idget$ "e put the rame into the "indo" %y
using 'rid()$ "hich "ill let 2kinter kno" that "e plan to place "idgets inside this
rame %y also using 'rid() instead o another method. )e could then call 'rid() on
each "idget instead o pac1() or place() %y pro'iding a ro" and column num%ers$
"hich start at row+( and column+( in the upper+let corner o the "indo".
A0
'on5t try to co0bine di..erent w%ys o. %ddin# wid#ets into % sin#(e .r%0e = .or
inst%nce? don5t use 'rid() on so0e wid#ets %nd pac1() on others. 7kinter h%s
no w%y to *rioritiHe one 0ethod o,er the other %nd usu%((y ends u* .reeHin#
your %**(ic%tion entire(y when you5,e #i,en it con.(ictin# *%ckin# instructions.
A
)e can assign 'alues to the arguments padA and pad or any gi'en "idget$ "hich "ill
A0 Actually$ they start counting at 0$ %ut cells "ithout any "idgets in them are ignoredB "e could ha'e
started "ith the irst cell at row+(? and column+*C i that "ere the location o our top let "idget$
and it "ould still appear in the upper let corner.
180
Real Python
RealPython.com
include extra space around the "idget hori*ontally and=or 'ertically. )e can also assign
'alues to the argument stic1 or each "idget$ "hich takes cardinal directions Flike a
compass. such as & or 6):B this "ill tell the "idget "hich side For sides. it should stick
to i there is extra room in that cell o the grid. >et&s look at these arguments in an
example7
from .1inter import K
window + .1()
m3rame + 3rame()
m3rame.'rid() # add frame to window usin' 'rid()
la0el.op%eft + %a0el(m3rame, teAt+"#7m at ((,()", 0d+";", relief+-H6[&6)
la0el.op%eft.'rid(row+(, column+(, padA+(??, pad+;?)
la0elJottom%eft + %a0el(m3rame, teAt+"#7m at (*,()", 0d+";", relief+-H6[&6)
la0elJottom%eft.'rid(row+*, column+(, stic1+&)
0utton,i'ht + Jutton(m3rame, teAt+"# span * rows", hei'ht+C)
0utton,i'ht.'rid(row+(, column+*, rowspan+*)
mainloop() # start the application
)e included a %order and sunken relie to the t"o la%els F(ust like "e did pre'iously
or the rame. so that "e could see their outlines. Decause "e ga'e large padA and
pad 'alues to the irst la%el$ it appears "ith lots o extra space around it$ centered in
the middle o the irst grid cell. 2he second la%el appears in the second ro" and irst
column$ right underneath the irst la%el$ %ut this time "e speciied stic1+& to say
that the la%el should stick to the east side o the grid cell i there is extra hori*ontal
space.
)e added a %utton in the second column$ speciying a height o J Ftext lines.. 2his
allo"s us to see that$ e'en though "e placed the %utton at row+($ since "e also
181
Real Python
RealPython.com
speciied rowspan+*$ the %utton is centered 'ertically across %oth the irst and second
ro"s.
$ince it o.ten t%kes % .%ir %0ount o. e..ort to #et wid#ets %rr%n#ed in % window
e6%ct(y %s you5d (ike? it5s usu%((y % #ood ide% to dr%w out % 0ock=u* o. wh%t you
w%nt your "2I %**(ic%tion to (ook (ike on *%*er be.ore doin# %ny codin# %t %((.
With % *hysic%( re.erence? it wi(( be 0uch e%sier to tr%ns(%te wh%t5s in your he%d
into "2I wid#ets or#%niHed in .r%0es.
A
2he %uttons "e&'e created so ar aren&t 'ery useul$ since they don&t yet do anything
"hen "e click on them. 6o"e'er$ "e can speciy a command argument to a %utton that
"ill run a unction o our choice. #or instance$ let&s create a simple unction
incrementJutton() that takes the num%er displayed on our %utton and increments it
%y one7
from .1inter import K
window + .1()
def incrementJutton()2
new6um0er + ( ) 0utton.c'et("teAt")
0utton.confi'(teAt+new6um0er)
mJutton + Jutton(teAt+(, command+incrementJutton)
mJutton.pac1()
mainloop() # start the application
-o" each time you click on the %utton$ it "ill add one to the 'alue %y coniguring the
%utton "ith a ne" teAt attri%ute. )e used the c'et() method on the %utton to
retrie'e the teAt currently displayed on the %uttonB "e can use c'et() in this same
"ay to get the 'alues taken %y other attri%utes o other types o "idgets as "ell.
2here are a num%er o other types o "idgets a'aila%le in 2kinter as "ellB a good ,uick
reerence can %e ound here. Desides la%els and %uttons$ one 'ery commonly used type
o "idget is an &ntr$ "hich allo"s a place or the user to enter a line o text.
An entry "orks a little dierently rom la%els and %uttons in that the text in the entry
182
Real Python
RealPython.com
%ox is %lank at irst. 0 you "ant to add deault text to display$ it must %e inserted
ater creating the entry using the insert() method$ "hich re,uires as its irst
argument a position in the text or inserting the ne" string. #or instance$ ater creating
a ne" &ntr "ith m&ntr + &ntr()$ "e "ould then say m&ntr.insert(?,
"default teAt") to add the string deault text to the entry %ox. 0n order to return
text currently in the entry %ox$ "e use the 'et() method instead o the usual c'et()
method. Doth these concepts are easier seen in an example7
from .1inter import K
window + .1()
entr( + &ntr()
entr(.pac1()
entr(.insert(?, "this is an entr")
entr* + &ntr()
entr*.pac1()
m.eAt + entr(.'et() # 'et the teAt from entr(
entr*.insert(?, m.eAt)
entr*.insert(P, "also ") # add "also" to the middle of m.eAt
mainloop() # start the application
6ere "e packed t"o entry %oxes into a "indo"$ adding ne" text at index position 0 to
entr( irst. )e added the text seen in entr* %y irst using 'et() to return the text
in entr($ inserting this same text into entr*$ then inserting additional text into this
string starting at index location <. )e can also speciy a "idth Fin characters. that "e
"ant an entry %ox to take up %y passing a 'alue to width "hen "e create the &ntr.
>et&s put all o these :50 pieces together into a single usa%le application. )e&ll modiy
the irst unction that "e "rote "ay %ack in chapter C to create a :50+%ased
temperature con'ersion application7
from .1inter import K
def recalc()2
183
Real Python
RealPython.com
cel.emp + entr@el.'et() # 'et temp from teAt entr
tr2 # calculate con"erted temperature and place it in la0el
far.emp + float(cel.emp) K UBC ) ;*
far.emp + round(far.emp, ;) # round to three decimal places
result3ar.confi'(teAt+far.emp)
eAcept Ealue&rror2 # user entered non!numeric temperature
result3ar.confi'(teAt+"in"alid")
# create the application window and add a 3rame
window + .1()
window.title(".emperature con"erter")
frame + 3rame()
frame.'rid(padA+C, pad+C) # pad top and left of frame C piAels 0efore 'rid
# create and add teAt la0els
la0el@el + %a0el(frame, teAt+"@elsius temperature2")
la0el@el.'rid(row+(, column+(, stic1+-)&)
la0el3ar + %a0el(frame, teAt+"3ahrenheit temperature2")
la0el3ar.'rid(row+*, column+(, stic1+-)&)
# create and add space for user entr of teAt
entr@el + &ntr(frame, width+Q)
entr@el.'rid(row+(, column+*)
entr@el.insert(?, ?)
# create and add la0el for teAt calculation result
result3ar + %a0el(frame)
result3ar.'rid(row+*, column+*)
# create and add 7recalculate7 0utton
0tn,ecalc + Jutton(frame, teAt+",ecalculate", command+recalc)
0tn,ecalc.'rid(row+(, column+;, rowspan+*)
recalc() # fill in first default temperature con"ersion
mainloop() # start the application
#irst "e created the unction recalc()$ "hich gets the Celsius temperature rom the
entry %ox$ con'erts it into #ahrenheit$ and sets that Frounded. num%er as the text o the
#ahrenheit temperature la%el. -otice ho" "e used the tr=eAcept structure to check
i the user entered something that isn&t a num%er so that "e can display in"alid as
184
Real Python
RealPython.com
the con'erted temperature instead o raising an error.
2he uses o :50 "idgets should all look amiliar to you no". )e used a 'rid() layout
"ith the 'alue -)& to the stic1 argument o our la%els so that they "ould %e right+
aligned. 2he %utton$ "hich is centered across t"o ro"s$ calls our recalc() unction so
that the current Celsius temperature is con'erted and redisplayed in the #ahrenheit
la%el each time the %utton is clickedB the actual %utton click %y the user is considered
an event$ and %y passing a unction name to the command argument "e ensure that the
%utton is listening or this e'ent so that it can take an action. )e can also call the
unction oursel'es$ "hich "e do %eore running the program in order to ill in a deault
con'erted 'alue to our #ahrenheit la%el.
#inally$ "e can also use the separate t13ile$ialo' module to allo" the user to open
and sa'e iles$ much like "e did %eore "ith 8asy:50. !ince "e aren&t presenting :50
elements one at a time$ ho"e'er$ ile dialogs in 2kinter "ill usually %e linked to other
speciic :50 "idgets ? or instance$ ha'ing the user click on a %utton in order to pop up a
ile dialog %ox. >et&s "rite a ,uick script that uses an @pen ile dialog to let the user
select either a .8G ile or a ..Y. ile and then displays the ull name o that ile %ack in
a la%el7
from .1inter import K
import t13ile$ialo'
window + .1()
frame + 3rame()
frame.pac1()
def open3ile()2 # as1 user to choose a file and update la0el
tpe%ist + 4("8thon scripts", "K.p"), (".eAt files", "K.tAt")5
file6ame + t13ile$ialo'.as1openfilename(filetpes+tpe%ist)
la0el3ile.confi'(teAt+file6ame)
# 0lan1 la0el to hold name of chosen file
la0el3ile + %a0el(frame)
la0el3ile.pac1()
# 0utton to clic1 on for ">pen" file dialo'
0utton>pen + Jutton(frame, teAt+"@hoose a file...", command+open3ile)
0utton>pen.pac1()
mainloop() # start the application
185
Real Python
RealPython.com
Clicking the %utton "ill cause our unction open3ile() to run$ "hich opens a ile
dialog using t13ile$ialo'.as1openfilename(). 4ake sure you import tk#ile1ialog
as "ell as 2kinter$ since they are actually separate modules3
)e passed tpe%ist into the argument filetpes o the
t13ile$ialo'.as1openfilename() unction in order to pro'ide a list o the
dierent types o iles that "e "ant the user to %e a%le to chooseB these are pro'ided as
a list o tuples$ "here the irst item in each tuple is a description o the ile type and
the second item in each tuple is the actual ile extension.
Oust like "ith 8asy:50$ the t13ile$ialo'.as1openfilename() unction returns the
ull name o the ile$ "hich "e can then set e,ual to our string file6ame and pass into
our la%el. 0 the user hit the Cancel %utton instead$ the unction returns 6one and our
la%el %ecomes %lank.
>ike"ise$ there is a t13ile$ialo'.as1sa"easfilename() unction that takes the
same arguments as t13ile$ialo'.as1openfilename() and "orks analogously to the
filesa"e0oA() o 8asy:50. )e can also pass a deault extension type to
as1sa"easfilename() in order to append a ile extension onto the name o the
pro'ided ile i the user didn&t happen to pro'ide one Falthough some operating systems
might ignore this argument.7
from .1inter import K
import t13ile$ialo'
window + .1()
frame + 3rame()
frame.pac1()
def sa"e3ile()2 # as1 user to choose a file and update la0el
tpe%ist + 4("8thon scripts", "K.p"), (".eAt files", "K.tAt")5
file6ame + t13ile$ialo'.as1sa"easfilename(filetpes+tpe%ist,
defaulteAtension+".p")
m.eAt + "# will sa"e2 " ) file6ame
186
Real Python
RealPython.com
la0el3ile.confi'(teAt+m.eAt)
# 0lan1 la0el to hold name of chosen file
la0el3ile + %a0el(frame)
la0el3ile.pac1()
# 0utton to clic1 on for ">pen" file dialo'
0utton>pen + Jutton(frame, teAt+"@hoose a file...", command+sa"e3ile)
0utton>pen.pac1()
mainloop() # start the application
A%o'e$ 0 na'igated to the older @2B8thon*QB and told the application to sa'e the
ile m-cript "ithout typing out any ile extension$ %ut %ecause "e pro'ided
defaulteAtension+".p" as an argument to as1sa"easfilename()$ this ending
"as automatically added to the name o the ile.
As mentioned at the start o this section$ 2kinter is a popular choice or :50 application
de'elopment$ and this introduction has only co'ered the most %asic use cases. 2here are
a num%er o other choices a'aila%le$ some o "hich oer additional lexi%ility and more
complicated unctionality ? although usually at the cost o the extra time it takes to
de'elop such detailed and complex applications. @nce you eel that you may need
something more customi*a%le than 2kinter$ "xPython is a good choice or a next step.
PyZt and Py:tk are t"o o the other most popular and "idely used :50 toolkits or
Python.
9e,iew e6ercises-
Recreate the 'arious "indo"s pictured and descri%ed in this section$
complete "ith all the same :50 "idgets and any necessary interaction$ %y
"riting your o"n scripts "ithout reerring to the pro'ided code
5sing 'rid() to organi*e your "idgets hori*ontally$ create a %utton that$
"hen clicked$ takes on the 'alue entered into an entry %ox to its right
187
Real Python
RealPython.com
Assignment 12.2: 0eturn of the poet
Write % scri*t D*oetryLwriter.*yF b%sed on the *oe0 #ener%tor cre%ted in
%ssi#n0ent 6.1 th%t %ssists the user in cre%tin# be%uti.u( *oetry throu#h % "2I.
= 7he user shou(d be instructed @in % (%be() to enter words into e%ch (ist? se*%r%tin#
words with co00%s. Cou c%n use the strin# split() 0ethod to #ener%te (ists o.
indi,idu%( words.
= Pro,ide % #rid (%yout with (%be(s .or 6ouns? Eer0s? /dLecti"es? 8repositions
%nd /d"er0s? where the user c%n su**(y % (ist o. words .or e%ch by ty*in# the0 into
entry bo6es.
= 4dd % D@reate our poemF button centered %t the botto0 o. the window th%t?
when c(icked? wi(( #ener%te %nd dis*(%y % r%ndo0 *oe0 in % (%be( be(ow the button.
I. the user does not su**(y enou#h words? the D*oe0F (%be( shou(d inste%d dis*(%y
te6t (ettin# the user know the error.
= 4dd % D-a"e our poemF button centered be(ow the *oe0 th%t? when c(icked?
%((ows the user to s%,e the *oe0 current(y bein# dis*(%yed %s % .7B7 .i(e by
*ro0*tin# the user with % D-a"e /sF di%(o# bo6. 4dd % de.%u(t .i(e e6tension o.
D.tAt %nd 0%ke sure th%t your *ro#r%0 does not #ener%te %n error i. the user
c(icks D@ancelF on the .i(e s%,e di%(o# bo6.
= Cou c%n %ssu0e th%t the user wi(( not su**(y %ny du*(ic%te words in %ny o. the
word (ists.
= :onus- 4dd % .unction chec1HniSue() th%t t%kes % (ist o. words %s %n %r#u0ent
%nd returns .rue or 3alse b%sed on whether or not th%t (ist cont%ins on(y uniIue
entries. 2se this .unction to %(ert the user i. du*(ic%te words %re *resent within %ny
o. the word (ists by dis*(%yin# the error in the D*oe0F (%be(. @Without this check?
we run the risk o. our *ro#r%0 enterin# %n in.inite (oo*A)
?
188
Real Python
RealPython.com
13) Web %**(ic%tions
1A.1. Create a simple "e% application
ou kno" ho" to "rite useul Python scripts$ and no" you "ant to sho" them o to
the "orld... %ut ho"/ 4ost non+programmers "on&t ha'e any use or your .p
script iles. Programs like Py0nstaller and cxI#ree*e help turn Python scripts into
executa%le programs that can %e run %y themsel'es on dierent platorms "ithout the
need to use Python to interpret the code. 4ore and more$ ho"e'er$ "e&re seeing a trend
a"ay rom desktop+%ased applications and to"ard "e% applications that can %e
accessed and run through 0nternet %ro"sers.
9
6istorically$ "e%sites on the 0nternet "ere ull o plain "e%pages that oered the exact
same inormation to e'ery userB you "ould re,uest a page$ and the inormation rom
that page "ould %e displayed. 2hese "e%pages "ere static %ecause their content
ne'er changedB a "e% ser'er "ould simply respond to a user&s re,uest or a "e%page %y
sending along that page$ regardless o "ho the user "as or "hat other actions the user
took.
2oday$ most "e%sites are actually "e% applications$ "hich oer dynamic "e%pages
that can change their content in any num%er o "ays. #or instance$ a "e%mail
application allo"s the user to interact "ith it$ displaying all sorts o dierent
inormation$ oten "hile staying in a single "e%page.
2he idea %ehind creating a Python+dri'en "e% application is that you can use Python
code to determine "hat content to sho" a user and "hat actions to take. 2he code is
actually run %y the "e% ser'er that hosts your "e%site$ so your user doesn&t need to
install anything to use your applicationB i the user has a %ro"ser and an 0nternet
connection$ then e'erything else "ill %e run online.
2he task o getting Python code to run on a "e%site is a complicated one$ %ut there are
a num%er o dierent "e% rame"orks a'aila%le or Python that automatically take care
189
Real Python
RealPython.com
o a lot o the details.
2he irst thing that you "ill need is a "e% hosting plan that allo"s and supports the
a%ility to run Python code. !ince these usually cost money Fand since not e'eryone e'en
has a "e%site.$ "e&ll stick "ith a ree alternati'e that is one o the simplest to set up7
:oogle App 8ngine$ "hich uses a "e% rame"ork called "e%app2.
2here are a num%er o other alternati'es F%oth ree and paid. that are more
customi*a%le$ and you can use "e%app2 on its o"n later "ithout relying on :oogle App
8ngine$ %ut getting started "ith :oogle App 8ngine "ill %e the ,uickest and easiest "ay
to %egin learning a%out "e% application de'elopment in Python.
#irst$ go here to do"nload and install the appropriate Python !1L or :oogle App
8ngine.
A1
!1L stands or $ot"are 'e'elopment Kit. 2his particular !1L includes t"o
main resources7 a "e% ser'er application$ "hich "ill allo" you to run your "e%
applications on your o"n computer "ithout actually putting them online$ and the :oogle
App 8ngine >auncher$ "hich "ill help to put your "e% applications online.
Deore "e di'e into "riting a "e% application$ let&s get a 'ery %road$ generali*ed
o'er'ie" o "hat&s a%out to happen. 2here are a lot o dierent pieces in'ol'ed$ and
they all ha'e to communicate "ith each other to unction correctly7
#irst$ your user makes a re,uest or a particular "e%page on your "e%site
Fi.e.$ %y typing a 5R> into a %ro"ser..
2his re,uest gets recei'ed %y the "e% ser'er that hosts your "e%site.
2he "e% ser'er uses App 8ngine to look at the coniguration ile or your
application. App 8ngine matches the user&s re,uest to a particular portion o
your Python script.
2his Python code is called up %y App 8ngine. )hen your code runs$ it "rites
out a response "e%page.
App 8ngine deli'ers this response %ack to your user through the "e% ser'er.
2he user can then 'ie" the "e% ser'er&s response Fi.e.$ %y displaying the
resulting "e%page in a %ro"ser..
A1 >inux users$ install the older in your BhomeBusername directory to a'oid typing out long paths later.
190
Real Python
RealPython.com
2he application "e&re going to create "ill rely on a couple dierent iles$ so the irst
thing "e need to do is make a pro(ect older to hold all o these iles. Create a ne"
older named first=app any"here you like F(ust remem%er "here it is..
A2
#irst "e
"ill "rite a 'ery simple Python script that can respond "ith the content o your
"e%page7
print "@ontent!.pe2 teAtBplain"
print ""
print "@on'ratulations, it7s a we0 app9"
!a'e this code in a script named hello.p inside your first=app older.
!o "hat&s "ith the irst t"o print statements/ )e% ser'ers communicate "ith users
Fusually %ro"sers. through 622P %y recei'ing *%%P requests and sending *%%P
responses. 2he 622P response that our application sends can ha'e %oth header lines and
a body.
)e added a header line to our 622P response in the irst line. 6eader lines contain
optional inormation to let a %ro"ser kno" ho" to interpret the %ody o the response. 0n
this case$ setting our header&s @ontent!.pe e,ual to the 'alue teAtBplain is
the "ay that our 622P response lets a %ro"ser kno" to expect the %ody to contain plain
text as opposed to 624> code$ an image$ or some other type o ile.
AA
>ea'ing a %lank
line ater this header line is ho" "e told the %ro"ser$ the header lines are o'er no"B
here comes the actual %ody to display.
2he %ody o the response is "hat "e "ill actually see "hen "e load the page in a
%ro"ser. 0n this case$ it&s (ust a simple string o text7 @on'ratulations, it7s a
we0 app9
Deore "e can run our "e% application$ "e need to pro'ide App 8ngine "ith a
configuration file. 2his is the ile that the "e% ser'er "ill use to get inormation a%out
"hat Python code "e "ant it to run. @pen up any text editor For another script "indo"
in 01>8. and copy the ollo"ing text into a ne" ile7
application2 hello
"ersion2 (
A2 >inux users$ you should sa'e the older in your BhomeBusername directory to keep your lie simple.
AA 4ost %ro"sers are smart enough to correctly iner the content type "ithout ha'ing to %e told
Fespecially i the content is text or 624>.$ %ut it&s usually saer to include this header line (ust in case.
191
Real Python
RealPython.com
runtime2 pthon*Q
api="ersion2 (
threadsafe2 false
handlers2
! url2 B.K
script2 hello.p
-o" name this ile app.aml and sa'e it in the same first=app older as the
Python script.
AC
4ake sure you get the spacing correctB the last line includes t"o leading
spaces so that script lines up under url. Oust like Python$ 9A4>
AJ
iles rely on
precise indentation.
2he 9A4> coniguration ile gi'es App 8ngine all the necessary inormation it needs to
run the "e% application. #irst$ application2 hello pro'ides a uni,ue identiying
name or the application so that "e "ill %e a%le to launch it laterB "e are gi'ing the
name hello to our "e% app.
2he line "ersion2 ( lets App 8ngine kno" that this is 'ersion 1 o our application.
F0 "e update this later to "ersion2 *$ App 8ngine "ill keep a copy o 'ersion 1 in
memory so that "e can go %ack to running this pre'ious 'ersion i necessary..
2he lines runtime2 pthon*Q and api="ersion2 ( let App 8ngine kno" that
"e "ant to use Python 2.E to run our application. F2here is currently only one 'ersion o
the Python AP0 oered %y :oogle..
2he line threadsafe2 false means that our "e% application isn&t designed to %e
a%le to recei'e multiple re,uests at onceB i App 8ngine has multiple re,uests then it
"ill send them to our application one at a time instead o all at once.
#inally "e deine our handlers to handle dierent "e%page re,uests rom our users
Fi.e.$ i a user re,uested the main page at B or another page at a dierent address on
our site.. 2hese re,uested paths can each %e assigned to a dierent piece o Python
code. 0n this case$ "e only ha'e one script$ hello.p$ so "e "ant to direct user
re,uests or any page on the "e%site to the same script. 0n these last t"o lines o the
AC 4ake sure that you&'e sa'e this ile "ith a .aml extension and that your text editor didn&t add a ile
extension o its o"n Fi.e.$ creating a ile like app.aml.p or app.aml.tAt..
AJ 0 you thought the acronym or P6P "as %ad; 9A4> stands or CA4> 4in&t 1arkup anguage.
192
Real Python
RealPython.com
coniguration ile$ "e say that any 5R> matching the regular expression B.K F"hich is
any 5R> on our site. should %e directed to the hello.p script.
@kay$ no" "e can finally take a look at our application3 0t&s not online yet$ %ut "e can
'ie" it %y running the application through our o"n local "e% ser'er Fthat can&t %e
accessed %y other users. using :oogle App 8ngine. 2his "ill help us simulate "hat things
"ill look like to a user once our application is online.
@pen the :oogle App 8ngine >auncher program$ then choose #ile Add 8xisting
Application; 9ou can then %ro"se to and select your first=app older that contains
the "e% application. Add the application using port <0<0$ then select the application in
the main "indo" and click the green Run %utton.
inu6 users- you "ill need to na'igate in your 2erminal to the directory just before the
first=app older Fi.e.$ its parent directory.$ then type the ollo"ing command to
launch the "e% application F"hich "ill run on port <0<0 %y deault.7
'oo'le=appen'ineBde"=appser"er.p first=appB
2he console "indo" that appears "ill track lots o extra inormation$ %ut your "e%
application is up and running once you see a %linking cursor.
2he port num%er can %e thought o as selecting a particular channel to use$ similar to
%roadcasting a tele'ision or radio channel. )e chose to run the "e% application on port
<0<0$ meaning that the user can essentially tune in to this port num%er and recei'e
communication rom our "e% ser'er. F)e could host a completely dierent "e%
application using a dierent port num%er and the t"o "ould not interere "ith each
other..
@nce the "e% application is running Fthis might take a little "hile.$ "e can click
Dro"se to 'ie" the "e% application in the deault "e% %ro"ser. 2his "ill open up the
page at the 5R> localhost2P?P? F"hich "e can also type into a %ro"ser manually
to load the "e% application..
AQ
2he "e% address localhost is (ust a "ay o saying
the "e% address o my o"n computer Fsince the application isn&t actually online yet..
AQ 5sing 0nternet 8xplorer$ you&ll ha'e to add http2BB to the 5R>. Alternati'ely$ use a real %ro"ser.
193
Real Python
RealPython.com
2he 2P?P? speciies that "e should listen or communication on port num%er <0<0.
AE

0 e'erything has %een set up correctly$ your %ro"ser should load a page that displays
the plain text7
@on'ratulations, it7s a we0 app9
I. you 0%ke %ny ch%n#es to your scri*t? %s (on# %s "oo#(e 4** +n#ine %uncher is
sti(( runnin# your %**(ic%tion? %(( you need to do in order to ,iew the newest
,ersion o. the web %**(ic%tion is to s%,e the scri*t %nd re(o%d the web*%#e. 4**
+n#ine wi(( %uto0%tic%((y (isten .or %ny ch%n#es th%t 0i#ht h%,e been 0%de.
A
)ell$ that&s a start. As ar as an application goes$ ho"e'er$ the Python script in'ol'ed
"as airly useless. 0n order to make something "ith a %it more potential$ "e need to
create a special o%(ect in our Python code called a :-X#/pplication. )!:0 stands or
We% $er'er "ate"ay Interace and is a "ay to allo" Python to communicate "ith the
"e% ser'er in a %etter "ay than simply printing a single chunk o inormation %ack as
a response. @ur ne" Python script$ "hich still (ust displays the same line o text$ is
considera%ly more complicated7
import we0app*
class Iain8a'e(we0app*.,eSuestHandler)2
def 'et(self)2
self.response.headers4"@ontent!.pe"5 + "teAtBplain"
self.response.write("@on'ratulations, it7s a we0 app9")
routes + 4("B", Iain8a'e)5
m/pp + we0app*.:-X#/pplication(routes, de0u'+.rue)
)e no" had to import we0app* in order to use )!:0. 0n the last line o our script$ "e
are using the "e%app2 "e% rame"ork to create a :-X#/pplication o%(ect named
m/pp that "ill allo" our code to communicate "ith the "e% ser'er.
2his time "e are creating a ne" class using the class key"ordB this means that
Iain8a'e is a ne" type o o%(ect Fspeciically$ a type o we0app*.,eSuestHandler
o%(ect. that can ha'e its o"n methods and attri%utes (ust like any other o%(ect. 8'en
though it looks like the 'et() method takes an argument o self$ this special
AE 9ou "ill only need to speciy a port num%er "hen running the "e% application rom your o"n computer.
622P communication online al"ays occurs on port <0 %y deault Fto pro'e this to yoursel$ try going to
a site like http7==google.com7<0 in a "e% %ro"ser.$ so typically no%ody needs to speciy a port online.
194
Real Python
RealPython.com
key"ord is automatically created and used internally %y the ne" o%(ect as a "ay to keep
track o itsel. )e ha'e to use this self key"ord "ithin a ne" o%(ect that "e&'e
deined$ %ecause the o%(ect needs to kno" "hen it&s reerring to its own methods and
attri%utes. #or instance$ "e ha'e to call self.response in order to access the
response stored in our Iain8a'e ,eSuestHandler o%(ect.
As the irst argument o our :-X#/pplication$ "e passed a list o tuples called
routes. 0n this case$ routes only contains one tuple$ ("B", Iain8a'e). 2his
route tells our )!:0 application that anyone accessing the main directory o our
application should get directed to Iain8a'e. )e call Iain8a'e a re,uest handler
%ecause it is in charge o handling any user re,uests or that particular "e%page.
2he B is ho" "e represent the main root directory o our application Fi.e.$ our
"e%site.. 0 "e had pro'ided a second tuple$ ("Bima'esB", #ma'es8a'e)$ then
anyone "ho accesses the Fhypothetical. images directory o our "e%site "ould %e
directed to the class #ma'es8a'e in the Python script.
0 "e make a mistake in the code$ our application&s de0u'+.rue argument "ill allo"
us to see the errors reported %y Python in our "e% applicationB other"ise$ all "e "ould
see is a C?? #nternal -er"er &rror message.
Decause o ho" "e deined routes$ "hen our "e% ser'er recei'es a re,uest to load the
page B$ we0app* creates a ne" Iain8a'e o%(ect Fcalled a request handler %ecause
it responds to the re,uest or a "e%page.. 2he 'et() method o Iain8a'e is
automatically called "hen it is created$ "hich is ho" our :-X#/pplication responds
to the "e% ser'er. 2he response is "ritten out "ith these t"o lines7
self.response.headers4"@ontent!.pe"5 + "teAtBplain"
self.response.write("@on'ratulations, it7s a we0 app9")
Again$ "e ha'e to "rite %oth a header line and a body. 2he header line gets packed into
headers like in a dictionary$ setting the 'alue o the @ontent!.pe e,ual to
teAtBplain. 2his time$ "e create the %ody o the response using the write()
method. )!:0 takes care o separating the header lines rom the %ody$ so this time
there&s no need to write() a %lank line irst.
195
Real Python
RealPython.com
)e no" ha'e to update our 9A4> coniguration ile as "ell7
application2 hello
"ersion2 (
runtime2 pthon*Q
api="ersion2 (
threadsafe2 false
handlers2
! url2 B.K
script2 hello.m/pp
2he only dierence rom the pre'ious coniguration ile is the 'ery last line$ "here "e
point the script to use hello.m/pp instead o hello.pB instead o the entire
Python script$ "e no" "ant the "e% ser'er to run the :-X#/pplication o%(ect inside
o our script named m/pp$ "hich "e access using the simple dot notation o
hello.m/pp.
0 all goes "ell$ you should no" %e a%le to sa'e these t"o iles$ reload the "e%page$ and
see the exact same thing as %eore7
@on'ratulations, it7s a we0 app9
I. you 0%ke % 0ist%ke in your Python scri*t? your web %**(ic%tion 0i#ht (o%d %
horrendous error *%#e th%t 0%kes it (ook %s i. you broke the Internet .or #ood.
'on5t *%nicA Qust (ook %t the (%st (ine? which wi(( *oint you to the s*eci.ic error
@usu%((y % (ine o. your code dis*(%yed in red) th%t c%used the entire ch%in o. .%i(ure.
I. you do end u* with %n error th%t your browser re.uses to #i,e you .urther %d,ice
%bout @inste%d showin# % DC?? #nternal -er"er &rrorF? e,en when you5,e set
your :-X#/pplication to h%,e de0u'+.rue)? you c%n try runnin# the Python
scri*t itse(. in I'+. 4(thou#h it won5t run @bec%use Python won5t be %b(e to .ind the
we0app* 0odu(e)? I'+ c%n sti(( *oint out i. your code h%s %ny synt%6 errors.
A
9e,iew e6ercises-
Play around "ith your "e% applicationB make small changes to the script and
see ho" App 8ngine responds
5se your :-X#/pplication to create a %asic 624> page %y changing the
@ontent!.pe header 'alue to teAtBhtml and then using write()
196
Real Python
RealPython.com
multiple times to respond "ith lines o 624> codeB or instance$ the irst
write() statement could %e self.response.write("<html>") to %egin
the 624> "e%page
1A.2. Create an interacti'e "e% application
o" that "e&'e upgraded our "e% application to use )!:0$ "e can create multiple
pages that interact "ith the user. )e&ll start %y creating an 624> orm that takes
some text input rom the user and displays that text %ack on a ne" page.
-
0 you aren&t amiliar "ith 624> orms$ you should take a moment to re'ie" the %asics
irst. )e already sa" an example o a %asic orm "ith the login.php page used or "e%
scraping practice in chapter 10.
2he irst 5R> o our "e% application "ill %e the main B page that users see %y deault.
@ur second page "ill %e located at Bwelcome Fi.e.$ this path "ill appear ater the
name o the "e%site.. 0n order to do this$ "e need to include t"o tuples in our routes7
routes + 4(7B7, Iain8a'e), (7Bwelcome7, Xreetin')5
)e don&t need to update the coniguration ile or$ %ecause "e still "ant any re,uest or
a "e%page to %e directed to our :-X#/pplication o%(ect m/pp inside the hello.p
script. #rom there$ m/pp is responsi%le or directing any "e%page re,uests to the
correct re,uest handler + either Iain8a'e or Xreetin'. @ur ull "e% application
code "ill look like this7
import we0app*
class Iain8a'e(we0app*.,eSuestHandler)2
def 'et(self)2
self.response.headers4"@ontent!.pe"5 + "teAtBhtml"
self.response.write("""
<html>
<head><title>&nter our name...<Btitle><Bhead>
<0od>
<form action+"Bwelcome" method+"post">
<input tpe+"teAt" name+"m6ame"><0r>
197
Real Python
RealPython.com
<input tpe+"su0mit" "alue+"-i'n #n">
<Bform>
<B0od>
<Bhtml>""")
class Xreetin'(we0app*.,eSuestHandler)2
def post(self)2
username + self.reSuest.'et("m6ame")
welcome-trin' + """<html><0od>
Hi there, {}9
<B0od><Bhtml>""".format(username)
self.response.headers4"@ontent!.pe"5 + "teAtBhtml"
self.response.write(welcome-trin')
routes + 4(7B7, Iain8a'e), (7Bwelcome7, Xreetin')5
m/pp + we0app*.:-X#/pplication(routes, de0u'+.rue)
2his time$ "e speciied the @ontent!.pe to %e teAtBhtml %ecause "e&re "riting
out "e%pages in 624> code. )e did this using multi+line strings$ although "e also could
ha'e %roken the content into multiple write() commands.
As %eore$ our main page Fhandled %y the re,uest handler Iain8a'e. has a 'et()
method so that it can respond to re,uests to get its inormation. 0n the content %ody$
"e included a title or our "e%page and a simple orm. @ur orm has a single text input
ield called m6ame and a su%mit %utton la%eled -i'n #n. )hen a user clicks on
the -i'n #n %utton$ our orm posts its data Fi.e.$ the 'alue o m6ame. to the
"e%page located at Bwelcome.
4ean"hile$ our Bwelcome page Fhandled %y the re,uest handler Xreetin'. has a
post() method so that it can respond "hen it recei'es posted data. )e could ha'e
used 'et() to send the user&s data Fand "e "ill in the next example.$ %ut inormation
that is sent using 'et() %ecomes a part o the 5R>B this "ould %ecome a pro%lem i "e
later decided that "e "ant the user to include sensiti'e inormation Flike a pass"ord..
A<
)ithin post()$ "e used self.reSuest.'et("m6ame") to get the user+supplied
'alue o m6ame rom the user&s post re,uest$ "hich "e stored in a string 'aria%le
called username. )e then created a welcome-trin'$ "hich is a multi+line string
representing the ull 624> code or our Bwelcome page$ including the inserted 'alue
A< Although it usually isn&t needed$ a single re,uest handler can handle %oth get and post re,uestsB
(ust include %oth a 'et() method and a put() method inside the deinition o the re,uest handler.
198
Real Python
RealPython.com
o username. As %eore$ "e then write() out the header line and content %ody to
display the resulting "e%page.
!a'e your script and reload the %ro"ser to 'ie" your ne" "e% application. -otice ho"$
"hen you -i'n #n to the "e% application$ you are directed to the ne" "e%page
localhost2P?P?Bwelcome + "hich should hopeully display %ack "hat you typed3
Actually$ there&s one important change "e need to make to our code. 2he act that "e
take input rom a user and display that input %ack without irst in'estigating "hat "e
are a%out to display is a hu#e security ho(e. !ure$ may%e you don&t expect to ha'e
malicious users "ho are acti'ely trying to %reak your application$ %ut ne'er
underestimate the potential or users to do unexpected things that cause your
application to %reak in unexpected "ays.
#or instance$ may%e someone decides that an appropriate username to enter into our
application is <0>. @ur Bwelcome "e%page ends up displaying7
Hi there, !
!ince "e&re inserting this text into 624> code$ the <0> "as interpreted as an 624>
tag to %egin making text %old ? so instead o greeting out user$ "e only change our
explanation point to %e displayed %old. F9ou can imagine ho" this might present a
security pro%lemB any user can no" "rite code that runs on our "e% ser'er..
2o a'oid this$ "e can use Python&s %uilt+in c'i.escape() unction$ "hich con'erts the
special 624> characters <$ >$ and ] into e,ui'alent representations that can %e
displayed correctly.
AU
9ou "ill irst need to import c'i into your Python script to use
this unctionality. 2hen$ "hen you 'et() the 'alue o m6ame rom the user&s re,uest$
you can con'ert any special 624> characters %y instead saying7
username + c'i.escape(self.reSuest.'et("m6ame"))
)ith these changes$ try re+running your "e% application and signing in "ith a username
o <0> again. 9ou should no" see it display the username %ack to you correctly7
Hi there, <b>!
AU C:0 FCommon :ate"ay 0nterace. programs are typically used %y "e% ser'ers to process user input.
199
Real Python
RealPython.com
@kay$ so "e can no" create one "e%page that helps the user post data to another
"e%page interacti'ely. )hat a%out using the 'et() method to make a single page
interacti'e/ >et&s look at an example "ith (ust a little %it more Python code %ehind it
and re'isit the temperature con'erter script that "e "rote "ay %ack in chapter C and
again as a simple :50 application.
2he "e%page "e "ant to display "ill ha'e a simple text ield "here the user can input a
temperature in degrees Celsius. )e "ill also include a @on"ert %utton to con'ert the
user&s supplied Celsius temperature into degrees #ahrenheit. 2his con'erted result "ill
%e displayed on the next line and "ill %e updated "hene'er the user clicks the
@on"ert %utton. 2he 624> or this page$ "ith place+holders or the actual
temperature 'alues$ "ill look like so7
<html>
<head><title>.emperature @on"erter<Btitle><Bhead>
<0od>
<form action+"B" method+"'et">
@elsius temperature2 <input tpe+"teAt" name+"cel.emp" "alue+{}>
<input tpe+"su0mit" "alue+"@on"ert"><0r>
3ahrenheit temperature2 {}
<Bform>
<B0od>
<Bhtml>
2his time$ our orm uses the 'et method "ith a orm action that points %ack to
the main page itsel. 0n other "ords$ "hen the user su%mits this orm %y clicking on the
@on"ert %utton$ instead o sending a post re,uest to a ne" "e%page$ the user
"ill send a 'et re,uest or the same page$ pro'iding the page "ith some input data.
Oust as "e did %eore$ "e "ill "ant to put the temperature con'ersion into a unction o
its o"n. 2he ull code "ill look as ollo"s7
import we0app*
def con"ert.emp(cel.emp)2
777 con"ert @elsius temperature to 3ahrenheit temperature 777
if cel.emp ++ ""2
return ""
tr2
far.emp + float(cel.emp) K UBC ) ;*
far.emp + round(far.emp, ;) # round to three decimal places
200
Real Python
RealPython.com
return str(far.emp)
eAcept Ealue&rror2 # user entered non!numeric temperature
return "in"alid input"
class Iain8a'e(we0app*.,eSuestHandler)2
def 'et(self)2
cel.emp + self.reSuest.'et("cel.emp")
far.emp + con"ert.emp(cel.emp)

self.response.headers4"@ontent!.pe"5 + "teAtBhtml"
self.response.write("""
<html>
<head><title>.emperature @on"erter<Btitle><Bhead>
<0od>
<form action+"B" method+"'et">
@elsius temperature2 <input tpe+"teAt"
name+"cel.emp" "alue+{}>
<input tpe+"su0mit" "alue+"@on"ert"><0r>
3ahrenheit temperature2 {}
<Bform>
<B0od>
<Bhtml>""".format(cel.emp, far.emp))
routes + 4(7B7, Iain8a'e)5
m/pp + we0app*.:-X#/pplication(routes, de0u'+.rue)
As %eore$ our con"ert.emp() unction checks to see i the user supplied a 'alid 'alue.
!ince the user "on&t ha'e supplied any 'alue "hen the page irst loads Fand "e don&t
"ant to start out %y saying in"alid input.$ "e check irst or this condition and
return an empty string i the text ield is also %lank.
)e used self.reSuest.'et("cel.emp") to get the user+supplied 'alue o cel.emp
rom the user&s get re,uest F(ust like "e did or the user&s post re,uest in the
pre'ious example.. 2he 624> code that "e write() out as a multi+line string no"
includes t"o user+supplied 'alues7 the cel.emp$ "hich is the 'alue that the user
entered into the text ield$ and the far.emp$ "hich is the calculated result returned %y
our unction. 0 "e had not "ritten the 'alue o cel.emp into the text %ox$ then this
input %ox "ould %e cleared "hen the user clicks on the %utton.
!a'e this script as temperature.p in the same first=app older$ then update
the app.aml coniguration ile accordingly. !ince "e renamed our script$ "e changed
the name o the module "here the :-X#/pplication o%(ect m/pp should %e loaded7
201
Real Python
RealPython.com
application2 temperature!con"erter
"ersion2 (
runtime2 pthon*Q
api="ersion2 (
threadsafe2 false
handlers2
! url2 B.K
script2 temperature.m/pp
)e also updated the name o the application (ust to pro'ide a descripti'e name or "hat
the application actually does. 8'en i you let App 8ngine running$ this name "ill update
automatically in the >auncher. -otice ho" "e used a dash %ut didn&t use any
capitali*ation in the nameB application names or :oogle App 8ngine can only include
lo"er+case letters$ digits and hyphens.
9ou should no" %e a%le to use your ne" "e% application$ supplying temperatures and
seeing the con'erted result appear on the same "e%page. !ince "e use a get re,uest$
"e can also no" see the user+supplied data appear in the 5R>. 0n act$ you can e'en
circum'ent the orm and pro'ide your o"n 'alue or cel.emp %y supplying an
appropriate address. #or instance$ try typing the 5R> localhost2P?P?BFcel.emp+;?
directly into your %ro"ser and you "ill see the resulting temperature con'ersion.
9e,iew e6ercises-
4odiy the log in "e% application example so that it only has a single main
"e%page that can recei'e get re,uests rom the userB instead o a %o'
#n %utton under the text ield$ make a Xreet me9 %utton that$ "hen
clicked$ reloads the page to greet the user %y name Fi a name has %een
supplied. and display the greeting orm again
Assignment 13.2: The poet gains a 1e% presence
9ecre%te the r%ndo0 *oe0 #ener%tor th%t we s%w in %ssi#n0ents 6.1 %nd 12.2
by turnin# it into %n inter%cti,e web %**(ic%tion. Cou shou(d use % web .or0
(ike the one %t *oe0=#ener%tor.%**s*ot.co0 to he(* your user #ener%te *oe0s.
Cou c%n ,iew the source o. this web*%#e to re,erse=en#ineer 0ost o. the necess%ry
H71 code. Cour web %**(ic%tion shou(d use % sin#(e web*%#e with % sin#(e .or0
th%t %cce*ts D#etF reIuests .ro0 the user.
?
202
Real Python
RealPython.com
:onus- e%rn how to use st%tic .i(es (ike 8$$ in your web %**(ic%tion to i0*ro,e its
o,er%(( %**e%r%nce %nd 0%ke your H71 code e%sier to re%d %nd 0%int%in.
1A.A. Put your "e% application online
t&s inally time to share your %eautiul "ork "ith the "orld. :etting your content
online is actually a airly simple process "ith :oogle App 8ngine. 0
:oogle pro'ides a ree ser'ice at appspot.com to allo" you to host up to ten dierent
"e% applications Fas long as you don&t ha'e millions o users accessing them e'ery
month$ in "hich case you "ill need to upgrade to a paid plan.. 9ou "ill irst need to go
to appengine.google.com and sign in to App 8ngine.
C0
@nce you&'e logged into App 8ngine$ you can create a ne" application and gi'e it a
uni,ue /pplication #dentifier$ "hich is the name o your "e% application. 2his
name "ill appear in the 5R> o your application$ "hich "ill look like7
http2BBour!application!name.appspot.com
!ince this is a direct 5R> that must %e uni,ue$ you might need to try a e" times %eore
you ind a name that isn&t already in use %y someone else.
C1
0&m going to use the
temperature con'ersion application and name mine temperature!con"erter +
"hich means you can&t3 )hate'er you end up using as your application identiier$ %e sure
to update your coniguration ile so that the name pro'ided or the application in
the 'ery irst line o the ile matches this application name. 2he title that you pro'ide
or your application "ill %e the name that appears on the "e%page&s title %ar Fso in this
case$ speciying a <title> in the 624> "as superluous..
@nce you&'e registered an application 01 and updated your "e% application to relect
this name$ you&re ready to go3 Oust click the $eplo %utton in App 8ngine >auncher
and log in "ith your :oogle account to load the application onto your ne" "e%page. A
ne" "indo" "ill appear$ oering details o the upload processB it may take a minute or
C0 0 you don&t ha'e a :oogle account yet Fseriously/.$ you "ill need to sign up to create one irst.
C1 0 you use :oogle Apps F"hich also includes a ree %asic plan.$ you can put the "e% application on your
:oogle Apps site as "ell.
203
Real Python
RealPython.com
t"o to complete.
inu6 users- you "ill need to na'igate to the older (ust before the first=app older$
then use the ollo"ing command or uploading the application through App 8ngine7
'oo'le=appen'ineBappcf'.p update first=appB
0 you see the message .his application does not eAist$ then either you ha'e
not registered the application correctly or the name o your "e% application does not
match the application identiier that you pro'ided.
Congratulations3 9ou no" ha'e a li'e "e%page o your o"n running Python code.
:oogle has a num%er o other handy %uilt+in eatures$ including the a%ility to store
persistent user data Fthat lasts e'en ater the user lea'es the "e%site. "ithin your
application and e'en a "ay to integrate your application "ith your users& :oogle
accounts. 2he current tutorials and documentation include unctional %ut only hal"ay
up+to+date example code$ although it can still pro'ide an idea o "hat is possi%le %eyond
the %asics.
#or complex "e%sites$ "riting out long %locks o 624> is airly ineicient and hard to
manage$ "hich is "hy a num%er o rame"orks ha'e %een de'eloped to help organi*e
and speed up the "e% de'elopment process using templates and pre+%uilt pieces o
code. 1(ango is perhaps the most popular "e% rame"ork. CherryPy and "e%2py are
other popular optionsB "e%2py is especially good at integrating "ith data%ases. All o
these "e% rame"orks can %e run on their o"n or set up through :oogle App 8ngine
instead o using "e%app2. 0n act$ App 8ngine supports 1(ango templates "ithin
"e%app2 %y deault. @ther micro+rame"orks that are gaining popularity or getting
smaller "e% de'elopment tasks done ,uickly include #lask and tipy.
204
Real Python
RealPython.com
/in%( 7hou#hts
ongratulations3 9ou&'e made it to the %eginning. 9ou already kno" enough to do a
lot o ama*ing things "ith Python$ %ut no" the real un starts7 it&s time to explore
on your o"n3
C
2he %est "ay to learn is %y sol'ing real pro%lems o your o"n. !ure$ your code might not
%e 'ery pretty or eicient "hen you&re (ust starting out$ %ut it "ill %e useful. 0 you
don&t think you ha'e any pro%lems o the 'ariety that Python could sol'e$ pick a popular
module that interests you and create your o"n pro(ect around it.
Part o "hat makes Python so great is the community. >og in at the RealPython.com
mem%ers& orum and help out other ne" Python studentsB the only "ay you kno" you&'e
really mastered a concepts is "hen you can explain it to someone else.
)hen you eel ready$ consider helping out "ith an open+source pro(ect on :it6u%. 0
pu**les are more your style$ try "orking through some o the mathematical challenges
on Pro(ect 8uler or the series o riddles at Python Challenge. 9ou can also sign up or
5dacity&s ree C!101 course to learn ho" to %uild a %asic search engine using Python ?
although you kno" most o the Python concepts co'ered there already3
0 you get stuck some"here along the "ay$ 0 guarantee that someone else has
encountered Fand potentially sol'ed. the exact same pro%lem %eoreB search around or
ans"ers$ particularly at !tack @'erlo"$ or ind a community o Pythonistas "illing to
help you out.
0 all else ails$ import this and take a moment to meditate on that which is Python.
205
Real Python
RealPython.com
4cknow(ed#e0ents
his %ook "ould not ha'e %een possi%le "ithout the help and support o so many
riends and colleagues. 2
#or pro'iding 'alua%le ad'ice and candid eed%ack$ 0 "ould like to thank Drian$ Peter$
Anna$ 1oug$ and especially !oia$ "ho %y no" has pro%a%ly read this material more
times than 0 ha'e. 2hanks as "ell to Oosh or taking the time to share his 'alua%le
experience and insights.
A special thanks to the Python !ot"are #oundation or allo"ing me to graiti their logo.
#inally$ my deepest thanks to all o my Lickstarter %ackers "ho took a chance on this
pro(ect. 0 ne'er expected to gather such a large group o helpul$ encouraging peopleB 0
truly %elie'e that my Lickstarter pro(ect "e%page might %e one o the nicest gatherings
o people that the 0nternet has e'er experienced.
0 hope that all o you "ill continue to %e acti'e in the community$ asking ,uestions and
sharing tips in the mem%er orum. 9our eed%ack has already shaped this course and "ill
continue to help me make impro'ements in uture editions$ so 0 look or"ard to hearing
rom all o you.
2his %ook "ould ne'er ha'e existed "ithout your generous support7
Den(amin Dangs%erg^O2^Romer 4agsino^1aniel O 6all^Oohn 4attaliano^Oordan V1O Re%irthV Oaco%s^Al :rimsley^Ral 6uelsmann$ :ermany^Amanda
Pingel Ramsay^8dser^Andre" V!te'eV A%rams^1iego !omarri%as D.^Oohn 4c:rath^_a" 4ai 2ang%au^#lorian Petriko'ics^Gictor Pera F_adar$ Croatia.^
xcm%uck`yahoo.com^1aniel R. >ucas^4atthe" C$ 1uda^Lenneth^6elena^Oason Laplan^Darry Oones^!te'en Lolln^4arek Re"ers^Andrey _huko'^1a'e
!chlicher^!ue Anne 2eo^Chris #orrence^2o%y :allo^Oako% Camp%ell^Christian V1is@rdArV Oohansson^!te'e )alsh^Ooost Romanus^Oa*se 2schosie Lo'bcs^
Dack Luo^Oames Anselm^Christian :er%randt^4ike !toops^4ichael A >unds'een^1a'id R. Dissonnette$ Or.^:eo 4ason^Ooco da !il'eira^Oason 0an !mith^
Anders Lring^Ruddi @li'er Dodholdt 1al^edgley^Richard Oapenga^Oake^Len 6arney^Drandon 6all^D. Chao^Chinmay Da(ikar^Clint >eClair^1a'in Reid+
4ontanaro^0saac 9ung^8spen 2orseth^2homas 6ogan^-ick Poenn^8ric Gogel^Oack !alis%ury^Oames Rank^Oamie Pierson^Christine Paluch^Peter >a"s^Len
6urst^Patrick VPapentV 2ennant^Anshu Pra%hat^Le'in )ilkinson^Ooshua 6uns%erger^-icholas Oohnson^4ax )oerner Chase^Oustin 6anssen^
pete.'argasmas`gmail.com^Oames 8d"ard Oohnson^:riin Oones^Do% Dyroad^6agen 1ias^Oerin 4athe"^Oasper Dlacketer^Oonathan >undstrom^1(ango
@ :ato^4athias 8hret^0nterphase 2echnologies^!tanton 6ooley^Odreme P.^4ichael 8d"ards^Ro%ert Do"nds^Patrick Cor%ett^Akshay Rao^6endricks
)eather%orne^)erner D^Paul 4ay^0smail 6assan^Akash :ordhan^Drian Ooseph Dixon^Peter :orys^Cydroiid^-icolas 6au'iller^Oack Carroll^1a'e Lin^
4ichael Anaya^1a'e Lilsheimer^Oay^Oake !tam%augh^1ustin C! )agner^#aridi Zaium^4ichael Ramos^Oim2^!'en Dorer^>ocutus^Oames VDakerV !tuart^
Chris Dro"ne^Oose Agra*^Lasper Rugaard^Ooseph Llas*ky^Drandon Cotton^1^>ucas 1erraugh^! Patterson^0an 4iles^Chuck 4c>ellan^ODoEUQ^1.O.4urray^
2om Randle^Anna^-a'te( !aggu^1ylan Dra%ec^O Cald"ell^Ooseph 2(on^Andy Dates^Charles 4eyer^!e%astian !ahlin^4ichael Phillips + )a'es f 2idings^
2oh Chee !eng^:arry V:orioV Padua^8ric )allmander^!ha*%ot^1iante 8d"ards^Almost6uman^Andy 8^4att !tult*^8ric Loerner^:areth !hippen^Lendal
8d"ards^Ro%ert !holl^R@d4Y^Lyle 6inkle^2immy Cra"ord^Ron )^2re'or 4iller^1re" Lamthong^9atin 4ehta^smash%roAJ^Lelsey Las*as^4ike^1uppy^
4ikk Lirstein^Adi% Lhoury^>ou )ard^4ilan Obnoghk^Den(amin !chlageter^Loen Gan den 8eckhout^Richard )o(tas*ak^4athias Drenner^4agnus -ygren^
6arrison 2an^Amin A*am^Chris A"esome^Andy )elsh^Lyle 6ughes^O. @"en^-ick 4anganelli^0'an _amotokhin^>iam Oens*^4atthe" Loryto"ski^1a'id >
206
Real Python
RealPython.com
!prague^Philipp Deckmann^>oren*o R G^4iles )ilkins^Andre" O. 1imond^!te'e 6arris^)ill Lnott^@dd 4agnus Ros%ach^Ouan 6ernai*^2omoyuki
!ugihara^Calum 4acken*ie^OD^-ick :.^2homas Perrella^0an 4c:uire^-eelyn^Oames Rodgers^4ark 1ixon^Che**as^Oessica >ed%etter^Ariel #ogel^
1a'ide Garni^!asha Drogan^Clint 4yers^Ro% 2rimarco^!amuel Oudd^trademar,ues.co^!tean^Oim @.^!imon 6edegaard^Ryan #agan^8d )oods^0acton
Zru*e^4entat^2homas Clarke + -itro8'il^!aym Dasheer^Le'in !pleid^8'aristo Ramos$ Or.^:rant >indsay^8rin 0^t"istcrat^Carter 2hayer^4ark !hocklee^
:erard Cochrane Or^4ichael O Carl^Anthony Allan^6o"ard Cheetham^Den Piper^Richard 6er"ig^2yler Piderit^OimminiLin^Ro%ert -g^Penguins Are #rom
!pace^Oames > 6ays^Lyle L.^-icholas O. Atkins^R. 2ra'is Dro"n^2 O )oo^Alexander Arias^C.!.Putnam^Peter )e%%^1mitriy >it'ak^Ciaran Regan^)arai
@toko^Oohn >angho^andre" %rennan^Andre" :rosner^(amora((^Adiel Ar'i*u^4ark -orgren^8ric R. !toeckel$ Or.^Pedro :ome*^Chris Conner^
`andersosthus^Chandra -agara(a^Oan P. 4onsch^Corra^2renty*^-icholas 6ehr^manmoe^>am Chuan Chang F!ingapore.^Roy :. Di'^1a'id !*ymc*ak^
Ronald !ingletary^!imone #.^Ooyce D FAustralia.^simon grensted^se%astien dominati^!tephen 2. 2ruong^4ichele :argiulo^Oonathan `Ardua 1oyle^
2ommy A.^!amuel 4organ^-ir #riedman^Pasha Lagan^:regory Lurts^D. )old^Drad #.^Ro%%ieP^#ernando Garela^4ichael >e%o"it*^4ichael 2 @li'ier^A.
Dacker^#redrik Larlsson$ 6almstad$ !"eden^1a'e >e"is^Andreas 4atern^Oon !trom^4ax 1ayan^Ooh.>ummel + :ermany^Oigar Patel^!ean R^8lly f
Andres^6ong 9i^1 Carter^2homas 4. Oohnson^4atthias Leller^8irik Dilet^1aniel @tero^2ed 1a'idson^1ougie V#resh #ingersV #riedman^Amr 4et"ally^
1ymatrix !olutions^1ylan 1emoe^2urki -. !hahel^Cory ! !poerl^Den D^4arc$ Lari$ Penelope$ and 4arylee 8'ans^-iklas VCartinaV Lillarsson^Paul ).^D.
:unaratnam^!tephanie 1elgado^coilercard^1a'e 2O^Ro%ert O. Romero^4atthe" Peterson^Drant )inter^1arkda'y^_ax 2ang^Anthony A :reen"ood Or.^
_achary 6o"ard^6al^Oohn A. Dooth^Ranoka^>arry 9ounger^:eorg #ischer F`snorpey.^2hor :. !teinsli^#rode 2horsdn^4ike and Oulia -elson^
codeImore^6unter 6arris^2errence 1eDeatham^Ryan )heeler^Oerrid 1.C. #uehrer^Rdmy G0-C8-2^Ro% )eatherly^!imon A^1aniel 9^Andr*e( )iktor^
8arthling7 one o Q %illion H and counting^Apos Cro,uelune^Adam Lim^i2rain 4alaysia^4adison 4ay^)illiam # 2odoro^4ark 1an%om^Carlos Anchia^Rick
Chepeus^R. Llein^!e%astian @ort^Drooks Cutter^1ylan 6utchison^Lilian Riedl^2om V6arryV 4ud"ay^Al Dillings^Andrii !udyn^Andre" @&:orman^!haCol%y
Oackson^Ro%ert @'ington^Drandon 5sher^Ooshua >e#e'er^)illiam 4iller^2. !iesmayer^-iclas Derndtsson^Drian Ar%ogast f Drynn Ar%orico^Ro%erto
Gele*^4att 4.^)14^'ee xiong^Oohn 2hayer^Daron Durkhart^-icholas A. 1e>ateur^Den 6amilton^Cole 4ercer^1ougie -ix^!haun )alker^@lo Dengtson^
4arek Delski^Chris Cannon^Do% Putnam^Oe 4c4orris^2imothy Phillips^Rodolo #. :u*man^Ooe Durg"in^Andreas Dorgstrjm^Philip Rat*sch^Lostas
!araidis^R. Arteaga^ull*ero^Petros Ring^6arold :arron^2homas V:earsV Dutler^-eil Droadley^OPao^A'iel 4ak^L(eld Oensen^0 P #reely^Arturo
:oicochea 6oeken^>eo !uted(a^Cameron Lellett^)erner Deytel^4uhammad Lhan^Oason 2rogdon^1ao 2ran^2homas Ou%erg^Andy -guyen^Petr
2omicek^8rik Rex^!tephen 4eri"ether^Den(amin Llasmer^1erick !chmidt^Lyle 2homas^R.-ana^Arpan Dho"mik^Oaco% A. 2hias^8lliot^0saiah !t. Pierre^
Oosh 4ilo^1rchuncks^1r. !am - Oaxsam^4atthe" 4. 4cLee^Lyle !immons^Oason -ell^1arcy 2o"nsend^Oesse 6oughton^8'an 1.^4arcel Arnold^2homas
!iemens^C 6odgson^Adrien 1.^D(krn !pongs'een^Oemma^8d 4atthe"s^-ik 4ohd 0mran + 4alaysia^Oason )e%er^O2R 6aldr^4atthe" Ringman^9oshio
:oto^8'an :ary 6echt^8ric >.^6annes 6auer^Ro%ert 4ais^6ighland 1ryside Rusno's^4ichael 2orres^4ike Alchus^Oonathan >. 4artin^@li'er :ra^1a'id
Anspaugh^Ooe :riesmer^:arrett 1unham^!ru(an Lotikela^>aurel Richards^>o'elesh^!arah :uermond^Drian Canada$ Ph1$ Assistant Proessor o
Computational !cience$ 5ni'ersity o !outh Carolina Deauort^!hao^Antti Lankaanpii^Carl #. Corneil^>airdI1a'e^-yholm #amily^Drandon :raham^4.
A. 4errell^Lyle #ra*ier^P2I!1^2ra'is Cor"ith^8lliot Oo%e^A R Collins^lr(an !kmme^Oay D Ro%ertson^Oim 4att^Christopher 6ola%ird^Ronny Garghese^
Claudia #oley^Andre" !imeon^1 :^Oay G. !chindler^1ouglas Dutler ALA !herpa1oug^Oon Pere*^Pieter 4aes^:a%riel 4cCann^Oohn 6ol%rook^4elissa
Cloud^0nukai^6enning #(ellheim^Oason 2sang^Oulio'n^Reagan !hort^Carlos Cla'ero Aymerich^Gaughan Allan^Oames 1ougherty^4iles Oohnson^!hir"in^
2homas 2aimre^4ichael 5rhausen^Cody C. #oster^Christoph :.). :ert*en^4ag^4att 4onach^2a%or^Ash"in.4anthena^>ance 2ully^-oGu! Re-oGa2i@^
Ooshua Droussard^>aurence >i'ermore^Ro% #la'ell^#a%ian und 6olger )inkl%auer^Adriano >o conte^1ecio Galeri^!tephen 8"ell^8rik _olan^1harm
Lapadia^8ste%an Darrios^4ehul^2homas #auser^-athan Pinck^:rant P^:ary^Oonathan 4oisan^1a'id )arsho"^8rica _ahka^#rederik >aursen^Piotr
-apiorko"ski^Chris )e%ster^Oames Lo%ulyar^Co%alt 6alley^1e"ey Lang^#all^!usan 8ngle^1a'id :ar%er^Re%ecka )alle%om^Pai !i"amutita^Ooel
:erstein^Drant Dagnall^4r. Dacker E^Cole !mith^:ary Androphy^Leith > 6udson^Anthony Oackman^Rdgis >5228R^Charles Ourica^Oosd :leiser^4ike
6enderson^Lhalid 4 Al-uaim^1an VCidonaDoyV 4urphy^Drian#<C^:unnar )ehrhahn^4arc 6er*og^>eon 1uckham^Oustin !.^1C^Lit !anta Ana^2om
Pritchard^6amilton Chapman^2aylor 1aniels^Andre" )ood^2omer #rid^Peter D. :oode^Oohn #ord^@tto 6o^>C2^)in1ragonQ<^#a%er 4.^1ouglas 1a'ies^
Oaco% 4ylet^-iels :amsgaard #rederiksen^4ark :reene^Ro% 1a'arnia^Alex^_a%rina ).^)illiam @chetski 6ellas^Oose 0. Rey^1ustin 2. Petersen^A
-emeth^Pra'een 2ipirneni^1erek 8theridge^O.). 2am^Andrei^:eorge !elem%o^>eo 8'ans^!andu Dogi -asse^Christopher O Ruth^8rin 2homas^4att
Pham^L4#!^2odd #rit*^Drandon R. !argent^%oo^>ord !har'ish 2hargon the 1estructor^Lylie V!hado"V !taord^8dd Almond^!tanley^Drandon 1a"alt^
!e%astian Daum^#. 0,%al^4ungo 6osseneer^_u%air )a,ar^4att Russell^!am >au^Oean+Pierre Duntinx^Oames :iannikos^Chris Lim%all^6appy^-athan
Craike^arieals`li'e.com^Asad Ansari^O. Rugged^!tephanie Oohnston^!hun(i^4ohammad Ammar Lhan^Oohn+8ric 1uour^Drad Leen^Ricardo 2orres de
Acha^1enis 4ittakarin^Oerey de >ange^!te"art C. Annis^-icholas :oguen^Gipul !hekha"at^1aniel 6utchison^`lo%stahcrushah^D(oern :oret*ki^6ans
de )ol^Ray Darron^:arrett Oordan^Den(amin >e%sant^Alessandro A. 4inali^carlope**i^Patrick 9ang^Lieran #ung^-iloc^1a'id 1uncan^2om -aughton^
Darry :.+A. )ilson^1a'e Clarke^!ha"n Yu^Le'in 1. 1ienst^1urk 1iggler^4arcus #riesl^Lris*tina O.^G. 1arre^1uane !i%illy$ 00^4ari(e Pierson^Anco 'an
Goskuilen^Ooey 'an den Derg^:il -ahmani^!tephen 9ip^Richard 6eying^Patrick 2hornton^Ali Al@hali^8ric >eDlanc^Cliton -e^!te'e VDoer%rauerV
)eidig^Oaco% 6ansha"^daedahl^>ee A%er^Oan 6eim%rodt^A,ui% #ateh^:ary Patton )ole^Oim >ong^mt/pbnka moustko'b^>ogan _iegenus^Paul
Casagrande^Oason 8 Ooyner^9'onne Caprini^:rehg 6ilston^Peter )ang^A(ay 4enon^Oaya :oda'arthy^_ack >o'eless^2im Cupp^GishG^Ansel D^4organ
6ough^4auricio R. Cru*^Ryan Oolly^1aryl )alleck^1erek 4ayer^1opest^Oakesmiley^>uminoCity:roup^Oe -go^Ronn 2re'ino^Adam )ilson^Ron Collins^
Charles 4 Drumit^Charles :uerrero^Adan Ouan Cha'e* 4artine*^_akir 6ussain^Oa"hny Cooke^R. :eorge Lomoto^-iko Chiu^!ean 4urphy^4. -eukirch^
Ro% Laplan^Dogt(an Logir^modopo^Lenny VLe1e_V 6ernande*^6dctor :racia^8ric #inken%iner^Achal :autam^!tdphane Z58-AR1^)ee )ing L"ong^Alan
Carpilo'sky^roland kjhler Fmondtagskind.^Oim Drasic^4ar(an :olo%^:areth Casey^_aina% Al+Ansari^>ee !mith^Christopher V!hi%umiV 6ar"ood^
!angeetha Oames^!ami alaara(i^Ro%ert ! !haer Or^Oohn Porter^6ua^Roxy 4artine*^1ennis 6ong^#ille+>oup^sodiume^4att -asi^>uis Rosado^2aylor
207
Real Python
RealPython.com
Darnett^1an 4iller^Christopher !o'iero^Army2ra1nAd^2he Pe%%le^Oaco% >edel^4ichael 1ax 0aco'one^1on Rose$ C>^Carl Dulger^1a'id Ryan^Dill 6or'ath
00^Charles !chrump^1a'id O. Lay^C. L. @lson^Ooe 1ietrich^4axim Luschpel^Andre" L. 2homas^yelinaung^#ayerealian^Carl 6. Dlom,'ist^Do% !he^
8ric^2hom 4aughan^Ronald Reyes^Le'in Lapka^Rami 2ai%ah^Rahul Anantharaman^Renato Donini -eto^Peter 9oung^Richard 1re*don^6ypermedia*^4ark
Cater^4ark 2homas :riin^Alain Drisard^Le'in 9uan^!igmund -ylund^Oaco% 4cClanahan^Oulius #oit*ik^Drian :arside^:ary 4eola$ Or.^Raymond 8l"ard^
Alex Pekaro'sky^!cott 2olinski `stolinski^Oarle 8riksen^6n'ar #alck+Andersen^Akay Zuinn^Dritish^Oako'^!te'e 8dholm^2om V1amageV 4innick^-icolas
>eu^Patrick 1&appollonio Gega F`4arlex.^4ichael Conner^Oonathan Renpening^4ario Dra*ina^!imon^`4ayank4isra^2hia V2V -ila"at^Carolyn 6arp^
Oustin Dlaisdell^#erris Chia^Oerey Ooy^>uke Da*e^!un 8n'ironmental$ Carol !tanek+4arkel^!ean :omer^PulsarU^Peter 1^Pierre :authier^Andre" O
-icholls^Le'in Dosak^!ean Oohnson^Adan :a%riel :utierre*^). 1. Po"ell^Oohn Lent^Leiran @&-eill^Deau 6ardy^4ichael 6erman^2imothy Lim^_ach
6agen^Cheryl 6o"ard^0'an Rya%iik^!kyler Lanegi^Oosh Dro"ning^Goided:in^)onuk Ooshua Oo^Rami Al:hanmi^Oerey Pannett^Alex ).^Peter 1ig%y^
4outemouteA<^Darry 6ay^@"en :i%son^!ohan !^4ichael 1iDlasi^Cmdr. !,uirrel^4i(o !aradin^Chi6ong >in^2omatico^!ergio 8ste%an :bl'e* 4artell^
2ra'is 6a"k^1ex^Russ -e^Anthony R. Ounk^-icholas 1e#onde^Ooel A. :ar*a^Lyle 4cCleary^_ach 2o%en^Peter )ard^Ooa,uin Oohnson^>ai Yue9ang^
Ryan 4. Allen^:ern Dlanston^4arc &6iro& 6orstmann^L Ro%erts^1an Perrera^Christopher Rush^!hane Doyce^!tephen ).^:ershom :annon+@&:ara^Drent
Oones^Drian 1ickens^Chris Cor%in^4att )eeks^2ripp Cook^Arman Chahal^terryo"en^1aniel 0saac^:rant A.^:eorge 1"yer^Ooseph Corcoran^1re"
Cra%%^Oohn :allagher^6ari.2^A'i^Leith Oansma^!kyler #orshage^4artie #.^8 A^1e'in A Lluk^Len Dro"n^2hanasis 1imas^Oake Prime^1a'id Pong^
Oonathan Lennedy^4att ).^Alan >ehman^Denny ). 2oho^Decki Dradsher^Oaco% :oldstein^Oason 6ulin^!ean :reenhalgh^Re%ekah L.^Gaira'an >axman^
d"ight^2imothy Doan^>i* Cherene^!u'asin 6osiriluk^8'an )iederspan^!hane O. Geness^14ontgomery^4L^C Pedersen^Oeremy #aircloth^Andre"
4ullen^4ark D.^4ichelle Yue^cho"ard<^Rather(olly !ponhol*^8liana Ra%ino"it*^Clarence 0ngram^amir^Lai -ikulainen^#ishnets<<^Philippe O.
:ia%%anelli^Ooseph Andersen^Larol )erner^Alex >ee^Arturo !an*^Oustin >e"er^8'an Gandermast^Ar'indar -arasimhan^Alex Cason^mind"arp^2ruls
D(kr'ik^Adam Reed^6um%erto V!il'er@neV Car'alho^P8 Reiman^Adrien Arculeo^4arcus V4ak*terV @lander^Asi Ahmed^Oenny >au^Ai )hykes^)olgang
Amadeus 4o*art^Oessica Rausch^Dila"al 6ameed^Philip 4. )oite^1aniel 4ilam^Drian >ucken%ill^#rancesco Rinaudo^Ro%ert >. 2o"nsend^Ooe )atkins^
4ichael )oo^9ui+4an 4ak^1re" Oohnston^AnotherLlog^Alik !^Oames 0ngham^2ony Clough^!laught*^Chelsea + Z5+D1^2( c^8rat Pauker^!nappy the
!napster^:hostRe'en^1an Oenkins^Lallahir^-athan :reco^Dilal Ahmed^-apoleon )ennerstrjm^Drad !parks^Oohn Darrett^maxCohen^9'onne >a"^!cott
#orney^4atthe" R. 6ouse^Ro%ert 4. #roese^Dryan -g^Phill Portlock^4atthe" 8r"in^:orle$ Radhakrishna^4ike Richardson$ A%undance media :roup$ !#$
CA^2he#at@ne^4ichal !edlak^4ike Patterson^>ouis 6elscher^Oosh Philips^Phossil^Charlie 2an^4axim Lharlamo'^Oordan Gittito"^4arcel Darros Aparici^
Piotr Doc*o/^4atthe" Cheok^#rank Claycom%^!tig 6arald :usta'sen^-oel !antiago^Oason Campisi^1e%ora Richards^-in(a%ot^-ickolas Carter$ @regon^
4anuel !ucco^4r4ookie^Ooshua Denton^4 Cochran^Drian Ricard^2a%i^Cody @ss^Dren Ro"e^Oonathan 2omek^Oonathan )am%ach^8rih :.^4aria L^matt^
Larl Vhair10V 4arko'ich^Oace #erguson^:retchen 0m%ergamo^Alexander 2ushinsky^4ichael f Drandi^4ark Llamik^8rik R Gele*^4ichael Pellman^!heldon
!a"chuk^dragonCe'er^4atthe" #isher^!cott Clausen^1a'id 6unter^Le'in 4cLen*ie^6ector !aldana^Andre" !aunders^Athanasios Lountouras^
Christopher Lay+Chalk^Rusty !tiles^4. C. Rosen^Lai _hao^4ichelle Poirier^Andre" L.^Anna Ro*en%aum^-ader Lhalil^0smail 4orgenegg^Chris Roark^
1ean Gan Deelen^Ron Gickers^-ick 2omd^8ric -ikolaisen^!>A^Lick 4olen'eld^G0C^-icholas !mith^6ugh Oass^8ric Rodrigue*^6annes 6onkasaari^Anthony
Darranco^8spen -ilssen^Chris !tratord^Callum :riiths^L(etil !'endsen^Drad Rosen%oom^Christophe 4@5C68>^Oaco% !hmerko'ich^:ary)ith1R^Craig
@ Connor `Craigieoc^Oustin 6aydt^)illiam )ood"ard !harp^:lo"hollo"^4ichael >ass^>achlan Collins^>ittle Rory^8ng. Ahmed A. Alshaia^1a'e Ruppel^
OC^Aguirrex^4ax >upo^:reg 6or'ath^1aniel :ourry Dustos^:regor )eg%erg^1illon 1e'elopment Corporation^Lyle @"en^4ark )ert^!tephen 6olt^
2ianie Chia^-aim Dusek^Anthony _.^Oaco% 8'an 6orne^Oames 6 >in^Ro% !cott^!am >i%%y^Ooseph Cicero^4artin !chmidinger^>ogan :ittelson^PCY8>^
8ric Dlohm^sipp11^!upporter rom Concord$ 4A^6adora^2yler !hipe^!pencer Cree^!te'e !artain !artain^Peter :errit >o"e^Ron >.^-adine Camp%ell^
Aiman Ahmed^Oerey O.#. Re%ultan^4ichael Dro"n^%urna%ytom^Oigga Oay Ricciardi^4ichal 4Nhlpachr^Aaron #ader^1aniel !cott^Crashman2Q00^0an R
)right^4ir*a Ooldic^Ro%ert Dlack"ell Fr%lack"e.^1a'id VCrutchV Crutchield^:rant VDeastV 6arper^!pence Londe^4ichael )an^8ric Lilroy^ron ursem^
Re%ecca 6 :oldman^!amuel 8. :iddins^Oeanclyde Cru*^Gince P^Oohnny O.^Alexander _a"ad*ki^)illiam Clements = Chicago 2echnology :roup^Allen
Porras^5drea 4^Ooled Loh f >ay"en^Renno Reinurm^Alex )ixted^>e'i Dlue 4aggard^Len 4ce"an^Austin Dutcher^Den(amin 1urie^Oimmy 6sieh^1"in^
!ir Adelaide^Dlake >aroux^>ucas :rjnlund^!imon Ou%in'ille^Aerie )ard^2him #rederik !trothmann^Chasester^>aughing 4agi^)agner$ 8arl^%rian"ik^
@"en -ess^#lb'io 4assayoshi @ota^%ishado"^Dill 8^#rank )ie%enga^-ick Leehn^Alex 2irrell^2om 6iggins^>P^2yler Cushing^0rina Pin(ae'a^2im Roark^
OP^Doris :ut%rod^Adam^Den(amin 4iramontes$ !r.^Anatoly 4yasko'sky^Ooseph )elt^domhaase^Oonathan 6. Chaney^Carlos Pioan^4att Garian^4ichael
Ruppe^Dernie !o%iera(^Le'in Dacon the 2hird^9usuke La(i^>ee V2ie:uyV Dratina^Oopl :aleran F2"itter `Chi%iOoel.^a*^8. !cott^)ill Phule^Oonathan
6ill^1aniel )augh^Al%erto Rodrigue* Dar%on^@mar _ahr^Ouuhhhstin^:a' Reid^Conny Oohansson^>G^4oni,ue >. !akalidis^4artin :lass%oro"^1an
:adigian^Gincent.gagnonJ`gmail.com^8d @&Drien^Oimmy Dhullar^Oames 4c-amara^6amad D. Al+:hara%ally^4ichael 9u^Oohn !aunders^4ark Lent
4almros^Anton 6arris^0 Letut Parikesit^Le'in @&1onnell^!ait 4esutcan 0lhaner^Conor 1. Cox^>ucas 8aton^4ike Rotch^Oess _hu^Anne 4arie 5y^:
4alone^-athan 6urd^Oohn >. :rant$ 000^8ric Ooel^Adil !hakour^!cott )iley^!am 6unter^>aura R. Alonso^1oug L.^-ardoYing^Den Dlair^Andre" Oames^
Ooe !paracino^!ha"n Al%ert^Puipui -g^!hane Alexander 4ott^!eth )illiams^Lristian 6ill^1re" !^!andra 6or^:purd^Ro%in @rlic^Armel C.^Oustin 1uino^
Christophe R. F1ar"iin.^etchasketcher^Ir00k^2omas 6ernande* F2toti.^8lena 4urphy^Ryan Riley Aiden #isher^>uke 2homas^Riel Chu^
nameasitappearsonlist^Philip #reidin^t^-athan 8mery^Andre"^Oesse Gentura^1an Lohl%eck^@* du !oleil$ 1ata 4ercenary^Phil )atts^Oohn Pinto^9u'al
>anger^!imon 8'ans^!te'e 2urc*yn^:etAdditi'e.com^-ick !no"den^Lris^4ichael >itman F`mlitman.^Peter 5ng^#argo Oillson^Patrick 9e'suko'^1ee
Dender^Dat%ean^Aris 40chalopoulos^2hreemoons^Christopher 9ap^2im )illiams^@. Oohnson^1a'id - Duggs^4yles Lel'in^4. >eiper^Drogan _um"alt^Roy
-ielsen^Oaen Laiser^Ooe C.^8mily Chen^Dryan Po"ell^!ayRoar.com F#ilm f 2G.^Alan 6atakeyama^Chris Pacheco^Alex :alick^p a d * e r o^Ouri Palokas^
:regg >am%^>ani 2amanaha Droad%ent^Ami no4iko^Aaron 6ar'ey^Angel !icairos^!hiloh -.^Latherine Alla"ay^AlamoCityPhoto.Com^Oohn >audun^:reg
Reyes^Oagmas^1an Allen FZ>1$ Australia.^1ustin -ieho^Ag^!cott 4.^8s%en 4klgaard^0an 4c!hane^2imothy :i%son^Zue^Oanice )hitson^Da%ur 6a%i%^
208
Real Python
RealPython.com
Drent Cappello^4eep 4eep^Oustin :.^!tuart )oods^Ryan Cook^4ike R.^Oohn !urdako"ski^8hren Cheung^po"erul hallucinogens^Ro%ert 1rake^!te'e
Rose^2renshin^4eeghan Appleman^6anning VDutchV Cordes3^Oosd de Oesqs 4edina Rhos^:uadalupe Ramire*^Andre" )illerding^-athAn 2al%ot F4D.^
Oorge 8ste%an^%chan<C^irans`gmail.com^Lrish^Gaughn Galencia^Oeromy hogg^Oorge 6idalgo :.^*om%ieturtle^4ors^Rick 1^Ro% !chutt^)ee >in^
incenseroute.com^0ce2iger^Oames 8. Daird^6ulusi @nur Lu*ucu^2he6odge^9annick !chei"iller^Ro%in ar'idsson^@li'er 1iestel^1aniel Lnell^8lise
>epple^#rank 8lias^!haun Dudding^!hane )illiams^Chin Lun -ing^8ike !teinig^6ogg Loh^Aaron4#O^Oohn P. 1oran^4 Dlaskie^8ric &6arry& Drisson^Chris
VLrispy<UV :uerin^1uck 1odgers^Oonathan Coon^!ally Oo Cunningham^Ooe 1esiderio^Anon^4ike !ison^!hane 6iggins^Russell )ee^:a%riel D.^2homas
!e%astian Oensen^Amy Pearse^Oames #inley^4ikhail 5shano'^Oames A8 )ilson^4ichael 1ussert^#elix Gar(ord !jderstrjm^8ric 4etelka^!tephen 6arland^
muuusiiik^!handra 0annucci^Ooe Racey^CookQQ^-icholas R. Audemorte^Oustin 4arsten^Darrett^_achary !mith^mctouch^1onald 1. Parker^Ro% !il'a^
Phillip Ganderpool^1a'id 6errera^@tto^Roland !antos^Peter the 4agniicent^Drandon D.^Drett Russell^Ooe Carter^Andre" Paulus^Peter 6arris^Drian
Laisner^!tean :j%el^4elissa Deher^Oesse D + Potato6andle^p"endel%oe^4atthias :indele^Andy !mith+2homas^8li*a%eth !.^8re* !imon^Andre" Cook^
)outer 'an der Aa^0ain Cadman^Lyle Dishop^Andre" Rosen^Alessandro V(u(uV #araoni^:eek1oc^Arran !tirton^A4C1^8ddie -guyen^!te'e !tout^Richard
Dolla^Oohn 6endrix 000^Palla' >askar^!cri'ener^Do%%inickle^Gi(ay !hankar G^_ach Peskin^4ark -eeley^os"insim^Ooe Driguglio^!tacy 8. Draxton^Alan >
Chan^4arkus #romher*^Oim @tto^-eil 8"ington^!arah -e"^6arish :o"da^8'a Ganamee^Peter Lnepley^RGPARLR8G08)!.C@4^Drad )heel^8ric
:utierre*^Oe )ilden^1a'e Coleman^Drian ! Deckham^Dill >ong^Oeremy Lirsch^2im 8r"ich^Ryan Galle^Oohn Palmer^Rick !ku%ic^Gincent Parker^1a'id
Gon 1erau^Oonathan )ang^Chris !tolte^2homas Doettge^Oochen !chmied%auer^1irk )iggins^1a'id Recor^Ooshua 6ep%urn^Pelayo Rey^Oa%%en !tick^
Amit pa*^Ro% D.^Art/rs -ar/ickis^4errick Roy%all^Oerome amos^!o%a^Garian 6e%ert^:eo A.^1a'e !trange^Roy Ar'enis^Ryan !.^!uresh Lumar^!tean
-ygren^Oohn 6^Oustin A. Aronson^1a'e C^Leegan )illough%y^4artin+Patrick 4olloy^1a'id 6ay^Oe Deck^!ean Callaghan^:reg 2u%alles^4ark #illey^
!omashekar Reddy^Oorge Palacio^:len Andre 2han^:arrett -.^:arry Do"lin^!athish L^>ucas A. 1eelipe^4ichael Ro%erts^-orman !ue^2ommaso
Antonini^6er%ert^#rank Ahrens^5%ere'an^Andy !choield^Amir Pri*ant^Dennett A. Dlot^Ro% 5do'ich^6olli Droadoot^Ray >ee Ramire*^Oerey
1an*iger^Le'in Rhodes^Drendon Gan 6ey*en^Oe !imon^Oamie 8. Dro"ne^Gote @%ama 2012 3^)el^nAAtrAAk^O. Phillip !te"art^dham^@'e Lristensen^
Phillip >in^!te'e Paulo^Oerry #u^Chris )ray^1aniel !ch"an^!ean Cantellay^A*mi A%u -oor^>ucas Gan 1eun^2he 4utilator^0saac Amaya^chandradeep^D.
:ra'es^Den(i^>eonard Chan^Oames !melt*er^:eorge 0oakimedes^Andre" Leh^Do%%y 2. Garghese^!ir -athan Reed Chiurco^Christian -issler^8than
Oohns^1a'id !trako'sky^>eslie 6ar%augh^Adam :ross^1arren Loh^4att Palmer^4ichael Anthony !ena^Dlade @lson^>arry !e,uino^(eremy le'itan^Rahul
!hah^4ike !chul*e^!mall%ee^4ark Oohanson^4!^Pat #erate^1ennis Chan^4atthe" 1 Oohnson^Oeerson 2an^8ric :^Oordan 2ucker^!teen Reinhart^
Den(amin Rea^Drendan Durke^@ppa :angam !tyle^P D 1ietsche^1aniel >auer^Oon 1^O#G^Oeremy :rise^Oames 2ang^Oean+Philippe Roy^2he :uru :uys^
4atthe" Chan^Anna Parikka^moh maya^Armand^Ro%ert Porter^Oe 6anlon^4egan @lea f Chad 2ungate^4arko !oikkeli^Oamie #inlay^Oack Collison^
@llie !il'iotti^Andre" 6ayden^Oay 1 )ilson^Pureum Lim^4ike 4udgett^Oerry 6orn^>uca Rossetto^gulaschsuppe^4artin >ang%rnten^ilupmy%o"l^O.
>a"ler^Ron A'eryt^Christopher 6. 9. Chiu^Oohn >ee^Oustin -guyen^Antoine D8R208R^uultier`gmail.com^Adrienne C^>arry 2ierney^4aris :a%alins^
4arco Dulgarini^!imon Gahr^!e%astian 6o(as^! >ie"^6elena 4ontau%an^Yiaoying _hang^Alan 6^6ic8t-unc^Oonathan D. Oohnson^!iam^2homas Richter^
4arc+Andrd Parent^Lristian -y%o^Oim and !am 4aloney^ian remulla^emmanuelordone*12`yahoo.com^5l 8liasson^Oames 4urphy^Adrian^Rodrigo
Lonrad^!imon Fpigeon head. Oack^Richard 6u%er^Andre" 6inett^Ro%ert C.^Catherine^#elipe #erreira de @li'eira^4ike P^-ate #o"ler^!imon Lhaimo'^
Lurt >ie%egott^segnor%lues^Le'in :laser^Dill #ischoer^:raham Peacock 6eath^Oared Pennell^Dlaine 6ilton^4auri*io$ 0taly^Ouha Oiiskeliinen^!arah
>ead%eater^Drian O >ester^somair^Oaku% !tano^Oohn Du**i^2he #ish^:reg A.^-ichole Austin^8rik )ilthil^-athaniel :riggs^4.Dair^4ar"an Al*arouni^
!imon Delkin^2he%eersno%s.com^:ary 6armon^Oohan @%erg^!tephen Dro"n^4atthe" 1"yer^Oulian -aydiche'^:reg @rtega^)ill 4anidis^Oogender
-agar^Drian Paul^Leith !anders^Chris #erreira^Chad )hittaker^!onic^Phinehas Dynum^Oeremy Oones^4ark >indsey^Loty 9ell^Den(amin #ernande*^
Christopher VDerrymanV Derry^Aaron :ers*to^Lel !te"art^Drian 2aylor^Oohn 6utchins^4ichael !. )atson^Ro%ert^1a'e !ergeant^2ed Reardon^1arcy
Lohls^Qapcyk^1a'id Rosen^Oaco% 4inne^Rich^Ron !"anson^Dad%oychoi^!hane Dailey^Yiaoyang^4. )uer*^4arty @tto^>eonardo 4. 4. Oorge^arkuana^
mary grace lim^Delleonte^L. 4athis^Ooel #ish%ein^-eal 4ullin^!tephan 6. )issel^Alex Oeuck^Dri Dear^1a'e >eCompte^Alessandro D.^Doding _hang^
2imothy Oack^1aniel !imaan^2roy V)rongto"nV 6all^Geli Lerim relik^Dhaskar Lrishna^Pa"el )lodarski^Curtis Richardson^Anders >ind'all^Dranden
>aurie^Angus 6aynes^-athan Dain^Oac,ues !chaeer^!pongeile^Oohn Reeser^)illiam >imratana^!ascha Lieer^!ikander >hote^!tean >arsson^Do%%y
Rester^1a'id > 6ill^1aniel 2o^Austin 60ll^Druce 2urner^1arryl 1&Aoust^Oames !ala*ar^:regory 1.2sikis^Oohn :oerl^4egat 1enney^Oon 2. -ilsson^>am Lee
)ei^Chia 9eak$)ong^@ndrea :raye^1a'id 4. :ra^4ark Rogerson^2roels Dager^1on 6ealey^Drandon Cushen%erry^1aniel Oeery^(ohn liu^0ddeen
Lhairul^9an2ing^deadly22sniper^AR->A@^Oonah 8aton^4ark #erguson^O )agsta^2ina Preston^Le'in O. >ee^Anthony Perrett^Rich )atts^Ro%ert Reagh^
!ukanta :anguly^1. -ielsen^4aryam >.^Oeremy !el^4arcus Pearl^Andre" R )asem^Philipp C. @pit*^Ooshua 4ichael -icholas V>etyV 2urner^8mmanuel
Deltran^Dryan 2hurnau^1Done^1aniel V6eru+urV >agerman^@li'er 4arshall^4atthe" 1eloughry^Oothi^Ooe !taton^!te'e !e"ard^6otau^Ooshua Christain^
Dryan Parry^1oug Philips^Drian Chia^4auricio `Reyes^8rik !ch"art*^:eorge Cammack^-ico !.^O. :i*ard^Oe Lu(ath^1a'e^Drian 6u,ueri*a^:usmundur
Dorgar :hslason^1a'e Poirier^#erran !elles^4ichael V4akaV :radin^Oack 1in*e^Llas :elinder^Lyle 0ngrelli^peter^Christine C. 6eisler^Lyle Dro"n^9annik
!chrecken%erger^!hiki Cheeei >ee^!ean 6ames^1a'id 2ran^Oames Ro%erts^Ooshua Do"den Faka Oaxrtech.^Amiya :upta^Dryan A^Drion Cook^C :unadi^
!cott 4orrison^6ag%ard Celine^2homas Gassky^Cliton 6illmann^Chance 8'ans^1a'id ) >una^Adi Lamdar^Peter 4. Lersulis^Ooseph Perera^Ri,i^Adam
!chuster^-adine @ng^Ak-et"orking^Aaron _uko^#rank 2illey^1ustin 6all^Oohn 4. Lu*ma^#elix Laeer^Dar%4acL^Rohan 4artin^#rancis Oames Dasco^
). 4ontes^6o"ard 4. >a"son 00^4ichael 4illiken^Llaus 2hiel F4unich+:8R.^Richard 1usold^Oohn 2 4c:ee 00^)illiam -ichols^:erad 2ro(e^Leith Re%ello^
%ytemap^Oason !.^6aynes Che"ning^@tinane 8pidio^Atah 0smail^Oohn L. 8stell^1a'id Dy"orth^#0::8^Oason :assel^:reg 4atyola^8ric >. )old^:lenn
#etty^Le'in 4c:ill^-athan O. !heusi^4 A !he'lo^Latie Camille #riedman^:reg 2hompson^:alina _u%ko'^Adam 1^!cott Paterson^6utch+
CaneGentures.com^2homas 2hrash^Denoit >achance^Pa%lo Ri'as^!kip !urette^4athe" Duttery^#RiC^Celeste 6. :al'e*^Christopher Donner^Anonymous
209