You are on page 1of 278

APythonBook

APythonBook:BeginningPython,Advanced
Python,andPythonExercises
Author:
DaveKuhlman
Contact:
dkuhlman@davekuhlman.org
Address:
http://www.davekuhlman.org

Page1
APythonBook

Revision
1.3a
Date
December15,2013
Copyright
Copyright(c)2009DaveKuhlman.AllRightsReserved.Thisdocumentissubject
totheprovisionsoftheOpenSourceMITLicense
http://www.opensource.org/licenses/mitlicense.php.
Abstract
ThisdocumentisaselflearningdocumentforacourseinPythonprogramming.
Thiscoursecontains(1)apartforbeginners,(2)adiscussionofseveraladvanced
topicsthatareofinteresttoPythonprogrammers,and(3)aPythonworkbookwith
lotsofexercises.

Page2
APythonBook

Contents
1Part1BeginningPython...........................................................................................10
1.1IntroductionsEtc...................................................................................................10
1.1.1Resources.......................................................................................................11
1.1.2AgeneraldescriptionofPython....................................................................12
1.1.3InteractivePython..........................................................................................15
1.2Lexicalmatters......................................................................................................15
1.2.1Lines..............................................................................................................15
1.2.2Comments......................................................................................................16
1.2.3Namesandtokens..........................................................................................16
1.2.4Blocksandindentation..................................................................................16
1.2.5Docstrings.....................................................................................................17
1.2.6Programstructure..........................................................................................17
1.2.7Operators.......................................................................................................18
1.2.8Alsosee.........................................................................................................19
1.2.9Codeevaluation.............................................................................................19
1.3Statementsandinspectionpreliminaries...........................................................20
1.4Builtindatatypes.................................................................................................21
1.4.1Numerictypes................................................................................................21
1.4.2Tuplesandlists..............................................................................................21
1.4.3Strings............................................................................................................24
1.4.3.1Thenewstring.formatmethod...............................................................26
1.4.3.2Unicodestrings......................................................................................27
1.4.4Dictionaries....................................................................................................29
1.4.5Files...............................................................................................................32
1.4.6Otherbuiltintypes........................................................................................35
1.4.6.1TheNonevalue/type..............................................................................35
1.4.6.2Booleanvalues.......................................................................................36
1.4.6.3Setsandfrozensets.................................................................................36
1.5FunctionsandClassesAPreview......................................................................36
1.6Statements.............................................................................................................37
1.6.1Assignmentstatement....................................................................................37
1.6.2importstatement............................................................................................39
1.6.3printstatement...............................................................................................41
1.6.4if:elif:else:statement...................................................................................43
1.6.5for:statement.................................................................................................44
1.6.6while:statement.............................................................................................48

Page3
APythonBook

1.6.7continueandbreakstatements.......................................................................48
1.6.8try:except:statement.....................................................................................49
1.6.9raisestatement...............................................................................................51
1.6.10with:statement.............................................................................................52
1.6.10.1Writingacontextmanager...................................................................52
1.6.10.2Usingthewith:statement....................................................................53
1.6.11del................................................................................................................54
1.6.12casestatement..............................................................................................55
1.7Functions,Modules,Packages,andDebugging....................................................55
1.7.1Functions.......................................................................................................55
1.7.1.1Thedefstatement...................................................................................55
1.7.1.2Returningvalues....................................................................................55
1.7.1.3Parameters..............................................................................................56
1.7.1.4Arguments..............................................................................................56
1.7.1.5Localvariables.......................................................................................57
1.7.1.6Otherthingstoknowaboutfunctions....................................................57
1.7.1.7Globalvariablesandtheglobalstatement.............................................58
1.7.1.8Docstringsforfunctions.......................................................................60
1.7.1.9Decoratorsforfunctions........................................................................60
1.7.2lambda...........................................................................................................61
1.7.3Iteratorsandgenerators.................................................................................62
1.7.4Modules.........................................................................................................67
1.7.4.1Docstringsformodules.........................................................................68
1.7.5Packages........................................................................................................68
1.8Classes...................................................................................................................69
1.8.1Asimpleclass................................................................................................69
1.8.2Definingmethods..........................................................................................70
1.8.3Theconstructor..............................................................................................70
1.8.4Membervariables..........................................................................................70
1.8.5Callingmethods.............................................................................................71
1.8.6Addinginheritance........................................................................................71
1.8.7Classvariables...............................................................................................72
1.8.8Classmethodsandstaticmethods.................................................................72
1.8.9Properties.......................................................................................................74
1.8.10Interfaces.....................................................................................................75
1.8.11Newstyleclasses.........................................................................................75
1.8.12Docstringsforclasses.................................................................................77
1.8.13Privatemembers..........................................................................................77
1.9SpecialTasks.........................................................................................................77
1.9.1Debuggingtools.............................................................................................77

Page4
APythonBook

1.9.2Fileinputandoutput......................................................................................78
1.9.3Unittests........................................................................................................80
1.9.3.1Asimpleexample..................................................................................80
1.9.3.2Unittestsuites........................................................................................81
1.9.3.3Additionalunittestfeatures....................................................................83
1.9.3.4GuidanceonUnitTesting......................................................................85
1.9.4doctest............................................................................................................85
1.9.5ThePythondatabaseAPI..............................................................................87
1.9.6InstallingPythonpackages............................................................................88
1.10MorePythonFeaturesandExercises..................................................................89
2Part2AdvancedPython............................................................................................90
2.1IntroductionPython201(Slightly)AdvancedPythonTopics.......................90
2.2RegularExpressions..............................................................................................90
2.2.1Definingregularexpressions.........................................................................90
2.2.2Compilingregularexpressions......................................................................91
2.2.3Usingregularexpressions..............................................................................91
2.2.4Usingmatchobjectstoextractavalue..........................................................92
2.2.5Extractingmultipleitems..............................................................................93
2.2.6Replacingmultipleitems...............................................................................94
2.3IteratorObjects......................................................................................................96
2.3.1ExampleAgeneratorfunction....................................................................98
2.3.2ExampleAclasscontainingageneratormethod......................................100
2.3.3ExampleAniteratorclass.........................................................................102
2.3.4ExampleAniteratorclassthatusesyield.................................................104
2.3.5ExampleAlistcomprehension.................................................................105
2.3.6ExampleAgeneratorexpression..............................................................105
2.4UnitTests............................................................................................................106
2.4.1Definingunittests........................................................................................106
2.4.1.1Createatestclass.................................................................................106
2.5ExtendingandembeddingPython......................................................................109
2.5.1Introductionandconcepts............................................................................109
2.5.2Extensionmodules.......................................................................................110
2.5.3SWIG...........................................................................................................112
2.5.4Pyrex............................................................................................................115
2.5.5SWIGvs.Pyrex...........................................................................................120
2.5.6Cython.........................................................................................................120
2.5.7Extensiontypes............................................................................................122
2.5.8Extensionclasses.........................................................................................122
2.6Parsing.................................................................................................................122
2.6.1Specialpurposeparsers...............................................................................123

Page5
APythonBook

2.6.2Writingarecursivedescentparserbyhand.................................................124
2.6.3Creatingalexer/tokenizerwithPlex...........................................................131
2.6.4Asurveyofexistingtools............................................................................141
2.6.5CreatingaparserwithPLY.........................................................................141
2.6.6Creatingaparserwithpyparsing.................................................................148
2.6.6.1Parsingcommadelimitedlines............................................................148
2.6.6.2Parsingfunctors...................................................................................149
2.6.6.3Parsingnames,phonenumbers,etc.....................................................150
2.6.6.4Amorecomplexexample....................................................................151
2.7GUIApplications................................................................................................153
2.7.1Introduction.................................................................................................153
2.7.2PyGtk...........................................................................................................153
2.7.2.1Asimplemessagedialogbox..............................................................153
2.7.2.2Asimpletextinputdialogbox.............................................................156
2.7.2.3Afileselectiondialogbox...................................................................158
2.7.3EasyGUI......................................................................................................160
2.7.3.1AsimpleEasyGUIexample................................................................161
2.7.3.2AnEasyGUIfileopendialogexample................................................161
2.8GuidanceonPackagesandModules...................................................................161
2.8.1Introduction.................................................................................................161
2.8.2ImplementingPackages...............................................................................162
2.8.3UsingPackages............................................................................................162
2.8.4DistributingandInstallingPackages...........................................................162
2.9EndMatter...........................................................................................................164
2.9.1AcknowledgementsandThanks..................................................................164
2.9.2SeeAlso.......................................................................................................164
3Part3PythonWorkbook.........................................................................................165
3.1Introduction.........................................................................................................165
3.2LexicalStructures................................................................................................165
3.2.1Variablesandnames....................................................................................165
3.2.2Linestructure...............................................................................................167
3.2.3Indentationandprogramstructure...............................................................168
3.3ExecutionModel.................................................................................................169
3.4BuiltinDataTypes.............................................................................................170
3.4.1Numbers......................................................................................................170
3.4.1.1Literalrepresentationsofnumbers......................................................171
3.4.1.2Operatorsfornumbers.........................................................................173
3.4.1.3Methodsonnumbers............................................................................175
3.4.2Lists.............................................................................................................175
3.4.2.1Literalrepresentationoflists...............................................................176

Page6
APythonBook

3.4.2.2Operatorsonlists.................................................................................178
3.4.2.3Methodsonlists...................................................................................178
3.4.2.4Listcomprehensions............................................................................180
3.4.3Strings..........................................................................................................182
3.4.3.1Characters............................................................................................183
3.4.3.2Operatorsonstrings.............................................................................184
3.4.3.3Methodsonstrings...............................................................................185
3.4.3.4Rawstrings..........................................................................................187
3.4.3.5Unicodestrings....................................................................................188
3.4.4Dictionaries..................................................................................................190
3.4.4.1Literalrepresentationofdictionaries...................................................190
3.4.4.2Operatorsondictionaries.....................................................................191
3.4.4.3Methodsondictionaries.......................................................................192
3.4.5Files.............................................................................................................195
3.4.6Afewmiscellaneousdatatypes..................................................................197
3.4.6.1None.....................................................................................................197
3.4.6.2ThebooleansTrueandFalse...............................................................197
3.5Statements...........................................................................................................198
3.5.1Assignmentstatement..................................................................................198
3.5.2printstatement.............................................................................................200
3.5.3if:statementexercises..................................................................................201
3.5.4for:statementexercises...............................................................................202
3.5.5while:statementexercises...........................................................................205
3.5.6breakandcontinuestatements.....................................................................206
3.5.7Exceptionsandthetry:except:andraisestatements...................................207
3.6Functions.............................................................................................................210
3.6.1Optionalargumentsanddefaultvalues.......................................................211
3.6.2Passingfunctionsasarguments...................................................................213
3.6.3Extraargsandkeywordargs.......................................................................214
3.6.3.1Orderofarguments(positional,extra,andkeywordargs)..................216
3.6.4Functionsandducktypingandpolymorphism...........................................216
3.6.5Recursivefunctions.....................................................................................217
3.6.6Generatorsanditerators...............................................................................219
3.7Objectorientedprogrammingandclasses..........................................................223
3.7.1Theconstructor............................................................................................224
3.7.2InheritanceImplementingasubclass.......................................................225
3.7.3Classesandpolymorphism..........................................................................227
3.7.4Recursivecallstomethods..........................................................................228
3.7.5Classvariables,classmethods,andstaticmethods.....................................230
3.7.5.1Decoratorsforclassmethodandstaticmethod.....................................233

Page7
APythonBook

3.8AdditionalandAdvancedTopics........................................................................234
3.8.1Decoratorsandhowtoimplementthem......................................................234
3.8.1.1Decoratorswitharguments..................................................................235
3.8.1.2Stackeddecorators...............................................................................236
3.8.1.3Morehelpwithdecorators...................................................................238
3.8.2Iterables.......................................................................................................239
3.8.2.1AfewpreliminariesonIterables..........................................................239
3.8.2.2Morehelpwithiterables......................................................................240
3.9ApplicationsandRecipes....................................................................................240
3.9.1XMLSAX,minidom,ElementTree,Lxml..............................................241
3.9.2Relationaldatabaseaccess...........................................................................249
3.9.3CSVcommaseparatedvaluefiles...........................................................255
3.9.4YAMLandPyYAML..................................................................................256
3.9.5Json..............................................................................................................258
4Part4GeneratingPythonBindingsforXML.........................................................260
4.1Introduction.........................................................................................................260
4.2Generatingthecode.............................................................................................261
4.3UsingthegeneratedcodetoparseandexportanXMLdocument.....................263
4.4Somecommandlineoptionsyoumightwanttoknow.......................................263
4.5Thegraphicalfrontend.......................................................................................264
4.6Addingapplicationspecificbehavior.................................................................265
4.6.1Implementingcustomsubclasses................................................................265
4.6.2Usingthegenerated"API"fromyourapplication......................................266
4.6.3Acombinedapproach..................................................................................267
4.7Specialsituationsanduses..................................................................................269
4.7.1Generic,typeindependentprocessing.........................................................269
4.7.1.1Step1generatethebindings............................................................270
4.7.1.2Step2addapplicationspecificcode................................................270
4.7.1.3Step3writeatest/driverharness.....................................................274
4.7.1.4Step4runthetestapplication..........................................................276
4.8Somehints...........................................................................................................276
4.8.1ChildrendefinedwithmaxOccursgreaterthan1........................................276
4.8.2Childrendefinedwithsimplenumerictypes...............................................277
4.8.3Thetypeofanelement'scharactercontent..................................................277
4.8.4Constructorsandtheirdefaultvalues..........................................................277

Page8
APythonBook

Preface
ThisbookisacollectionofmaterialsthatI'veusedwhenconductingPythontrainingand
alsomaterialsfrommyWebsitethatareintendedforselfinstruction.
Youmaypreferamachinereadablecopyofthisbook.Youcanfinditinvariousformats
here:
HTMLhttp://www.davekuhlman.org/python_book_01.html
PDFhttp://www.davekuhlman.org/python_book_01.pdf
ODF/OpenOfficehttp://www.davekuhlman.org/python_book_01.odt
And,letmethankthestudentsinmyPythonclasses.Theirquestionsandsuggestions
wereagreathelpinthepreparationofthesematerials.

Page9
APythonBook

1Part1BeginningPython

1.1IntroductionsEtc
Introductions
Practicalmatters:restrooms,breakroom,lunchandbreaktimes,etc.
StartingthePythoninteractiveinterpreter.Also,IPythonandIdle.
Runningscripts
EditorsChooseaneditorwhichyoucanconfiguresothatitindentswith4spaces,not
tabcharacters.ForalistofeditorsforPython,see:
http://wiki.python.org/moin/PythonEditors.Afewpossibleeditors:
SciTEhttp://www.scintilla.org/SciTE.html.
MSWindowsonly(1)TextPadhttp://www.textpad.com;(2)UltraEdit
http://www.ultraedit.com/.
JedSeehttp://www.jedsoft.org/jed/.
EmacsSeehttp://www.gnu.org/software/emacs/and
http://www.xemacs.org/faq/xemacsfaq.html.
jEditRequiresabitofcustomizationforPythonSeehttp://jedit.org.
Vimhttp://www.vim.org/
Geanyhttp://www.geany.org/
Andmanymore.
Interactiveinterpreters:
python
ipython
Idle
IDEsAlsosee
http://en.wikipedia.org/wiki/List_of_integrated_development_environments_for_Python:
PyWinMSWindowsonly.Availableat:
http://sourceforge.net/projects/pywin32/.
WingIDESeehttp://wingware.com/wingide/.
Eclipsehttp://eclipse.org/.ThereisapluginthatsupportsPython.
KdevelopLinux/KDESeehttp://www.kdevelop.org/.
EricLinuxKDE?Seehttp://ericide.pythonprojects.org/index.html
EmacsandSciTEwillevaluateaPythonbufferwithintheeditor.

Page10
APythonBook

1.1.1Resources
Whereelsetogethelp:
Pythonhomepagehttp://www.python.org
Pythonstandarddocumentationhttp://www.python.org/doc/.
Youwillalsofindlinkstotutorialsthere.
FAQshttp://www.python.org/doc/faq/.
ThePythonWikihttp://wiki.python.org/
ThePythonPackageIndexLotsofPythonpackages
https://pypi.python.org/pypi
Specialinterestgroups(SIGs)http://www.python.org/sigs/
Otherpythonrelatedmailinglistsandlistsforspecificapplications(forexample,
Zope,Twisted,etc).Try:http://dir.gmane.org/search.php?match=python.
http://sourceforge.netLotsofprojects.Searchfor"python".
USENETcomp.lang.python.CanalsobeaccessedthroughGmane:
http://dir.gmane.org/gmane.comp.python.general.
ThePythontutoremaillisthttp://mail.python.org/mailman/listinfo/tutor
Localdocumentation:
OnMSWindows,thePythondocumentationisinstalledwiththestandard
installation.
InstallthestandardPythondocumentationonyourmachinefrom
http://www.python.org/doc/.
pydoc.Example,onthecommandline,type:pydocre.
Importamodule,thenviewits.__doc__attribute.
Attheinteractiveprompt,usehelp(obj).Youmightneedtoimportitfirst.
Example:
>>>importurllib
>>>help(urllib)
InIPython,thequestionmarkoperatorgiveshelp.Example:
In[13]:open?
Type:builtin_function_or_method
BaseClass:<type'builtin_function_or_method'>
StringForm:<builtinfunctionopen>
Namespace:Pythonbuiltin
Docstring:
open(name[,mode[,buffering]])>fileobject

Openafileusingthefile()type,returnsafile
object.
ConstructorDocstring:
x.__init__(...)initializesx;see
x.__class__.__doc__forsignature

Page11
APythonBook

Callable:Yes
Calldef:Callingdefinitionnotavailable.Call
docstring:
x.__call__(...)<==>x(...)

1.1.2AgeneraldescriptionofPython
Pythonisahighlevelgeneralpurposeprogramminglanguage:
Becausecodeisautomaticallycompiledtobytecodeandexecuted,Pythonis
suitableforuseasascriptinglanguage,Webapplicationimplementation
language,etc.
BecausePythoncanbeextendedinCandC++,Pythoncanprovidethespeed
neededforevencomputeintensivetasks.
Becauseofitsstrongstructuringconstructs(nestedcodeblocks,functions,
classes,modules,andpackages)anditsconsistentuseofobjectsand
objectorientedprogramming,Pythonenablesustowriteclear,logical
applicationsforsmallandlargetasks.
ImportantfeaturesofPython:
Builtinhighleveldatatypes:strings,lists,dictionaries,etc.
Theusualcontrolstructures:if,ifelse,ifelifelse,while,plusapowerful
collectioniterator(for).
Multiplelevelsoforganizationalstructure:functions,classes,modules,and
packages.Theseassistinorganizingcode.Anexcellentandlargeexampleisthe
Pythonstandardlibrary.
CompileontheflytobytecodeSourcecodeiscompiledtobytecodewithouta
separatecompilestep.Sourcecodemodulescanalsobe"precompiled"tobyte
codefiles.
ObjectorientedPythonprovidesaconsistentwaytouseobjects:everythingis
anobject.And,inPythonitiseasytoimplementnewobjecttypes(calledclasses
inobjectorientedprogramming).
ExtensionsinCandC++Extensionmodulesandextensiontypescanbewritten
byhand.Therearealsotoolsthathelpwiththis,forexample,SWIG,sip,Pyrex.
JythonisaversionofPythonthat"playswellwith"Java.See:TheJythonProject
http://www.jython.org/Project/.
Somethingsyouwillneedtoknow:
Pythonusesindentationtoshowblockstructure.Indentoneleveltoshowthe
beginningofablock.Outdentoneleveltoshowtheendofablock.Asan
example,thefollowingCstylecode:
if(x)
{

Page12
APythonBook

if(y)
{
f1()
}
f2()
}
inPythonwouldbe:
ifx:
ify:
f1()
f2()
And,theconventionistousefourspaces(andnohardtabs)foreachlevelofindentation.
Actually,it'smorethanaconvention;it'spracticallyarequirement.Followingthat
"convention"willmakeitsomucheasiertomergeyourPythoncodewithcodefrom
othersources.
AnoverviewofPython:
AscriptinglanguagePythonissuitable(1)forembedding,(2)forwritingsmall
unstructuredscripts,(3)for"quickanddirty"programs.
Notascriptinglanguage(1)Pythonscales.(2)Pythonencouragesustowrite
codethatisclearandwellstructured.
Interpreted,butalsocompiledtobytecode.Modulesareautomaticallycompiled
(to.pyc)whenimported,butmayalsobeexplicitlycompiled.
Providesaninteractivecommandlineandinterpretershell.Infact,thereare
several.
DynamicForexample:
Typesareboundtovalues,nottovariables.
Functionandmethodlookupisdoneatruntime.
Valuesareinspectable.
Thereisaninteractiveinterpreter,morethanone,infact.
Youcanlistthemethodssupportedbyanygivenobject.
Stronglytypedatruntime,notcompiletime.Objects(values)haveatype,but
variablesdonot.
ReasonablyhighlevelHighlevelbuiltindatatypes;highlevelcontrol
structures(forwalkinglistsanditerators,forexample).
ObjectorientedAlmosteverythingisanobject.Simpleobjectdefinition.Data
hidingbyagreement.Multipleinheritance.Interfacesbyconvention.
Polymorphism.
HighlystructuredStatements,functions,classes,modules,andpackagesenable
ustowritelarge,wellstructuredapplications.Whystructure?Readability,
locateability,modifiability.
Explicitness

Page13
APythonBook

Firstclassobjects:
Definition:Can(1)passtofunction;(2)returnfromfunction;(3)stuffintoa
datastructure.
Operatorscanbeappliedtovalues(notvariables).Example:f(x)[3]
Indentedblockstructure"Pythonispseudocodethatruns."
EmbeddingandextendingPythonPythonprovidesawelldocumentedand
supportedway(1)toembedthePythoninterpreterinC/C++applicationsand(2)
toextendPythonwithmodulesandobjectsimplementedinC/C++.
Insomecases,SWIGcangeneratewrappersforexistingC/C++code
automatically.Seehttp://www.swig.org/
CythonenablesustogenerateCcodefromPythonandto"easily"create
wrappersforC/C++functions.See
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
ToembedandextendPythonwithJava,thereisJython.See
http://www.jython.org/
Automaticgarbagecollection.(But,thereisagcmoduletoallowexplicitcontrol
ofgarbagecollection.)
Comparisonwithotherlanguages:compiledlanguages(e.g.C/C++);Java;Perl,
Tcl,andRuby.Pythonexcellsat:developmentspeed,executionspeed,clarityand
maintainability.
VarietiesofPython:
CPythonStandardPython2.ximplementedinC.
JythonPythonfortheJavaenvironmenthttp://www.jython.org/
PyPyPythonwithaJITcompilerandstacklessmodehttp://pypy.org/
StacklessPythonwithenhancedthreadsupportandmicrothreadsetc.
http://www.stackless.com/
IronPythonPythonfor.NETandtheCLRhttp://ironpython.net/
Python3Thenew,newPython.Thisisintendedasareplacementfor
Python2.x.http://www.python.org/doc/.Afewdifferences(fromPython
2.x):
Theprintstatementchangedtotheprintfunction.
Stringsareunicodebydefault.
Classesareall"newstyle"classes.
Changestosyntaxforcatchingexceptions.
Changestointegersnolonginteger;integerdivisionwithautomatic
converttofloat.
Morepervasiveuseofiterables(ratherthancollections).
Etc.
ForamoreinformationaboutdifferencesbetweenPython2.xandPython3.x,
seethedescriptionofthevariousfixesthatcanbeappliedwiththe2to3tool:

Page14
APythonBook

http://docs.python.org/3/library/2to3.html#fixers
Themigrationtool,2to3,easestheconversionof2.xcodeto3.x.
AlsoseeTheZenofPythonhttp://www.python.org/peps/pep0020.html.Or,at
thePythoninteractiveprompt,type:
>>>importthis

1.1.3InteractivePython
IfyouexecutePythonfromthecommandlinewithnoscript(noarguments),Python
givesyouaninteractiveprompt.ThisisanexcellentfacilityforlearningPythonandfor
tryingsmallsnippetsofcode.Manyoftheexamplesthatfollowweredevelopedusing
thePythoninteractiveprompt.
StartthePythoninteractiveinterpreterbytypingpythonwithnoargumentsatthe
commandline.Forexample:
$python
Python2.6.1(r261:67515,Jan112009,15:19:23)
[GCC4.3.2]onlinux2
Type"help","copyright","credits"or"license"formore
information.
>>>print'hello'
hello
>>>
YoumayalsowanttoconsiderusingIDLE.IDLEisagraphicalintegrateddevelopment
environmentforPython;itcontainsaPythonshell.ItislikelythatIdlewasinstalledfor
youwhenyouinstalledPython.YouwillfindascripttostartupIDLEinthe
Tools/scriptsdirectoryofyourPythondistribution.IDLErequiresTkinter.
Inaddition,therearetoolsthatwillgiveyouamorepowerfulandfancyPython
interactiveinterpreter.OneexampleisIPython,whichisavailableat
http://ipython.scipy.org/.

1.2Lexicalmatters

1.2.1Lines
Pythondoeswhatyouwantittodomostofthetimesothatyouonlyhavetoadd
extracharacterssomeofthetime.
Statementseparatorisasemicolon,butisonlyneededwhenthereismorethan
onestatementonaline.And,writingmorethanonestatementonthesamelineis
consideredbadform.
ContinuationlinesAbackslashaslastcharacterofthelinemakesthe

Page15
APythonBook

followinglineacontinuationofthecurrentline.But,notethatanopening
"context"(parenthesis,squarebracket,orcurlybracket)makesthebackslash
unnecessary.

1.2.2Comments
Everythingafter"#"onalineisignored.Noblockcomments,butdocstringsarea
commentinquotesatthebeginningofamodule,class,methodorfunction.Also,editors
withsupportforPythonoftenprovidetheabilitytocommentoutselectedblocksofcode,
usuallywith"##".

1.2.3Namesandtokens
Allowedcharacters:azAZ09underscore,andmustbeginwithaletteror
underscore.
Namesandidentifiersarecasesensitive.
Identifierscanbeofunlimitedlength.
Specialnames,customizing,etc.Usuallybeginandendindoubleunderscores.
SpecialnameclassesSingleanddoubleunderscores.
SingleleadingsingleunderscoreSuggestsa"private"methodorvariable
name.Notimportedby"frommoduleimport*".
SingletrailingunderscoreUseittoavoidconflictswithPythonkeywords.
DoubleleadingunderscoresUsedinaclassdefinitiontocausename
mangling(weakhiding).But,notoftenused.
NamingconventionsNotrigid,but:
Modulesandpackagesalllowercase.
GlobalsandconstantsUppercase.
ClassesBumpycapswithinitialupper.
MethodsandfunctionsAlllowercasewithwordsseparatedbyunderscores.
LocalvariablesLowercase(withunderscorebetweenwords)orbumpy
capswithinitialloweroryourchoice.
GoodadviceFollowtheconventionsusedinthecodeonwhichyouare
working.
Names/variablesinPythondonothaveatype.Valueshavetypes.

1.2.4Blocksandindentation
Pythonrepresentsblockstructureandnestedblockstructurewithindentation,notwith
beginandendbrackets.
TheemptyblockUsethepassnoopstatement.
Benefitsoftheuseofindentationtoindicatestructure:

Page16
APythonBook

Reducestheneedforacodingstandard.Onlyneedtospecifythatindentationis4
spacesandnohardtabs.
Reducesinconsistency.Codefromdifferentsourcesfollowthesameindentation
style.Ithasto.
Reduceswork.Onlyneedtogettheindentationcorrect,notbothindentationand
brackets.
Reducesclutter.Eliminatesallthecurlybrackets.
Ifitlookscorrect,itiscorrect.Indentationcannotfoolthereader.
EditorconsiderationsThestandardis4spaces(nohardtabs)foreachindentationlevel.
Youwillneedatexteditorthathelpsyourespectthat.

1.2.5Docstrings
Docstringsarelikecomments,buttheyarecarriedwithexecutingcode.Docstringscan
beviewedwithseveraltools,e.g.help(),obj.__doc__,and,inIPython,aquestion
mark(?)afteranamewillproducehelp.
Adocstringiswrittenasaquotedstringthatisatthetopofamoduleorthefirstlines
aftertheheaderlineofafunctionorclass.
Wecanusetriplequotingtocreatedocstringsthatspanmultiplelines.
Therearealsotoolsthatextractandformatdocstrings,forexample:
pydocDocumentationgeneratorandonlinehelpsystem
http://docs.python.org/lib/modulepydoc.html.
epydocEpydoc:AutomaticAPIDocumentationGenerationforPython
http://epydoc.sourceforge.net/index.html
SphinxCanalsoextractdocumentationfromPythondocstrings.See
http://sphinxdoc.org/index.html.
Seethefollowingforsuggestionsandmoreinformationondocstrings:Docstring
conventionshttp://www.python.org/dev/peps/pep0257/.

1.2.6Programstructure
Executiondef,class,etcareexecutablestatementsthataddsomethingtothe
currentnamespace.Modulescanbebothexecutableandimportable.
Statements,datastructures,functions,classes,modules,packages.
Functions
Classes
Modulescorrespondtofileswitha"*.py"extension.Packagescorrespondtoa
directory(orfolder)inthefilesystem;apackagecontainsafilenamed
"__init__.py".Bothmodulesandpackagescanbeimported(seesectionimport

Page17
APythonBook

statement).
PackagesAdirectorycontainingafilenamed"__init__.py".Canprovide
additionalinitializationwhenthepackageoramoduleinitisloaded(imported).

1.2.7Operators
See:http://docs.python.org/ref/operators.html.Pythondefinesthefollowing
operators:
+***///%
<<>>&|^~
<><=>===!=<>
Thecomparisonoperators<>and!=arealternatespellingsofthesameoperator.
!=isthepreferredspelling;<>isobsolescent.
Logicaloperators:
andorisnotin
Therearealso(1)thedotoperator,(2)thesubscriptoperator[],andthe
function/methodcalloperator().
Forinformationontheprecedencesofoperators,seethetableat
http://docs.python.org/2/reference/expressions.html#operatorprecedence,which
isreproducedbelow.
Forinformationonwhatthedifferentoperatorsdo,thesectioninthe"Python
LanguageReference"titled"Specialmethodnames"maybeofhelp:
http://docs.python.org/2/reference/datamodel.html#specialmethodnames
ThefollowingtablesummarizestheoperatorprecedencesinPython,fromlowest
precedence(leastbinding)tohighestprecedence(mostbinding).Operatorsonthe
samelinehavethesameprecedence.Unlessthesyntaxisexplicitlygiven,
operatorsarebinary.Operatorsonthesamelinegrouplefttoright(exceptfor
comparisons,includingtests,whichallhavethesameprecedenceandchainfrom
lefttorightseesection5.9andexponentiation,whichgroupsfromrightto
left):
OperatorDescription
==========================================
lambdaLambdaexpression
orBooleanOR
andBooleanAND
notxBooleanNOT
in,notinMembershiptests
is,isnotIdentitytests
<,<=,>,>=,<>,!=,==Comparisons
|BitwiseOR
^BitwiseXOR
&BitwiseAND
<<,>>Shifts

Page18
APythonBook

+,Additionandsubtraction
*,/,%Multiplication,division,
remainder
+x,xPositive,negative
~xBitwisenot
**Exponentiation
x.attributeAttributereference
x[index]Subscription
x[index:index]Slicing
f(arguments...)Functioncall
(expressions...)Bindingortupledisplay
[expressions...]Listdisplay
{key:datum...}Dictionarydisplay
`expressions...`Stringconversion
Notethatmostoperatorsresultincallstomethodswithspecialnames,for
example__add__,__sub__,__mul__,etc.SeeSpecialmethodnames
http://docs.python.org/2/reference/datamodel.html#specialmethodnames
Later,wewillseehowtheseoperatorscanbeemulatedinclassesthatyoudefine
yourself,throughtheuseofthesespecialnames.

1.2.8Alsosee
FormoreonlexicalmattersandPythonstyles,see:
CodeLikeaPythonista:IdiomaticPython
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html.
StyleGuideforPythonCodehttp://www.python.org/dev/peps/pep0008/
Theflake8stylecheckingprogram.Seehttps://pypi.python.org/pypi/flake8.Also
seethepylintcodechecker:https://pypi.python.org/pypi/pylint.

1.2.9Codeevaluation
UnderstandingthePythonexecutionmodelHowPythonevaluatesandexecutesyour
code.
Evaluatingexpressions.
Creatingnames/variablesBindingThefollowingallcreatenames(variables)and
bindvalues(objects)tothem:(1)assignment,(2)functiondefinition,(3)classdefinition,
(4)functionandmethodcall,(5)importingamodule,...
FirstclassobjectsAlmostallobjectsinPythonarefirstclass.Definition:Anobjectis
firstclassif:(1)wecanputitinastructuredobject;(2)wecanpassittoafunction;(3)
wecanreturnitfromafunction.
ReferencesObjects(orreferencestothem)canbeshared.Whatdoesthismean?
Theobject(s)satisfytheidentitytestoperatoris.

Page19
APythonBook

Thebuiltinfunctionid()returnsthesamevalue.
Theconsequencesformutableobjectsaredifferentfromthoseforimmutable
objects.
Changing(updating)amutableobjectreferencedthroughonevariableor
containeralsochangesthatobjectreferencedthroughothervariablesor
containers,becauseitisthesameobject.
del()Thebuiltinfunctiondel()removesareference,not(necessarily)the
objectitself.

1.3Statementsandinspectionpreliminaries
printExample:
printobj
print"one","two",'three'
for:Example:
stuff=['aa','bb','cc']
foriteminstuff:
printitem
LearnwhatthetypeofanobjectisExample:
type(obj)
Learnwhatattributesanobjecthasandwhatit'scapabilitiesareExample:
dir(obj)
value="amessage"
dir(value)
GethelponaclassoranobjectExample:
help(str)
help("")
value="abc"
help(value)
help(value.upper)
InIPython(butnotstandardPython),youcanalsogethelpattheinteractivepromptby
typing"?"and"??"afteranobject.Example:
In[48]:a=''
In[49]:a.upper?
Type:builtin_function_or_method
StringForm:<builtinmethodupperofstrobjectat0x7f1c426e0508>
Docstring:
S.upper()>string

Page20
APythonBook

ReturnacopyofthestringSconvertedtouppercase.

1.4Builtindatatypes
Forinformationonbuiltindatatypes,seesectionBuiltinTypes
http://docs.python.org/lib/types.htmlinthePythonstandarddocumentation.

1.4.1Numerictypes
Thenumerictypesare:
PlainintegersSameprecisionasaClong,usuallya32bitbinarynumber.
LongintegersDefinewith100L.But,plainintegersareautomatically
promotedwhenneeded.
FloatsImplementedasaCdouble.Precisiondependsonyourmachine.See
sys.float_info.
ComplexnumbersDefinewith,forexample,3jorcomplex(3.0,2.0).
See2.3.4NumericTypesint,float,long,complex
http://docs.python.org/lib/typesnumeric.html.
Pythondoesmixedarithmetic.
Integerdivisiontruncates.ThisischangedinPython3.Usefloat(n)toforcecoercion
toafloat.Example:
In[8]:a=4
In[9]:b=5
In[10]:a/b
Out[10]:0#possiblywrong?
In[11]:float(a)/b
Out[11]:0.8
Applyingthefunctioncalloperator(parentheses)toatypeorclasscreatesaninstanceof
thattypeorclass.
ScientificandheavilynumericprogrammingHighlevelPythonisnotveryefficientfor
numericalprogramming.But,therearelibrariesthathelpNumpyandSciPySee:
SciPy:ScientificToolsforPythonhttp://scipy.org/

1.4.2Tuplesandlists
ListAlistisadynamicarray/sequence.Itisorderedandindexable.Alistismutable.
Listconstructors:[],list().
range()andxrange():

Page21
APythonBook

range(n)createsalistofnintegers.Optionalargumentsarethestartinginteger
andastride.
xrangeislikerange,exceptthatitcreatesaniteratorthatproducestheitems
inthelistofintegersinsteadofthelistitself.
TuplesAtupleisasequence.Atupleisimmutable.
Tupleconstructors:(),butreallyacomma;alsotuple().
Tuplesarelikelists,butarenotmutable.
Pythonlistsare(1)heterogeneous(2)indexable,and(3)dynamic.Forexample,wecan
addtoalistandmakeitlonger.
Notesonsequenceconstructors:
Toconstructatuplewithasingleelement,use(x,);atuplewithasingle
elementrequiresacomma.
Youcanspreadelementsacrossmultiplelines(andnoneedforbackslash
continuationcharacter"\").
Acommacanfollowthelastelement.
Thelengthofatupleorlist(orothercontainer):len(mylist).
Operatorsforlists:
Try:list1+list2,list1*n,list1+=list2,etc.
Comparisonoperators:<,==,>=,etc.
Testformembershipwiththeinoperator.Example:
In[77]:a=[11,22,33]
In[78]:a
Out[78]:[11,22,33]
In[79]:22ina
Out[79]:True
In[80]:44ina
Out[80]:False
Subscription:
Indexingintoasequence
NegativeindexesEffectively,lengthofsequenceplus(minus)index.
SlicingExample:data[2:5].Defaultvalues:beginningandendoflist.
SlicingwithstridesExample:data[::2].
OperationsontuplesNooperationsthatchangethetuple,sincetuplesareimmutable.
Wecandoiterationandsubscription.Wecando"contains"(theinoperator)andgetthe
length(thelen()operator).Wecanusecertainbooleanoperators.
OperationsonlistsOperationssimilartotuplesplus:
Appendmylist.append(newitem).

Page22
APythonBook

Insertmylist.insert(index,newitem).Noteonefficiency:The
insertmethodisnotasfastastheappendmethod.Ifyoufindthatyouneed
todoalargenumberofmylist.insert(0,obj)(thatis,insertingatthe
beginningofthelist)considerusingadequeinstead.See:
http://docs.python.org/2/library/collections.html#collections.deque.Or,use
appendandreverse.
Extendmylist.extend(anotherlist).Alsocanuse+and+=.
Removemylist.remove(item)andmylist.pop().Notethat
append()togetherwithpop()implementsastack.
Deletedelmylist[index].
PopGetlast(rightmost)itemandremovefromlistmylist.pop().
Listoperators+,*,etc.
Formoreoperationsandoperatorsonsequences,see:
http://docs.python.org/2/library/stdtypes.html#sequencetypesstrunicodelisttuplebyte
arraybufferxrange.
Exercises:
Createanemptylist.Append4stringstothelist.Thenpoponeitemofftheend
ofthelist.Solution:
In[25]:a=[]
In[26]:a.append('aaa')
In[27]:a.append('bbb')
In[28]:a.append('ccc')
In[29]:a.append('ddd')
In[30]:printa
['aaa','bbb','ccc','ddd']
In[31]:a.pop()
Out[31]:'ddd'
Usetheforstatementtoprinttheitemsinthelist.Solution:
In[32]:foritemina:
....:printitem
....:
aaa
bbb
ccc
Usethestringjoinoperationtoconcatenatetheitemsinthelist.Solution:
In[33]:'||'.join(a)
Out[33]:'aaa||bbb||ccc'
Uselistscontainingthree(3)elementstocreateandshowatree:
In[37]:b=['bb',None,None]
In[38]:c=['cc',None,None]
In[39]:root=['aa',b,c]

Page23
APythonBook

In[40]:
In[40]:
In[40]:defshow_tree(t):
....:ifnott:
....:return
....:printt[0]
....:show_tree(t[1])
....:show_tree(t[2])
....:
....:
In[41]:show_tree(root)
aa
bb
cc
Notethatwewilllearnabetterwaytorepresenttreestructureswhenwecover
implementingclassesinPython.

1.4.3Strings
Stringsaresequences.Theyareimmutable.Theyareindexable.Theyareiterable.
Foroperationsonstrings,seehttp://docs.python.org/lib/stringmethods.htmloruse:
>>>help(str)
Or:
>>>dir("abc")
Stringoperations(methods).
Stringoperators,e.g.+,<,<=,==,etc..
Constructors/literals:
Quotes:singleanddouble.Escapingquotesandotherspecialcharacterswitha
backslash.
TriplequotingUsetriplesinglequotesordoublequotestodefinemultiline
strings.
str()Theconstructorandthenameofthetype/class.
'aSeparator'.join(aList)
Manymore.
Escapecharactersinstrings\t,\n,\\,etc.
StringformattingSee:
http://docs.python.org/2/library/stdtypes.html#stringformattingoperations
Examples:
In[18]:name='dave'

Page24
APythonBook

In[19]:size=25
In[20]:factor=3.45
In[21]:print'Name:%sSize:%dFactor:%3.4f'%(name,size,
factor,)
Name:daveSize:25Factor:3.4500
In[25]:print'Name:%sSize:%dFactor:%08.4f'%(name,size,
factor,)
Name:daveSize:25Factor:003.4500
Iftherighthandargumenttotheformattingoperatorisadictionary,thenyoucan
(actually,must)usethenamesofkeysinthedictionaryinyourformatstrings.Examples:
In[115]:values={'vegetable':'chard','fruit':'nectarine'}
In[116]:'Ilove%(vegetable)sandIlove%(fruit)s.'%values
Out[116]:'IlovechardandIlovenectarine.'
Alsoconsiderusingtherightjustifyandleftjustifyoperations.Examples:
mystring.rjust(20),mystring.ljust(20,':').
InPython3,thestr.formatmethodispreferredtothestringformattingoperator.
ThismethodisalsoavailableinPython2.7.Ithasbenefitsandadvantagesoverthestring
formattingoperator.Youcanstartlearningaboutithere:
http://docs.python.org/2/library/stdtypes.html#stringmethods
Exercises:
Usealiteraltocreateastringcontaining(1)asinglequote,(2)adoublequote,(3)
bothasingleanddoublequote.Solutions:
"Some'quoted'text."
'Some"quoted"text.'
'Some"quoted"\'extra\'text.'
Writeastringliteralthatspansmultiplelines.Solution:
"""Thisstring
spansseverallines
becauseitisalittlelong.
"""
Usethestringjoinoperationtocreateastringthatcontainsacolonasa
separator.Solution:
>>>content=[]
>>>content.append('finch')
>>>content.append('sparrow')
>>>content.append('thrush')
>>>content.append('jay')
>>>contentstr=':'.join(content)
>>>printcontentstr
finch:sparrow:thrush:jay
Usestringformattingtoproduceastringcontainingyourlastandfirstnames,

Page25
APythonBook

separatedbyacomma.Solution:
>>>first='Dave'
>>>last='Kuhlman'
>>>full='%s,%s'%(last,first,)
>>>printfull
Kuhlman,Dave

IncrementallybuildinguplargestringsfromlotsofsmallstringstheoldwaySince
stringsinPythonareimmutable,appendingtoastringrequiresareallocation.So,itis
fastertoappendtoalist,thenusejoin.Example:
In[25]:strlist=[]
In[26]:strlist.append('Line#1')
In[27]:strlist.append('Line#2')
In[28]:strlist.append('Line#3')
In[29]:str='\n'.join(strlist)
In[30]:printstr
Line#1
Line#2
Line#3

IncrementallybuildinguplargestringsfromlotsofsmallstringsthenewwayThe
+=operationonstringshasbeenoptimized.So,whenyoudothisstr1+=str2,
evenmanytimes,itisefficient.
Thetranslatemethodenablesustomapthecharactersinastring,replacingthosein
onetablebythoseinanother.And,themaketransfunctioninthestringmodule,
makesiteasytocreatethemappingtable:
importstring

deftest():
a='axbycz'
t=string.maketrans('abc','123')
printa
printa.translate(t)

test()

1.4.3.1Thenewstring.formatmethod
Thenewwaytodostringformatting(whichisstandardinPython3andperhaps
preferredfornewcodeinPython2)istousethestring.formatmethod.Seehere:
http://docs.python.org/2/library/stdtypes.html#str.format
http://docs.python.org/2/library/string.html#formatstringsyntax
http://docs.python.org/2/library/string.html#formatspecificationminilanguage
Someexamples:

Page26
APythonBook

In[1]:'aaa{1}bbb{0}ccc{1}ddd'.format('xx','yy',)
Out[1]:'aaayybbbxxcccyyddd'
In[2]:'number:{0:05d}ok'.format(25)
Out[2]:'number:00025ok'
In[4]:'n1:{num1}n2:{num2}'.format(num2=25,num1=100)
Out[4]:'n1:100n2:25'
In[5]:'n1:{num1}n2:{num2}again:{num1}'.format(num2=25,
num1=100)
Out[5]:'n1:100n2:25again:100'
In[6]:'number:{:05d}ok'.format(25)
Out[6]:'number:00025ok'
In[7]:values={'name':'dave','hobby':'birding'}
In[8]:'user:{name}activity:{hobby}'.format(**values)
Out[8]:'user:daveactivity:birding'

1.4.3.2Unicodestrings
Representingunicode:
In[96]:a=u'abcd'
In[97]:a
Out[97]:u'abcd'
In[98]:b=unicode('efgh')
In[99]:b
Out[99]:u'efgh'
Converttounicode:a_string.decode(encoding).Examples:
In[102]:'abcd'.decode('utf8')
Out[102]:u'abcd'
In[103]:
In[104]:'abcd'.decode(sys.getdefaultencoding())
Out[104]:u'abcd'
Convertoutofunicode:a_unicode_string.encode(encoding).Examples:
In[107]:a=u'abcd'
In[108]:a.encode('utf8')
Out[108]:'abcd'
In[109]:a.encode(sys.getdefaultencoding())
Out[109]:'abcd'
In[110]:b=u'Sel\xe7uk'
In[111]:printb.encode('utf8')
Seluk
TestforunicodetypeExample:
In[122]:importtypes
In[123]:a=u'abcd'
In[124]:type(a)istypes.UnicodeType
Out[124]:True
In[125]:

Page27
APythonBook

In[126]:type(a)istype(u'')
Out[126]:True
Orbetter:
In[127]:isinstance(a,unicode)
Out[127]:True
Anexamplewithacharacter"c"withahachek:
In[135]:name='IvanKrsti\xc4\x87'
In[136]:name.decode('utf8')
Out[136]:u'IvanKrsti\u0107'
In[137]:
In[138]:len(name)
Out[138]:12
In[139]:len(name.decode('utf8'))
Out[139]:11
Youcanalsocreateaunicodecharacterbyusingtheunichr()builtinfunction:
In[2]:a='aa'+unichr(170)+'bb'
In[3]:a
Out[3]:u'aa\xaabb'
In[6]:b=a.encode('utf8')
In[7]:b
Out[7]:'aa\xc2\xaabb'
In[8]:printb
aabb
GuidanceforuseofencodingsandunicodeIfyouareworkingwithamultibyte
characterset:
1. Convert/decodefromanexternalencodingtounicodeearly
(my_string.decode(encoding)).
2. Doyourworkinunicode.
3. Convert/encodetoanexternalencodinglate
(my_string.encode(encoding)).
Formoreinformation,see:
UnicodeInPython,CompletelyDemystifiedhttp://farmdev.com/talks/unicode/
PEP100:PythonUnicodeIntegration
http://www.python.org/dev/peps/pep0100/
InthePythonstandardlibrary:
codecsCodecregistryandbaseclasses
http://docs.python.org/2/library/codecs.html#modulecodecs
StandardEncodings
http://docs.python.org/2/library/codecs.html#standardencodings
Ifyouarereadingandwritingmultibytecharacterdatafromortoafile,thenlookatthe

Page28
APythonBook

codecs.open()inthecodecsmodule
http://docs.python.org/2/library/codecs.html#codecs.open.
HandlingmultibytecharactersetsinPython3iseasier,Ithink,butdifferent.Onehintis
tousetheencodingkeywordparametertotheopenbuiltinfunction.Hereisan
example:
deftest():
infile=open('infile1.txt','r',encoding='utf8')
outfile=open('outfile1.txt','w',encoding='utf8')
forlineininfile:
line=line.upper()
outfile.write(line)
infile.close()
outfile.close()

test()

1.4.4Dictionaries
Adictionaryisacollection,whosevaluesareaccessiblebykey.Itisacollectionof
namevaluepairs.
Theorderofelementsinadictionaryisundefined.But,wecaniterateover(1)thekeys,
(2)thevalues,and(3)theitems(keyvaluepairs)inadictionary.Wecansetthevalueof
akeyandwecangetthevalueassociatedwithakey.
Keysmustbeimmutableobjects:ints,strings,tuples,...
Literalsforconstructingdictionaries:
d1={}
d2={key1:value1,key2:value2,}
Constructorfordictionariesdict()canbeusedtocreateinstancesoftheclassdict.
Someexamples:
dict({'one':2,'two':3})
dict({'one':2,'two':3}.items())
dict({'one':2,'two':3}.iteritems())
dict(zip(('one','two'),(2,3)))
dict([['two',3],['one',2]])
dict(one=2,two=3)
dict([(['one','two'][i2],i)foriin(2,3)])
Foroperationsondictionaries,seehttp://docs.python.org/lib/typesmapping.htmloruse:
>>>help({})
Or:

Page29
APythonBook

>>>dir({})
IndexingAccessoradditemstoadictionarywiththeindexingoperator[].Example:
In[102]:dict1={}
In[103]:dict1['name']='dave'
In[104]:dict1['category']=38
In[105]:dict1
Out[105]:{'category':38,'name':'dave'}
Someoftheoperationsproducethekeys,thevalues,andtheitems(pairs)inadictionary.
Examples:
In[43]:d={'aa':111,'bb':222}
In[44]:d.keys()
Out[44]:['aa','bb']
In[45]:d.values()
Out[45]:[111,222]
In[46]:d.items()
Out[46]:[('aa',111),('bb',222)]
Wheniteratingoverlargedictionaries,usemethodsiterkeys(),itervalues(),
anditeritems().Example:
In[47]:
In[47]:d={'aa':111,'bb':222}
In[48]:forkeyind.iterkeys():
....:printkey
....:
....:
aa
bb
Totestfortheexistenceofakeyinadictionary,usetheinoperatororthe
mydict.has_key(k)method.Theinoperatorispreferred.Example:
>>>d={'tomato':101,'cucumber':102}
>>>k='tomato'
>>>kind
True
>>>d.has_key(k)
True
Youcanoftenavoidtheneedforatestbyusingmethodget.Example:
>>>d={'tomato':101,'cucumber':102}
>>>d.get('tomato',1)
101
>>>d.get('chard',1)
1
>>>ifd.get('eggplant')isNone:
...print'missing'

Page30
APythonBook

...
missing
Dictionary"view"objectsprovidedynamic(automaticallyupdated)viewsofthekeysor
thevaluesortheitemsinadictionary.Viewobjectsalsosupportsetoperations.Create
viewswithmydict.viewkeys(),mydict.viewvalues(),and
mydict.viewitems().See:
http://docs.python.org/2/library/stdtypes.html#dictionaryviewobjects.
Thedictionarysetdefaultmethodprovidesawaytogetthevalueassociatedwitha
keyfromadictionaryandtosetthatvalueifthekeyismissing.Example:
In[106]:a
Out[106]:{}
In[108]:a.setdefault('cc',33)
Out[108]:33
In[109]:a
Out[109]:{'cc':33}
In[110]:a.setdefault('cc',44)
Out[110]:33
In[111]:a
Out[111]:{'cc':33}
Exercises:
Writealiteralthatdefinesadictionaryusingbothstringliteralsandvariables
containingstrings.Solution:
>>>first='Dave'
>>>last='Kuhlman'
>>>name_dict={first:last,'Elvis':'Presley'}
>>>printname_dict
{'Dave':'Kuhlman','Elvis':'Presley'}
Writestatementsthatiterateover(1)thekeys,(2)thevalues,and(3)theitemsin
adictionary.(Note:Requiresintroductionoftheforstatement.)Solutions:
>>>d={'aa':111,'bb':222,'cc':333}
>>>forkeyind.keys():
...printkey
...
aa
cc
bb
>>>forvalueind.values():
...printvalue
...
111
333
222
>>>foritemind.items():
...printitem

Page31
APythonBook

...
('aa',111)
('cc',333)
('bb',222)
>>>forkey,valueind.items():
...printkey,'::',value
...
aa::111
cc::333
bb::222
Additionalnotesondictionaries:
Youcanuseiterkeys(),itervalues(),iteritems()toobtain
iteratorsoverkeys,values,anditems.
Adictionaryitselfisiterable:ititeratesoveritskeys.So,thefollowingtwolines
areequivalent:
forkinmyDict:printk
forkinmyDict.iterkeys():printk
Theinoperatortestsforakeyinadictionary.Example:
In[52]:mydict={'peach':'sweet','lemon':'tangy'}
In[53]:key='peach'
In[54]:ifkeyinmydict:
....:printmydict[key]
....:
sweet

1.4.5Files
Openafilewiththeopenfactorymethod.Example:
In[28]:f=open('mylog.txt','w')
In[29]:f.write('message#1\n')
In[30]:f.write('message#2\n')
In[31]:f.write('message#3\n')
In[32]:f.close()
In[33]:f=file('mylog.txt','r')
In[34]:forlineinf:
....:printline,
....:
message#1
message#2
message#3
In[35]:f.close()
Notes:
Usethe(builtin)open(path,mode)functiontoopenafileandcreateafile
object.Youcouldalsousefile(),butopen()isrecommended.

Page32
APythonBook

Afileobjectthatisopenforreadingatextfilesupportstheiteratorprotocoland,
therefore,canbeusedinaforstatement.Ititeratesoverthelinesinthefile.This
ismostlikelyonlyusefulfortextfiles.
openisafactorymethodthatcreatesfileobjects.Useittoopenfilesforreading,
writing,andappending.Examples:
infile=open('myfile.txt','r')#openforreading
outfile=open('myfile.txt','w')#openfor(over)
writing
log=open('myfile.txt','a')#openfor
appendingtoexistingcontent
Whenyouhavefinishedwithafile,closeit.Examples:
infile.close()
outfile.close()
Youcanalsousethewith:statementtoautomaticallyclosethefile.Example:
withopen('tmp01.txt','r')asinfile:
forxininfile:
printx,
Theaboveworksbecauseafileisacontextmanager:itobeysthecontext
managerprotocol.Afilehasmethods__enter__and__exit__,andthe
__exit__methodautomaticallyclosesthefileforus.Seethesectiononthe
with:statement.
Inordertoopenmultiplefiles,youcannestwith:statements,oruseasingle
with:statementwithmultiple"expressionastarget"clauses.Example:
deftest():
#
#usemultiplenestedwith:statements.
withopen('small_file.txt','r')asinfile:
withopen('tmp_outfile.txt','w')asoutfile:
forlineininfile:
outfile.write('line:%s'%
line.upper())
printinfile
printoutfile
#
#useasinglewith:statement.
withopen('small_file.txt','r')asinfile,\
open('tmp_outfile.txt','w')asoutfile:
forlineininfile:
outfile.write('line:%s'%line.upper())
printinfile
printoutfile

test()
fileisthefiletypeandcanbeusedasaconstructortocreatefileobjects.But,

Page33
APythonBook

openispreferred.
Linesreadfromatextfilehaveanewline.Stripitoffwithsomethinglike:
line.rstrip('\n').
Forbinaryfilesyoushouldaddthebinarymode,forexample:rb,wb.Formore
aboutmodes,seethedescriptionoftheopen()functionatBuiltinFunctions
http://docs.python.org/lib/builtinfuncs.html.
Learnmoreaboutfileobjectsandthemethodstheyprovideat:2.3.9FileObjects
http://docs.python.org/2/library/stdtypes.html#fileobjects.
Youcanalsoappendtoanexistingfile.Notethe"a"modeinthefollowingexample:
In[39]:f=open('mylog.txt','a')
In[40]:f.write('message#4\n')
In[41]:f.close()
In[42]:f=file('mylog.txt','r')
In[43]:forlineinf:
....:printline,
....:
message#1
message#2
message#3
message#4
In[44]:f.close()
Forbinaryfiles,add"b"tothemode.NotstrictlynecessaryonUNIX,butneededonMS
Windows.And,youwillwanttomakeyourcodeportableacrossplatforms.Example:
In[62]:importzipfile
In[63]:outfile=open('tmp1.zip','wb')
In[64]:zfile=zipfile.ZipFile(outfile,'w',zipfile.ZIP_DEFLATED)
In[65]:zfile.writestr('entry1','myheroeshavealwaysbeen
cowboys')
In[66]:zfile.writestr('entry2','andtheystillareitseems')
In[67]:zfile.writestr('entry3','sadlyinsearchofand')
In[68]:zfile.writestr('entry4','onstepinbackof')
In[69]:
In[70]:zfile.writestr('entry4','onestepinbackof')
In[71]:zfile.writestr('entry5','themselvesandtheirslowmoving
ways')
In[72]:zfile.close()
In[73]:outfile.close()
In[75]:
$
$unziplvtmp1.zip
Archive:tmp1.zip
LengthMethodSizeRatioDateTimeCRC32Name

34Defl:N366%05290817:04f6b7d921entry1
27Defl:N297%05290817:0710da8f3dentry2
22Defl:N249%05290817:073fd17fdaentry3
18Defl:N2011%05290817:08d55182e6entry4

Page34
APythonBook

19Defl:N2111%05290817:081a892acdentry4
37Defl:N395%05290817:09e213708centry5

1571698%6files
Exercises:
Readallofthelinesofafileintoalist.Printthe3rdand5thlinesinthefile/list.
Solution:
In[55]:f=open('tmp1.txt','r')
In[56]:lines=f.readlines()
In[57]:f.close()
In[58]:lines
Out[58]:['the\n','big\n','brown\n','dog\n',
'had\n','long\n','hair\n']
In[59]:printlines[2]
brown

In[61]:printlines[4]
had
Morenotes:
Stripnewlines(andotherwhitespace)fromastringwithmethodsstrip(),
lstrip(),andrstrip().
Getthecurrentpositionwithinafilebyusingmyfile.tell().
Setthecurrentpositionwithinafilebyusingmyfile.seek().Itmaybe
helpfultouseos.SEEK_CURandos.SEEK_END.Forexample:
f.seek(2,os.SEEK_CUR)advancesthepositionbytwo
f.seek(3,os.SEEK_END)setsthepositiontothethirdtolast.
f.seek(25)setsthepositionrelativetothebeginningofthefile.

1.4.6Otherbuiltintypes
OtherbuiltindatatypesaredescribedinsectionBuiltinTypes
http://docs.python.org/lib/types.htmlinthePythonstandarddocumentation.

1.4.6.1TheNonevalue/type
TheuniquevalueNoneisusedtoindicate"novalue","nothing","nonexistence",etc.
ThereisonlyoneNonevalue;inotherwords,it'sasingleton.
UseistotestforNone.Example:
>>>flag=None
>>>
>>>ifflagisNone:
...print'clear'

Page35
APythonBook

...
clear
>>>ifflagisnotNone:
...print'hello'
...
>>>

1.4.6.2Booleanvalues
TrueandFalsearethebooleanvalues.
Thefollowingvaluesalsocountasfalse,forexample,inanif:statement:False,
numericzero,None,theemptystring,anemptylist,anemptydictionary,anyempty
container,etc.Allothervalues,includingTrue,actastruevalues.

1.4.6.3Setsandfrozensets
Asetisanunorderedcollectionofimmutableobjects.Asetdoesnotcontainduplicates.
Setssupportseveralsetoperations,forexample:union,intersection,difference,...
Afrozensetislikeaset,exceptthatafrozensetisimmutable.Therefore,afrozensetis
hashableandcanbeusedasakeyinadictionary,anditcanbeaddedtoaset.
Createasetwiththesetconstructor.Examples:
>>>a=set()
>>>a
set([])
>>>a.add('aa')
>>>a.add('bb')
>>>a
set(['aa','bb'])
>>>b=set([11,22])
>>>b
set([11,22])
>>>c=set([22,33])
>>>b.union(c)
set([33,11,22])
>>>b.intersection(c)
set([22])
Formoreinformationonsets,see:SetTypesset,frozenset
http://docs.python.org/lib/typesset.html

1.5FunctionsandClassesAPreview
StructuredcodePythonprogramsaremadeupofexpressions,statements,functions,
classes,modules,andpackages.

Page36
APythonBook

Pythonobjectsarefirstclassobjects.
Expressionsareevaluated.
Statementsareexecuted.
Functions(1)areobjectsand(2)arecallable.
ObjectorientedprogramminginPython.Modeling"realworld"objects.(1)
Encapsulation;(2)datahiding;(3)inheritance.Polymorphism.
Classes(1)encapsulation;(2)datahiding;(3)inheritance.
Anoverviewofthestructureofatypicalclass:(1)methods;(2)theconstructor;(3)class
(static)variables;(4)super/subclasses.

1.6Statements

1.6.1Assignmentstatement
Formtarget=expression.
Possibletargets:
Identifier
TupleorlistCanbenested.Leftandrightsidesmusthaveequivalentstructure.
Example:
>>>x,y,z=11,22,33
>>>[x,y,z]=111,222,333
>>>a,(b,c)=11,(22,33)
>>>a,B=11,(22,33)
Thisfeaturecanbeusedtosimulateanenum:
In[22]:LITTLE,MEDIUM,LARGE=range(1,4)
In[23]:LITTLE
Out[23]:1
In[24]:MEDIUM
Out[24]:2
Subscriptionofasequence,dictionary,etc.Example:
In[10]:a=range(10)
In[11]:a
Out[11]:[0,1,2,3,4,5,6,7,8,9]
In[12]:a[3]='abc'
In[13]:a
Out[13]:[0,1,2,'abc',4,5,6,7,8,9]
In[14]:
In[14]:b={'aa':11,'bb':22}
In[15]:b

Page37
APythonBook

Out[15]:{'aa':11,'bb':22}
In[16]:b['bb']=1000
In[17]:b['cc']=2000
In[18]:b
Out[18]:{'aa':11,'bb':1000,'cc':2000}
AsliceofasequenceNotethatthesequencemustbemutable.Example:
In[1]:a=range(10)
In[2]:a
Out[2]:[0,1,2,3,4,5,6,7,8,9]
In[3]:a[2:5]=[11,22,33,44,55,66]
In[4]:a
Out[4]:[0,1,11,22,33,44,55,66,5,6,7,8,9]
AttributereferenceExample:
>>>classMyClass:
...pass
...
>>>anObj=MyClass()
>>>anObj.desc='pretty'
>>>printanObj.desc
pretty
Thereisalsoaugmentedassignment.Examples:
>>>index=0
>>>index+=1
>>>index+=5
>>>index+=f(x)
>>>index=1
>>>index*=3
Thingstonote:
Assignmenttoanamecreatesanewvariable(ifitdoesnotexistinthe
namespace)andabinding.Specifically,itbindsavaluetothenewname.Calling
afunctionalsodoesthistothe(formal)parameterswithinthelocalnamespace.
InPython,alanguagewithdynamictyping,thedatatypeisassociatedwiththe
value,notthevariable,asisthecaseinstaticallytypedlanguages.
Assignmentcanalsocausesharingofanobject.Example:
obj1=A()
obj2=obj1
Checktodeterminethatthesameobjectissharedwithid(obj)ortheis
operator.Example:
In[23]:a=range(10)
In[24]:a
Out[24]:[0,1,2,3,4,5,6,7,8,9]
In[25]:b=a
In[26]:b

Page38
APythonBook

Out[26]:[0,1,2,3,4,5,6,7,8,9]
In[27]:b[3]=333
In[28]:b
Out[28]:[0,1,2,333,4,5,6,7,8,9]
In[29]:a
Out[29]:[0,1,2,333,4,5,6,7,8,9]
In[30]:aisb
Out[30]:True
In[31]:printid(a),id(b)
3103792031037920
Youcanalsodomultipleassignmentinasinglestatement.Example:
In[32]:a=b=123
In[33]:a
Out[33]:123
In[34]:b
Out[34]:123
In[35]:
In[35]:
In[35]:a=b=[11,22]
In[36]:aisb
Out[36]:True
Youcaninterchange(swap)thevalueoftwovariablesusingassignmentand
packing/unpacking:
>>>a=111
>>>b=222
>>>a,b=b,a
>>>a
222
>>>b
111

1.6.2importstatement
Makemodule(orobjectsinthemodule)available.
Whatimportdoes:
Evaluatethecontentofamodule.
Likelytocreatevariablesinthelocal(module)namespace.
Evaluationofaspecificmoduleonlyhappensonceduringagivenrunofthe
program.Therefore,amoduleissharedacrossanapplication.
Amoduleisevaluatedfromtoptobottom.Laterstatementscanreplacevalues
createdearlier.Thisistrueoffunctionsandclasses,aswellas(other)variables.
Whichstatementsareevaluated?Assignment,class,def,...
Usethefollowingidiomtomakeamodulebothrunableandimportable:
if__name__=='__main__':

Page39
APythonBook

#importpdb;pdb.set_trace()
main()#or"test()"orsomeotherfunction
definedinmodule
Notes:
Theaboveconditionwillbetrueonlywhenthemoduleisrunasascriptand
willnotbetruewhenthemoduleisimported.
Thelinecontainingpdbcanbecopiedanyplaceinyourprogramand
uncommented,andthentheprogramwilldropintothePythondebugger
whenthatlocationisreached.
Whereimportlooksformodules:
sys.pathshowswhereitlooks.
Therearesomestandardplaces.
AddadditionaldirectoriesbysettingtheenvironmentvariablePYTHONPATH.
Youcanalsoaddpathsbymodifyingsys.path,forexample:
importsys
sys.path.insert(0,'/path/to/my/module')
Packagesneedafilenamed__init__.py.
ExtensionsTodeterminewhatextensionsimportlooksfor,do:
>>>importimp
>>>imp.get_suffixes()
[('.so','rb',3),('module.so','rb',3),('.py','U',
1),('.pyc','rb',2)]
Formsoftheimportstatement:
importANamesinthelocal(module)namespaceareaccessiblewiththedot
operator.
importAasBImportthemoduleA,butbindthemoduleobjecttothe
variableB.
importA1,A2Notrecommended
fromAimportB
fromAimportB1,B2
fromAimportBasC
fromAimport*Notrecommended:cluttersandmixesnamespaces.
fromA.BimportC(1)PossiblyimportobjectCfrommoduleBin
packageAor(2)possiblyimportmoduleCfromsubpackageBinpackageA.
importA.B.CToreferenceattributesinC,mustusefullyqualifiedname,
forexampleuseA.B.C.DtoreferenceDinsideofC.
Morenotesontheimportstatement:
TheimportstatementandpackagesAfilenamed__init__.pyisrequiredin
apackage.Thisfileisevaluatedthefirsttimeeitherthepackageisimportedora

Page40
APythonBook

fileinthepackageisimported.Question:Whatismadeavailablewhenyoudo
importaPackage?Answer:Allvariables(names)thatareglobalinsidethe
__init__.pymoduleinthatpackage.But,seenotesontheuseof__all__:
Theimportstatementhttp://docs.python.org/ref/import.html
Theuseofif__name__=="__main__":Makesamoduleboth
importableandexecutable.
UsingdotsintheimportstatementFromthePythonlanguagereferencemanual:
"Hierarchicalmodulenames:whenthemodulenamescontains
oneormoredots,themodulesearchpathiscarriedout
differently.Thesequenceofidentifiersuptothelastdotisused
tofindapackage;thefinalidentifieristhensearchedinside
thepackage.Apackageisgenerallyasubdirectoryofa
directoryonsys.paththathasafile__init__.py."
See:Theimportstatementhttp://docs.python.org/ref/import.html
Exercises:
Importamodulefromthestandardlibrary,forexamplere.
Importanelementfromamodulefromthestandardlibrary,forexampleimport
compilefromtheremodule.
CreateasimplePythonpackagewithasinglemoduleinit.Solution:
1. Createadirectorynamedsimplepackageinthecurrentdirectory.
2. Createan(empty)__init__.pyinthenewdirectory.
3. Createansimple.pyinthenewdirectory.
4. Addasimplefunctionnametest1insimple.py.
5. Importusinganyofthefollowing:
>>>importsimplepackage.simple
>>>fromsimplepackageimportsimple
>>>fromsimplepackage.simpleimporttest1
>>>fromsimplepackage.simpleimporttest1asmytest

1.6.3printstatement
printsendsoutputtosys.stdout.Itaddsanewline,unlessanextracommais
added.
Argumentstoprint:
MultipleitemsSeparatedbycommas.
Endwithcommatosuppresscarriagereturn.
Usestringformattingformorecontroloveroutput.
Alsoseevarious"prettyprinting"functionsandmethods,inparticular,pprint.
See3.27pprintDataprettyprinter

Page41
APythonBook

http://docs.python.org/lib/modulepprint.html.
StringformattingArgumentsareatuple.Reference:2.3.6.2StringFormatting
Operationshttp://docs.python.org/lib/typesseqstrings.html.
Canalsousesys.stdout.Notethatacarriagereturnisnotautomaticallyadded.
Example:
>>>importsys
>>>sys.stdout.write('hello\n')
ControllingthedestinationandformatofprintReplacesys.stdoutwithaninstance
ofanyclassthatimplementsthemethodwritetakingoneparameter.Example:
importsys

classWriter:
def__init__(self,file_name):
self.out_file=file(file_name,'a')
defwrite(self,msg):
self.out_file.write('[[%s]]'%msg)
defclose(self):
self.out_file.close()

deftest():
writer=Writer('outputfile.txt')
save_stdout=sys.stdout
sys.stdout=writer
print'hello'
print'goodbye'
writer.close()
#Showtheoutput.
tmp_file=file('outputfile.txt')
sys.stdout=save_stdout
content=tmp_file.read()
tmp_file.close()
printcontent

test()
Thereisanalternativeformoftheprintstatementthattakesafilelikeobject,in
particularanobjectthathasawritemethod.Forexample:
In[1]:outfile=open('tmp.log','w')
In[2]:print>>outfile,'Message#1'
In[3]:print>>outfile,'Message#2'
In[4]:print>>outfile,'Message#3'
In[5]:outfile.close()
In[6]:
In[6]:infile=open('tmp.log','r')
In[7]:forlineininfile:
...:print'Line:',line.rstrip('\n')
...:

Page42
APythonBook

Line:Message#1
Line:Message#2
Line:Message#3
In[8]:infile.close()
FuturedeprecationwarningThereisnoprintstatementinPython3.Thereisaprint
builtinfunction.

1.6.4if:elif:else:statement
Atemplatefortheif:statement:
ifcondition1:
statements
elifcondition2:
statements
elifcondition3:
statements
else:
statements
Theelifandelseclausesareoptional.
ConditionsExpressionsAnythingthatreturnsavalue.Comparewitheval()and
exec.
Truthvalues:
FalseFalse,None,numericzero,theemptystring,anemptycollection(list
ortupleordictionaryor...).
TrueTrueandeverythingelse.
Operators:
andandorNotethatbothandandordoshortcircuitevaluation.
not
isandisnotTheidenticalobject.Cf.aisbandid(a)==id(b).
UsefultotestforNone,forexample:
ifxisNone:
...
ifxisnotNone:
...
inandnotinCanbeusedtotestforexistenceofakeyinadictionaryorfor
thepresenceofavalueinacollection.
Theinoperatortestsforequality,notidentity.
Example:
>>>d={'aa':111,'bb':222}
>>>'aa'ind

Page43
APythonBook

True
>>>'aa'notind
False
>>>'xx'ind
False
Comparisonoperators,forexample==,!=,<,<=,...
Thereisanifexpression.Example:
>>>a='aa'
>>>b='bb'
>>>x='yes'ifa==belse'no'
>>>x
'no'
Notes:
Theelif:clausesandtheelse:clauseareoptional.
Theif:,elif:,andelse:clausesareallheaderlinesinthesensethatthey
areeachfollowedbyanindentedblockofcodeandeachoftheseheaderlines
endswithacolon.(Toputanemptyblockafteroneofthese,oranyother,
statementheaderline,usethepassstatement.It'seffectivelyanoop.)
Parenthesesaroundtheconditioninanif:orelif:arenotrequiredandare
consideredbadform,unlesstheconditionextendsovermultiplelines,inwhich
caseparenthesesarepreferredoveruseofalinecontinuationcharacter(backslash
attheendoftheline).
Exercises:
Writeanifstatementwithanandoperator.
Writeanifstatementwithanoroperator.
Writeanifstatementcontainingbothandandoroperators.

1.6.5for:statement
Iterateoverasequenceoran"iterable"object.
Form:
forxiny:
block
IteratorSomenotesonwhatitmeanstobeiterable:
Aniterableissomethingthatcanbeusedinaniteratorcontext,forexample,ina
for:statement,inalistcomprehension,andinageneratorexpression.
Sequencesandcontainersareiterable.Examples:tuples,lists,strings,
dictionaries.
Instancesofclassesthatobeytheiteratorprotocolareiterable.See

Page44
APythonBook

http://docs.python.org/lib/typeiter.html.
Wecancreateaniteratorobjectwithbuiltinfunctionssuchasiter()and
enumerate().SeeBuiltinFunctions
http://docs.python.org/lib/builtinfuncs.htmlinthePythonstandardlibrary
reference.
Functionsthatusetheyieldstatement,produceaniterator,althoughit'sactually
calledagenerator.
Aniterableimplementstheiteratorinterfaceandsatisfiestheiteratorprotocol.
Theiteratorprotocol:__iter__()andnext()methods.See2.3.5Iterator
Types(http://docs.python.org/lib/typeiter.html).
Testingfor"iterability":
Ifyoucanuseanobjectinafor:statement,it'siterable.
Iftheexpresioniter(obj)doesnotproduceaTypeErrorexception,it's
iterable.
Somewaystoproduceiterators:
iter()andenumerate()See:
http://docs.python.org/lib/builtinfuncs.html.
some_dict.iterkeys(),some_dict.itervalues(),
some_dict.iteritems().
Useasequenceinaniteratorcontext,forexampleinaforstatement.Lists,
tuples,dictionaries,andstringscanbeusedinaniteratorcontexttoproducean
iterator.
GeneratorexpressionsLatestPythononly.Syntacticallylikelist
comprehensions,but(1)surroundedbyparenthesesinsteadofsquarebracketsand
(2)uselazyevaluation.
AclassthatimplementstheiteratorprotocolExample:
classA(object):
def__init__(self):
self.data=[11,22,33]
self.idx=0
def__iter__(self):
returnself
defnext(self):
ifself.idx<len(self.data):
x=self.data[self.idx]
self.idx+=1
returnx
else:
raiseStopIteration

deftest():
a=A()
forxina:

Page45
APythonBook

printx

test()
NotethattheiteratorprotocolchangesinPython3.
Afunctioncontainingayieldstatement.See:
Yieldexpressions
http://docs.python.org/2/reference/expressions.html#yieldexpressions
Theyieldstatement
http://docs.python.org/2/reference/simple_stmts.html#theyieldstatement
AlsoseeitertoolsmoduleinthePythonstandardlibraryformuchmorehelp
withiterators:itertoolsFunctionscreatingiteratorsforefficientlooping
http://docs.python.org/2/library/itertools.html#moduleitertools
Thefor:statementcanalsodounpacking.Example:
In[25]:items=['apple','banana','cherry','date']
In[26]:foridx,iteminenumerate(items):
....:print'%d.%s'%(idx,item,)
....:
0.apple
1.banana
2.cherry
3.date
Theforstatementcanalsohaveanoptionalelse:clause.Theelse:clauseis
executediftheforstatementcompletesnormally,thatisifabreakstatementisnot
executed.
Helpfulfunctionswithfor:
enumerate(iterable)Returnsaniterablethatproducespairs(tuples)
containingcount(index)andvalue.Example:
>>>foridx,valueinenumerate([11,22,33]):
...printidx,value
...
011
122
233
range([start,]stop[,step])andxrange([start,]stop[,
step]).
ListcomprehensionsSincelistcomprehensionscreatelists,theyareusefulinfor
statements,although,whenthenumberofelementsislarge,youshouldconsiderusinga
generatorexpressioninstead.Alistcomprehensionlooksabitlikeafor:statement,but
isinsidesquarebrackets,anditisanexpression,notastatement.Twoforms(among
others):
[f(x)forxiniterable]

Page46
APythonBook

[f(x)forxiniterableift(x)]
GeneratorexpressionsAgeneratorexpressionlookssimilartoalistcomprehension,
exceptthatitissurroundedbyparenthesesratherthansquarebrackets.Example:
In[28]:items=['apple','banana','cherry','date']
In[29]:gen1=(item.upper()foriteminitems)
In[30]:forxingen1:
....:print'x:',x
....:
x:APPLE
x:BANANA
x:CHERRY
x:DATE
Exercises:
Writealistcomprehensionthatreturnsallthekeysinadictionarywhose
associatedvaluesaregreaterthanzero.
Thedictionary:{'aa':11,'cc':33,'dd':55,'bb':22}
Solution:[x[0]forxinmy_dict.iteritems()ifx[1]>
0]
Writealistcomprehensionthatproducesevenintegersfrom0to10.Useafor
statementtoiterateoverthosevalues.Solution:
forxin[yforyinrange(10)ify%2==0]:
print'x:%s'%x
Writealistcomprehensionthatiteratesovertwolistsandproducesallthe
combinationsofitemsfromthelists.Solution:
In[19]:a=range(4)
In[20]:b=[11,22,33]
In[21]:a
Out[21]:[0,1,2,3]
In[22]:b
Out[22]:[11,22,33]
In[23]:c=[(x,y)forxinaforyinb]
In[24]:printc
[(0,11),(0,22),(0,33),(1,11),(1,22),(1,33),
(2,11),(2,22),(2,33),(3,11),(3,22),(3,33)]
But,notethatinthepreviousexercise,ageneratorexpressionwouldoftenbebetter.A
generatorexpressionislikealistcomprehension,exceptthat,insteadofcreatingthe
entirelist,itproducesageneratorthatcanbeusedtoproduceeachoftheelements.
Thebreakandcontinuestatementsareoftenusefulinaforstatement.Seecontinue
andbreakstatements
Theforstatementcanalsohaveanoptionalelse:clause.Theelse:clauseis
executediftheforstatementcompletesnormally,thatisifabreakstatementisnot
executed.Example:

Page47
APythonBook

foritemindata1:
ifitem>100:
value1=item
break
else:
value1='notfound'
print'value1:',value1
Whenrun,itprints:
value1:notfound

1.6.6while:statement
Form:
whilecondition:
block
Thewhile:statementisnotoftenusedinPythonbecausethefor:statementis
usuallymoreconvenient,moreidiomatic,andmorePythonic.
Exercises:
Writeawhilestatementthatprintsintegersfromzeroto5.Solution:
count=0
whilecount<5:
count+=1
printcount
Thebreakandcontinuestatementsareoftenusefulinawhilestatement.See
continueandbreakstatements
Thewhilestatementcanalsohaveanoptionalelse:clause.Theelse:clauseis
executedifthewhilestatementcompletesnormally,thatisifabreakstatementisnot
executed.

1.6.7continueandbreakstatements
Thebreakstatementexitsfromaloop.
Thecontinuestatementcausesexecutiontoimmediatelycontinueatthestartofthe
loop.
Canbeusedinfor:andwhile:.
Whenthefor:statementorthewhile:statementhasanelse:clause,theblockin
theelse:clauseisexecutedonlyifabreakstatementisnotexecuted.
Exercises:

Page48
APythonBook

Usingbreak,writeawhilestatementthatprintsintegersfromzeroto5.
Solution:
count=0
whileTrue:
count+=1
ifcount>5:
break
printcount
Notes:
Aforstatementthatusesrange()orxrange()wouldbebetterthana
whilestatementforthisuse.
Usingcontinue,writeawhilestatementthatprocessesonlyevenintegers
from0to10.Note:%isthemodulooperator.Solution:
count=0
whilecount<10:
count+=1
ifcount%2==0:
continue
printcount

1.6.8try:except:statement
Exceptionsareasystematicandconsistentwayofprocessingerrorsand"unusual"events
inPython.
CaughtanduncaughtexceptionsUncaughtexceptionsterminateaprogram.
Thetry:statementcatchesanexception.
AlmostallerrorsinPythonareexceptions.
Evaluation(executionmodel)ofthetrystatementWhenanexceptionoccursinthe
tryblock,evenifinsideanestedfunctioncall,executionofthetryblockendsandthe
exceptclausesaresearchedforamatchingexception.
TracebacksAlsoseethetracebackmodule:
http://docs.python.org/lib/moduletraceback.html
Exceptionsareclasses.
Exceptionclassessubclassing,args.
Anexceptionclassinanexcept:clausecatchesinstancesofthatexceptionclassand
allsubclasses,butnotsuperclasses.
BuiltinexceptionclassesSee:
Moduleexceptions.

Page49
APythonBook

Builtinexceptionshttp://docs.python.org/lib/moduleexceptions.html.
UserdefinedexceptionclassessubclassesofException.
Example:
try:
raiseRuntimeError('thissillyerror')
exceptRuntimeError,exp:
print"[[[%s]]]"%exp
Reference:http://docs.python.org/lib/moduleexceptions.html
Youcanalsogettheargumentspassedtotheconstructorofanexceptionobject.Inthe
aboveexample,thesewouldbe:
exp.args
Whywouldyoudefineyourownexceptionclass?Oneanswer:Youwantauserofyour
codetocatchyourexceptionandnoothers.
Catchinganexceptionbyexceptionclasscatchesexceptionsofthatclassandallits
subclasses.So:
exceptSomeExceptionClass,exp:
matchesandcatchesanexceptionifSomeExceptionClassistheexceptionclassorabase
class(superclass)oftheexceptionclass.Theexceptionobject(usuallyaninstanceof
someexceptionclass)isboundtoexp.
Amore"modern"syntaxis:
exceptSomeExceptionClassasexp:
So:
classMyE(ValueError):
pass

try:
raiseMyE()
exceptValueError:
print'caughtexception'
willprint"caughtexception",becauseValueErrorisabaseclassofMyE.
Alsoseetheentriesfor"EAFP"and"LBYL"inthePythonglossary:
http://docs.python.org/3/glossary.html.
Exercises:
Writeaverysimple,emptyexceptionsubclass.Solution:
classMyE(Exception):

Page50
APythonBook

pass
Writeatry:except:statementthatraisesyourexceptionandalsocatchesit.
Solution:
try:
raiseMyE('hellotheredave')
exceptMyE,e:
printe

1.6.9raisestatement
Throworraiseanexception.
Forms:
raiseinstance
raiseMyExceptionClass(value)preferred.
raiseMyExceptionClass,value
Theraisestatementtakes:
An(instanceof)abuiltinexceptionclass.
AninstanceofclassExceptionor
AninstanceofabuiltinsubclassofclassExceptionor
AninstanceofauserdefinedsubclassofclassExceptionor
Oneoftheaboveclassesand(optionally)avalue(forexample,astringora
tuple).
Seehttp://docs.python.org/ref/raise.html.
Foralistofbuiltinexceptions,seehttp://docs.python.org/lib/moduleexceptions.html.
Thefollowingexampledefinesanexceptionsubclassandthrowsaninstanceofthat
subclass.Italsoshowshowtopassandcatchmultipleargumentstotheexception:
classNotsobadError(Exception):
pass

deftest(x):
try:
ifx==0:
raiseNotsobadError('amoderatelybaderror','nottoo
bad')
exceptNotsobadError,e:
print'Errorargs:%s'%(e.args,)

test(0)
Whichprintsoutthefollowing:
Errorargs:('amoderatelybaderror','nottoobad')

Page51
APythonBook

Notes:
Inordertopassinmultipleargumentswiththeexception,weuseatuple,orwe
passmultipleargumentstotheconstructor.
Thefollowingexampledoesasmallamountofprocessingofthearguments:
classNotsobadError(Exception):
"""Anexceptionclass.
"""
defget_args(self):
return'::::'.join(self.args)

deftest(x):
try:
ifx==0:
raiseNotsobadError('amoderatelybaderror','nottoo
bad')
exceptNotsobadError,e:
print'Errorargs:{{{%s}}}'%(e.get_args(),)

test(0)

1.6.10with:statement
Thewithstatementenablesustouseacontextmanager(anyobjectthatsatisfiesthe
contextmanagerprotocol)toaddcodebefore(onentryto)andafter(onexitfrom)a
blockofcode.

1.6.10.1Writingacontextmanager
Acontextmanagerisaninstanceofaclassthatsatisfiesthisinterface:
classContext01(object):
def__enter__(self):
pass
def__exit__(self,exc_type,exc_value,traceback):
pass
Hereisanexamplethatusestheabovecontextmanager:
classContext01(object):
def__enter__(self):
print'in__enter__'
return'somevalueorother'#usuallywewanttoreturn
self
def__exit__(self,exc_type,exc_value,traceback):
print'in__exit__'
Notes:

Page52
APythonBook

The__enter__methodiscalledbeforeourblockofcodeisentered.
Usually,butnotalways,wewillwantthe__enter__methodtoreturnself,
thatis,theinstanceofourcontextmanagerclass.Wedothissothatwecanwrite:
withMyContextManager()asobj:
pass
andthenusetheinstance(objinthiscase)inthenestedblock.
The__exit__methodiscalledwhenourblockofcodeisexitedeither
normallyorbecauseofanexception.
Ifanexceptionissupplied,andthemethodwishestosuppresstheexception(i.e.,
preventitfrombeingpropagated),itshouldreturnatruevalue.Otherwise,the
exceptionwillbeprocessednormallyuponexitfromthismethod.
Iftheblockexitsnormally,thevalueofexc_type,exc_value,and
tracebackwillbeNone.
Formoreinformationonthewith:statement,seeContextManagerTypes
http://docs.python.org/2/library/stdtypes.html#contextmanagertypes.
Seemodulecontextlibforstrangewaysofwritingcontextmanagers:
http://docs.python.org/2/library/contextlib.html#modulecontextlib

1.6.10.2Usingthewith:statement
Hereareexamples:
#example1
withContext01():
print'inbody'

#example2
withContext02()asa_value:
print'inbody'
print'a_value:"%s"'%(a_value,)
a_value.some_method_in_Context02()

#example3
withopen(infilename,'r')asinfile,open(outfilename,'w')as
outfile:
forlineininfile:
line=line.rstrip()
outfile.write('%s\n'%line.upper())
Notes:
Intheformwith...asval,thevaluereturnedbythe__enter__
methodisassignedtothevariable(valinthiscase).
Inordertousemorethanonecontextmanager,youcannestwith:statements,
orseparateusesofofthecontextmanagerswithcommas,whichisusually

Page53
APythonBook

preferred.Seeexample3above.

1.6.11del
Thedelstatementcanbeusedto:
Removenamesfromnamespace.
Removeitemsfromacollection.
Ifnameislistedinaglobalstatement,thendelremovesnamefromtheglobal
namespace.
Namescanbea(nested)list.Examples:
>>>dela
>>>dela,b,c
Wecanalsodeleteitemsfromalistordictionary(andperhapsfromotherobjectsthatwe
cansubscript).Examples:
In[9]:d={'aa':111,'bb':222,'cc':333}
In[10]:printd
{'aa':111,'cc':333,'bb':222}
In[11]:deld['bb']
In[12]:printd
{'aa':111,'cc':333}
In[13]:
In[13]:a=[111,222,333,444]
In[14]:printa
[111,222,333,444]
In[15]:dela[1]
In[16]:printa
[111,333,444]
And,wecandeleteanattributefromaninstance.Example:
In[17]:classA:
....:pass
....:
In[18]:a=A()
In[19]:a.x=123
In[20]:dir(a)
Out[20]:['__doc__','__module__','x']
In[21]:printa.x
123
In[22]:dela.x
In[23]:dir(a)
Out[23]:['__doc__','__module__']
In[24]:printa.x

exceptions.AttributeErrorTraceback(mostrecentcalllast)

Page54
APythonBook

/home/dkuhlman/a1/Python/Test/<console>

AttributeError:Ainstancehasnoattribute'x'

1.6.12casestatement
ThereisnocasestatementinPython.Usetheif:statementwithasequenceofelif:
clauses.Or,useadictionaryoffunctions.

1.7Functions,Modules,Packages,andDebugging

1.7.1Functions

1.7.1.1Thedefstatement
Thedefstatementisusedtodefinefunctionsandmethods.
Thedefstatementisevaluated.Itproducesafunction/method(object)andbindsittoa
variableinthecurrentnamespace.
Althoughthedefstatementisevaluated,thecodeinitsnestedblockisnotexecuted.
Therefore,manyerrorsmaynotbedetecteduntileachandeverypaththroughthatcodeis
tested.Recommendations:(1)UseaPythoncodechecker,forexampleflake8or
pylint;(2)DothoroughtestingandusethePythonunittestframework.Pythonic
wisdom:Ifit'snottested,it'sbroken.

1.7.1.2Returningvalues
Thereturnstatementisusedtoreturnvaluesfromafunction.
Thereturnstatementtakeszeroormorevalues,separatedbycommas.Usingcommas
actuallyreturnsasingletuple.
ThedefaultvalueisNone.
Toreturnmultiplevalues,useatupleorlist.Don'tforgetthat(assignment)unpacking
canbeusedtocapturemultiplevalues.Returningmultipleitemsseparatedbycommasis
equivalenttoreturningatuple.Example:
In[8]:deftest(x,y):
...:returnx*3,y*4
...:
In[9]:a,b=test(3,4)
In[10]:printa
9

Page55
APythonBook

In[11]:printb
16

1.7.1.3Parameters
DefaultvaluesExample:
In[53]:deft(max=5):
....:forvalinrange(max):
....:printval
....:
....:
In[54]:t(3)
0
1
2
In[55]:t()
0
1
2
3
4
Givingaparameteradefaultvaluemakesthatparameteroptional.
Note:Ifafunctionhasaparameterwithadefaultvalue,thenall"normal"arguments
mustproceedtheparameterswithdefaultvalues.Morecompletely,parametersmustbe
givenfromlefttorightinthefollowingorder:
1. Normalarguments.
2. Argumentswithdefaultvalues.
3. Argumentlist(*args).
4. Keywordarguments(**kwargs).
Listparameters*args.It'satuple.
Keywordparameters**kwargs.It'sadictionary.

1.7.1.4Arguments
Whencallingafunction,valuesmaybepassedtoafunctionwithpositionalargumentsor
keywordarguments.
Positionalargumentsmustplacedbefore(totheleftof)keywordarguments.
Passingliststoafunctionasmultipleargumentssome_func(*aList).Effectively,
thissyntaxcausesPythontounrollthearguments.Example:
deffn1(*args,**kwargs):
fn2(*args,**kwargs)

Page56
APythonBook

1.7.1.5Localvariables
CreatinglocalvariablesAnybindingoperationcreatesalocalvariable.Examplesare
(1)parametersofafunction;(2)assignmenttoavariableinafunction;(3)theimport
statement;(4)etc.Contrastwithaccessingavariable.
VariablelookupTheLGB/LEGBruleThelocal,enclosing,global,builtinscopes
aresearchedinthatorder.See:http://www.python.org/dev/peps/pep0227/
TheglobalstatementInsideafunction,wemustuseglobalwhenwewanttoset
thevalueofaglobalvariable.Example:
deffn():
globalSome_global_variable,Another_global_variable
Some_global_variable='hello'
...

1.7.1.6Otherthingstoknowaboutfunctions
FunctionsarefirstclassYoucanstoretheminastructure,passthemtoa
function,andreturnthemfromafunction.
Functioncallscantakekeywordarguments.Example:
>>>test(size=25)
Formalparameterstoafunctioncanhavedefaultvalues.Example:
>>>deftest(size=0):
...
Donotusemutableobjectsasdefaultvalues.
Youcan"capture"remainingargumentswith*args,and**kwargs.(Spelling
isnotsignificant.)Example:
In[13]:deftest(size,*args,**kwargs):
....:printsize
....:printargs
....:printkwargs
....:
....:
In[14]:test(32,'aa','bb',otherparam='xyz')
32
('aa','bb')
{'otherparam':'xyz'}
Normalargumentsmustcomebeforedefaultargumentswhichmustcomebefore
keywordarguments.
Afunctionthatdoesnotexplicitlyreturnavalue,returnsNone.
Inordertosetthevalueofaglobalvariable,declarethevariablewithglobal.
Exercises:

Page57
APythonBook

Writeafunctionthattakesasingleargument,printsthevalueoftheargument,
andreturnstheargumentasastring.Solution:
>>>deft(x):
...print'x:%s'%x
...return'[[%s]]'%x
...
>>>t(3)
x:3
'[[3]]'
Writeafunctionthattakesavariablenumberofargumentsandprintsthemall.
Solution:
>>>deft(*args):
...forarginargs:
...print'arg:%s'%arg
...
>>>t('aa','bb','cc')
arg:aa
arg:bb
arg:cc
Writeafunctionthatprintsthenamesandvaluesofkeywordargumentspassedto
it.Solution:
>>>deft(**kwargs):
...forkeyinkwargs.keys():
...print'key:%svalue:%s'%(key,
kwargs[key],)
...
>>>t(arg1=11,arg2=22)
key:arg1value:11
key:arg2value:22

1.7.1.7Globalvariablesandtheglobalstatement
Bydefault,assignmentinafunctionormethodcreateslocalvariables.
Reference(notassignment)toavariable,accessesalocalvariableifithasalreadybeen
created,elseaccessesaglobalvariable.
Inordertoassignavaluetoaglobalvariable,declarethevariableasglobalatthe
beginningofthefunctionormethod.
Ifinafunctionormethod,youbothreferenceandassigntoavariable,thenyoumust
either:
1. Assigntothevariablefirst,or
2. Declarethevariableasglobal.
Theglobalstatementdeclaresoneormorevariables,separatedbycommas,tobe
global.

Page58
APythonBook

Someexamples:
In[1]:
In[1]:X=3
In[2]:deft():
...:printX
...:
In[3]:
In[3]:t()
3
In[4]:defs():
...:X=4
...:
In[5]:
In[5]:
In[5]:s()
In[6]:t()
3
In[7]:X=1
In[8]:defu():
...:globalX
...:X=5
...:
In[9]:
In[9]:u()
In[10]:t()
5
In[16]:defv():
....:x=X
....:X=6
....:returnx
....:
In[17]:
In[17]:v()

Traceback(mostrecentcalllast):
File"<ipythonconsole>",line1,in<module>
File"<ipythonconsole>",line2,inv
UnboundLocalError:localvariable'X'referencedbeforeassignment
In[18]:defw():
....:globalX
....:x=X
....:X=7
....:returnx
....:
In[19]:
In[19]:w()
Out[19]:5
In[20]:X
Out[20]:7

Page59
APythonBook

1.7.1.8Docstringsforfunctions
Adddocstringsasatriplequotedstringbeginningwiththefirstlineofafunctionor
method.Seeepydocforasuggestedformat.

1.7.1.9Decoratorsforfunctions
Adecoratorperformsatransformationonafunction.Examplesofdecoratorsthatare
builtinfunctionsare:@classmethod,@staticmethod,and@property.See:
http://docs.python.org/2/library/functions.html#builtinfunctions
Adecoratorisappliedusingthe"@"characteronalineimmediatelypreceedingthe
functiondefinitionheader.Examples:
classSomeClass(object):

@classmethod
defHelloClass(cls,arg):
pass
##HelloClass=classmethod(HelloClass)

@staticmethod
defHelloStatic(arg):
pass
##HelloStatic=staticmethod(HelloStatic)

#
#Define/implementadecorator.
defwrapper(fn):
definner_fn(*args,**kwargs):
print'>>'
result=fn(*args,**kwargs)
print'<<'
returnresult
returninner_fn

#
#Applyadecorator.
@wrapper
deffn1(msg):
pass
##fn1=wrapper(fn1)
Notes:
Thedecoratorform(withthe"@"character)isequivalenttotheform
(commentedout)thatcallsthedecoratorfunctionexplicitly.
Theuseofclassmethodsandstaticmethodwillbeexplainedlaterinthe
sectiononobjectorientedprogramming.
Adecoratorisimplementedasafunction.Therefore,tolearnaboutsomespecific

Page60
APythonBook

decorator,youshouldsearchforthedocumentationonortheimplementationof
thatfunction.Rememberthatinordertouseafunction,itmustbedefinedinthe
currentmoduleorimportedbythecurrentmoduleorbeabuiltin.
Theformthatexplicitlycallsthedecoratorfunction(commentedoutinthe
exampleabove)isequivalenttotheformusingthe"@"character.

1.7.2lambda
Usealambda,asaconvenience,whenyouneedafunctionthatboth:
isanonymous(doesnotneedaname)and
containsonlyanexpressionandnostatements.
Example:
In[1]:fn=lambdax,y,z:(x**2)+(y*2)+z
In[2]:fn(4,5,6)
Out[2]:32
In[3]:
In[3]:format=lambdaobj,category:'The"%s"isa"%s".'%(obj,
category,)
In[4]:format('pinetree','conifer')
Out[4]:'The"pinetree"isa"conifer".'
Alambdacantakemultipleargumentsandcanreturn(likeafunction)multiplevalues.
Example:
In[79]:a=lambdax,y:(x*3,y*4,(x,y))
In[80]:
In[81]:a(3,4)
Out[81]:(9,16,(3,4))
Suggestion:Insomecases,alambdamaybeusefulasaneventhandler.
Example:
classTest:
def__init__(self,first='',last=''):
self.first=first
self.last=last
deftest(self,formatter):
"""
Testforlambdas.
formatterisafunctiontaking2arguments,firstandlast
names.Itshouldreturntheformattedname.
"""
msg='Mynameis%s'%(formatter(self.first,self.last),)
printmsg

deftest():
t=Test('Dave','Kuhlman')

Page61
APythonBook

t.test(lambdafirst,last:'%s%s'%(first,last,))
t.test(lambdafirst,last:'%s,%s'%(last,first,))

test()
Alambdaenablesustodefine"functions"wherewedonotneednamesforthose
functions.Example:
In[45]:a=[
....:lambdax:x,
....:lambdax:x*2,
....:]
In[46]:
In[46]:a
Out[46]:[<function__main__.<lambda>>,<function__main__.<lambda>>]
In[47]:a[0](3)
Out[47]:3
In[48]:a[1](3)
Out[48]:6
Reference:http://docs.python.org/2/reference/expressions.html#lambda

1.7.3Iteratorsandgenerators
Concepts:
iterator
Anditeratorissomethingthatsatisfiestheiteratorprotocol.Clue:Ifit'saniterator,
youcanuseitinafor:statement.
generator
Ageneratorisaclassorfunctionthatimplementsaniterator,i.e.thatimplementsthe
iteratorprotocol.
theiteratorprotocol
Anobjectsatisfiestheiteratorprotocolifitdoesthefollowing:
Itimplementsa__iter__method,whichreturnsaniteratorobject.
Itimplementsanextfunction,whichreturnsthenextitemfromthe
collection,sequence,stream,etcofitemstobeiteratedover
ItraisestheStopIterationexceptionwhentheitemsareexhaustedand
thenext()methodiscalled.
yield
Theyieldstatementenablesustowritefunctionsthataregenerators.Such
functionsmaybesimilartocoroutines,sincetheymay"yield"multipletimesandare
resumed.

Page62
APythonBook

Formoreinformationoniterators,seethesectiononiteratortypesinthePythonLibrary
Referencehttp://docs.python.org/2/library/stdtypes.html#iteratortypes.
Formoreontheyieldstatement,see:
http://docs.python.org/2/reference/simple_stmts.html#theyieldstatement
Actually,yieldisanexpression.Formoreonyieldexpressionsandonthenext()
andsend()generatormethods,aswellasothers,see:Yieldexpression
http://docs.python.org/2/reference/expressions.html#yieldexpressionsinthePython
languagereferencemanual.
Afunctionormethodcontainingayieldstatementimplementsagenerator.Addingthe
yieldstatementtoafunctionormethodturnsthatfunctionormethodintoonewhich,
whencalled,returnsagenerator,i.e.anobjectthatimplementstheiteratorprotocol.
Agenerator(afunctioncontainingyield)providesaconvenientwaytoimplementa
filter.But,alsoconsider:
Thefilter()builtinfunction
Listcomprehensionswithanifclause
Hereareafewexamples:
defsimplegenerator():
yield'aaa'#Note1
yield'bbb'
yield'ccc'

deflist_tripler(somelist):
foriteminsomelist:
item*=3
yielditem

deflimit_iterator(somelist,max):
foriteminsomelist:
ifitem>max:
return#Note2
yielditem

deftest():
print'1.',''*30
it=simplegenerator()
foriteminit:
printitem
print'2.',''*30
alist=range(5)
it=list_tripler(alist)
foriteminit:
printitem
print'3.',''*30
alist=range(8)

Page63
APythonBook

it=limit_iterator(alist,4)
foriteminit:
printitem
print'4.',''*30
it=simplegenerator()
try:
printit.next()#Note3
printit.next()
printit.next()
printit.next()
exceptStopIteration,exp:#Note4
print'reachedendofsequence'

if__name__=='__main__':
test()
Notes:
1. Theyieldstatementreturnsavalue.Whenthenextitemisrequestedandthe
iteratoris"resumed",executioncontinuesimmediatelyaftertheyield
statement.
2. Wecanterminatethesequencegeneratedbyaniteratorbyusingareturn
statementwithnovalue.
3. Toresumeagenerator,usethegenerator'snext()orsend()methods.
send()islikenext(),butprovidesavaluetotheyieldexpression.
4. Wecanalternativelyobtaintheitemsinasequencebycallingtheiterator's
next()method.Sinceaniteratorisafirstclassobject,wecansaveitinadata
structureandcanpassitaroundforuseatdifferentlocationsandtimesinour
program.
1. Whenaniteratorisexhaustedorempty,itthrowstheStopIteration
exception,whichwecancatch.
Andhereistheoutputfromrunningtheaboveexample:
$pythontest_iterator.py
1.
aaa
bbb
ccc
2.
0
3
6
9
12
3.
0
1
2
3

Page64
APythonBook

4
4.
aaa
bbb
ccc
reachedendofsequence
Aninstanceofaclasswhichimplementsthe__iter__method,returninganiterator,is
iterable.Forexample,itcanbeusedinaforstatementorinalistcomprehension,orin
ageneratorexpression,orasanargumenttotheiter()builtinmethod.But,notice
thattheclassmostlikelyimplementsageneratormethodwhichcanbecalleddirectly.
ExamplesThefollowingcodeimplementsaniteratorthatproducesalltheobjectsina
treeofobjects:
classNode:
def__init__(self,data,children=None):
self.initlevel=0
self.data=data
ifchildrenisNone:
self.children=[]
else:
self.children=children
defset_initlevel(self,initlevel):self.initlevel=initlevel
defget_initlevel(self):returnself.initlevel
defaddchild(self,child):
self.children.append(child)
defget_data(self):
returnself.data
defget_children(self):
returnself.children
defshow_tree(self,level):
self.show_level(level)
print'data:%s'%(self.data,)
forchildinself.children:
child.show_tree(level+1)
defshow_level(self,level):
print''*level,
#
#Generatormethod#1
#Thisgeneratorturnsinstancesofthisclassintoiterable
objects.
#
defwalk_tree(self,level):
yield(level,self,)
forchildinself.get_children():
forlevel1,tree1inchild.walk_tree(level+1):
yieldlevel1,tree1
def__iter__(self):
returnself.walk_tree(self.initlevel)

Page65
APythonBook

#
#Generatormethod#2
#Thisgeneratorusesasupportfunction(walk_list)whichcalls
#thisfunctiontorecursivelywalkthetree.
#Ifeffect,thisiteratesoverthesupportfunction,which
#iteratesoverthisfunction.
#
defwalk_tree(tree,level):
yield(level,tree)
forchildinwalk_list(tree.get_children(),level+1):
yieldchild

defwalk_list(trees,level):
fortreeintrees:
fortreeinwalk_tree(tree,level):
yieldtree

#
#Generatormethod#3
#Thisgeneratorislikemethod#2,butcallsitself(asan
iterator),
#ratherthancallingasupportfunction.
#
defwalk_tree_recur(tree,level):
yield(level,tree,)
forchildintree.get_children():
forlevel1,tree1inwalk_tree_recur(child,level+1):
yield(level1,tree1,)

defshow_level(level):
print''*level,

deftest():
a7=Node('777')
a6=Node('666')
a5=Node('555')
a4=Node('444')
a3=Node('333',[a4,a5])
a2=Node('222',[a6,a7])
a1=Node('111',[a2,a3])
initLevel=2
a1.show_tree(initLevel)
print'='*40
forlevel,iteminwalk_tree(a1,initLevel):
show_level(level)
print'item:',item.get_data()
print'='*40
forlevel,iteminwalk_tree_recur(a1,initLevel):
show_level(level)
print'item:',item.get_data()

Page66
APythonBook

print'='*40
a1.set_initlevel(initLevel)
forlevel,itemina1:
show_level(level)
print'item:',item.get_data()
iter1=iter(a1)
printiter1
printiter1.next()
printiter1.next()
printiter1.next()
printiter1.next()
printiter1.next()
printiter1.next()
printiter1.next()
##printiter1.next()
returna1

if__name__=='__main__':
test()
Notes:
AninstanceofclassNodeis"iterable".Itcanbeuseddirectlyinafor
statement,alistcomprehension,etc.So,forexample,whenaninstanceofNode
isusedinaforstatement,itproducesaniterator.
WecouldalsocalltheNode.walk_methoddirectlytoobtainaniterator.
MethodNode.walk_treeandfunctionswalk_treeand
walk_tree_recuraregenerators.Whencalled,theyreturnaniterator.They
dothisbecausetheyeachcontainayieldstatement.
Thesemethods/functionsarerecursive.Theycallthemselves.Sincetheyare
generators,theymustcallthemselvesinacontextthatusesaniterator,for
exampleinaforstatement.

1.7.4Modules
AmoduleisaPythonsourcecodefile.
Amodulecanbeimported.Whenimported,themoduleisevaluated,andamoduleobject
iscreated.Themoduleobjecthasattributes.Thefollowingattributesareofspecial
interest:
__doc__Thedocstringofthemodule.
__name__Thenameofthemodulewhenthemoduleisimported,butthe
string"__main__"whenthemoduleisexecuted.
Othernamesthatarecreated(bound)inthemodule.
Amodulecanberun.
Tomakeamodulebothimportableandrunable,usethefollowingidiom(attheendof

Page67
APythonBook

themodule):
defmain():
o
o
o

if__name__=='__main__':
main()
WherePythonlooksformodules:
Seesys.path.
Standardplaces.
EnvironmentvariablePYTHONPATH.
Notesaboutmodulesandobjects:
Amoduleisanobject.
Amodule(object)canbeshared.
Aspecificmoduleisimportedonlyonceinasinglerun.Thismeansthatasingle
moduleobjectissharedbyallthemodulesthatimportit.

1.7.4.1Docstringsformodules
Adddocstringsasatriplequotedstringatornearthetopofthefile.Seeepydocfora
suggestedformat.

1.7.5Packages
Apackageisadirectoryonthefilesystemwhichcontainsafilenamed__init__.py.
The__init__.pyfile:
Whyisitthere?Itmakesmodulesinthedirectory"importable".
Can__init__.pybeempty?Yes.Or,justincludeacomment.
Whenisitevaluated?Itisevaluatedthefirsttimethatanapplicationimports
anythingfromthatdirectory/package.
Whatcanyoudowithit?Anycodethatshouldbeexecutedexactlyonceand
duringimport.Forexample:
Performinitializationneededbythepackage.
Makevariables,functions,classes,etcavailable.Forexample,whenthe
packageisimportedratherthanmodulesinthepackage.Youcanalsoexpose
objectsdefinedinmodulescontainedinthepackage.
Defineavariablenamed__all__tospecifythelistofnamesthatwillbe
importedbyfrommy_packageimport*.Forexample,ifthefollowingis
presentinmy_package/__init__.py:

Page68
APythonBook

__all__=['func1','func2',]
Then,frommy_packageimport*willimportfunc1andfunc2,but
notothernamesdefinedinmy_package.
Notethat__all__canbeusedatthemodulelevel,aswellasatthepackage
level.
Formoreinformation,seethesectiononpackagesinthePythontutorial:
http://docs.python.org/2/tutorial/modules.html#packages.
Guidanceandsuggestions:
"Flatisbetter"Usethe__init__.pyfiletopresenta"flat"viewoftheAPI
foryourcode.Enableyouruserstodoimportmypackageandthen
reference:
mypackage.item1
mypackage.item2
mypackage.item3
Etc.
Whereitem1,item2,etccomposetheAPIyouwantyouruserstouse,even
thoughtheimplementationoftheseitemsmaybeburieddeepinyourcode.
Usethe__init__.pymoduletopresenta"clean"API.Presentonlytheitems
thatyouintendyouruserstouse,andbydoingso,"hide"itemsyoudonotintend
themtouse.

1.8Classes
Classesmodelthebehaviorofobjectsinthe"real"world.Methodsimplementthe
behaviorsofthesetypesofobjects.Membervariableshold(current)state.Classesenable
ustoimplementnewdatatypesinPython.
Theclass:statementisusedtodefineaclass.Theclass:statementcreatesaclass
objectandbindsittoaname.

1.8.1Asimpleclass
In[104]:classA:
.....:pass
.....:
In[105]:a=A()
Todefineanewstyleclass(recommended),inheritfromobjectorfromanotherclass
thatdoes.Example:
In[21]:classA(object):
....:pass
....:

Page69
APythonBook

In[22]:
In[22]:a=A()
In[23]:a
Out[23]:<__main__.Aobjectat0x82fbfcc>

1.8.2Definingmethods
Amethodisafunctiondefinedinclassscopeandwithfirstparameterself:
In[106]:classB(object):
.....:defshow(self):
.....:print'hellofromB'
.....:
In[107]:b=B()
In[108]:b.show()
hellofromB
Amethodaswedescribeithereismoreproperlycalledaninstancemethod,inorderto
distinguishitfromclassmethodsandstaticmethods.

1.8.3Theconstructor
Theconstructorisamethodnamed__init__.
Exercise:Defineaclasswithamembervariablenameandashowmethod.Useprint
toshowthename.Solution:
In[109]:classA(object):
.....:def__init__(self,name):
.....:self.name=name
.....:defshow(self):
.....:print'name:"%s"'%self.name
.....:
In[111]:a=A('dave')
In[112]:a.show()
name:"dave"
Notes:
Theselfvariableisexplicit.Itreferencesthecurrentobject,thatistheobject
whosemethodiscurrentlyexecuting.
Thespelling("self")isoptional,buteveryonespellsitthatway.

1.8.4Membervariables
DefiningmembervariablesMembervariablesarecreatedwithassignment.Example:
classA(object):
def__init__(self,name):

Page70
APythonBook

self.name=name
AsmallgotchaDothis:
In[28]:classA(object):
....:def__init__(self,items=None):
....:ifitemsisNone:
....:self.items=[]
....:else:
....:self.items=items
Donotdothis:
In[29]:classB:
....:def__init__(self,items=[]):#wrong.listctor
evaluatedonlyonce.
....:self.items=items
Inthesecondexample,thedefstatementandthelistconstructorareevaluatedonly
once.Therefore,theitemmembervariableofallinstancesofclassB,willsharethesame
value,whichismostlikelynotwhatyouwant.

1.8.5Callingmethods
Usetheinstanceandthedotoperator.
Callingamethoddefinedinthesameclassorasuperclass:
FromoutsidetheclassUsetheinstance:
some_object.some_method()
an_array_of_of_objects[1].another_method()
FromwithinthesameclassUseself:
self.a_method()
Fromwithasubclasswhenthemethodisinthesuperclassandthereisa
methodwiththesamenameinthecurrentclassUsetheclass(name)oruse
super:
SomeSuperClass.__init__(self,arg1,arg2)
super(CurrentClass,
self).__init__(arg1,arg2)
CallingamethoddefinedinaspecificsuperclassUsetheclass(name).

1.8.6Addinginheritance
ReferencingsuperclassesUsethebuiltinsuperortheexplicitnameofthe
superclass.Useofsuperispreferred.Forexample:
In[39]:classB(A):

Page71
APythonBook

....:def__init__(self,name,size):
....:super(B,self).__init__(name)
....:#A.__init__(self,name)#anolderalternative
form
....:self.size=size
Theuseofsuper()maysolveproblemssearchingforthebaseclasswhenusing
multipleinheritance.Abettersolutionistonotusemultipleinheritance.
Youcanalsousemultipleinheritance.But,itcancauseconfusion.Forexample,inthe
following,classCinheritsfrombothAandB:
classC(A,B):
...
PythonsearchessuperclassesMRO(methodresolutionorder).Ifonlysingleinheritance
isinvolved,thereislittleconfusion.Ifmultipleinheritanceisbeingused,thesearchorder
ofsuperclassescangetcomplexseehere:
http://www.python.org/download/releases/2.3/mro
Formoreinformationoninheritance,seethetutorialinthestandardPython
documentationset:9.5Inheritanceand9.5.1MultipleInheritance.
Watchoutforproblemswithinheritingfrommultipleclassesthathaveacommonbase
class.

1.8.7Classvariables
Alsocalledstaticdata.
Aclassvariableissharedbyinstancesoftheclass.
Defineatclasslevelwithassignment.Example:
classA(object):
size=5
defget_size(self):
returnA.size
Referencewithclassname.variable.
Caution:self.variable=xcreatesanewmembervariable.

1.8.8Classmethodsandstaticmethods
Instance(plain)methods:
Aninstancemethodreceivestheinstanceasitsfirstargument.
Classmethods:
Aclassmethodreceivestheclassasitsfirstargument.
Defineclassmethodswithbuiltinfunctionclassmethod()orwithdecorator

Page72
APythonBook

@classmethod.
Seethedescriptionofclassmethod()builtinfunctionat"Builtin
Functions":http://docs.python.org/2/library/functions.html#classmethod
Staticmethods:
Astaticmethodreceivesneithertheinstancenortheclassasitsfirstargument.
Definestaticmethodswithbuiltinfunctionstaticmethod()orwith
decorator@staticmethod.
Seethedescriptionofstaticmethod()builtinfunctionat"Builtin
Functions":http://docs.python.org/2/library/functions.html#staticmethod
Notesondecorators:
Adecoratoroftheform@afuncisthesameasm=afunc(m).So,this:
@afunc
defm(self):pass
isthesameas:
defm(self):pass
m=afunc(m)
Youcanusedecorators@classmethodand@staticmethod(insteadofthe
classmethod()andstaticmethod()builtinfunctions)todeclareclass
methodsandstaticmethods.
Example:
classB(object):

Count=0

defdup_string(x):
s1='%s%s'%(x,x,)
returns1
dup_string=staticmethod(dup_string)

@classmethod
defshow_count(cls,msg):
print'%s%d'%(msg,cls.Count,)

deftest():
printB.dup_string('abcd')
B.show_count('hereisthecount:')
Analternativewaytoimplement"staticmethods"Usea"plain",modulelevel
function.Forexample:
In[1]:definc_count():
...:A.count+=1
...:
In[2]:

Page73
APythonBook

In[2]:defdec_count():
...:A.count=1
...:
In[3]:
In[3]:classA:
...:count=0
...:defget_count(self):
...:returnA.count
...:
In[4]:
In[4]:a=A()
In[5]:a.get_count()
Out[5]:0
In[6]:
In[6]:
In[6]:inc_count()
In[7]:inc_count()
In[8]:a.get_count()
Out[8]:2
In[9]:
In[9]:b=A()
In[10]:b.get_count()
Out[10]:2

1.8.9Properties
Thepropertybuiltinfunctionenablesustowriteclassesinawaythatdoesnotrequirea
useroftheclasstousegettersandsetters.Example:
classTestProperty(object):
def__init__(self,description):
self._description=description
def_set_description(self,description):
print'settingdescription'
self._description=description
def_get_description(self):
print'gettingdescription'
returnself._description
description=property(_get_description,_set_description)
Thepropertybuiltinfunctionisalsoadecorator.So,thefollowingisequivalentto
theaboveexample:
classTestProperty(object):
def__init__(self,description):
self._description=description

@property
defdescription(self):
print'gettingdescription'
returnself._description

Page74
APythonBook

@description.setter
defdescription(self,description):
print'settingdescription'
self._description=description
Notes:
Wemarktheinstancevariableasprivatebyprefixingitwithandunderscore.
Thenameoftheinstancevariableandthenameofthepropertymustbedifferent.
Iftheyarenot,wegetrecursionandanerror.
Formoreinformationonproperties,seeBuiltinFunctionsproperties
http://docs.python.org/2/library/functions.html#property

1.8.10Interfaces
InPython,toimplementaninterfaceistoimplementamethodwithaspecificnameanda
specificarguments.
"Ducktyping"Ifitwalkslikeaduckandquackslikeaduck...
Onewaytodefinean"interface"istodefineaclasscontainingmethodsthathavea
headerandadocstringbutnoimplementation.
Additionalnotesoninterfaces:
Interfacesarenotenforced.
Aclassdoesnothavetoimplementallofaninterface.

1.8.11Newstyleclasses
Anewstyleclassisonethatsubclassesobjectoraclassthatsubclassesobject(that
is,anothernewstyleclass).
YoucansubclassPython'sbuiltindatatypes.
Asimpleexamplethefollowingclassextendsthelistdatatype:
classC(list):
defget_len(self):
returnlen(self)

c=C((11,22,33))
c.get_len()

c=C((11,22,33,44,55,66,77,88))
printc.get_len()
#Prints"8".
Aslightlymorecomplexexamplethefollowingclassextendsthedictionary

Page75
APythonBook

datatype:
classD(dict):
def__init__(self,data=None,name='no_name'):
ifdataisNone:
data={}
dict.__init__(self,data)
self.name=name
defget_len(self):
returnlen(self)
defget_keys(self):
content=[]
forkeyinself:
content.append(key)
contentstr=','.join(content)
returncontentstr
defget_name(self):
returnself.name

deftest():
d=D({'aa':111,'bb':222,'cc':333})
#Prints"3"
printd.get_len()
#Prints"'aa,cc,bb'"
printd.get_keys()
#Prints"no_name"
printd.get_name()
Somethingstorememberaboutnewstyleclasses:
Inordertobenewstyle,aclassmustinherit(directlyorindirectly)from
object.Notethatifyouinheritfromabuiltintype,yougetthisautomatically.
Newstyleclassesunifytypesandclasses.
Youcansubclass(builtin)typessuchasdict,str,list,file,etc.
Thebuiltintypesnowprovidefactoryfunctions:dict(),str(),int(),
file(),etc.
ThebuiltintypesareintrospectableUsex.__class__,
dir(x.__class__),isinstance(x,list),etc.
Newstyleclassesgiveyoupropertiesanddescriptors.
Newstyleclassesenableyoutodefinestaticmethods.Actually,allclassesenable
youtodothis.
Anewstyleclassisauserdefinedtype.Foraninstanceofanewstyleclassx,
type(x)isthesameasx.__class__.
Formoreonnewstyleclasses,see:http://www.python.org/doc/newstyle/
Exercises:
Writeaclassandasubclassofthisclass.
Givethesuperclassonemembervariable,aname,whichcanbeenteredwhen

Page76
APythonBook

aninstanceisconstructed.
Givethesubclassonemembervariable,adescription;thesubclassconstructor
shouldallowentryofbothnameanddescription.
Putashow()methodinthesuperclassandoverridetheshow()methodin
thesubclass.
Solution:
classA(object):
def__init__(self,name):
self.name=name
defshow(self):
print'name:%s'%(self.name,)

classB(A):
def__init__(self,name,desc):
A.__init__(self,name)
self.desc=desc
defshow(self):
A.show(self)
print'desc:%s'%(self.desc,)

1.8.12Docstringsforclasses
Adddocstringsasa(triplequoted)stringbeginningwiththefirstlineofaclass.See
epydocforasuggestedformat.

1.8.13Privatemembers
Addanleadingunderscoretoamembername(methodordatavariable)to"suggest"that
thememberisprivate.

1.9SpecialTasks

1.9.1Debuggingtools
pdbThePythondebugger:
Startthedebuggerbyrunninganexpression:
pdb.run('expression')
Example:
if__name__=='__main__':
importpdb
pdb.run('main()')
Startupthedebuggerataspecificlocationwiththefollowing:

Page77
APythonBook

importpdb;pdb.set_trace()
Example:
if__name__=='__main__':
importpdb
pdb.set_trace()
main()
Gethelpfromwithinthedebugger.Forexample:
(Pdb)help
(Pdb)helpnext
CanalsoembedIPythonintoyourcode.See
http://ipython.scipy.org/doc/manual/manual.html.
ipdbAlsoconsiderusingipdb(andIPython).Theipdbdebuggerinteractive
prompthassomeadditionalfeatures,forexample,itdoestabnamecompletion.
Inspecting:
importinspect
Seehttp://docs.python.org/lib/moduleinspect.html.
Don'tforgettotrydir(obj)andtype(obj)andhelp(obj),first.
Miscellaneoustools:
id(obj)
globals()andlocals().
dir(obj)Returnsinterestingnames,butlistisnotnecessarilycomplete.
obj.__class__
cls.__bases__
obj.__class__.__bases__
obj.__doc__.Butusually,help(obj)isbetter.Itproducesthedocstring.
Customizetherepresentationofyourclass.Definethefollowingmethodsinyour
class:
__repr__()Calledby(1)repr(),(2)interactiveinterpreterwhen
representationisneeded.
__str__()Calledby(1)str(),(2)stringformatting.
pdbisimplementedwiththecmdmoduleinthePythonstandardlibrary.Youcan
implementsimilarcommandlineinterfacesbyusingcmd.See:cmdSupportfor
lineorientedcommandinterpretershttp://docs.python.org/lib/modulecmd.html.

1.9.2Fileinputandoutput
Createafileobject.Useopen().
Thisexamplereadsandprintseachlineofafile:

Page78
APythonBook

deftest():
f=file('tmp.py','r')
forlineinf:
print'line:',line.rstrip()
f.close()

test()
Notes:
Atextfileisaniterable.Ititeratesoverthelinesinafile.Thefollowingisa
commonidiom:
infile=file(filename,'r')
forlineininfile:
process_a_line(line)
infile.close()
string.rstrip()stripsnewlineandotherwhitespacefromtherightsideof
eachline.Tostripnewlinesonly,butnototherwhitespace,tryrstrip('\n').
Otherwaysofreadingfromafile/streamobject:my_file.read(),
my_file.readline(),my_file.readlines(),
Thisexamplewriteslinesoftexttoafile:
deftest():
f=file('tmp.txt','w')
forchin'abcdefg':
f.write(ch*10)
f.write('\n')
f.close()

test()
Notes:
Thewritemethod,unliketheprintstatement,doesnotautomaticallyadd
newlinecharacters.
Mustclosefileinordertoflushoutput.Or,usemy_file.flush().
And,don'tforgetthewith:statement.Itmakesclosingfilesautomatic.Thefollowing
exampleconvertsallthevowelsinaninputfiletouppercaseandwritestheconverted
linestoanoutputfile:
importstring

defshow_file(infilename,outfilename):
tran_table=string.maketrans('aeiou','AEIOU')
withopen(infilename,'r')asinfile,open(outfilename,'w')as
outfile:
forlineininfile:
line=line.rstrip()
outfile.write('%s\n'%line.translate(tran_table))

Page79
APythonBook

1.9.3Unittests
Formoredocumentationontheunittestframework,seeunittestUnittesting
frameworkhttp://docs.python.org/2/library/unittest.html#moduleunittest
ForhelpandmoreinformationdothefollowingatthePythoninteractiveprompt:
>>>importunittest
>>>help(unittest)
And,youcanreadthesource:Lib/unittest.pyinthePythonstandardlibrary.

1.9.3.1Asimpleexample
Hereisaverysimpleexample.Youcanfindmoreinformationaboutthisprimitiveway
ofstructuringunittestsinthelibrarydocumentationfortheunittestmoduleBasic
examplehttp://docs.python.org/lib/minimalexample.html
importunittest

classUnitTests02(unittest.TestCase):

deftestFoo(self):
self.failUnless(False)

classUnitTests01(unittest.TestCase):

deftestBar01(self):
self.failUnless(False)

deftestBar02(self):
self.failUnless(False)

defmain():
unittest.main()

if__name__=='__main__':
main()
Notes:
Thecalltounittest.main()runsalltestsinalltestfixturesinthemodule.It
actuallycreatesaninstanceofclassTestPrograminmodule
Lib/unittest.py,whichautomaticallyrunstests.
Testfixturesareclassesthatinheritfromunittest.TestCase.
Withinatestfixture(aclass),thetestsareanymethodswhosenamesbeginwith
theprefix"test".
Inanytest,wecheckforsuccessorfailurewithinheritedmethodssuchas
failIf(),failUnless(),assertNotEqual(),etc.Formoreonthese

Page80
APythonBook

methods,seethelibrarydocumentationfortheunittestmoduleTestCase
Objectshttp://docs.python.org/lib/testcaseobjects.html.
Ifyouwanttochange(1)thetestmethodprefixor(2)thefunctionusedtosort
(theorderof)executionoftestswithinatestfixture,thenyoucancreateyourown
instanceofclassunittest.TestLoaderandcustomizeit.Forexample:
defmain():
my_test_loader=unittest.TestLoader()
my_test_loader.testMethodPrefix='check'
my_test_loader.sortTestMethodsUsing=my_cmp_func
unittest.main(testLoader=my_test_loader)

if__name__=='__main__':
main()

But,seethenotesinsectionAdditionalunittestfeaturesforinstructionsona
(possibly)betterwaytodothis.

1.9.3.2Unittestsuites
Hereisanother,notquitesosimple,example:
#!/usr/bin/envpython

importsys,popen2
importgetopt
importunittest

classGenTest(unittest.TestCase):

deftest_1_generate(self):
cmd='python../generateDS.pyfoout2sup.pysout2sub.py
people.xsd'
outfile,infile=popen2.popen2(cmd)
result=outfile.read()
outfile.close()
infile.close()
self.failUnless(len(result)==0)

deftest_2_compare_superclasses(self):
cmd='diffout1sup.pyout2sup.py'
outfile,infile=popen2.popen2(cmd)
outfile,infile=popen2.popen2(cmd)
result=outfile.read()
outfile.close()
infile.close()
#print'len(result):',len(result)
#Ignorethedifferinglinescontainingthedate/time.
#self.failUnless(len(result)<130and
result.find('Generated')>1)

Page81
APythonBook

self.failUnless(check_result(result))

deftest_3_compare_subclasses(self):
cmd='diffout1sub.pyout2sub.py'
outfile,infile=popen2.popen2(cmd)
outfile,infile=popen2.popen2(cmd)
result=outfile.read()
outfile.close()
infile.close()
#Ignorethedifferinglinescontainingthedate/time.
#self.failUnless(len(result)<130and
result.find('Generated')>1)
self.failUnless(check_result(result))

defcheck_result(result):
flag1=0
flag2=0
lines=result.split('\n')
len1=len(lines)
iflen1<=5:
flag1=1
s1='\n'.join(lines[:4])
ifs1.find('Generated')>1:
flag2=1
returnflag1andflag2

#Makethetestsuite.
defsuite():
#Thefollowingisobsolete.SeeLib/unittest.py.
#returnunittest.makeSuite(GenTest)
loader=unittest.TestLoader()
#oralternatively
#loader=unittest.defaultTestLoader
testsuite=loader.loadTestsFromTestCase(GenTest)
returntestsuite

#Makethetestsuiteandrunthetests.
deftest():
testsuite=suite()
runner=unittest.TextTestRunner(sys.stdout,verbosity=2)
runner.run(testsuite)

USAGE_TEXT="""
Usage:
pythontest.py[options]
Options:
h,helpDisplaythishelpmessage.
Example:
pythontest.py

Page82
APythonBook

"""

defusage():
printUSAGE_TEXT
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=0:
usage()
test()

if__name__=='__main__':
main()
#importpdb
#pdb.run('main()')
Notes:
GenTestisourtestsuiteclass.Itinheritsfromunittest.TestCase.
EachmethodinGenTestwhosenamebeginswith"test"willberunasatest.
Thetestsareruninalphabeticorderbymethodname.
DefaultsinclassTestLoaderforthetestnameprefixandsortcomparison
functioncanbeoverridden.See5.3.8TestLoaderObjects
http://docs.python.org/lib/testloaderobjects.html.
AtestcaseclassmayalsoimplementmethodsnamedsetUp()and
tearDown()toberunbeforeandaftertests.See5.3.5TestCaseObjects
http://docs.python.org/lib/testcaseobjects.html.Actually,thefirsttestmethodin
ourexampleshould,perhaps,beasetUp()method.
Thetestsusecallssuchasself.failUnless()toreporterrors.Theseare
inheritedfromclassTestCase.See5.3.5TestCaseObjects
http://docs.python.org/lib/testcaseobjects.html.
Functionsuite()createsaninstanceofthetestsuite.
Functiontest()runsthetests.

1.9.3.3Additionalunittestfeatures
And,thefollowingexampleshowsseveraladditionalfeatures.Seethenotesthatfollow

Page83
APythonBook

thecode:
importunittest

classUnitTests02(unittest.TestCase):
deftestFoo(self):
self.failUnless(False)
defcheckBar01(self):
self.failUnless(False)

classUnitTests01(unittest.TestCase):
#Note1
defsetUp(self):
print'settingupUnitTests01'
deftearDown(self):
print'tearingdownUnitTests01'
deftestBar01(self):
print'testingtestBar01'
self.failUnless(False)
deftestBar02(self):
print'testingtestBar02'
self.failUnless(False)

deffunction_test_1():
name='mona'
assertnotname.startswith('mo')

defcompare_names(name1,name2):
ifname1<name2:
return1
elifname1>name2:
return1
else:
return0

defmake_suite():
suite=unittest.TestSuite()
#Note2
suite.addTest(unittest.makeSuite(UnitTests01,
sortUsing=compare_names))
#Note3
suite.addTest(unittest.makeSuite(UnitTests02,prefix='check'))
#Note4
suite.addTest(unittest.FunctionTestCase(function_test_1))
returnsuite

defmain():
suite=make_suite()
runner=unittest.TextTestRunner()
runner.run(suite)

if__name__=='__main__':

Page84
APythonBook

main()
Notes:
1. Ifyourunthiscode,youwillnoticethatthesetUpandtearDownmethodsin
classUnitTests01arerunbeforeandaftereachtestinthatclass.
2. Wecancontroltheorderinwhichtestsarerunbypassingacomparefunctionto
themakeSuitefunction.Thedefaultisthecmpbuiltinfunction.
3. Wecancontrolwhichmethodsinatestfixtureareselectedtoberunbypassing
theoptionalargumentprefixtothemakeSuitefunction.
4. Ifwehaveanexistingfunctionthatwewantto"wrap"andrunasaunittest,we
cancreateatestcasefromafunctionwiththeFunctionTestCasefunction.If
wedothat,noticethatweusetheassertstatementtotestandpossiblycause
failure.

1.9.3.4GuidanceonUnitTesting
Whyshouldweuseunittests?Manyreasons,including:
Withoutunittests,cornercasesmaynotbechecked.Thisisespeciallyimportant,
sincePythondoesrelativelylittlecompiletimeerrorchecking.
Unittestsfacilitateafrequentandshortdesignandimplementandrelease
developmentcycle.SeeONLamp.comExtremePython
http://www.onlamp.com/pub/a/python/2001/03/28/pythonnews.htmlandWhatis
XPhttp://www.xprogramming.com/what_is_xp.htm.
Designingthetestsbeforewritingthecodeis"agoodidea".
Additionalnotes:
Inatestclass,instancemethodssetUpandtearDownarerunautomatically
beforeeachandaftereachindividualtest.
Inatestclass,classmethodssetUpClassandtearDownClassarerun
automaticallyoncebeforeandafterallthetestsinaclass.
ModulelevelfunctionssetUpModuleandtearDownModulearerunbefore
andafteranytestsinamodule.
Insomecasesyoucanalsoruntestsdirectlyfromthecommandline.Dothe
followingforhelp:
$pythonmunittesthelp

1.9.4doctest
Forsimpletestharnesses,considerusingdoctest.Withdoctestyoucan(1)runa
testatthePythoninteractiveprompt,then(2)copyandpastethattestintoadocstringin
yourmodule,andthen(3)runthetestsautomaticallyfromwithinyourmoduleunder

Page85
APythonBook

doctest.
ThereareexamplesandexplanationinthestandardPythondocumentation:5.2doctest
TestinteractivePythonexampleshttp://docs.python.org/lib/moduledoctest.html.
Asimplewaytousedoctestinyourmodule:
1. RunseveraltestsinthePythoninteractiveinterpreter.Notethatbecause
doctestlooksfortheinterpreter's">>>"prompt,youmustusethestandard
interpreter,andnot,forexample,IPython.Also,makesurethatyouincludealine
withthe">>>"promptaftereachsetofresults;thisenablesdoctestto
determinetheextentofthetestresults.
2. Usecopyandpaste,toinsertthetestsandtheirresultsfromyourinteractive
sessionintothedocstrings.
3. Addthefollowingcodeatthebottomofyourmodule:
def_test():
importdoctest
doctest.testmod()

if__name__=="__main__":
_test()
Hereisanexample:
deff(n):
"""
Printsomethingfunny.

>>>f(1)
10
>>>f(2)
10
>>>f(3)
0
"""
ifn==1:
return10
elifn==2:
return10
else:
return0

deftest():
importdoctest,test_doctest
doctest.testmod(test_doctest)

if__name__=='__main__':
test()
And,hereistheoutputfromrunningtheabovetestwiththevflag:

Page86
APythonBook

$pythontest_doctest.pyv
Runningtest_doctest.__doc__
0of0examplesfailedintest_doctest.__doc__
Runningtest_doctest.f.__doc__
Trying:f(1)
Expecting:10
ok
Trying:f(2)
Expecting:10
ok
Trying:f(3)
Expecting:0
ok
0of3examplesfailedintest_doctest.f.__doc__
Runningtest_doctest.test.__doc__
0of0examplesfailedintest_doctest.test.__doc__
2itemshadnotests:
test_doctest
test_doctest.test
1itemspassedalltests:
3testsintest_doctest.f
3testsin3items.
3passedand0failed.
Testpassed.

1.9.5ThePythondatabaseAPI
PythondatabaseAPIdefinesastandardinterfaceforaccesstoarelationaldatabase.
InordertousethisAPIyoumustinstallthedatabaseadapter(interfacemodule)foryour
particulardatabase,e.g.PostgreSQL,MySQL,Oracle,etc.
YoucanlearnmoreaboutthePythonDBAPIhere:
http://www.python.org/dev/peps/pep0249/
Thefollowingsimpleexampleusessqlite3http://docs.python.org/2/library/sqlite3.html
#!/usr/bin/envpython

"""
Createarelationaldatabaseandatableinit.
Addsomerecords.
Readanddisplaytherecords.
"""

importsys
importsqlite3

defcreate_table(db_name):
con=sqlite3.connect(db_name)
cursor=con.cursor()
cursor.execute('''CREATETABLEplants

Page87
APythonBook

(nametext,desctext,catint)''')
cursor.execute(
'''INSERTINTOplantsVALUES('tomato','redandjuicy',
1)''')
cursor.execute(
'''INSERTINTOplantsVALUES('pepper','greenandcrunchy',
2)''')
cursor.execute('''INSERTINTOplantsVALUES('pepper','purple',
2)''')
con.commit()
con.close()

defretrieve(db_name):
con=sqlite3.connect(db_name)
cursor=con.cursor()
cursor.execute('''select*fromplants''')
rows=cursor.fetchall()
printrows
print''*40
cursor.execute('''select*fromplants''')
forrowincursor:
printrow
con.close()

deftest():
args=sys.argv[1:]
iflen(args)!=1:
sys.stderr.write('\nusage:test_db.py<db_name>\n\n')
sys.exit(1)
db_name=args[0]
create_table(db_name)
retrieve(db_name)

test()

1.9.6InstallingPythonpackages
Simple:
$pythonsetup.pybuild
$pythonsetup.pyinstall#asroot
Morecomplex:
LookforaREADMEorINSTALLfileattherootofthepackage.
Typethefollowingforhelp:
$pythonsetup.pycmdhelp
$pythonsetup.pyhelpcommands
$pythonsetup.pyhelp[cmd1cmd2...]
And,forevenmoredetails,seeInstallingPythonModules

Page88
APythonBook

http://docs.python.org/inst/inst.html
pipisbecomingpopularforinstallingandmanagingPythonpackages.See:
https://pypi.python.org/pypi/pip
Also,considerusingvirtualenv,especiallyifyoususpectorworrythatinstalling
somenewpackagewillalterthebehaviorofapackagecurrentlyinstalledonyour
machine.See:https://pypi.python.org/pypi/virtualenv.virtualenvcreatesadirectory
andsetsupaPythonenvironmentintowhichyoucaninstallandusePythonpackages
withoutchangingyourusualPythoninstallation.

1.10MorePythonFeaturesandExercises
[Astimepermits,explainmorefeaturesanddomoreexercisesasrequestedbyclass
members.]
ThankstoDavidGoodgerforthefollowinglistorreferences.His"CodeLikea
Pythonista:IdiomaticPython"
(http://python.net/~goodger/projects/pycon/2007/idiomatic/)isworthacarefulreading:
"PythonObjects",FredrikLundh,http://www.effbot.org/zone/pythonobjects.htm
"HowtothinklikeaPythonista",MarkHammond,
http://python.net/crew/mwh/hacks/objectthink.html
"Pythonmain()functions",GuidovanRossum,
http://www.artima.com/weblogs/viewpost.jsp?thread=4829
"PythonIdiomsandEfficiency",http://jaynes.colorado.edu/PythonIdioms.html
"Pythontrack:pythonidioms",
http://www.cs.caltech.edu/courses/cs11/material/python/misc/python_idioms.html
"BePythonic",ShalabhChaturvedi,http://shalabh.infogami.com/Be_Pythonic2
"PythonIsNotJava",PhillipJ.Eby,
http://dirtsimple.org/2004/12/pythonisnotjava.html
"WhatisPythonic?",MartijnFaassen,
http://faassen.ntree.net/blog/view/weblog/2005/08/06/0
"SortingMiniHOWTO",AndrewDalke,
http://wiki.python.org/moin/HowTo/Sorting
"PythonIdioms",http://www.gungfu.de/facts/wiki/Main/PythonIdioms
"PythonFAQs",http://www.python.org/doc/faq/

Page89
APythonBook

2Part2AdvancedPython

2.1IntroductionPython201(Slightly)AdvancedPythonTopics
Thisdocumentisintendedasnotesforacourseon(slightly)advancedPythontopics.

2.2RegularExpressions
Formorehelponregularexpressions,see:
reRegularexpressionoperationshttp://docs.python.org/library/re.html
RegularExpressionHOWTOhttp://docs.python.org/howto/regex.html

2.2.1Definingregularexpressions
Aregularexpressionpatternisasequenceofcharactersthatwillmatchsequencesof
charactersinatarget.
Thepatternsorregularexpressionscanbedefinedasfollows:
Literalcharactersmustmatchexactly.Forexample,"a"matches"a".
Concatenatedpatternsmatchconcatenatedtargets.Forexample,"ab"("a"
followedby"b")matches"ab".
Alternatepatterns(separatedbyaverticalbar)matcheitherofthealternative
patterns.Forexample,"(aaa)|(bbb)"willmatcheither"aaa"or"bbb".
Repeatingandoptionalitems:
"abc*"matches"ab"followedbyzeroormoreoccurancesof"c",forexample,
"ab","abc","abcc",etc.
"abc+"matches"ab"followedbyoneormoreoccurancesof"c",forexample,
"abc","abcc",etc,butnot"ab".
"abc?"matches"ab"followedbyzerooroneoccurancesof"c",forexample,
"ab"or"abc".
SetsofcharactersCharactersandsequencesofcharactersinsquarebrackets
formaset;asetmatchesanycharacterinthesetorrange.Forexample,"[abc]"
matches"a"or"b"or"c".And,forexample,"[_az09]"matchesanunderscore
oranylowercaseletteroranydigit.
GroupsParenthesesindicateagroupwithapattern.Forexample,"ab(cd)*ef"is
apatternthatmatches"ab"followedbyanynumberofoccurancesof"cd"
followedby"ef",forexample,"abef","abcdef","abcdcdef",etc.
Therearespecialnamesforsomesetsofcharacters,forexample"\d"(anydigit),

Page90
APythonBook

"\w"(anyalphanumericcharacter),"\W"(anynonalphanumericcharacter),etc.
Moremoreinformation,seePythonLibraryReference:RegularExpression
Syntaxhttp://docs.python.org/library/re.html#regularexpressionsyntax
Becauseoftheuseofbackslashesinpatterns,youareusuallybetteroffdefiningregular
expressionswithrawstrings,e.g.r"abc".

2.2.2Compilingregularexpressions
Whenaregularexpressionistobeusedmorethanonce,youshouldconsidercompiling
it.Forexample:
importsys,re

pat=re.compile('aa[bc]*dd')

while1:
line=raw_input('Enteraline("q"toquit):')
ifline=='q':
break
ifpat.search(line):
print'matched:',line
else:
print'nomatch:',line
Comments:
Weimportmodulereinordertouseregularexpresions.
re.compile()compilesaregularexpressionsothatwecanreusethe
compiledregularexpressionwithoutcompilingitrepeatedly.

2.2.3Usingregularexpressions
Usematch()tomatchatthebeginningofastring(ornotatall).
Usesearch()tosearchastringandmatchthefirststringfromtheleft.
Herearesomeexamples:
>>>importre
>>>pat=re.compile('aa[09]*bb')
>>>x=pat.match('aa1234bbccddee')
>>>x
<_sre.SRE_Matchobjectat0x401e9608>
>>>x=pat.match('xxxxaa1234bbccddee')
>>>x
>>>type(x)
<type'NoneType'>
>>>x=pat.search('xxxxaa1234bbccddee')
>>>x

Page91
APythonBook

<_sre.SRE_Matchobjectat0x401e9608>
Notes:
Whenamatchorsearchissuccessful,itreturnsamatchobject.Whenitfails,it
returnsNone.
Youcanalsocallthecorrespondingfunctionsmatchandsearchintheremodule,
e.g.:
>>>x=re.search(pat,'xxxxaa1234bbccddee')
>>>x
<_sre.SRE_Matchobjectat0x401e9560>
Foralistoffunctionsintheremodule,seeModuleContents
http://docs.python.org/library/re.html#modulecontents.

2.2.4Usingmatchobjectstoextractavalue
Matchobjectsenableyoutoextractmatchedsubstringsafterperformingamatch.A
matchobjectisreturnedbysuccessfulmatch.Thepartofthetargetavailableinthematch
objectistheportionmatchedbygroupsinthepattern,thatistheportionofthepattern
insideparentheses.Forexample:
In[69]:mo=re.search(r'height:(\d*)width:(\d*)','height:123
width:456')
In[70]:mo.groups()
Out[70]:('123','456')
Hereisanotherexample:
importsys,re

Targets=[
'Thereare<<25>>sparrows.',
'Isee<<15>>finches.',
'Thereisnothinghere.',
]

deftest():
pat=re.compile('<<([09]*)>>')
forlineinTargets:
mo=pat.search(line)
ifmo:
value=mo.group(1)
print'value:%s'%value
else:
print'nomatch'

test()
Whenweruntheabove,itprintsoutthefollowing:

Page92
APythonBook

value:25
value:15
nomatch
Explanation:
Intheregularexpression,putparenthesesaroundtheportionoftheregular
expressionthatwillmatchwhatyouwanttoextract.Eachpairofparentheses
marksoffagroup.
Afterthesearch,checktodetermineiftherewasasuccessfulmatchbychecking
foramatchingobject."pat.search(line)"returnsNoneifthesearchfails.
Ifyouspecifymorethanonegroupinyourregularexpression(morethatonepair
ofparentheses),thenyoucanuse"value=mo.group(N)"toextractthevalue
matchedbytheNthgroupfromthematchingobject."value=mo.group(1)"
returnsthefirstextractedvalue;"value=mo.group(2)"returnsthesecond;etc.An
argumentof0returnsthestringmatchedbytheentireregularexpression.
Inaddition,youcan:
Use"values=mo.groups()"togetatuplecontainingthestringsmatchedbyall
groups.
Use"mo.expand()"tointerpolatethegroupvaluesintoastring.Forexample,
"mo.expand(r'value1:\1value2:\2')"insertsthevaluesofthefirstandsecond
groupintoastring.Ifthefirstgroupmatched"aaa"andthesecondmatched
"bbb",thenthisexamplewouldproduce"value1:aaavalue2:bbb".Forexample:
In[76]:mo=re.search(r'h:(\d*)w:(\d*)','h:123
w:456')
In[77]:mo.expand(r'Height:\1Width:\2')
Out[77]:'Height:123Width:456'

2.2.5Extractingmultipleitems
Youcanextractmultipleitemswithasinglesearch.Hereisanexample:
importsys,re

pat=re.compile('aa([09]*)bb([09]*)cc')

while1:
line=raw_input('Enteraline("q"toquit):')
ifline=='q':
break
mo=pat.search(line)
ifmo:
value1,value2=mo.group(1,2)
print'value1:%svalue2:%s'%(value1,value2)
else:
print'nomatch'

Page93
APythonBook

Comments:
Usemultipleparenthesizedsubstringsintheregularexpressiontoindicatethe
portions(groups)tobeextracted.
"mo.group(1,2)"returnsthevaluesofthefirstandsecondgroupinthestring
matched.
Wecouldalsohaveused"mo.groups()"toobtainatuplethatcontainsboth
values.
Yetanotheralternativewouldhavebeentousethefollowing:print
mo.expand(r'value1:\1value2:\2').

2.2.6Replacingmultipleitems
Asimplewaytoperformmultiplereplacementsusingaregularexpressionistousethe
re.subn()function.Hereisanexample:
In[81]:re.subn(r'\d+','***','thereare203birdssittingin2
trees')
Out[81]:('thereare***birdssittingin***trees',2)
Formorecomplexreplacements,useafunctioninsteadofaconstantreplacementstring:
importre

defrepl_func(mo):
s1=mo.group(1)
s2='*'*len(s1)
returns2

deftest():
pat=r'(\d+)'
in_str='thereare2034birdsin21trees'
out_str,count=re.subn(pat,repl_func,in_str)
print'in:"%s"'%in_str
print'out:"%s"'%out_str
print'count:%d'%count

test()
Andwhenweruntheabove,itproduces:
in:"thereare2034birdsin21trees"
out:"thereare****birdsin**trees"
count:2
Notes:
Thereplacementfunctionreceivesoneargument,amatchobject.
There.subn()functionreturnsatuplecontainingtwovalues:(1)thestring
afterreplacementsand(2)thenumberofreplacementsperformed.

Page94
APythonBook

HereisanevenmorecomplexexampleYoucanlocatesubstrings(slices)ofamatch
andreplacethem:
importsys,re

pat=re.compile('aa([09]*)bb([09]*)cc')

while1:
line=raw_input('Enteraline("q"toquit):')
ifline=='q':
break
mo=pat.search(line)
ifmo:
value1,value2=mo.group(1,2)
start1=mo.start(1)
end1=mo.end(1)
start2=mo.start(2)
end2=mo.end(2)
print'value1:%sstart1:%dend1:%d'%(value1,start1,
end1)
print'value2:%sstart2:%dend2:%d'%(value2,start2,
end2)
repl1=raw_input('Enterreplacement#1:')
repl2=raw_input('Enterreplacement#2:')
newline=(line[:start1]+repl1+line[end1:start2]+
repl2+line[end2:])
print'newline:%s'%newline
else:
print'nomatch'
Explanation:
Alternatively,use"mo.span(1)"insteadof"mo.start(1)"and"mo.end(1)"inorder
togetthestartandendofasubmatchinasingleoperation."mo.span(1)"returnsa
tuple:(start,end).
Puttogetheranewstringwithstringconcatenationfrompiecesoftheoriginal
stringandreplacementvalues.Youcanusestringslicestogetthesubstringsof
theoriginalstring.Inourcase,thefollowinggetsthestartofthestring,addsthe
firstreplacement,addsthemiddleoftheoriginalstring,addsthesecond
replacement,andfinally,addsthelastpartoftheoriginalstring:
newline=line[:start1]+repl1+line[end1:start2]+
repl2+line[end2:]
Youcanalsousethesubfunctionormethodtodosubstitutions.Hereisanexample:
importsys,re

pat=re.compile('[09]+')

print'Replacingdecimaldigits.'

Page95
APythonBook

while1:
target=raw_input('Enteratargetline("q"toquit):')
iftarget=='q':
break
repl=raw_input('Enterareplacement:')
result=pat.sub(repl,target)
print'result:%s'%result
Hereisanotherexampleoftheuseofafunctiontoinsertcalculatedreplacements.
importsys,re,string

pat=re.compile('[am]+')

defreplacer(mo):
returnstring.upper(mo.group(0))

print'Uppercasingam.'
while1:
target=raw_input('Enteratargetline("q"toquit):')
iftarget=='q':
break
result=pat.sub(replacer,target)
print'result:%s'%result
Notes:
Ifthereplacementargumenttosubisafunction,thatfunctionmusttakeone
argument,amatchobject,andmustreturnthemodified(orreplacement)value.
Thematchedsubstringwillbereplacedbythevaluereturnedbythisfunction.
Inourcase,thefunctionreplacerconvertsthematchedvaluetouppercase.
Thisisalsoaconvenientuseforalambdainsteadofanamedfunction,forexample:
importsys,re,string

pat=re.compile('[am]+')

print'Uppercasingam.'
while1:
target=raw_input('Enteratargetline("q"toquit):')
iftarget=='q':
break
result=pat.sub(
lambdamo:string.upper(mo.group(0)),
target)
print'result:%s'%result

2.3IteratorObjects
Note1:YouwillneedasufficientlyrecentversionofPythoninordertouseiteratorsand
generators.IbelievethattheywereintroducedinPython2.2.

Page96
APythonBook

Note2:TheiteratorprotocolhaschangedslightlyinPythonversion3.0.
Goalsforthissection:
Learnhowtoimplementageneratorfunction,thatis,afunctionwhich,when
called,returnsaniterator.
Learnhowtoimplementaclasscontainingageneratormethod,thatis,amethod
which,whencalled,returnsaniterator.
Learntheiteratorprotocol,specificallywhatmethodsaniteratormustsupportand
whatthosemethodsmustdo.
Learnhowtoimplementaniteratorclass,thatis,aclasswhoseinstancesare
iteratorobjects.
Learnhowtoimplementrecursiveiteratorgenerators,thatis,aniteratorgenerator
whichrecursivelyproducesiteratorgenerators.
Learnthatyourimplementationofaniteratorobject(aniteratorclass)can
"refresh"itselfandlearnatleastonewaytodothis.
Definitions:
IteratorAnditeratorisanobjectthatsatisfies(implements)theiteratorprotocol.
IteratorprotocolAnobjectimplementstheiteratorprotocolifitimplementsboth
anext()andan__iter__()methodwhichsatisfytheserules:(1)the
__iter__()methodmustreturntheiterator;(2)thenext()methodshould
returnthenextitemtobeiteratedoverandwhenfinished(therearenomore
items)shouldraisetheStopIterationexception.Theiteratorprotocolis
describedatIteratorTypes
http://docs.python.org/library/stdtypes.html#iteratortypes.
IteratorclassAclassthatimplements(satisfies)theiteratorprotocol.In
particular,theclassimplementsnext()and__iter__()methodsas
describedaboveandinIteratorTypes
http://docs.python.org/library/stdtypes.html#iteratortypes.
(Iterator)generatorfunctionAfunction(ormethod)which,whencalled,returns
aniteratorobject,thatis,anobjectthatsatisfiestheiteratorprotocol.Afunction
containingayieldstatementautomaticallybecomesagenerator.
GeneratorexpressionAnexpressionwhichproducesaniteratorobject.
Generatorexpressionshaveaformsimilartoalistcomprehension,butare
enclosedinparenthesesratherthansquarebrackets.Seeexamplebelow.
Afewadditionalbasicpoints:
Afunctionthatcontainsayieldstatementisageneratorfunction.Whencalled,it
returnsaniterator,thatis,anobjectthatprovidesnext()and__iter__()
methods.
Theiteratorprotocolisdescribedhere:PythonStandardLibrary:IteratorTypes
http://docs.python.org/library/stdtypes.html#iteratortypes.

Page97
APythonBook

Aclassthatdefinesbothanext()methodanda__iter__()methodsatisfies
theiteratorprotocol.So,instancesofsuchaclasswillbeiterators.
Pythonprovidesavarietyofwaystoproduce(implement)iterators.Thissection
describesafewofthoseways.Youshouldalsolookattheiter()builtin
function,whichisdescribedinThePythonStandardLibrary:BuiltinFunctions:
iter()http://docs.python.org/library/functions.html#iter.
Aniteratorcanbeusedinaniteratorcontext,forexampleinaforstatement,ina
listcomprehension,andinageneratorexpression.Whenaniteratorisusedinan
iteratorcontext,theiteratorproducesitsvalues.
Thissectionattemptstoprovideexamplesthatillustratethegenerator/iteratorpattern.
Whyisthisimportant?
Oncemastered,itisasimple,convenient,andpowerfulprogrammingpattern.
Ithasmanyandpervasiveuses.
Ithelpstolexicallyseparatetheproducercodefromtheconsumercode.Doingso
makesiteasiertolocateproblemsandtomodifyorfixcodeinawaythatis
localizedanddoesnothaveunwantedsideeffects.
Implementingyourowniterators(andgenerators)enablesyoutodefineyourown
abstractsequences,thatis,sequenceswhosecompositionaredefinedbyyour
computationsratherthanbytheirpresenceinacontainer.Infact,youriteratorcan
calculateorretrievevaluesaseachoneisrequested.
ExamplesTheremainderofthissectionprovidesasetofexampleswhichimplement
anduseiterators.

2.3.1ExampleAgeneratorfunction
Thisfunctioncontainsayieldstatement.Therefore,whenwecallit,itproducesan
iterator:
defgenerateItems(seq):
foriteminseq:
yield'item:%s'%item

anIter=generateItems([])
print'dir(anIter):',dir(anIter)
anIter=generateItems([111,222,333])
forxinanIter:
printx
anIter=generateItems(['aaa','bbb','ccc'])
printanIter.next()
printanIter.next()
printanIter.next()
printanIter.next()
Runningthisexampleproducesthefollowingoutput:

Page98
APythonBook

dir(anIter):['__class__','__delattr__','__doc__',
'__getattribute__',
'__hash__','__init__','__iter__','__new__','__reduce__',
'__reduce_ex__','__repr__','__setattr__','__str__','gi_frame',
'gi_running','next']
item:111
item:222
item:333
item:aaa
item:bbb
item:ccc
Traceback(mostrecentcalllast):
File"iterator_generator.py",line14,in?
printanIter.next()
StopIteration
Notesandexplanation:
Thevaluereturnedbythecalltothegenerator(function)isaniterator.Itobeys
theiteratorprotocol.Thatis,dir(anIter)showsthatithasboth
__iter__()andnext()methods.
Becausethisobjectisaniterator,wecanuseaforstatementtoiterateoverthe
valuesreturnedbythegenerator.
Wecanalsogetitsvaluesbyrepeatedlycallingthenext()method,untilit
raisestheStopIterationexception.Thisabilitytocallthenextmethodenablesus
topasstheiteratorobjectaroundandgetvaluesatdifferentlocationsinourcode.
Oncewehaveobtainedallthevaluesfromaniterator,itis,ineffect,"empty"or
"exhausted".Theiteratorprotocol,infact,specifiesthatonceaniteratorraisesthe
StopIterationexception,itshouldcontinuetodoso.Anotherwaytosaythisis
thatthereisno"rewind"operation.But,youcancallthethegeneratorfunction
againtogeta"fresh"iterator.
Analternativeandperhapssimplerwaytocreateaninteratoristouseagenerator
expression.Thiscanbeusefulwhenyoualreadyhaveacollectionoriteratortowork
with.
Thenfollowingexampleimplementsafunctionthatreturnsageneratorobject.Theeffect
istogeneratetheobjectsinacollectionwhichexcludingitemsinasepartecollection:
DATA=[
'lemon',
'lime',
'grape',
'apple',
'pear',
'watermelon',
'canteloupe',
'honeydew',
'orange',

Page99
APythonBook

'grapefruit',
]

defmake_producer(collection,excludes):
gen=(itemforitemincollectionifitemnotinexcludes)
returngen

deftest():
iter1=make_producer(DATA,('apple','orange','honeydew',))
print'%s'%iter1
forfruitiniter1:
printfruit

test()
Whenrun,thisexampleproducesthefollowing:
$pythonworkbook063.py
<generatorobject<genexpr>at0x7fb3d0f1bc80>
lemon
lime
grape
pear
watermelon
canteloupe
grapefruit
Notes:
Ageneratorexpressionlooksalmostlikealistcomprehension,butissurrounded
byparenthesesratherthansquarebrackets.Formoreonlistcomprehensionssee
sectionExampleAlistcomprehension.
Themake_producerfunctionreturnstheobjectproducedbythegenerator
expression.

2.3.2ExampleAclasscontainingageneratormethod
Eachtimethismethodiscalled,itproducesa(new)iteratorobject.Thismethodis
analogoustotheiterkeysanditervaluesmethodsinthedictionarybuiltinobject:
#
#Aclassthatprovidesaniteratorgeneratormethod.
#
classNode:
def__init__(self,name='<noname>',value='<novalue>',
children=None):
self.name=name
self.value=value
self.children=children
ifchildrenisNone:
self.children=[]

Page100
APythonBook

else:
self.children=children
defset_name(self,name):self.name=name
defget_name(self):returnself.name
defset_value(self,value):self.value=value
defget_value(self):returnself.value
defiterchildren(self):
forchildinself.children:
yieldchild
#
#Printinformationonthisnodeandwalkoverallchildrenand
#grandchildren...
defwalk(self,level=0):
print'%sname:%svalue:%s'%(
get_filler(level),self.get_name(),self.get_value(),)
forchildinself.iterchildren():
child.walk(level+1)

#
#Anfunctionthatistheequivalentofthewalk()methodin
#classNode.
#
defwalk(node,level=0):
print'%sname:%svalue:%s'%(
get_filler(level),node.get_name(),node.get_value(),)
forchildinnode.iterchildren():
walk(child,level+1)

defget_filler(level):
return''*level

deftest():
a7=Node('gilbert','777')
a6=Node('fred','666')
a5=Node('ellie','555')
a4=Node('daniel','444')
a3=Node('carl','333',[a4,a5])
a2=Node('bill','222',[a6,a7])
a1=Node('alice','111',[a2,a3])
#Usethewalkmethodtowalktheentiretree.
print'Usingthemethod:'
a1.walk()
print'='*30
#Usethewalkfunctiontowalktheentiretree.
print'Usingthefunction:'
walk(a1)

test()
Runningthisexampleproducesthefollowingoutput:
Usingthemethod:
name:alicevalue:111

Page101
APythonBook

name:billvalue:222
name:fredvalue:666
name:gilbertvalue:777
name:carlvalue:333
name:danielvalue:444
name:ellievalue:555
==============================
Usingthefunction:
name:alicevalue:111
name:billvalue:222
name:fredvalue:666
name:gilbertvalue:777
name:carlvalue:333
name:danielvalue:444
name:ellievalue:555
Notesandexplanation:
Thisclasscontainsamethoditerchildrenwhich,whencalled,returnsaniterator.
Theyieldstatementinthemethoditerchildrenmakesitintoagenerator.
Theyieldstatementreturnsoneitemeachtimeitisreached.Thenexttimethe
iteratorobjectis"called"itresumesimmediatelyaftertheyieldstatement.
Afunctionmayhaveanynumberofyieldstatements.
Aforstatementwilliterateoveralltheitemsproducedbyaniteratorobject.
Thisexampleshowstwowaystousethegenerator,specifically:(1)thewalk
methodintheclassNodeand(2)thewalkfunction.Bothcallthegenerator
iterchildrenandbothdoprettymuchthesamething.

2.3.3ExampleAniteratorclass
Thisclassimplementstheiteratorprotocol.Therefore,instancesofthisclassareiterators.
Thepresenceofthenext()and__iter__()methodsmeansthatthisclass
implementstheiteratorprotocolandmakesinstancesofthisclassiterators.
Notethatwhenaniteratoris"exhausted"it,normally,cannotbereusedtoiterateoverthe
sequence.However,inthisexample,weprovidearefreshmethodwhichenablesusto
"rewind"andreusetheiteratorinstance:
#
#Aniteratorclassthatdoes*not*use``yield``.
#Thisiteratorproduceseveryotheriteminasequence.
#
classIteratorExample:
def__init__(self,seq):
self.seq=seq
self.idx=0
defnext(self):
self.idx+=1
ifself.idx>=len(self.seq):

Page102
APythonBook

raiseStopIteration
value=self.seq[self.idx]
self.idx+=1
returnvalue
def__iter__(self):
returnself
defrefresh(self):
self.idx=0

deftest_iteratorexample():
a=IteratorExample('edcba')
forxina:
printx
print''
a.refresh()
forxina:
printx
print'='*30
a=IteratorExample('abcde')
try:
printa.next()
printa.next()
printa.next()
printa.next()
printa.next()
printa.next()
exceptStopIteration,e:
print'stopping',e

test_iteratorexample()
Runningthisexampleproducesthefollowingoutput:
d
b

d
b
==============================
b
d
stopping
Notesandexplanation:
Thenextmethodmustkeeptrackofwhereitisandwhatitemitshouldproduce
next.
Alert:TheiteratorprotocolhaschangedslightlyinPython3.0.Inparticular,the
next()methodhasbeenrenamedto__next__().See:PythonStandard
Library:IteratorTypes
http://docs.python.org/3.0/library/stdtypes.html#iteratortypes.

Page103
APythonBook

2.3.4ExampleAniteratorclassthatusesyield
Theremaybetimeswhenthenextmethodiseasierandmorestraightforwardto
implementusingyield.Ifso,thenthisclassmightserveasanmodel.Ifyoudonotfeel
theneedtodothis,thenyoushouldignorethisexample:
#
#Aniteratorclassthatuses``yield``.
#Thisiteratorproduceseveryotheriteminasequence.
#
classYieldIteratorExample:
def__init__(self,seq):
self.seq=seq
self.iterator=self._next()
self.next=self.iterator.next
def_next(self):
flag=0
forxinself.seq:
ifflag:
flag=0
yieldx
else:
flag=1
def__iter__(self):
returnself.iterator
defrefresh(self):
self.iterator=self._next()
self.next=self.iterator.next

deftest_yielditeratorexample():
a=YieldIteratorExample('edcba')
forxina:
printx
print''
a.refresh()
forxina:
printx
print'='*30
a=YieldIteratorExample('abcde')
try:
printa.next()
printa.next()
printa.next()
printa.next()
printa.next()
printa.next()
exceptStopIteration,e:
print'stopping',e

test_yielditeratorexample()
Runningthisexampleproducesthefollowingoutput:

Page104
APythonBook

d
b

d
b
==============================
b
d
stopping
Notesandexplanation:
Becausethe_nextmethodusesyield,callingit(actually,callingtheiterator
objectitproduces)inaniteratorcontextcausesittobe"resumed"immediately
aftertheyieldstatement.Thisreducesbookkeepingabit.
However,withthisstyle,wemustexplicitlyproduceaniterator.Wedothisby
callingthe_nextmethod,whichcontainsayieldstatement,andisthereforea
generator.Thefollowingcodeinourconstructor(__init__)completesthe
setupofourclassasaniteratorclass:
self.iterator=self._next()
self.next=self.iterator.next
Rememberthatweneedboth__iter__()andnext()methodsin
YieldIteratorExampletosatisfytheiteratorprotocol.The__iter__()
methodisalreadythereandtheabovecodeintheconstructorcreatesthenext()
method.

2.3.5ExampleAlistcomprehension
Alistcomprehensionlooksabitlikeaniterator,butitproducesalist.See:ThePython
LanguageReference:Listdisplays
http://docs.python.org/reference/expressions.html#listdisplaysformoreonlist
comprehensions.
Hereisanexample:
In[4]:deff(x):
...:returnx*3
...:
In[5]:list1=[11,22,33]
In[6]:list2=[f(x)forxinlist1]
In[7]:printlist2
[33,66,99]

2.3.6ExampleAgeneratorexpression
Ageneratorexpressionlooksquitesimilartoalistcomprehension,butisenclosedin

Page105
APythonBook

parenthesesratherthansquarebrackets.Unlikealistcomprehension,agenerator
expressiondoesnotproducealist;itproducesangeneratorobject.Ageneratorobjectis
aniterator.
Formoreongeneratorexpressions,seeThePythonLanguageReference:Generator
expressionshttp://docs.python.org/reference/expressions.html#generatorexpressions.
Thefollowingexampleusesageneratorexpressiontoproduceaniterator:
mylist=range(10)

deff(x):
returnx*3

genexpr=(f(x)forxinmylist)

forxingenexpr:
printx
Notesandexplanation:
Thegeneratorexpression(f(x)forxinmylist)producesaniteratorobject.
Noticethatwecanusetheiteratorobjectlaterinourcode,cansaveitinadata
structure,andcanpassittoafunction.

2.4UnitTests
UnittestandthePythonunittestframeworkprovideaconvenientwaytodefineandrun
teststhatensurethataPythonapplicationproducesspecifiedresults.
Thissection,whileitwillnotattempttoexplaineverythingabouttheunittestframework,
willprovideexamplesofseveralstraightforwardwaystoconstructandruntests.
Someassumptions:
Wearegoingtodevelopasoftwareprojectincrementally.Wewillnotimplement
andreleaseallatonce.Therefore,eachtimeweaddtoourexistingcodebase,we
needawaytoverifythatouradditions(andfixes)havenotcausednewproblems
inoldcode.
Addingnewcodetoexistingcodewillcauseproblems.Weneedtobeableto
check/testforthoseproblemsateachstep.
Asweaddcode,weneedtobeabletoaddtestsforthatnewcode,too.

2.4.1Definingunittests

2.4.1.1Createatestclass.
Inthetestclass,implementanumberofmethodstoperformyourtests.Nameyourtest

Page106
APythonBook

methodswiththeprefix"test".Hereisanexample:
importunittest

classMyTest(unittest.TestCase):
deftest_one(self):
#sometestcode
pass
deftest_two(self):
#sometestcode
pass
Createatestharness.Hereisanexample:
importunittest

#makethetestsuite.
defsuite():
loader=unittest.TestLoader()
testsuite=loader.loadTestsFromTestCase(MyTest)
returntestsuite

#Makethetestsuite;runthetests.
deftest():
testsuite=suite()
runner=unittest.TextTestRunner(sys.stdout,verbosity=2)
result=runner.run(testsuite)
Hereisamorecompleteexample:
importsys,StringIO,string
importunittest
importwebserv_example_heavy_sub

#Acomparisonfunctionforcaseinsenstivesorting.
defmycmpfunc(arg1,arg2):
returncmp(string.lower(arg1),string.lower(arg2))

classXmlTest(unittest.TestCase):
deftest_import_export1(self):
inFile=file('test1_in.xml','r')
inContent=inFile.read()
inFile.close()
doc=webserv_example_heavy_sub.parseString(inContent)
outFile=StringIO.StringIO()
outFile.write('<?xmlversion="1.0"?>\n')
doc.export(outFile,0)
outContent=outFile.getvalue()
outFile.close()
self.failUnless(inContent==outContent)

#makethetestsuite.
defsuite():

Page107
APythonBook

loader=unittest.TestLoader()
#Changethetestmethodprefix:test>trial.
#loader.testMethodPrefix='trial'
#Changethecomparisonfunctionthatdeterminestheorderof
tests.
#loader.sortTestMethodsUsing=mycmpfunc
testsuite=loader.loadTestsFromTestCase(XmlTest)
returntestsuite

#Makethetestsuite;runthetests.
deftest_main():
testsuite=suite()
runner=unittest.TextTestRunner(sys.stdout,verbosity=2)
result=runner.run(testsuite)

if__name__=="__main__":
test_main()
Runningtheabovescriptproducesthefollowingoutput:
test_import_export(__main__.XmlTest)...ok



Ran1testin0.035s

OK
Afewnotesonthisexample:
Thisexampleteststheabilitytoparseanxmldocumenttest1_in.xmlandexport
thatdocumentbacktoXML.ThetestsucceedsiftheinputXMLdocumentand
theexportedXMLdocumentarethesame.
ThecodewhichisbeingtestedparsesanXMLdocumentreturnedbyarequestto
AmazonWebservices.YoucanlearnmoreaboutAmazonWebservicesat:
http://www.amazon.com/webservices.ThiscodewasgeneratedfromanXML
SchemadocumentbygenerateDS.py.Soweareineffect,testinggenerateDS.py.
YoucanfindgenerateDS.pyat:
http://http://www.davekuhlman.org/#generatedspy.
Testingforsuccess/failureandreportingfailuresUsethemethodslistedat
http://www.python.org/doc/current/lib/testcaseobjects.htmltotestforandreport
successandfailure.Inourexample,weused"self.failUnless(inContent==
outContent)"toensurethatthecontentweparsedandthecontentthatwe
exportedwerethesame.
Addadditionaltestsbyaddingmethodswhosenameshavetheprefix"test".If
youpreferadifferentprefixfortestsnames,addsomethinglikethefollowingto
theabovescript:
loader.testMethodPrefix='trial'

Page108
APythonBook

Bydefault,thetestsarerunintheorderoftheirnamessortedbythecmp
function.So,ifneeded,youcancontroltheorderofexecutionoftestsby
selectingtheirnames,forexample,usingnamesliketest_1_checkderef,
test_2_checkcalc,etc.Or,youcanchangethecomparisonfunctionbyadding
somethinglikethefollowingtotheabovescript:
loader.sortTestMethodsUsing=mycmpfunc
Asabitofmotivationforcreatingandusingunittests,whiledevelopingthisexample,I
discoveredseveralerrors(ormaybe"specialfeatures")ingenerateDS.py.

2.5ExtendingandembeddingPython

2.5.1Introductionandconcepts
Extendingvs.embeddingTheyaredifferentbutrelated:
ExtendingPythonmeanstoimplementanextensionmoduleoranextensiontype.
AnextensionmodulecreatesanewPythonmodulewhichisimplementedin
C/C++.FromPythoncode,anextensionmoduleappearstobejustlikeamodule
implementedinPythoncode.AnextensiontypecreatesanewPython(builtin)
typewhichisimplementedinC/C++.FromPythoncode,anextensiontype
appearstobejustlikeabuiltintype.
EmbeddingPython,bycontrast,istoputthePythoninterpreterwithinan
application(i.e.linkitin)sothattheapplicationcanrunPythonscripts.The
scriptscanbeexecutedortriggeredinavarietyofways,e.g.theycanbeboundto
keysonthekeyboardortomenuitems,theycanbetriggeredbyexternalevents,
etc.Usually,inordertomaketheembeddedPythoninterpreteruseful,Pythonis
alsoextendedwithfunctionsfromtheembeddingapplication,sothatthescripts
cancallfunctionsthatareimplementedbytheembeddingC/C++application.
DocumentationThetwoimportantsourcesforinformationaboutextendingand
embeddingarethefollowing:
ExtendingandEmbeddingthePythonInterpreter
http://www.python.org/doc/current/ext/ext.html
Python/CAPIReferenceManual
http://www.python.org/doc/current/api/api.html
Typesofextensions:
ExtensionmodulesFromthePythonside,itappearstobeaPythonmodule.
Usuallyitexportsfunctions.
ExtensiontypesUsedtoimplementanewPythondatatype.
ExtensionclassesFromthePythonside,itappearstobeaclass.

Page109
APythonBook

ToolsThereareseveraltoolsthatsupportthedevelopmentofPythonextensions:
SWIGLearnaboutSWIGat:http://www.swig.org
PyrexLearnaboutPyrexat:
http://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
ThereisalsoCython,whichseemstobeanadvancedversionof,oratleastan
alternativetoPyrex.See:CythonCExtensionsforPython
http://www.cython.org/

2.5.2Extensionmodules
WritinganextensionmodulebyhandWhattodo:
Createthe"init"functionThenameofthisfunctionmustbe"init"followedby
thenameofthemodule.Everyextensionmodulemusthavesuchafunction.
CreatethefunctiontableThistablemapsfunctionnames(referencedfrom
Pythoncode)tofunctionpointers(implementedinC/C++).
Implementeachwrapperfunction.
ImplementingawrapperfunctionWhattodo:
1. CapturetheargumentswithPyArg_ParseTuple.Theformatstringspecifieshow
argumentsaretobeconvertedandcaptured.See1.7ExtractingParametersin
ExtensionFunctions.Herearesomeofthemostcommonlyusedtypes:
Use"i","s","f",etctoconvertandcapturesimpletypessuchasintegers,
strings,floats,etc.
Use"O"togetapointertoPython"complex"typessuchaslists,tuples,
dictionaries,etc.
Useitemsinparenthesestocaptureandunpacksequences(e.g.listsand
tuples)offixedlength.Example:
if(!PyArg_ParseTuple(args,"(ii)(ii)",&x,&y,
&width,&height))
{
returnNULL;
}/*if*/
Asamplecallmightbe:
lowerLeft=(x1,y1)
extent=(width1,height1)
scan(lowerLeft,extent)
Use":aName"(colon)attheendoftheformatstringtoprovideafunction
nameforerrormessages.Example:
if(!PyArg_ParseTuple(args,"O:setContentHandler",
&pythonInstance))
{

Page110
APythonBook

returnNULL;
}/*if*/
Use";anerrormessage"(semicolon)attheendoftheformatstringtoprovide
astringthatreplacesthedefaulterrormessage.
Docsareavailableat:http://www.python.org/doc/current/ext/parseTuple.html.
2. Writethelogic.
3. HandleerrorsandexceptionsYouwillneedtounderstandhowto(1)clearing
errorsandexceptionsand(2)Raiseerrors(exceptions).
ManyfunctionsinthePythonCAPIraiseexceptions.Youwillneedtocheck
forandcleartheseexceptions.Hereisanexample:
char*message;
intmessageNo;

message=NULL;
messageNo=1;
/*Istheargumentastring?
*/
if(!PyArg_ParseTuple(args,"s",&message))
{
/*It'snotastring.Cleartheerror.
*Thentrytogetamessagenumber(an
integer).
*/
PyErr_Clear();
if(!PyArg_ParseTuple(args,"i",&messageNo))
{
o
o
o
YoucanalsoraiseexceptionsinyourCcodethatcanbecaught(ina
"try:except:"block)backinthecallingPythoncode.Hereisanexample:
if(n==0)
{
PyErr_SetString(PyExc_ValueError,"Valuemust
notbezero");
returnNULL;
}
SeeInclude/pyerrors.hinthePythonsourcedistributionformore
exception/errortypes.
And,youcantestwhetherafunctioninthePythonCAPIthatyouhavecalled
hasraisedanexception.Forexample:
if(PyErr_Occurred())
{
/*Anexceptionwasraised.
*Dosomethingaboutit.

Page111
APythonBook

*/
o
o
o
Formoredocumentationonerrorsandexceptions,see:
http://www.python.org/doc/current/api/exceptionHandling.html.
4. Createandreturnavalue:
ForeachbuiltinPythontypethereisasetofAPIfunctionstocreateand
manipulateit.Seethe"Python/CAPIReferenceManual"foradescriptionof
thesefunctions.Forexample,see:
http://www.python.org/doc/current/api/intObjects.html
http://www.python.org/doc/current/api/stringObjects.html
http://www.python.org/doc/current/api/tupleObjects.html
http://www.python.org/doc/current/api/listObjects.html
http://www.python.org/doc/current/api/dictObjects.html
Etc.
ThereferencecountYouwillneedtofollowPython'srulesforreference
countingthatPythonusestogarbagecollectobjects.Youcanlearnabout
theserulesathttp://www.python.org/doc/current/ext/refcounts.html.Youwill
notwantPythontogarbagecollectobjectsthatyoucreatetooearlyortoolate.
WithrespecttoPythonobjectscreatedwiththeabovefunctions,thesenew
objectsareownedandmaybepassedbacktoPythoncode.However,there
aresituationswhereyourC/C++codewillnotautomaticallyownareference,
forexamplewhenyouextractanobjectfromacontainer(alist,tuple,
dictionary,etc).Inthesecasesyoushouldincrementthereferencecountwith
Py_INCREF.

2.5.3SWIG
Note:OurdiscussionandexamplesareforSWIGversion1.3
SWIGwilloftenenableyoutogeneratewrappersforfunctionsinanexistingCfunction
library.SWIGdoesnotunderstandeverythinginCheaderfiles.Butitdoesafairly
impressivejob.Youshouldtryitfirstbeforeresortingtothehardworkofwriting
wrappersbyhand.
MoreinformationonSWIGisathttp://www.swig.org.
Herearesomestepsthatyoucanfollow:
1. CreateaninterfacefileEvenwhenyouarewrappingfunctionsdefinedinan
existingheaderfile,creatinganinterfacefileisagoodidea.Includeyourexisting
headerfileintoit,thenaddwhateverelseyouneed.Hereisanextremelysimple
exampleofaSWIGinterfacefile:

Page112
APythonBook

%moduleMyLibrary

%{
#include"MyLibrary.h"
%}

%include"MyLibrary.h"
Comments:
The"%{"and"%}"bracketsaredirectivestoSWIG.Theysay:"Addthecode
betweenthesebracketstothegeneratedwrapperfilewithoutprocessingit.
The"%include"statementsays:"Copythefileintotheinterfacefilehere.In
effect,youareaskingSWIGtogeneratewrappersforallthefunctionsinthis
headerfile.Ifyouwantwrappersforonlysomeofthefunctionsinaheader
file,thencopyorreproducefunctiondeclarationsforthedesiredfunctions
here.Anexample:
%moduleMyLibrary

%{
#include"MyLibrary.h"
%}

intcalcArea(intwidth,intheight);
intcalcVolume(intradius);
Thisexamplewillgeneratewrappersforonlytwofunctions.
YoucanfindmoreinformationaboutthedirectivesthatareusedinSWIG
interfacefilesintheSWIGUserManual,inparticularat:
http://www.swig.org/Doc1.3/Preprocessor.html
http://www.swig.org/Doc1.3/Python.html
2. Generatethewrappers:
swigpythonMyLibrary.i
3. Compileandlinkthelibrary.OnLinux,youcanusesomethinglikethefollowing:
gcccMyLibrary.c
gcccI/usr/local/include/python2.3MyLibrary_wrap.c
gccsharedMyLibrary.oMyLibrary_wrap.oo
_MyLibrary.so
Notethatweproduceasharedlibrarywhosenameisthemodulenameprefixed
withanunderscore.SWIGalsogeneratesa.pyfile,withouttheleading
underscore,whichwewillimportfromourPythoncodeandwhich,inturn,
importsthesharedlibrary.
4. Usetheextensionmoduleinyourpythoncode:
Python2.3b1(#1,Apr252003,20:36:09)
[GCC2.95.420011002(Debianprerelease)]onlinux2

Page113
APythonBook

Type"help","copyright","credits"or"license"for
moreinformation.
>>>importMyLibrary
>>>MyLibrary.calcArea(4.0,5.0)
20.0
Hereisamakefilethatwillexecuteswigtogeneratewrappers,thencompileandlinkthe
extension.
CFLAGS=I/usr/local/include/python2.3
all:_MyLibrary.so
_MyLibrary.so:MyLibrary.oMyLibrary_wrap.o
gccsharedMyLibrary.oMyLibrary_wrap.oo_MyLibrary.so
MyLibrary.o:MyLibrary.c
gcccMyLibrary.coMyLibrary.o
MyLibrary_wrap.o:MyLibrary_wrap.c
gccc${CFLAGS}MyLibrary_wrap.coMyLibrary_wrap.o
MyLibrary_wrap.c:MyLibrary.i
swigpythonMyLibrary.i
clean:
rmfMyLibrary.pyMyLibrary.oMyLibrary_wrap.c
MyLibrary_wrap.o_MyLibrary.so
Hereisanexampleofrunningthismakefile:
$makefMyLibrary_makefileclean
rmfMyLibrary.pyMyLibrary.oMyLibrary_wrap.c\
MyLibrary_wrap.o_MyLibrary.so
$makefMyLibrary_makefile
gcccMyLibrary.coMyLibrary.o
swigpythonMyLibrary.i
gcccI/usr/local/include/python2.3MyLibrary_wrap.co
MyLibrary_wrap.o
gccsharedMyLibrary.oMyLibrary_wrap.oo_MyLibrary.so
And,hereareCsourcefilesthatcanbeusedinourexample.
MyLibrary.h:
/*MyLibrary.h
*/

Page114
APythonBook

floatcalcArea(floatwidth,floatheight);
floatcalcVolume(floatradius);

intgetVersion();

intgetMode();
MyLibrary.c:
/*MyLibrary.c
*/

floatcalcArea(floatwidth,floatheight)
{
return(width*height);
}

floatcalcVolume(floatradius)
{
return(3.14*radius*radius);
}

intgetVersion()
{
return123;
}

intgetMode()
{
return1;
}

2.5.4Pyrex
PyrexisausefultoolforwritingPythonextensions.BecausethePyrexlanguageis
similartoPython,writingextensionsinPyrexiseasierthandoingsoinC.Cython
appearstobetheanewerversionofPyrex.
MoreinformationisonPyrexandCythonisat:
Pyrexhttp://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
CythonCExtensionsforPythonhttp://www.cython.org/
HereisasimplefunctiondefinitioninPyrex:
#python_201_pyrex_string.pyx

importstring

defformatString(objects1,objects2):
s1=string.strip(s1)
s2=string.strip(s2)

Page115
APythonBook

s3='<<%s||%s>>'%(s1,s2)
s4=s3*4
returns4
And,hereisamakefile:
CFLAGS=DNDEBUGO3WallWstrictprototypesfPIC\
I/usr/local/include/python2.3

all:python_201_pyrex_string.so

python_201_pyrex_string.so:python_201_pyrex_string.o
gccsharedpython_201_pyrex_string.oo
python_201_pyrex_string.so

python_201_pyrex_string.o:python_201_pyrex_string.c
gccc${CFLAGS}python_201_pyrex_string.co
python_201_pyrex_string.o

python_201_pyrex_string.c:python_201_pyrex_string.pyx
pyrexcpython_201_pyrex_string.pyx

clean:
rmfpython_201_pyrex_string.sopython_201_pyrex_string.o\
python_201_pyrex_string.c
Hereisanotherexample.Inthisone,onefunctioninthe.pyxfilecallsanother.Hereis
theimplementationfile:
#python_201_pyrex_primes.pyx

defshowPrimes(intkmax):
plist=primes(kmax)
forpinplist:
print'prime:%d'%p

cdefprimes(intkmax):
cdefintn,k,i
cdefintp[1000]
result=[]
ifkmax>1000:
kmax=1000
k=0
n=2
whilek<kmax:
i=0
whilei<kandn%p[i]<>0:
i=i+1
ifi==k:
p[k]=n
k=k+1
result.append(n)
n=n+1

Page116
APythonBook

returnresult
And,hereisamakefile:
#CFLAGS=DNDEBUGgO3WallWstrictprototypesfPIC#
I/usr/local/include/python2.3CFLAGS=DNDEBUG
I/usr/local/include/python2.3
all:python_201_pyrex_primes.so
python_201_pyrex_primes.so:python_201_pyrex_primes.o
gccsharedpython_201_pyrex_primes.oopython_201_pyrex_primes.so
python_201_pyrex_primes.o:python_201_pyrex_primes.c
gccc${CFLAGS}python_201_pyrex_primes.copython_201_pyrex_primes.o
python_201_pyrex_primes.c:python_201_pyrex_primes.pyx
pyrexcpython_201_pyrex_primes.pyx
clean:
rmfpython_201_pyrex_primes.sopython_201_pyrex_primes.o
python_201_pyrex_primes.c
Hereistheoutputfromrunningthemakefile:
$makefpython_201_pyrex_makeprimesclean
rmfpython_201_pyrex_primes.sopython_201_pyrex_primes.o\
python_201_pyrex_primes.c
$makefpython_201_pyrex_makeprimes
pyrexcpython_201_pyrex_primes.pyx
gcccDNDEBUGI/usr/local/include/python2.3
python_201_pyrex_primes.copython_201_pyrex_primes.o
gccsharedpython_201_pyrex_primes.oopython_201_pyrex_primes.so
Hereisaninteractiveexampleofitsuse:
$python
Python2.3b1(#1,Apr252003,20:36:09)
[GCC2.95.420011002(Debianprerelease)]onlinux2
Type"help","copyright","credits"or"license"formore
information.
>>>importpython_201_pyrex_primes
>>>dir(python_201_pyrex_primes)
['__builtins__','__doc__','__file__','__name__','showPrimes']
>>>python_201_pyrex_primes.showPrimes(5)
prime:2
prime:3
prime:5
prime:7

Page117
APythonBook

prime:11
ThisnextexampleshowshowtousePyrextoimplementanewextensiontype,thatisa
newPythonbuiltintype.Noticethattheclassisdeclaredwiththecdefkeyword,which
tellsPyrextogeneratetheCimplementationofatypeinsteadofaclass.
Hereistheimplementationfile:
#python_201_pyrex_clsprimes.pyx

"""Animplementationofprimeshandlingclass
forademonstrationofPyrex.
"""

cdefclassPrimes:
"""Aclasscontainingfunctionsfor
handlingprimes.
"""

defshowPrimes(self,intkmax):
"""Showarangeofprimes.
Usethemethodprimes()togeneratetheprimes.
"""
plist=self.primes(kmax)
forpinplist:
print'prime:%d'%p

defprimes(self,intkmax):
"""Generatetheprimesintherange0kmax.
"""
cdefintn,k,i
cdefintp[1000]
result=[]
ifkmax>1000:
kmax=1000
k=0
n=2
whilek<kmax:
i=0
whilei<kandn%p[i]<>0:
i=i+1
ifi==k:
p[k]=n
k=k+1
result.append(n)
n=n+1
returnresult
And,hereisamakefile:
CFLAGS=DNDEBUGI/usr/local/include/python2.3

all:python_201_pyrex_clsprimes.so

Page118
APythonBook

python_201_pyrex_clsprimes.so:python_201_pyrex_clsprimes.o
gccsharedpython_201_pyrex_clsprimes.oo
python_201_pyrex_clsprimes.so

python_201_pyrex_clsprimes.o:python_201_pyrex_clsprimes.c
gccc${CFLAGS}python_201_pyrex_clsprimes.co
python_201_pyrex_clsprimes.o

python_201_pyrex_clsprimes.c:python_201_pyrex_clsprimes.pyx
pyrexcpython_201_pyrex_clsprimes.pyx

clean:
rmfpython_201_pyrex_clsprimes.so
python_201_pyrex_clsprimes.o\
python_201_pyrex_clsprimes.c
Hereisoutputfromrunningthemakefile:
$makefpython_201_pyrex_makeclsprimesclean
rmfpython_201_pyrex_clsprimes.sopython_201_pyrex_clsprimes.o\
python_201_pyrex_clsprimes.c
$makefpython_201_pyrex_makeclsprimes
pyrexcpython_201_pyrex_clsprimes.pyx
gcccDNDEBUGI/usr/local/include/python2.3
python_201_pyrex_clsprimes.copython_201_pyrex_clsprimes.o
gccsharedpython_201_pyrex_clsprimes.oo
python_201_pyrex_clsprimes.so
Andhereisaninteractiveexampleofitsuse:
$python
Python2.3b1(#1,Apr252003,20:36:09)
[GCC2.95.420011002(Debianprerelease)]onlinux2
Type"help","copyright","credits"or"license"formore
information.
>>>importpython_201_pyrex_clsprimes
>>>dir(python_201_pyrex_clsprimes)
['Primes','__builtins__','__doc__','__file__','__name__']
>>>primes=python_201_pyrex_clsprimes.Primes()
>>>dir(primes)
['__class__','__delattr__','__doc__','__getattribute__',
'__hash__',
'__init__','__new__','__reduce__','__reduce_ex__','__repr__',
'__setattr__','__str__','primes','showPrimes']
>>>primes.showPrimes(4)
prime:2
prime:3
prime:5
prime:7
DocumentationAlsonoticethatPyrexpreservesthedocumentationforthemodule,the
class,andthemethodsintheclass.Youcanshowthisdocumentationwithpydoc,as

Page119
APythonBook

follows:
$pydocpython_201_pyrex_clsprimes
Or,inPythoninteractivemode,use:
$python
Python2.3b1(#1,Apr252003,20:36:09)
[GCC2.95.420011002(Debianprerelease)]onlinux2
Type"help","copyright","credits"or"license"formore
information.
>>>importpython_201_pyrex_clsprimes
>>>help(python_201_pyrex_clsprimes)

2.5.5SWIGvs.Pyrex
ChooseSWIGwhen:
YoualreadyhaveanexistingCorC++implementationofthecodeyouwantto
callfromPython.InthiscaseyouwantSWIGtogeneratethewrappers.Butnote
thatCythonpromisestoenableyoutoquicklywrapandcallfunctions
implementedinC.
YouwanttowritetheimplementationinCorC++byhand.Perhaps,becauseyou
thinkyoucandosoquickly,forexample,orbecauseyoubelievethatyoucan
makeithighlyoptimized.Then,youwanttobeabletogeneratethePython
(extension)wrappersforitquickly.
ChoosePyrexwhen:
YoudonothaveaC/C++implementationandyouwantaneasierwaytowrite
thatCimplementation.WritingPyrexcode,whichisalotlikePython,iseasier
thanwritingCorC++codebyhand).
YoustarttowritetheimplementationinC,thenfindthatitrequireslotsofcallsto
thePythonCAPI,andyouwanttoavoidhavingtolearnhowtodothat.

2.5.6Cython
HereisasimpleexamplethatusesCythontowrapafunctionimplementedinC.
FirsttheCheaderfile:
/*test_c_lib.h*/

intcalculate(intwidth,intheight);
And,theCimplementationfile:
/*test_c_lib.c*/

Page120
APythonBook

#include"test_c_lib.h"

intcalculate(intwidth,intheight)
{
intresult;
result=width*height*3;
returnresult;
}
HereisaCythonfilethatcallsourCfunction:
#test_c.pyx

#DeclaretheexternalCfunction.
cdefexternfrom"test_c_lib.h":
intcalculate(intwidth,intheight)

deftest(w,h):
#CalltheexternalCfunction.
result=calculate(w,h)
print'resultfromcalculate:%d'%result
Wecancompileourcodeusingthisscript(onLinux):
#!/bin/bashx
cythontest_c.pyx
gcccfPICI/usr/local/include/python2.6otest_c.otest_c.c
gcccfPICI/usr/local/include/python2.6otest_c_lib.o
test_c_lib.c
gccsharedfPICI/usr/local/include/python2.6otest_c.so
test_c.otest_c_lib.o
HereisasmallPythonfilethatusesthewrapperthatwewroteinCython:
#run_test_c.py

importtest_c

deftest():
test_c.test(4,5)
test_c.test(12,15)

if__name__=='__main__':
test()
And,whenwerunit,weseethefollowing:
$pythonrun_test_c.py
resultfromcalculate:60
resultfromcalculate:540

Page121
APythonBook

2.5.7Extensiontypes
ThegoalAnewbuiltindatatypeforPython.
ExistingexamplesObjects/listobject.c,Objects/stringobject.c,Objects/dictobject.c,etc
inthePythonsourcecodedistribution.
InolderversionsofthePythonsourcecodedistribution,atemplatefortheCcodewas
providedinObjects/xxobject.c.Objects/xxobject.cisnolongerincludedinthePython
sourcecodedistribution.However:
Thediscussionandexamplesforcreatingextensiontypeshavebeenexpanded.
See:ExtendingandEmbeddingthePythonInterpreter,2.DefiningNewTypes
http://docs.python.org/extending/newtypes.html.
IntheTools/framerdirectoryofthePythonsourcecodedistributionthereisan
applicationthatwillgenerateaskeletonforanextensiontypefromaspecification
objectwritteninPython.RunTools/framer/example.pytoseeitinaction.
And,youcanusePyrextogenerateanewbuiltintype.Todoso,implementa
Python/PyrexclassanddeclaretheclasswiththePyrexkeywordcdef.Infact,youmay
wanttousePyrextogenerateaminimalextensiontype,andtheneditthatgeneratedcode
toinsertandaddfunctionalitybyhand.SeethePyrexsectionforanexample.
Pyrexalsogoessomewaytowardgivingyouaccessto(existing)Cstructsandfunctions
fromPython.

2.5.8Extensionclasses
ExtensionclassestheeasywaySWIGshadowclasses.
StartwithanimplementationofaC++classanditsheaderfile.
UsethefollowingSWIGflags:
swigc++pythonmymodule.i
MoreinformationisavailablewiththeSWIGdocumentationat:
http://www.swig.org/Doc1.3/Python.html.
ExtensionclassesthePyrexwayAnalternatieistousePyrextocompileaclass
definitionthatdoesnothavethecdefkeyword.UsingcdefontheclasstellsPyrexto
generateanextensiontypeinsteadofaclass.Youwillhavetodeterminewhetheryou
wantanextensionclassoranextensiontype.

2.6Parsing
Pythonisanexcellentlanguagefortextanalysis.

Page122
APythonBook

Insomecases,simplysplittinglinesoftextintowordswillbeenough.Inthesecasesuse
string.split().
Inothercases,regularexpressionsmaybeabletodotheparsingyouneed.Ifso,seethe
sectiononregularexpressionsinthisdocument.
However,insomecases,morecomplexanalysisofinputtextisrequired.Thissection
describessomeofthewaysthatPythoncanhelpyouwiththiscomplexparsingand
analysis.

2.6.1Specialpurposeparsers
ThereareanumberofspecialpurposeparserswhichyouwillfindinthePythonstandard
library:
ConfigParserparserConfigurationfileparser
http://docs.python.org/library/configparser.html
getoptParserforcommandlineoptions
http://docs.python.org/library/getopt.html
optparseMorepowerfulcommandlineoptionparser
http://docs.python.org/library/optparse.html
urlparseParseURLsintocomponents
http://docs.python.org/library/urlparse.html
csvCSV(commaseparatedvalues)FileReadingandWriting
http://docs.python.org/library/csv.html#modulecsv
os.pathCommonpathnamemanipulations
http://docs.python.org/library/os.path.html
XMLparsersandXMLtoolsThereislotsofsupportforparsingandprocessingXML
inPython.Hereareafewplacestolookforsupport:
ThePythonstandardlibraryStructuredMarkupProcessingTools
http://docs.python.org/library/markup.html.
Inparticular,youmaybeinterestedinxml.dom.minidomLightweightDOM
implementationhttp://docs.python.org/library/xml.dom.minidom.html.
ElementTreeYoucanthinkofElementTreeasanenhancedDOM(document
objectmodel).Manyfinditeasiertousethanminidom.ElementTreeisinthe
Pythonstandardlibrary,anddocumentationishere:ElementTreeOverview
http://effbot.org/zone/elementindex.htm.
LxmlmimicstheElementTreeAPI,buthasadditionalcapabilities.Findoutabout
Lxmlatlxmlhttp://codespeak.net/lxml/index.htmlNotethatlxmlalsohas
supportforXPathandXSLT.
Dave'ssupportforPythonandXMLhttp://www.rexx.com/~dkuhlman.

Page123
APythonBook

2.6.2Writingarecursivedescentparserbyhand
Forsimplegrammars,thisisnotsohard.
Youwillneedtoimplement:
Arecognizermethodorfunctionforeachproductionruleinyourgrammar.Each
recognizermethodbeginslookingatthecurrenttoken,thenconsumesasmany
tokensasneededtorecognizeit'sownproductionrule.Itcallstherecognizer
functionsforanynonterminalsonitsrighthandside.
AtokenizerSomethingthatwillenableeachrecognizerfunctiontogettokens,
onebyone.Thereareavarietyofwaystodothis,e.g.(1)afunctionthat
producesalistoftokensfromwhichrecognizerscanpoptokens;(2)agenerator
whosenextmethodreturnsthenexttoken;etc.
Asanexample,we'llimplementarecursivedescentparserwritteninPythonforthe
followinggrammer:
Prog::=Command|CommandProg
Command::=Func_call
Func_call::=Term'('Func_call_list')'
Func_call_list::=Func_call|Func_call','Func_call_list
Term=<word>
Hereisanimplementationofarecursivedescentparserfortheabovegrammar:
#!/usr/bin/envpython

"""
Arecursivedescentparserexample.

Usage:
pythonrparser.py[options]<inputfile>
Options:
h,helpDisplaythishelpmessage.
Example:
pythonrparser.pymyfile.txt

Thegrammar:
Prog::=Command|CommandProg
Command::=Func_call
Func_call::=Term'('Func_call_list')'
Func_call_list::=Func_call|Func_call','Func_call_list
Term=<word>
"""

importsys
importstring
importtypes
importgetopt

Page124
APythonBook

#
#TousetheIPythoninteractiveshelltoinspectyourrunning
#application,uncommentthefollowinglines:
#
##fromIPython.ShellimportIPShellEmbed
##ipshell=IPShellEmbed((),
##banner='>>>>>>>>IntoIPython>>>>>>>>',
##exit_msg='<<<<<<<<OutofIPython<<<<<<<<')
#
#Thenaddthefollowinglineatthepointinyourcodewhere
#youwanttoinspectruntimevalues:
#
#ipshell('somemessagetoidentifywhereweare')
#
#Formoreinformationsee:http://ipython.scipy.org/moin/
#

#
#Constants
#

#ASTnodetypes
NoneNodeType=0
ProgNodeType=1
CommandNodeType=2
FuncCallNodeType=3
FuncCallListNodeType=4
TermNodeType=5

#Tokentypes
NoneTokType=0
LParTokType=1
RParTokType=2
WordTokType=3
CommaTokType=4
EOFTokType=5

#Dictionarytomapnodetypevaluestonodetypenames
NodeTypeDict={
NoneNodeType:'NoneNodeType',
ProgNodeType:'ProgNodeType',
CommandNodeType:'CommandNodeType',
FuncCallNodeType:'FuncCallNodeType',
FuncCallListNodeType:'FuncCallListNodeType',
TermNodeType:'TermNodeType',
}

#
#RepresentationofanodeintheAST(abstractsyntaxtree).
#
classASTNode:
def__init__(self,nodeType,*args):
self.nodeType=nodeType

Page125
APythonBook

self.children=[]
foriteminargs:
self.children.append(item)
defshow(self,level):
self.showLevel(level)
print'NodeType%s'%NodeTypeDict[self.nodeType]
level+=1
forchildinself.children:
ifisinstance(child,ASTNode):
child.show(level)
eliftype(child)==types.ListType:
foriteminchild:
item.show(level)
else:
self.showLevel(level)
print'Child:',child
defshowLevel(self,level):
foridxinrange(level):
print'',

#
#Therecursivedescentparserclass.
#Containsthe"recognizer"methods,whichimplementthegrammar
#rules(above),onerecognizermethodforeachproductionrule.
#
classProgParser:
def__init__(self):
pass

defparseFile(self,infileName):
self.infileName=infileName
self.tokens=None
self.tokenType=NoneTokType
self.token=''
self.lineNo=1
self.infile=file(self.infileName,'r')
self.tokens=genTokens(self.infile)
try:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
exceptStopIteration:
raiseRuntimeError,'Emptyfile'
result=self.prog_reco()
self.infile.close()
self.infile=None
returnresult

defparseStream(self,instream):
self.tokens=genTokens(instream,'<instream>')
try:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
exceptStopIteration:

Page126
APythonBook

raiseRuntimeError,'Emptyfile'
result=self.prog_reco()
returnresult

defprog_reco(self):
commandList=[]
while1:
result=self.command_reco()
ifnotresult:
break
commandList.append(result)
returnASTNode(ProgNodeType,commandList)

defcommand_reco(self):
ifself.tokenType==EOFTokType:
returnNone
result=self.func_call_reco()
returnASTNode(CommandNodeType,result)

deffunc_call_reco(self):
ifself.tokenType==WordTokType:
term=ASTNode(TermNodeType,self.token)
self.tokenType,self.token,self.lineNo=
self.tokens.next()
ifself.tokenType==LParTokType:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
result=self.func_call_list_reco()
ifresult:
ifself.tokenType==RParTokType:
self.tokenType,self.token,self.lineNo=\
self.tokens.next()
returnASTNode(FuncCallNodeType,term,
result)
else:
raiseParseError(self.lineNo,'missingright
paren')
else:
raiseParseError(self.lineNo,'badfunccall
list')
else:
raiseParseError(self.lineNo,'missingleftparen')
else:
returnNone

deffunc_call_list_reco(self):
terms=[]
while1:
result=self.func_call_reco()
ifnotresult:
break
terms.append(result)
ifself.tokenType!=CommaTokType:

Page127
APythonBook

break
self.tokenType,self.token,self.lineNo=
self.tokens.next()
returnASTNode(FuncCallListNodeType,terms)

#
#Theparseerrorexceptionclass.
#
classParseError(Exception):
def__init__(self,lineNo,msg):
RuntimeError.__init__(self,msg)
self.lineNo=lineNo
self.msg=msg
defgetLineNo(self):
returnself.lineNo
defgetMsg(self):
returnself.msg

defis_word(token):
forletterintoken:
ifletternotinstring.ascii_letters:
returnNone
return1

#
#Generatethetokens.
#Usage:
#gen=genTokens(infile)
#tokType,tok,lineNo=gen.next()
#...
defgenTokens(infile):
lineNo=0
while1:
lineNo+=1
try:
line=infile.next()
except:
yield(EOFTokType,None,lineNo)
toks=line.split()
fortokintoks:
ifis_word(tok):
tokType=WordTokType
eliftok=='(':
tokType=LParTokType
eliftok==')':
tokType=RParTokType
eliftok==',':
tokType=CommaTokType
yield(tokType,tok,lineNo)

deftest(infileName):
parser=ProgParser()
#ipshell('(test)#1\nCtrlDtoexit')

Page128
APythonBook

result=None
try:
result=parser.parseFile(infileName)
exceptParseError,exp:
sys.stderr.write('ParseError:(%d)%s\n'%\
(exp.getLineNo(),exp.getMsg()))
ifresult:
result.show(0)

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=1:
usage()
inputfile=args[0]
test(inputfile)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Commentsandexplanation:
ThetokenizerisaPythongenerator.ItreturnsaPythongeneratorthatcan
produce"(tokType,tok,lineNo)"tuples.Ourtokenizerissosimplemindedthat
wehavetoseparateallofourtokenswithwhitespace.(Alittlelater,we'llseehow
tousePlextoovercomethislimitation.)
Theparserclass(ProgParser)containstherecognizermethodsthatimplementthe
productionrules.Eachofthesemethodsrecognizesasyntacticconstructdefined
byarule.Inourexample,thesemethodshavenamesthatendwith"_reco".
Wecouldhave,alternatively,implementedourrecognizersasglobalfunctions,
insteadofasmethodsinaclass.However,usingaclassgivesusaplaceto"hang"
thevariablesthatareneededacrossmethodsandsavesusfromhavingtouse
("evil")globalvariables.
Arecognizermethodrecognizesterminals(syntacticelementsontherighthand
sideofthegrammarruleforwhichthereisnogrammarrule)by(1)checkingthe
tokentypeandthetokenvalue,andthen(2)callingthetokenizertogetthenext
token(becauseithasconsumedatoken).

Page129
APythonBook

Arecognizermethodchecksforandprocessesanonterminal(syntacticelements
ontherighthandsideforwhichthereisagrammarrule)bycallingtherecognizer
methodthatimplementsthatnonterminal.
Ifarecognizermethodfindsasyntaxerror,itraisesanexceptionofclass
ParserError.
SinceourexamplerecursivedescentparsercreatesanAST(anabstractsyntax
tree),wheneverarecognizermethodsuccessfullyrecognizesasyntacticconstruct,
itcreatesaninstanceofclassASTNodetorepresentitandreturnsthatinstanceto
itscaller.TheinstanceofASTNodehasanodetypeandcontainschildnodes
whichwereconstructedbyrecognizermethodscalledbythisone(i.e.that
representnonterminalsontherighthandsideofagrammarrule).
Eachtimearecognizermethod"consumesatoken",itcallsthetokenizertoget
thenexttoken(andtokentypeandlinenumber).
Thetokenizerreturnsatokentypeinadditiontothetokenvalue.Italsoreturnsa
linenumberforerrorreporting.
ThesyntaxtreeisconstructedfrominstancesofclassASTNode.
TheASTNodeclasshasashowmethod,whichwalkstheASTandproduces
output.Youcanimaginethatasimilarmethodcoulddocodegeneration.And,
youshouldconsiderthepossibilityofwritinganalogoustreewalkmethodsthat
performtaskssuchasoptimization,annotationoftheAST,etc.
And,hereisasampleofthedatawecanapplythisparserto:
aaa()
bbb(ccc())
ddd(eee(),fff(ggg(),hhh(),iii()))
And,ifweruntheparseronthethisinputdata,wesee:
$pythonworkbook045.pyworkbook045.data
NodeTypeProgNodeType
NodeTypeCommandNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:aaa
NodeTypeFuncCallListNodeType
NodeTypeCommandNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:bbb
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:ccc
NodeTypeFuncCallListNodeType
NodeTypeCommandNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType

Page130
APythonBook

Child:ddd
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:eee
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:fff
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:ggg
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:hhh
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:iii
NodeTypeFuncCallListNodeType

2.6.3Creatingalexer/tokenizerwithPlex
LexicalanalysisThetokenizerinourrecursivedescentparserexamplewas(for
demonstrationpurposes)overlysimple.Youcanalwayswritemorecomplextokenizers
byhand.However,formorecomplex(andreal)tokenizers,youmaywanttouseatoolto
buildyourtokenizer.
Inthissectionwe'lldescribePlexanduseittoproduceatokenizerforourrecursive
descentparser.
YoucanobtainPlexathttp://www.cosc.canterbury.ac.nz/~greg/python/Plex/.
Inordertouseit,youmaywanttoaddPlex1.1.4/PlextoyourPYTHONPATH.
HereisasimpleexamplefromthePlextutorial:
#!/usr/bin/envpython

"""
SamplePlexlexer

Usage:
pythonplex_example.pyinputfile
"""

importsys
importPlex

Page131
APythonBook

defcount_lines(scanner,text):
scanner.line_count+=1
print''*60

deftest(infileName):
letter=Plex.Range("AZaz")
digit=Plex.Range("09")
name=letter+Plex.Rep(letter|digit)
number=Plex.Rep1(digit)
space=Plex.Any("\t")
endline=Plex.Str('\n')
#comment=Plex.Str('"')+Plex.Rep(Plex.AnyBut('"'))+
Plex.Str('"')
resword=Plex.Str("if","then","else","end")
lexicon=Plex.Lexicon([
(endline,count_lines),
(resword,'keyword'),
(name,'ident'),
(number,'int'),
(Plex.Any("+*/=<>"),'operator'),
(space,Plex.IGNORE),
#(comment,'comment'),
(Plex.Str('('),'lpar'),
(Plex.Str(')'),'rpar'),
#commentssurroundedby(*and*)
(Plex.Str("(*"),Plex.Begin('comment')),
Plex.State('comment',[
(Plex.Str("*)"),Plex.Begin('')),
(Plex.AnyChar,Plex.IGNORE),
]),
])
infile=open(infileName,"r")
scanner=Plex.Scanner(lexicon,infile,infileName)
scanner.line_count=0
whileTrue:
token=scanner.read()
iftoken[0]isNone:
break
position=scanner.position()
posstr=('(%d,%d)'%(position[1],
position[2],)).ljust(10)
tokstr='"%s"'%token[1]
tokstr=tokstr.ljust(20)
print'%stok:%stokType:%s'%(posstr,tokstr,token[0],)
print'line_count:%d'%scanner.line_count

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]

Page132
APythonBook

iflen(args)!=1:
usage()
infileName=args[0]
test(infileName)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Hereisabitofdataonwhichwecanusetheabovelexer:
mass=(height*(*somecomment*)width*depth)/density
totalmass=totalmass+mass
And,whenweapplytheabovetestprogramtothisdata,hereiswhatwesee:
$pythonplex_example.pyplex_example.data
(1,0)tok:"mass"tokType:ident
(1,5)tok:"="tokType:operator
(1,7)tok:"("tokType:lpar
(1,8)tok:"height"tokType:ident
(1,15)tok:"*"tokType:operator
(1,36)tok:"width"tokType:ident
(1,42)tok:"*"tokType:operator
(1,44)tok:"depth"tokType:ident
(1,49)tok:")"tokType:rpar
(1,51)tok:"/"tokType:operator
(1,53)tok:"density"tokType:ident

(2,0)tok:"totalmass"tokType:ident
(2,10)tok:"="tokType:operator
(2,12)tok:"totalmass"tokType:ident
(2,22)tok:"+"tokType:operator
(2,24)tok:"mass"tokType:ident

line_count:2
Commentsandexplanation:
Createalexiconfromscanningpatterns.
SeethePlextutorialandreference(andbelow)formoreinformationonhowto
constructthepatternsthatmatchvarioustokens.
Createascannerwithalexicon,aninputfile,andaninputfilename.
Thecall"scanner.read()"getsthenexttoken.Itreturnsatuplecontaining(1)the
tokenvalueand(2)thetokentype.
Thecall"scanner.position()"getsthepositionofthecurrenttoken.Itreturnsa
tuplecontaining(1)theinputfilename,(2)thelinenumber,and(3)thecolumn
number.
Wecanexecuteamethodwhenagiventokenisfoundbyspecifyingthefunction
asthetokenaction.Inourexample,thefunctioniscount_lines.Maintainingaline

Page133
APythonBook

countisactuallyunneeded,sincethepositiongivesusthisinformation.However,
noticehowweareabletomaintainavalue(inourcaseline_count)asan
attributeofthescanner.
And,herearesomecommentsonconstructingthepatternsusedinalexicon:
Plex.Rangeconstructsapatternthatmatchesanycharacterintherange.
Plex.Repconstructsapatternthatmatchesasequenceofzeroormoreitems.
Plex.Rep1constructsapatternthatmatchesasequenceofoneormoreitems.
pat1+pat2constructsapatternthatmatchesasequencecontainingpat1
followedbypat2.
pat1|pat2constructsapatternthatmatcheseitherpat1orpat2.
Plex.Anyconstructsapatternthatmatchesanyonecharacterinitsargument.
Nowlet'srevisitourrecursivedescentparser,thistimewithatokenizerbuiltwithPlex.
Thetokenizeristrivial,butwillserveasanexampleofhowtohookitintoaparser:
#!/usr/bin/envpython

"""
ArecursivedescentparserexampleusingPlex.
ThisexampleusesPlextoimplementatokenizer.

Usage:
pythonpython_201_rparser_plex.py[options]<inputfile>
Options:
h,helpDisplaythishelpmessage.
Example:
pythonpython_201_rparser_plex.pymyfile.txt

Thegrammar:

Prog::=Command|CommandProg
Command::=Func_call
Func_call::=Term'('Func_call_list')'
Func_call_list::=Func_call|Func_call','Func_call_list
Term=<word>

"""

importsys,string,types
importgetopt
importPlex

##fromIPython.ShellimportIPShellEmbed
##ipshell=IPShellEmbed((),
##banner='>>>>>>>>IntoIPython>>>>>>>>',
##exit_msg='<<<<<<<<OutofIPython<<<<<<<<')

#
#Constants
#

Page134
APythonBook

#ASTnodetypes
NoneNodeType=0
ProgNodeType=1
CommandNodeType=2
FuncCallNodeType=3
FuncCallListNodeType=4
TermNodeType=5

#Tokentypes
NoneTokType=0
LParTokType=1
RParTokType=2
WordTokType=3
CommaTokType=4
EOFTokType=5

#Dictionarytomapnodetypevaluestonodetypenames
NodeTypeDict={
NoneNodeType:'NoneNodeType',
ProgNodeType:'ProgNodeType',
CommandNodeType:'CommandNodeType',
FuncCallNodeType:'FuncCallNodeType',
FuncCallListNodeType:'FuncCallListNodeType',
TermNodeType:'TermNodeType',
}

#
#RepresentationofanodeintheAST(abstractsyntaxtree).
#
classASTNode:
def__init__(self,nodeType,*args):
self.nodeType=nodeType
self.children=[]
foriteminargs:
self.children.append(item)
defshow(self,level):
self.showLevel(level)
print'NodeType%s'%NodeTypeDict[self.nodeType]
level+=1
forchildinself.children:
ifisinstance(child,ASTNode):
child.show(level)
eliftype(child)==types.ListType:
foriteminchild:
item.show(level)
else:
self.showLevel(level)
print'Child:',child
defshowLevel(self,level):
foridxinrange(level):
print'',

Page135
APythonBook

#
#Therecursivedescentparserclass.
#Containsthe"recognizer"methods,whichimplementthegrammar
#rules(above),onerecognizermethodforeachproductionrule.
#
classProgParser:
def__init__(self):
self.tokens=None
self.tokenType=NoneTokType
self.token=''
self.lineNo=1
self.infile=None
self.tokens=None

defparseFile(self,infileName):
self.tokens=None
self.tokenType=NoneTokType
self.token=''
self.lineNo=1
self.infile=file(infileName,'r')
self.tokens=genTokens(self.infile,infileName)
try:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
exceptStopIteration:
raiseRuntimeError,'Emptyfile'
result=self.prog_reco()
self.infile.close()
self.infile=None
returnresult

defparseStream(self,instream):
self.tokens=None
self.tokenType=NoneTokType
self.token=''
self.lineNo=1
self.tokens=genTokens(self.instream,'<stream>')
try:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
exceptStopIteration:
raiseRuntimeError,'Emptystream'
result=self.prog_reco()
self.infile.close()
self.infile=None
returnresult

defprog_reco(self):
commandList=[]
while1:
result=self.command_reco()
ifnotresult:
break

Page136
APythonBook

commandList.append(result)
returnASTNode(ProgNodeType,commandList)

defcommand_reco(self):
ifself.tokenType==EOFTokType:
returnNone
result=self.func_call_reco()
returnASTNode(CommandNodeType,result)

deffunc_call_reco(self):
ifself.tokenType==WordTokType:
term=ASTNode(TermNodeType,self.token)
self.tokenType,self.token,self.lineNo=
self.tokens.next()
ifself.tokenType==LParTokType:
self.tokenType,self.token,self.lineNo=
self.tokens.next()
result=self.func_call_list_reco()
ifresult:
ifself.tokenType==RParTokType:
self.tokenType,self.token,self.lineNo=\
self.tokens.next()
returnASTNode(FuncCallNodeType,term,
result)
else:
raiseParseError(self.lineNo,'missingright
paren')
else:
raiseParseError(self.lineNo,'badfunccall
list')
else:
raiseParseError(self.lineNo,'missingleftparen')
else:
returnNone

deffunc_call_list_reco(self):
terms=[]
while1:
result=self.func_call_reco()
ifnotresult:
break
terms.append(result)
ifself.tokenType!=CommaTokType:
break
self.tokenType,self.token,self.lineNo=
self.tokens.next()
returnASTNode(FuncCallListNodeType,terms)

#
#Theparseerrorexceptionclass.
#
classParseError(Exception):
def__init__(self,lineNo,msg):

Page137
APythonBook

RuntimeError.__init__(self,msg)
self.lineNo=lineNo
self.msg=msg
defgetLineNo(self):
returnself.lineNo
defgetMsg(self):
returnself.msg

#
#Generatethetokens.
#Usageexample
#gen=genTokens(infile)
#tokType,tok,lineNo=gen.next()
#...
defgenTokens(infile,infileName):
letter=Plex.Range("AZaz")
digit=Plex.Range("09")
name=letter+Plex.Rep(letter|digit)
lpar=Plex.Str('(')
rpar=Plex.Str(')')
comma=Plex.Str(',')
comment=Plex.Str("#")+Plex.Rep(Plex.AnyBut("\n"))
space=Plex.Any("\t\n")
lexicon=Plex.Lexicon([
(name,'word'),
(lpar,'lpar'),
(rpar,'rpar'),
(comma,'comma'),
(comment,Plex.IGNORE),
(space,Plex.IGNORE),
])
scanner=Plex.Scanner(lexicon,infile,infileName)
while1:
tokenType,token=scanner.read()
name,lineNo,columnNo=scanner.position()
iftokenType==None:
tokType=EOFTokType
token=None
eliftokenType=='word':
tokType=WordTokType
eliftokenType=='lpar':
tokType=LParTokType
eliftokenType=='rpar':
tokType=RParTokType
eliftokenType=='comma':
tokType=CommaTokType
else:
tokType=NoneTokType
tok=token
yield(tokType,tok,lineNo)

deftest(infileName):
parser=ProgParser()

Page138
APythonBook

#ipshell('(test)#1\nCtrlDtoexit')
result=None
try:
result=parser.parseFile(infileName)
exceptParseError,exp:
sys.stderr.write('ParseError:(%d)%s\n'%\
(exp.getLineNo(),exp.getMsg()))
ifresult:
result.show(0)

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=1:
usage()
infileName=args[0]
test(infileName)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
And,hereisasampleofthedatawecanapplythisparserto:
#TestforrecursivedescentparserandPlex.
#Command#1
aaa()
#Command#2
bbb(ccc())#Anendoflinecomment.
#Command#3
ddd(eee(),fff(ggg(),hhh(),iii()))
#Endoftest
And,whenwerunourparser,itproducesthefollowing:
$pythonplex_recusive.pyplex_recusive.data
NodeTypeProgNodeType
NodeTypeCommandNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:aaa
NodeTypeFuncCallListNodeType
NodeTypeCommandNodeType

Page139
APythonBook

NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:bbb
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:ccc
NodeTypeFuncCallListNodeType
NodeTypeCommandNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:ddd
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:eee
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:fff
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:ggg
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:hhh
NodeTypeFuncCallListNodeType
NodeTypeFuncCallNodeType
NodeTypeTermNodeType
Child:iii
NodeTypeFuncCallListNodeType
Comments:
Wecannowputcommentsinourinput,andtheywillbeignored.Comments
beginwitha"#"andcontinuetotheendofline.Seethedefinitionofcommentin
functiongenTokens.
Thistokenizerdoesnotrequireustoseparatetokenswithwhitespaceasdidthe
simpletokenizerintheearlierversionofourrecursivedescentparser.
Thechangeswemadeovertheearlierversionwereto:
1. ImportPlex.
2. ReplacethedefinitionofthetokenizerfunctiongenTokens.
3. ChangethecalltogenTokenssothatthecallpassesinthefilename,whichis
neededtocreatethescanner.
OurnewversionofgenTokensdoesthefollowing:
1. Createpatternsforscanning.
2. Createalexicon(aninstanceofPlex.Lexicon),whichusesthepatterns.

Page140
APythonBook

3. Createascanner(aninstanceofPlex.Scanner),whichusesthelexicon.
4. Executealoopthatreadstokens(fromthescanner)and"yields"eachone.

2.6.4Asurveyofexistingtools
Forcomplexparsingtasks,youmaywanttoconsiderthefollowingtools:
kwParsingAparsergeneratorinPython
http://gadfly.sourceforge.net/kwParsing.html
PLYPythonLexYacchttp://systems.cs.uchicago.edu/ply/
PyLRFastLRparsinginpython
http://starship.python.net/crew/scott/PyLR.html
YappsTheYappsParserGeneratorSystem
http://theory.stanford.edu/~amitp/Yapps/
And,forlexicalanalysis,youmayalsowanttolookhere:
UsingRegularExpressionsforLexicalAnalysis
http://effbot.org/zone/xmlscanner.htm
Plexhttp://www.cosc.canterbury.ac.nz/~greg/python/Plex/.
Inthesectionsbelow,wegiveexamplesandnotesabouttheuseofPLYandpyparsing.

2.6.5CreatingaparserwithPLY
InthissectionwewillshowhowtoimplementourparserexamplewithPLY.
FirstdownloadPLY.Itisavailablehere:PLY(PythonLexYacc)
http://www.dabeaz.com/ply/
ThenaddthePLYdirectorytoyourPYTHONPATH.
LearnhowtoconstructlexersandparserswithPLYbyreadingdoc/ply.htmlinthe
distributionofPLYandbylookingattheexamplesinthedistribution.
Forthoseofyouwhowantamorecomplexexample,seeAPythonParserforthe
RELAXNGCompactSyntax,whichisimplementedwithPLY.
Now,hereisourexampleparser.Commentsandexplanationsarebelow:
#!/usr/bin/envpython

"""
Aparserexample.
ThisexampleusesPLYtoimplementalexerandparser.

Thegrammar:

Prog::=Command*
Command::=Func_call

Page141
APythonBook

Func_call::=Term'('Func_call_list')'
Func_call_list::=Func_call*
Term=<word>

Hereisasample"program"touseasinput:

#TestforrecursivedescentparserandPlex.
#Command#1
aaa()
#Command#2
bbb(ccc())#Anendoflinecomment.
#Command#3
ddd(eee(),fff(ggg(),hhh(),iii()))
#Endoftest
"""

importsys
importtypes
importgetopt
importply.lexaslex
importply.yaccasyacc

#
#Globals
#

startlinepos=0

#
#Constants
#

#ASTnodetypes
NoneNodeType=0
ProgNodeType=1
CommandNodeType=2
CommandListNodeType=3
FuncCallNodeType=4
FuncCallListNodeType=5
TermNodeType=6

#Dictionarytomapnodetypevaluestonodetypenames
NodeTypeDict={
NoneNodeType:'NoneNodeType',
ProgNodeType:'ProgNodeType',
CommandNodeType:'CommandNodeType',
CommandListNodeType:'CommandListNodeType',
FuncCallNodeType:'FuncCallNodeType',
FuncCallListNodeType:'FuncCallListNodeType',
TermNodeType:'TermNodeType',
}

Page142
APythonBook

#RepresentationofanodeintheAST(abstractsyntaxtree).
#
classASTNode:
def__init__(self,nodeType,*args):
self.nodeType=nodeType
self.children=[]
foriteminargs:
self.children.append(item)
defappend(self,item):
self.children.append(item)
defshow(self,level):
self.showLevel(level)
print'NodeType:%s'%NodeTypeDict[self.nodeType]
level+=1
forchildinself.children:
ifisinstance(child,ASTNode):
child.show(level)
eliftype(child)==types.ListType:
foriteminchild:
item.show(level)
else:
self.showLevel(level)
print'Value:',child
defshowLevel(self,level):
foridxinrange(level):
print'',

#
#Exceptionclasses
#
classLexerError(Exception):
def__init__(self,msg,lineno,columnno):
self.msg=msg
self.lineno=lineno
self.columnno=columnno
defshow(self):
sys.stderr.write('Lexererror(%d,%d)%s\n'%\
(self.lineno,self.columnno,self.msg))

classParserError(Exception):
def__init__(self,msg,lineno,columnno):
self.msg=msg
self.lineno=lineno
self.columnno=columnno
defshow(self):
sys.stderr.write('Parsererror(%d,%d)%s\n'%\
(self.lineno,self.columnno,self.msg))

#
#Lexerspecification
#
tokens=(
'NAME',

Page143
APythonBook

'LPAR','RPAR',
'COMMA',
)

#Tokens

t_LPAR=r'\('
t_RPAR=r'\)'
t_COMMA=r'\,'
t_NAME=r'[azAZ_][azAZ09_]*'

#Ignorewhitespace
t_ignore='\t'

#Ignorecomments('#'toendofline)
deft_COMMENT(t):
r'\#[^\n]*'
pass

deft_newline(t):
r'\n+'
globalstartlinepos
startlinepos=t.lexer.lexpos1
t.lineno+=t.value.count("\n")

deft_error(t):
globalstartlinepos
msg="Illegalcharacter'%s'"%(t.value[0])
columnno=t.lexer.lexposstartlinepos
raiseLexerError(msg,t.lineno,columnno)

#
#Parserspecification
#
defp_prog(t):
'prog:command_list'
t[0]=ASTNode(ProgNodeType,t[1])

defp_command_list_1(t):
'command_list:command'
t[0]=ASTNode(CommandListNodeType,t[1])

defp_command_list_2(t):
'command_list:command_listcommand'
t[1].append(t[2])
t[0]=t[1]

defp_command(t):
'command:func_call'
t[0]=ASTNode(CommandNodeType,t[1])

defp_func_call_1(t):
'func_call:termLPARRPAR'

Page144
APythonBook

t[0]=ASTNode(FuncCallNodeType,t[1])

defp_func_call_2(t):
'func_call:termLPARfunc_call_listRPAR'
t[0]=ASTNode(FuncCallNodeType,t[1],t[3])

defp_func_call_list_1(t):
'func_call_list:func_call'
t[0]=ASTNode(FuncCallListNodeType,t[1])

defp_func_call_list_2(t):
'func_call_list:func_call_listCOMMAfunc_call'
t[1].append(t[3])
t[0]=t[1]

defp_term(t):
'term:NAME'
t[0]=ASTNode(TermNodeType,t[1])

defp_error(t):
globalstartlinepos
msg="Syntaxerrorat'%s'"%t.value
columnno=t.lexer.lexposstartlinepos
raiseParserError(msg,t.lineno,columnno)

#
#ParsetheinputanddisplaytheAST(abstractsyntaxtree)
#
defparse(infileName):
startlinepos=0
#Buildthelexer
lex.lex(debug=1)
#Buildtheparser
yacc.yacc()
#Readtheinput
infile=file(infileName,'r')
content=infile.read()
infile.close()
try:
#Dotheparse
result=yacc.parse(content)
#DisplaytheAST
result.show(0)
exceptLexerError,exp:
exp.show()
exceptParserError,exp:
exp.show()

USAGE_TEXT=__doc__

defusage():
printUSAGE_TEXT
sys.exit(1)

Page145
APythonBook

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=1:
usage()
infileName=args[0]
parse(infileName)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Applyingthisparsertothefollowinginput:
#TestforrecursivedescentparserandPlex.
#Command#1
aaa()
#Command#2
bbb(ccc())#Anendoflinecomment.
#Command#3
ddd(eee(),fff(ggg(),hhh(),iii()))
#Endoftest
producesthefollowingoutput:
NodeType:ProgNodeType
NodeType:CommandListNodeType
NodeType:CommandNodeType
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:aaa
NodeType:CommandNodeType
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:bbb
NodeType:FuncCallListNodeType
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:ccc
NodeType:CommandNodeType
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:ddd
NodeType:FuncCallListNodeType
NodeType:FuncCallNodeType

Page146
APythonBook

NodeType:TermNodeType
Value:eee
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:fff
NodeType:FuncCallListNodeType
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:ggg
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:hhh
NodeType:FuncCallNodeType
NodeType:TermNodeType
Value:iii
Commentsandexplanation:
CreatingthesyntaxtreeBasically,eachrule(1)recognizesanonterminal,(2)
createsanode(possiblyusingthevaluesfromtherighthandsideoftherule),and
(3)returnsthenodebysettingthevalueoft[0].Adeviationfromthisisthe
processingofsequences,discussedbelow.
Sequencesp_command_list_1andp_command_list_1showhowtohandle
sequencesofitems.Inthiscase:
p_command_list_1recognizesacommandandcreatesaninstanceof
ASTNodewithtypeCommandListNodeTypeandaddsthecommandtoitasa
child,and
p_command_list_2recognizesanadditionalcommandandaddsit(asachild)
totheinstanceofASTNodethatrepresentsthelist.
DistinguishingbetweendifferentformsofthesameruleInordertoprocess
alternativestothesameproductionruledifferently,weusedifferentfunctions
withdifferentimplementations.Forexample,weuse:
p_func_call_1torecognizeandprocess"func_call:termLPARRPAR"(a
functioncallwithoutarguments),and
p_func_call_2torecognizeandprocess"func_call:termLPARfunc_call_list
RPAR"(afunctioncallwitharguments).
ReportingerrorsOurparserreportsthefirsterrorandquits.We'vedonethisby
raisinganexceptionwhenwefindanerror.Weimplementtwoexceptionclasses:
LexerErrorandParserError.Implementingmorethanoneexceptionclassenables
ustodistinguishbetweendifferentclassesoferrors(notethemultipleexcept:
clausesonthetry:statementinfunctionparse).And,weuseaninstanceofthe
exceptionclassasacontainerinorderto"bubbleup"informationabouttheerror
(e.g.amessage,alinenumber,andacolumnnumber).

Page147
APythonBook

2.6.6Creatingaparserwithpyparsing
pyparsingisarelativelynewparsingpackageforPython.Itwasimplementedandis
supportedbyPaulMcGuireanditshowspromise.Itappearsespeciallyeasytouseand
seemsespeciallyappropriateinparticularforquickparsingtasks,althoughithasfeatures
thatmakesomecomplexparsingtaskseasy.ItfollowsaverynaturalPythonstylefor
constructingparsers.
Gooddocumentationcomeswiththepyparsingdistribution.Seefile
HowToUseParsing.html.So,Iwon'ttrytorepeatthathere.Whatfollowsisanattemptto
provideseveralquickexamplestohelpyousolvesimpleparsingtasksasquicklyas
possible.
Youwillalsowanttolookatthesamplesintheexamplesdirectory,whicharevery
helpful.Myexamplesbelowarefairlysimple.Youcanseemoreoftheabilityof
pyparsingtohandlecomplextasksintheexamples.
WheretogetitYoucanfindpyparsingat:PyparsingWikiHome
http://pyparsing.wikispaces.com/
HowtoinstallitPutthepyparsingmodulesomewhereonyourPYTHONPATH.
Andnow,hereareafewexamples.

2.6.6.1Parsingcommadelimitedlines
Note:Thisexampleisfordemonstrationpurposesonly.Ifyoureallytoneedtoparse
commadelimitedfields,youcanprobablydosomuchmoreeasilywiththeCSV(comma
separatedvalues)moduleinthePythonstandardlibrary.
Hereisasimplegrammarforlinescontainingfieldsseparatedbycommas:
importsys
frompyparsingimportalphanums,ZeroOrMore,Word

fieldDef=Word(alphanums)
lineDef=fieldDef+ZeroOrMore(","+fieldDef)

deftest():
args=sys.argv[1:]
iflen(args)!=1:
print'usage:pythonpyparsing_test1.py<datafile.txt>'
sys.exit(1)
infilename=sys.argv[1]
infile=file(infilename,'r')
forlineininfile:
fields=lineDef.parseString(line)
printfields

Page148
APythonBook

test()
Hereissomesampledata:
abcd,defg
11111,22222,33333
And,whenwerunourparseronthisdatafile,hereiswhatwesee:
$pythoncomma_parser.pysample1.data
['abcd',',','defg']
['11111',',','22222',',','33333']
Notesandexplanation:
NotehowthegrammarisconstructedfromnormalPythoncallstofunctionand
object/classconstructors.I'veconstructedtheparserinlinebecausemyexample
issimple,butconstructingtheparserinafunctionorevenamodulemightmake
senseformorecomplexgrammars.pyparsingmakesiteasytousethesethese
differentstyles.
Use"+"tospecifyasequence.Inourexample,alineDefisafieldDef
followedby....
UseZeroOrMoretospecifyrepetition.Inourexample,alineDefisa
fieldDeffollowedbyzeroormoreoccurancesofcommaandfieldDef.
ThereisalsoOneOrMorewhenyouwanttorequireatleastoneoccurance.
Parsingcommadelimitedtexthappenssofrequentlythatpyparsingprovidesa
shortcut.Replace:
lineDef=fieldDef+ZeroOrMore(","+fieldDef)
with:
lineDef=delimitedList(fieldDef)
AndnotethatdelimitedListtakesanoptionalargumentdelimusedtospecify
thedelimiter.Thedefaultisacomma.

2.6.6.2Parsingfunctors
Thisexampleparsesexpressionsoftheformfunc(arg1,arg2,arg3):
frompyparsingimportWord,alphas,alphanums,nums,ZeroOrMore,
Literal

lparen=Literal("(")
rparen=Literal(")")
identifier=Word(alphas,alphanums+"_")
integer=Word(nums)
functor=identifier
arg=identifier|integer

Page149
APythonBook

args=arg+ZeroOrMore(","+arg)
expression=functor+lparen+args+rparen

deftest():
content=raw_input("Enteranexpression:")
parsedContent=expression.parseString(content)
printparsedContent

test()
Explanation:
UseLiteraltospecifyafixedstringthatistobematchedexactly.Inourexample,
alparenisa(.
Wordtakesanoptionalsecondargument.Withasingle(string)argument,it
matchesanycontiguouswordmadeupofcharactersinthestring.Withtwo
(string)argumentsitmatchesawordwhosefirstcharacterisinthefirststringand
whoseremainingcharactersareinthesecondstring.So,ourdefinitionof
identifiermatchesawordwhosefirstcharacterisanalphaandwhoseremaining
charactersarealphanumericsorunderscore.Asanotherexample,youcanthink
ofWord("0123456789")asanalogoustoaregexpcontainingthepattern"[09]+".
Useaverticalbarforalternation.Inourexample,anargcanbeeitheranidentifier
oraninteger.

2.6.6.3Parsingnames,phonenumbers,etc.
Thisexampleparsesexpressionshavingthefollowingform:
Inputformat:
[name][phone][city,statezip]
Last,first1112223333city,ca99999
Hereistheparser:
importsys
frompyparsingimportalphas,nums,ZeroOrMore,Word,Group,
Suppress,Combine

lastname=Word(alphas)
firstname=Word(alphas)
city=Group(Word(alphas)+ZeroOrMore(Word(alphas)))
state=Word(alphas,exact=2)
zip=Word(nums,exact=5)

name=Group(lastname+Suppress(",")+firstname)
phone=Combine(Word(nums,exact=3)+""+Word(nums,exact=3)+""
+Word(nums,exact=4))
location=Group(city+Suppress(",")+state+zip)

record=name+phone+location

Page150
APythonBook

deftest():
args=sys.argv[1:]
iflen(args)!=1:
print'usage:pythonpyparsing_test3.py<datafile.txt>'
sys.exit(1)
infilename=sys.argv[1]
infile=file(infilename,'r')
forlineininfile:
line=line.strip()
iflineandline[0]!="#":
fields=record.parseString(line)
printfields

test()
And,hereissomesampleinput:
Jabberer,Jerry1112223333Bakersfield,CA95111
Kackler,Kerry1112223334Fresno,CA95112
Louderdale,Larry1112223335LosAngeles,CA94001
Hereisoutputfromparsingtheaboveinput:
[['Jabberer','Jerry'],'1112223333',[['Bakersfield'],'CA',
'95111']]
[['Kackler','Kerry'],'1112223334',[['Fresno'],'CA','95112']]
[['Louderdale','Larry'],'1112223335',[['Los','Angeles'],'CA',
'94001']]
Comments:
Weusethelen=nargumenttotheWordconstructortoresticttheparserto
acceptingaspecificnumberofcharacters,forexampleinthezipcodeandphone
number.Wordalsoacceptsmin=n''and``max=ntoenableyoutorestrict
thelengthofawordtowithinarange.
WeuseGrouptogrouptheparsedresultsintosublists,forexampleinthe
definitionofcityandname.Groupenablesustoorganizetheparseresultsinto
simpleparsetrees.
WeuseCombinetojoinparsedresultsbackintoasinglestring.Forexample,in
thephonenumber,wecanrequiredashesandyetjointheresultsbackintoa
singlestring.
WeuseSuppresstoremoveunneededsubelementsfromparsedresults.For
example,wedonotneedthecommabetweenlastandfirstname.

2.6.6.4Amorecomplexexample
Thisexample(thankstoPaulMcGuire)parsesamorecomplexstructureandproducesa
dictionary.

Page151
APythonBook

Hereisthecode:
frompyparsingimportLiteral,Word,Group,Dict,ZeroOrMore,alphas,
nums,\
delimitedList
importpprint

testData="""
++++++++++
||A1|B1|C1|D1|A2|B2|C2|D2|
+=======+======+======+======+======+======+======+======+======+
|min|7|43|7|15|82|98|1|37|
|max|11|52|10|17|85|112|4|39|
|ave|9|47|8|16|84|106|3|38|
|sdev|1|3|1|1|1|3|1|1|
++++++++++
"""

#Definegrammarfordatatable
heading=(Literal(
"++++++++++")
+
"||A1|B1|C1|D1|A2|B2|C2|D2|"+
"+=======+======+======+======+======+======+======+======+======+").
suppress()

vert=Literal("|").suppress()
number=Word(nums)
rowData=Group(vert+Word(alphas)+vert+
delimitedList(number,"|")+
vert)
trailing=Literal(
"++++++++++").
suppress()

datatable=heading+Dict(ZeroOrMore(rowData))+trailing

defmain():
#Nowparsedataandprintresults
data=datatable.parseString(testData)
print"data:",data
print"data.asList():",
pprint.pprint(data.asList())
print"datakeys:",data.keys()
print"data['min']:",data['min']
print"data.max:",data.max

if__name__=='__main__':
main()
Whenwerunthis,itproducesthefollowing:
data:[['min','7','43','7','15','82','98','1','37'],

Page152
APythonBook

['max','11','52','10','17','85','112','4','39'],
['ave','9','47','8','16','84','106','3','38'],
['sdev','1','3','1','1','1','3','1','1']]
data.asList():[['min','7','43','7','15','82','98','1','37'],
['max','11','52','10','17','85','112','4','39'],
['ave','9','47','8','16','84','106','3','38'],
['sdev','1','3','1','1','1','3','1','1']]
datakeys:['ave','min','sdev','max']
data['min']:['7','43','7','15','82','98','1','37']
data.max:['11','52','10','17','85','112','4','39']
Notes:
NotetheuseofDicttocreateadictionary.Theprintstatementsshowhowtoget
attheitemsinthedictionary.
NotehowwecanalsogettheparseresultsasalistbyusingmethodasList.
Again,weusesuppresstoremoveunneededitemsfromtheparseresults.

2.7GUIApplications

2.7.1Introduction
ThissectionwillhelpyoutoputaGUI(graphicaluserinterface)inyourPython
program.
WewilluseaparticularGUIlibrary:PyGTK.We'vechosenthisbecauseitisreasonably
lightweightandourgoalistoembedlightweightGUIinterfacesinan(possibly)
existingapplication.
ForsimplerGUIneeds,considerEasyGUI,whichisalsodescribedbelow.
FormoreheavyweightGUIneeds(forexample,completeGUIapplications),youmay
wanttoexploreWxPython.SeetheWxPythonhomepageat:http://www.wxpython.org/

2.7.2PyGtk
InformationaboutPyGTKishere:ThePyGTKhomepagehttp://www.pygtk.org//.

2.7.2.1Asimplemessagedialogbox
InthissectionweexplainhowtopopupasimpledialogboxfromyourPython
application.
Todothis,dothefollowing:
1. ImportgtkintoyourPythonmodule.
2. Definethedialoganditsbehavior.

Page153
APythonBook

3. Createaninstanceofthedialog.
4. Runtheeventloop.
Hereisasamplethatdisplaysamessagebox:
#!/usr/bin/envpython

importsys
importgetopt
importgtk

classMessageBox(gtk.Dialog):
def__init__(self,message="",buttons=(),pixmap=None,
modal=True):
gtk.Dialog.__init__(self)
self.connect("destroy",self.quit)
self.connect("delete_event",self.quit)
ifmodal:
self.set_modal(True)
hbox=gtk.HBox(spacing=5)
hbox.set_border_width(5)
self.vbox.pack_start(hbox)
hbox.show()
ifpixmap:
self.realize()
pixmap=Pixmap(self,pixmap)
hbox.pack_start(pixmap,expand=False)
pixmap.show()
label=gtk.Label(message)
hbox.pack_start(label)
label.show()
fortextinbuttons:
b=gtk.Button(text)
b.set_flags(gtk.CAN_DEFAULT)
b.set_data("user_data",text)
b.connect("clicked",self.click)
self.action_area.pack_start(b)
b.show()
self.ret=None
defquit(self,*args):
self.hide()
self.destroy()
gtk.main_quit()
defclick(self,button):
self.ret=button.get_data("user_data")
self.quit()

#createamessagebox,andreturnwhichbuttonwaspressed
defmessage_box(title="MessageBox",message="",buttons=(),
pixmap=None,
modal=True):
win=MessageBox(message,buttons,pixmap=pixmap,modal=modal)
win.set_title(title)

Page154
APythonBook

win.show()
gtk.main()
returnwin.ret

deftest():
result=message_box(title='Test#1',
message='Hereisyourmessage',
buttons=('Ok','Cancel'))
print'result:',result

USAGE_TEXT="""
Usage:
pythonsimple_dialog.py[options]
Options:
h,helpDisplaythishelpmessage.
Example:
pythonsimple_dialog.py
"""

defusage():
printUSAGE_TEXT
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=0:
usage()
test()

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Someexplanation:
First,weimportgtk
NextwedefineaclassMessageBoxthatimplementsamessagebox.Herearea
fewimportantthingstoknowaboutthatclass:
Itisasubclassofgtk.Dialog.
Itcreatesalabelandpacksitintothedialog'sclientarea.NotethataDialogis
aWindowthatcontainsavboxatthetopofandanaction_areaatthebottom
ofitsclientarea.Theintensionisforustopackmiscellaneouswidgetsinto
thevboxandtoputbuttonssuchas"Ok","Cancel",etcintotheaction_area.

Page155
APythonBook

Itcreatesonebuttonforeachbuttonlabelpassedtoitsconstructor.The
buttonsareallconnectedtotheclickmethod.
Theclickmethodsavesthevalueoftheuser_dataforthebuttonthatwas
clicked.Inourexample,thisvaluewillbeeither"Ok"or"Cancel".
And,wedefineafunction(message_box)that(1)createsaninstanceofthe
MessageBoxclass,(2)setsitstitle,(3)showsit,(4)startsitseventloopsothatit
cangetandprocesseventsfromtheuser,and(5)returnstheresulttothecaller(in
thiscase"Ok"or"Cancel").
Ourtestingfunction(test)callsfunctionmessage_boxandprintstheresult.
Thislookslikequiteabitofcode,untilyounoticethattheclassMessageBoxand
thefunctionmessage_boxcouldbeputitautilitymoduleandreused.

2.7.2.2Asimpletextinputdialogbox
And,hereisanexamplethatdisplaysantextinputdialog:
#!/usr/bin/envpython

importsys
importgetopt
importgtk

classEntryDialog(gtk.Dialog):
def__init__(self,message="",default_text='',modal=True):
gtk.Dialog.__init__(self)
self.connect("destroy",self.quit)
self.connect("delete_event",self.quit)
ifmodal:
self.set_modal(True)
box=gtk.VBox(spacing=10)
box.set_border_width(10)
self.vbox.pack_start(box)
box.show()
ifmessage:
label=gtk.Label(message)
box.pack_start(label)
label.show()
self.entry=gtk.Entry()
self.entry.set_text(default_text)
box.pack_start(self.entry)
self.entry.show()
self.entry.grab_focus()
button=gtk.Button("OK")
button.connect("clicked",self.click)
button.set_flags(gtk.CAN_DEFAULT)
self.action_area.pack_start(button)
button.show()
button.grab_default()
button=gtk.Button("Cancel")

Page156
APythonBook

button.connect("clicked",self.quit)
button.set_flags(gtk.CAN_DEFAULT)
self.action_area.pack_start(button)
button.show()
self.ret=None
defquit(self,w=None,event=None):
self.hide()
self.destroy()
gtk.main_quit()
defclick(self,button):
self.ret=self.entry.get_text()
self.quit()

definput_box(title="InputBox",message="",default_text='',
modal=True):
win=EntryDialog(message,default_text,modal=modal)
win.set_title(title)
win.show()
gtk.main()
returnwin.ret

deftest():
result=input_box(title='Test#2',
message='Enteravaluexxx:',
default_text='adefaultvalue')
ifresultisNone:
print'Canceled'
else:
print'result:"%s"'%result

USAGE_TEXT="""
Usage:
pythonsimple_dialog.py[options]
Options:
h,helpDisplaythishelpmessage.
Example:
pythonsimple_dialog.py
"""

defusage():
printUSAGE_TEXT
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()

Page157
APythonBook

iflen(args)!=0:
usage()
test()

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Mostoftheexplanationforthemessageboxexampleisrelevanttothisexample,too.
Herearesomedifferences:
OurEntryDialogclassconstructorcreatesinstanceofgtk.Entry,setsitsdefault
value,andpacksitintotheclientarea.
Theconstructoralsoautomaticallycreatestwobuttons:"OK"and"Cancel".The
"OK"buttonisconnecttotheclickmethod,whichsavesthevalueoftheentry
field.The"Cancel"buttonisconnecttothequitmethod,whichdoesnotsavethe
value.
And,ifclassEntryDialogandfunctioninput_boxlookusableanduseful,add
themtoyourutilityguimodule.

2.7.2.3Afileselectiondialogbox
Thisexampleshowsafileselectiondialogbox:
#!/usr/bin/envpython

importsys
importgetopt
importgtk

classFileChooser(gtk.FileSelection):
def__init__(self,modal=True,multiple=True):
gtk.FileSelection.__init__(self)
self.multiple=multiple
self.connect("destroy",self.quit)
self.connect("delete_event",self.quit)
ifmodal:
self.set_modal(True)
self.cancel_button.connect('clicked',self.quit)
self.ok_button.connect('clicked',self.ok_cb)
ifmultiple:
self.set_select_multiple(True)
self.ret=None
defquit(self,*args):
self.hide()
self.destroy()
gtk.main_quit()
defok_cb(self,b):
ifself.multiple:
self.ret=self.get_selections()

Page158
APythonBook

else:
self.ret=self.get_filename()
self.quit()

deffile_sel_box(title="Browse",modal=False,multiple=True):
win=FileChooser(modal=modal,multiple=multiple)
win.set_title(title)
win.show()
gtk.main()
returnwin.ret

deffile_open_box(modal=True):
returnfile_sel_box("Open",modal=modal,multiple=True)
deffile_save_box(modal=True):
returnfile_sel_box("SaveAs",modal=modal,multiple=False)

deftest():
result=file_open_box()
print'openresult:',result
result=file_save_box()
print'saveresult:',result

USAGE_TEXT="""
Usage:
pythonsimple_dialog.py[options]
Options:
h,helpDisplaythishelpmessage.
Example:
pythonsimple_dialog.py
"""

defusage():
printUSAGE_TEXT
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help'])
except:
usage()
relink=1
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=0:
usage()
test()

if__name__=='__main__':
main()
#importpdb
#pdb.run('main()')

Page159
APythonBook

Alittleguidance:
Thereisapredefinedfileselectiondialog.Wesubclassit.
Thisexampledisplaysthefileselectiondialogtwice:oncewithatitle"Open"and
oncewithatitle"SaveAs".
Notehowwecancontrolwhetherthedialogallowsmultiplefileselections.And,
ifweselectthemultipleselectionmode,thenweuseget_selectionsinsteadof
get_filenameinordertogettheselectedfilenames.
Thedialogcontainsbuttonsthatenabletheuserto(1)createanewfolder,(2)
deleteafile,and(3)renameafile.Ifyoudonotwanttheusertoperformthese
operations,thencallhide_fileop_buttons.Thiscalliscommentedoutinour
samplecode.
Notethattherearealsopredefineddialogsforfontselection(FontSelectionDialog)and
colorselection(ColorSelectionDialog)

2.7.3EasyGUI
IfyourGUIneedsareminimalist(maybeapopupdialogortwo)andyourapplicationis
imperativeratherthaneventdriven,thenyoumaywanttoconsiderEasyGUI.Asthe
namesuggests,itisextremelyeasytouse.
HowtoknowwhenyoumightbeabletouseEasyGUI:
Yourapplicationdoesnotneedtoruninawindowcontainingmenusandamenu
bar.
YourGUIneedsamounttolittlemorethandisplayingadialognowandthento
getresponsesfromtheuser.
Youdonotwanttowriteaneventdrivenapplication,thatis,oneinwhichyour
codesitsandwaitsforthetheusertoinitiateoperation,forexample,withmenu
items.
EasyGUIplusdocumentationandexamplesareavailableatEasyGUIhomepageat
SourceForgehttp://easygui.sourceforge.net/
EasyGUIprovidesfunctionsforavarietyofcommonlyneededdialogboxes,including:
Amessageboxdisplaysamessage.
Ayes/nomessageboxdisplays"Yes"and"No"buttons.
Acontinue/cancelmessageboxdisplays"Continue"and"Cancel"buttons.
Achoiceboxdisplaysaselectionlist.
Anenterboxallowsentryofalineoftext.
Anintegerboxallowsentryofaninterger.
Amultipleentryboxallowsentryintomultiplefields.
Codeandtextboxessupportthedisplayoftextinmonospacedorporportional

Page160
APythonBook

fonts.
Fileanddirectoryboxesenabletheusertoselectafileoradirectory.
SeethedocumentationattheEasyGUIWebsiteformorefeatures.
ForademonstrationofEasyGUI'scapabilities,runtheeasygui.pyasaPythonscript:
$pythoneasygui.py

2.7.3.1AsimpleEasyGUIexample
Hereisasimpleexamplethatpromptstheuserforanentry,thenshowstheresponseina
messagebox:
importeasygui

deftesteasygui():
response=easygui.enterbox(msg='Enteryourname:',title='Name
Entry')
easygui.msgbox(msg=response,title='YourResponse')

testeasygui()

2.7.3.2AnEasyGUIfileopendialogexample
Thisexamplepresentsadialogtoallowtheusertoselectafile:
importeasygui

deftest():
response=easygui.fileopenbox(msg='Selectafile')
print'filename:%s'%response

test()

2.8GuidanceonPackagesandModules

2.8.1Introduction
Pythonhasanexcellentrangeofimplementationorganizationstructures.Theserange
fromstatementsandcontrolstructures(atalowlevel)throughfunctions,methods,and
classes(atanintermediatelevel)andmodulesandpackagesatanupperlevel.
Thissectionprovidessomeguidancewiththeuseofpackages.Inparticular:
Howtoconstructandimplementthem.
Howtousethem.
Howtodistributeandinstallthem.

Page161
APythonBook

2.8.2ImplementingPackages
APythonpackageisacollectionofPythonmodulesinadiskdirectory.
Inordertobeabletoimportindividualmodulesfromadirectory,thedirectorymust
containafilenamed__init__.py.(Notethatrequirementdoesnotapplytodirectoriesthat
arelistedinPYTHONPATH.)The__init__.pyservesseveralpurposes:
Thepresenceofthefile__init__.pyinadirectorymarksthedirectoryasaPython
package,whichenablesimportingmodulesfromthedirectory.
Thefirsttimeanapplicationimportsanymodulefromthedirectory/package,the
codeinthemodule__init__isevaluated.
Ifthepackageitselfisimported(asopposedtoanindividualmodulewithinthe
directory/package),thenitisthe__init__thatisimported(andevaluated).

2.8.3UsingPackages
Onesimplewaytoenabletheusertoimportanduseapackageistoinstructtheuseto
importindividualmodulesfromthepackage.
Asecond,slightlymoreadvancedwaytoenabletheusertoimportthepackageisto
exposethosefeaturesofthepackageinthe__init__module.Supposethatmodulemod1
containsfunctionsfun1aandfun1bandsupposethatmodulemod2containsfunctions
fun2aandfun2b.Thenfile__init__.pymightcontainthefollowing:
frommod1importfun1a,fun1b
frommod2importfun2a,fun2b
Then,ifthefollowingisevaluatedintheuser'scode:
importtestpackages
Thentestpackageswillcontainfun1a,fun1b,fun2a,andfun2b.
Forexample,hereisaninteractivesessionthatdemostratesimportingthepackage:
>>>importtestpackages
>>>printdir(testpackages)
[`__builtins__',`__doc__',`__file__',`__name__',
`__path__',
`fun1a',`fun1b',`fun2a',`fun2b',`mod1',`mod2']

2.8.4DistributingandInstallingPackages
Distutils(PythonDistributionUtilities)hasspecialsupportfordistrubutingandinstalling
packages.Learnmorehere:DistributingPythonModules
http://docs.python.org/distutils/index.html.

Page162
APythonBook

Asourexample,imaginethatwehaveadirectorycontainingthefollowing:
Testpackages
Testpackages/README
Testpackages/MANIFEST.in
Testpackages/setup.py
Testpackages/testpackages/__init__.py
Testpackages/testpackages/mod1.py
Testpackages/testpackages/mod2.py
NoticethesubdirectoryTestpackages/testpackagescontainingthefile__init__.py.
ThisisthePythonpackagethatwewillinstall.
We'lldescribehowtoconfiguretheabovefilessothattheycanbepackagedasasingle
distributionfileandsothatthePythonpackagetheycontaincanbeinstalledasapackage
byDistutils.
TheMANIFEST.infileliststhefilesthatwewantincludedinourdistribution.Hereis
thecontentsofourMANIFEST.infile:
includeREADMEMANIFESTMANIFEST.in
includesetup.py
includetestpackages/*.py
Thesetup.pyfiledescribestoDistutils(1)howtopackagethedistributionfileand(2)
howtoinstallthedistribution.Hereisthecontentsofoursamplesetup.py:
#!/usr/bin/envpython

fromdistutils.coreimportsetup#[1]

long_description='TestsforinstallinganddistributingPython
packages'

setup(name='testpackages',#[2]
version='1.0a',
description='TestsforPythonpackages',
maintainer='DaveKuhlman',
maintainer_email='dkuhlman@rexx.com',
url='http://www.rexx.com/~dkuhlman',
long_description=long_description,
packages=['testpackages']#[3]
)
Explanation:
1. WeimportthenecessarycomponentfromDistutils.
2. Wedescribethepackageanditsdeveloper/maintainer.
3. Wespecifythedirectorythatistobeinstalledasapackage.Whentheuser
installsourdistribution,thisdirectoryandallthemodulesinitwillbeinstalledas
apackage.

Page163
APythonBook

Now,tocreateadistributionfile,werunthefollowing:
pythonsetup.pysdistformats=gztar
whichwillcreateafiletestpackages1.0a.tar.gzunderthedirectorydist.
Then,youcangivethisdistributionfiletoapotentialuser,whocaninstallitbydoingthe
following:
$tarxvzftestpackages1.0a.tar.gz
$cdtestpackages1.0a
$pythonsetup.pybuild
$pythonsetup.pyinstall#asroot

2.9EndMatter

2.9.1AcknowledgementsandThanks
ThankstotheimplementorsofPythonforproducinganexceptionallyusableand
enjoyableprogramminglanguage.
ThankstoDaveBeazleyandothersforSWIGandPLY.
ThankstoGregEwingforPyrexandPlex.
ThankstoJamesHenstridgeforPyGTK.

2.9.2SeeAlso
ThemainPythonWebSitehttp://www.python.orgformoreinformationon
Python.
PythonDocumentationhttp://www.python.org/doc/forlotsofdocumentation
onPython
Dave'sWebSitehttp://http://www.davekuhlman.orgformoresoftwareand
informationonusingPythonforXMLandtheWeb.
TheSWIGhomepagehttp://www.swig.orgformoreinformationonSWIG
(SimplifiedWrapperandInterfaceGenerator).
ThePyrexhomepagehttp://www.cosc.canterbury.ac.nz/~greg/python/Pyrex/
formoreinformationonPyrex.
PLY(PythonLexYacc)homepagehttp://www.dabeaz.com/ply/formore
informationonPLY.
ThePlexhomepagehttp://www.cosc.canterbury.ac.nz/greg.ewing/python/Plex/
formoreinformationonPlex.
DistributingPythonModuleshttp://docs.python.org/distutils/index.htmlfor
informationonthePythonDistributionUtilities(Distutils).

Page164
APythonBook

3Part3PythonWorkbook

3.1Introduction
ThisdocumenttakesaworkbookandexercisewithsolutionsapproachtoPython
training.Itishopedthatthosewhofeelaneedforlessexplanationandmorepractical
exerciseswillfindthisuseful.
Afewnotesabouttheexercises:
I'vetriedtoincludesolutionsformostoftheexercises.Hopefully,youwillbe
abletocopyandpastethesesolutionsintoyourtexteditor,thenextendand
experimentwiththem.
IusetwointeractivePythoninterpreters(althoughtheyarethesamePython
underneath).Whenyouseethisprompt>>>,it'sthestandardPythoninterpreter.
And,whenyouseethispromptIn[1]:,it'sIPython
http://ipython.scipy.org/moin/.
ThelatestversionofthisdocumentisatmyWebsite(URLabove).
Ifyouhavecommentsorsuggestions,pleasesendthemmyway.

3.2LexicalStructures

3.2.1Variablesandnames
Anameisanycombinationofletters,digits,andtheunderscore,butthefirstcharacter
mustbealetteroranunderscore.Namesmaybeofanylength.
Caseissignificant.
Exercises:
1. Whichofthefollowingarevalidnames?
1. total
2. total_of_all_vegetables
3. bigtitle1
4. _inner_func
5. 1bigtitle
6. bigtitle1
2. Whichorthefollowingpairsarethesamename:
1. the_last_itemandthe_last_item

Page165
APythonBook

2. the_last_itemandThe_Last_Item
3. itemianditemj
4. item1anditeml
Solutions:
1. Items1,2,4,and6arevalid.Item3isnotasinglename,butisthreeitems
separatedbytheminusoperator.Item5isnotvalidbecauseitbeginswithadigit.
2. Pythonnamesarecasesensitive,whichmeans:
1. the_last_itemandthe_last_itemarethesame.
2. the_last_itemandThe_Last_ItemaredifferentThesecondname
hasanuppercasecharacters.
3. itemianditemjaredifferent.
4. item1anditemlaredifferentThisonemaybedifficulttosee,
dependingonthefontyouareviewing.Onenameendswiththedigitone;the
otherendswiththealphacharacter"el".Andthisexampleprovidesagood
reasontouse"1"and"l"judiciouslyinnames.
ThefollowingarekeywordsinPythonandshouldnotbeusedasvariablenames:

anddelfromnotwhile
aselifglobalorwith
assertelseifpassyield
breakexceptimportprint
classexecinraise
continuefinallyisreturn
defforlambdatry
Exercises:
1. WhichofthefollowingarevalidnamesinPython?
1. _global
2. global
3. file
Solutions:
1. Donotusekeywordsforvariablenames:
1. Valid
2. Notavalidname."global"isakeyword.
3. Valid,however,"file"isthenameofabuiltintype,asyouwilllearnlater,so
youareadvisednottoredefineit.Hereareafewofthenamesofbuiltin
types:"file","int","str","float","list","dict",etc.SeeBuiltinTypes
http://docs.python.org/lib/types.htmlformorebuiltintypes..
ThefollowingareoperatorsinPythonandwillseparatenames:
+***///%
<<>>&|^~

Page166
APythonBook

<><=>===!=<>

andorisnotin

Also:()[].(dot)
But,notethatthePythonstyleguidesuggeststhatyouplaceblanksaroundbinary
operators.Oneexceptiontothisruleisfunctionargumentsandparametersforfunctions:
itissuggestedthatyounotputblanksaroundtheequalsign(=)usedtospecifykeyword
argumentsanddefaultparameters.
Exercises:
1. Whichofthefollowingaresinglenamesandwhicharenamesseparatedby
operators?
1. fruit_collection
2. fruitcollection
Solutions:
1. Donotuseadash,orotheroperator,inthemiddleofaname:
1. fruit_collectionisasinglename
2. fruitcollectionistwonamesseparatedbyadash.

3.2.2Linestructure
InPython,normallywewriteonestatementperline.Infact,Pythonassumesthis.
Therefore:
Statementseparatorsarenotnormallyneeded.
But,ifwewantmorethanonestatementonaline,weuseastatementseparator,
specificallyasemicolon.
And,ifwewanttoextendastatementtoasecondorthirdlineandsoon,we
sometimesneedtodoabitextra.
ExtendingaPythonstatementtoasubsequentlineFollowthesetworules:
1. Ifthereisanopencontext,nothingspecialneedbedonetoextendastatement
acrossmultiplelines.Anopencontextisanopenparenthesis,anopensquare
bracket,oranopencurlybracket.
2. Wecanalwaysextendastatementonafollowinglinebyplacingabackslashas
thelastcharacteroftheline.
Exercises:
1. Extendthefollowingstatementtoasecondlineusingparentheses:
total_count=tree_count+vegetable_count+
fruit_count
2. Extendthefollowingstatementtoasecondlineusingthebackslashline

Page167
APythonBook

continuationcharacter:
total_count=tree_count+vegetable_count+
fruit_count
Solutions:
1. ParenthesescreateanopencontextthattellsPythonthatastatementextendsto
thenextline:
total_count=(tree_count+
vegetable_count+fruit_count)
2. AbackslashasthelastcharacteronlinetellsPythonthatthecurrentstatement
extendstothenextline:
total_count=tree_count+\
vegetable_count+fruit_count
Forextendingalineonasubsequentline,whichisbetter,parenthesesorabackslash?
Hereisaquote:
"ThepreferredwayofwrappinglonglinesisbyusingPython'simplied
linecontinuationinsideparentheses,bracketsandbraces.Ifnecessary,
youcanaddanextrapairofparenthesesaroundanexpression,but
sometimesusingabackslashlooksbetter."
PEP8:StyleGuideforPythonCode
http://www.python.org/dev/peps/pep0008/

3.2.3Indentationandprogramstructure
Pythonusesindentationtoindicateprogramstructure.Thatistosay,inordertonesta
blockofcodeinsideacompoundstatement,youindentthatnestedcode.Thisisdifferent
frommanyprogramminglanguageswhichusesomesortofbeginandendmarkers,for
examplecurlybrackets.
ThestandardcodingpracticeforPythonistousefourspacesperindentationlevelandto
notusehardtabs.(SeetheStyleGuideforPythonCode.)Becauseofthis,youwillwant
touseatexteditorthatyoucanconfiguresothatitwillusefourspacesforindentation.
SeehereforalistofPythonfriendlytexteditors:PythonEditors.
Exercises:
1. Giventhefollowing,nesttheprintstatementinsidetheifstatement:
ifx>0:

printx
2. Nestthesetwolines:

Page168
APythonBook

z=x+y
printz
insidethefollowingfunctiondefinitionstatement:
defshow_sum(x,y):
Solutions:
1. Indentationindicatesthatonestatementisnestedinsideanotherstatement:
ifx>0:
printx
2. Indentationindicatesthatablockofstatementsisnestedinsideanotherstatement:
defshow_sum(x,y):
z=x+y
printz

3.3ExecutionModel
Hereareafewrules:
1. PythonevaluatesPythoncodefromthetopofamoduledowntothebottomofa
module.
2. Bindingstatementsattoplevelcreatenames(andbindvaluestothosenames)as
Pythonevaluatescode.Furthermore,anameisnotcreateduntilitisboundtoa
value/object.
3. Anestedreferencetoaname(forexample,insideafunctiondefinitionorinthe
nestedblockofanifstatement)isnotuseduntilthatnestedcodeisevaluated.
Exercises:
1. Willthefollowingcodeproduceanerror?
show_version()
defshow_version():
print'Version1.0a'
2. Willthefollowingcodeproduceanerror?
deftest():
show_version()

defshow_version():
print'Version1.0a'

test()
3. Willthefollowingcodeproduceanerror?Assumethatshow_configisnot
defined:
x=3

Page169
APythonBook

ifx>5:
show_config()
Solutions:
1. Answer:Yes,itgeneratesanerror.Thenameshow_versionwouldnotbe
createdandboundtoavalueuntilthedeffunctiondefinitionstatementbindsa
functionobjecttoit.Thatisdoneaftertheattempttouse(call)thatobject.
2. Answer:No.Thefunctiontest()doescallthefunctionshow_version(),
butsincetest()isnotcalleduntilaftershow_version()isdefined,thatis
OK.
3. Answer:No.It'sbadcode,butinthiscasewillnotgenerateanerror.Sincexis
lessthan5,thebodyoftheifstatementisnotevaluated.
N.B.Thisexampleshowswhyitisimportantduringtestingthateverylineof
codeinyourPythonprogrambeevaluated.HereisgoodPythonicadvice:"Ifit's
nottested,it'sbroken."

3.4BuiltinDataTypes
Eachofthesubsectionsinthissectiononbuiltindatatypeswillhaveasimilarstructure:
1. Abriefdescriptionofthedatatypeanditsuses.
2. RepresentationandconstructionHowtorepresentaninstanceofthedatatype.
Howtocodealiteralrepresentationthatcreatesanddefinesaninstance.Howto
createaninstanceofthebuiltintype.
3. Operatorsthatareapplicabletothedatatype.
4. Methodsimplementedandsupportedbythedatatype.

3.4.1Numbers
Thenumbersyouwillusemostcommonlyarelikelytobeintegersandfloats.Python
alsohaslongintegersandcomplexnumbers.
Afewfactsaboutnumbers(inPython):
Pythonwillconverttousingalongintegerautomaticallywhenneeded.Youdo
notneedtoworryaboutexceedingthesizeofa(standard)integer.
ThesizeofthelargestintegerinyourversionofPythonisinsys.maxint.To
learnwhatitis,do:
>>>importsys
>>>printsys.maxint
9223372036854775807
Theaboveshowthemaximumsizeofanintegerona64bitversionofPython.
Youcanconvertfromintegertofloatbyusingthefloatconstructor.Example:

Page170
APythonBook

>>>x=25
>>>y=float(x)
>>>printy
25.0
Pythondoes"mixedarithmetic".Youcanadd,multiply,anddivideintegersand
floats.Whenyoudo,Python"promotes"theresulttoafloat.

3.4.1.1Literalrepresentationsofnumbers
Anintegerisconstructedwithaseriesofdigitsortheintegerconstructor(int(x)).Be
awarethatasequenceofdigitsbeginningwithzerorepresentsanoctalvalue.Examples:
>>>x1=1234
>>>x2=int('1234')
>>>x3=25
>>>x1
1234
>>>x2
1234
>>>x3
25
Afloatisconstructedeitherwithdigitsandadot(example,12.345)orwith
engineering/scientificnotationorwiththefloatconstructor(float(x)).Examples:
>>>x1=2.0e3
>>>x1=1.234
>>>x2=1.234
>>>x3=float('1.234')
>>>x4=2.0e3
>>>x5=2.0e3
>>>printx1,x2,x3,x4,x5
1.2341.2341.2342000.00.002
Exercises:
Constructthesenumericvalues:
1. Integerzero
2. Floatingpointzero
3. Integeronehundredandone
4. Floatingpointonethousand
5. Floatingpointonethousandusingscientificnotation
6. Createapositiveinteger,anegativeinteger,andzero.Assignthemtovariables
7. Writeseveralarithmeticexpressions.Bindthevaluestovariables.Useavariety
ofoperators,e.g.+,,/,*,etc.Useparenthesestocontroloperatorscope.
8. Createseveralfloatsandassignthemtovariables.
9. Writeseveralarithmeticexpressionscontainingyourfloatvariables.

Page171
APythonBook

10. Writeseveralexpressionsusingmixedarithmetic(integersandfloats).Obtaina
floatasaresultofdivisionofoneintegerbyanother;dosobyexplicitly
convertingoneintegertoafloat.
Solutions:
1. 0
2. 0.0,0.,or.0
3. 101
4. 1000.0
5. 1e3or1.0e3
6. Asigningintegervaluestovariables:
In[7]:value1=23
In[8]:value2=14
In[9]:value3=0
In[10]:value1
Out[10]:23
In[11]:value2
Out[11]:14
In[12]:value3
Out[12]:0
7. Assigningexpressionvaluestovariables:
value1=4*(3+5)
value2=(value1/3.0)2
8. Assigningfloatstovariables:
value1=0.01
value2=3.0
value3=3e4
9. Assigningexpressionscontainingvarialbes:
value4=value1*(value2value3)
value4=value1+value2+value3value4
10. Mixedarithmetic:
x=5
y=8
z=float(x)/y
Youcanalsoconstructintegersandfloatsusingtheclass.Callingaclass(using
parenthesesafteraclassname,forexample)producesaninstanceoftheclass.
Exercises:
1. Constructanintegerfromthestring"123".
2. Constructafloatfromtheinteger123.
3. Constructanintegerfromthefloat12.345.
Solutions:

Page172
APythonBook

1. Usetheintdatatypetoconstructanintegerinstancefromastring:
int("123")
2. Usethefloatdatatypetoconstructafloatinstancefromaninteger:
float(123)
3. Usetheintdatatypetoconstructanintegerinstancefromafloat:
int(12.345)#>12
Noticethattheresultistruncatedtotheintegerpart.

3.4.1.2Operatorsfornumbers
Youcanusemostofthefamiliaroperatorswithnumbers,forexample:
+***///%
<<>>&|^~
<><=>===!=<>
Lookhereforanexplanationoftheseoperatorswhenappliedtonumbers:Numeric
Typesint,float,long,complexhttp://docs.python.org/lib/typesnumeric.html.
Someoperatorstakeprecedenceoverothers.ThetableintheWebpagejustreferenced
abovealsoshowsthatorderofpriority.
Hereisabitofthattable:
Allnumerictypes(exceptcomplex)supportthefollowingoperations,
sortedbyascendingpriority(operationsinthesameboxhavethe
same
priority;allnumericoperationshaveahigherprioritythan
comparison
operations):

OperationResult

x+ysumofxandy
xydifferenceofxandy
x*yproductofxandy
x/yquotientofxandy
x//y(floored)quotientofxandy
x%yremainderofx/y
xxnegated
+xxunchanged
abs(x)absolutevalueormagnitudeofx
int(x)xconvertedtointeger
long(x)xconvertedtolonginteger
float(x)xconvertedtofloatingpoint
complex(re,im)acomplexnumberwithrealpartre,imaginarypart
im.imdefaultstozero.
c.conjugate()conjugateofthecomplexnumberc

Page173
APythonBook

divmod(x,y)thepair(x//y,x%y)
pow(x,y)xtothepowery
x**yxtothepowery
Noticealsothatthesameoperatormayperformadifferentfunctiondependingonthe
datatypeofthevaluetowhichitisapplied.
Exercises:
1. Addthenumbers3,4,and5.
2. Add2totheresultofmultiplying3by4.
3. Add2plus3andmultiplytheresultby4.
Solutions:
1. Arithmeticexpressionsarefollowstandardinfixalgebraicsyntax:
3+4+5
2. Useanotherinfixexpression:
2+3*4
Or:
2+(3*4)
But,inthiscasetheparenthesesarenotnecessarybecausethe*operatorbinds
moretightlythanthe+operator.
3. Useparenthesestocontrolorderofevaluation:
(2+3)*4
Notethatthe*operatorhasprecedenceover(bindstighterthan)the+operator,
sotheparenthesesareneeded.
Pythondoesmixedarithemetic.Whenyouapplyanoperationtoanintegerandafloat,it
promotestheresulttothe"higher"datatype,afloat.
Ifyouneedtoperformanoperationonseveralintegers,butwantuseafloatingpoint
operation,firstconvertoneoftheintegerstoafloatusingfloat(x),whicheffectively
createsaninstanceofclassfloat.
TrythefollowingatyourPythoninteractiveprompt:
1. 1.0+2
2. 2/3Noticethattheresultistruncated.
3. float(2)/3Noticethattheresultisnottruncated.
Exercises:
1. Giventhefollowingassignments:
x=20
y=50

Page174
APythonBook

Dividexbyygivingafloatresult.
Solutions:
1. Promoteoneoftheintegerstofloatbeforeperformingthedivision:
z=float(x)/y

3.4.1.3Methodsonnumbers
Mostofthemethodsimplementedbythedatatypes(classes)intandfloatarespecial
methodsthatarecalledthroughtheuseofoperators.Specialmethodsoftenhavenames
thatbeginandendwithadoubleunderscore.Toseealistofthespecialnamesandabit
ofanindicationofwheneachiscalled,doanyofthefollowingatthePythoninteractive
prompt:
>>>help(int)
>>>help(32)
>>>help(float)
>>>help(1.23)
>>>dir(1)
>>>dir(1.2)

3.4.2Lists
Listsareacontainerdatatypethatactsasadynamicarray.Thatistosay,alistisa
sequencethatcanbeindexedintoandthatcangrowandshrink.
Atupleisanindexablecontainer,likealist,exceptthatatupleisimmutable.
Afewcharacteristicsoflistsandtuples:
Alisthasa(current)lengthGetthelengthofalistwithlen(mylist).
AlisthasanorderTheitemsinalistareordered,andyoucanthinkofthat
orderasgoingfromlefttoright.
AlistisheterogeneousYoucaninsertdifferenttypesofobjectsintothesame
list.
Listsaremutable,buttuplesarenot.Thus,thefollowingaretrueoflists,butnot
oftuples:
Youcanextendedoraddtoalist.
Youcanshrinkalistbydeletingitemsfromit.
Youcaninsertitemsintothemiddleofalistoratthebeginningofalist.You
canadditemstotheendofalist.
Youcanchangewhichitemisatagivenpositioninalist.

Page175
APythonBook

3.4.2.1Literalrepresentationoflists
Theliteralrepresentationofalistissquarebracketscontainingzeroormoreitems
separatedbycommas.
Examples:
1. TrytheseatthePythoninteractiveprompt:
>>>[11,22,33]
>>>['aa','bb','cc',]
>>>[100,'apple',200,'banana',]#Thelastcomma
is
>>>optional.
2. Alistcancontainlists.Infactalistcancontainanykindofobject:
>>>[1,[2,3],4,[5,6,7,],8]
3. Listsareheterogenous,thatis,differentkindsofobjectscanbeinthesamelist.
Hereisalistthatcontainsanumber,astring,andanotherlist:
>>>[123,'abc',[456,789]]
Exercises:
1. Create(define)thefollowingtuplesandlistsusingaliteral:
1. Atupleofintegers
2. Atupleofstrings
3. Alistofintegers
4. Alistofstrings
5. Alistoftuplesortupleoflists
6. Alistofintegersandstringsandtuples
7. Atuplecontainingexactlyoneitem
8. Anemptytuple
2. Doeachofthefollowing:
1. Printthelengthofalist.
2. PrinteachiteminthelistIterateovertheitemsinoneofyourlists.Print
eachitem.
3. Appendanitemtoalist.
4. Insertanitematthebeginningofalist.Insertaniteminthemiddleofalist.
5. Addtwoliststogether.Dosobyusingboththeextendmethodandtheplus
(+)operator.Whatisthedifferencebetweenextendingalistandaddingtwo
lists?
6. Retrievethe2nditemfromoneofyourtuplesorlists.
7. Retrievethe2nd,3rd,and4thitems(aslice)fromoneofyourtuplesorlists.
8. Retrievethelast(rightmost)iteminoneofyourlists.
9. Replaceaniteminalistwithanewitem.

Page176
APythonBook

10. Poponeitemofftheendofyourlist.
11. Deleteanitemfromalist.
12. Dothefollowinglistmanipulations:
1. Writeafunctionthattakestwoarguments,alistandanitem,andthat
appendstheitemtothelist.
2. Createanemptylist,
3. Callyourfunctionseveraltimestoappenditemstothelist.
4. Then,printouteachiteminthelist.
Solutions:
1. WecandefinelistliteralsatthePythonorIPythoninteractiveprompt:
1. Createatupleusingcommas,optionallywithparentheses:
In[1]:a1=(11,22,33,)
In[2]:a1
Out[2]:(11,22,33)
2. Quotedcharactersseparatedbycommascreateatupleofstrings:
In[3]:a2=('aaa','bbb','ccc')
In[4]:a2
Out[4]:('aaa','bbb','ccc')
3. Itemsseparatedbycommasinsidesquarebracketscreatealist:
In[26]:a3=[100,200,300,]
In[27]:a3
Out[27]:[100,200,300]
4. Stringsseparatedbycommasinsidesquarebracketscreatealistofstrings:
In[5]:a3=['basil','parsley','coriander']
In[6]:a3
Out[6]:['basil','parsley','coriander']
In[7]:
5. Atupleoralistcancontaintuplesandlists:
In[8]:a5=[(11,22),(33,44),(55,)]
In[9]:a5
Out[9]:[(11,22),(33,44),(55,)]
6. Alistortuplecancontainitemsofdifferenttypes:
In[10]:a6=[101,102,'abc',"def",(201,202),
('ghi','jkl')]
In[11]:a6
Out[11]:[101,102,'abc','def',(201,202),
('ghi','jkl')]
7. Inordertocreateatuplecontainingexactlyoneitem,wemustuseacomma:
In[13]:a7=(6,)
In[14]:a7

Page177
APythonBook

Out[14]:(6,)
8. Inordertocreateanemptytuple,usethetupleclass/typetocreateaninstance
ofaemptytuple:
In[21]:a=tuple()
In[22]:a
Out[22]:()
In[23]:type(a)
Out[23]:<type'tuple'>

3.4.2.2Operatorsonlists
Thereareseveraloperatorsthatareapplicabletolists.Hereishowtofindoutabout
them:
Dodir([])ordir(any_list_instance).Someoftheitemswith
specialnames(leadingandtrainingdoubleunderscores)willgiveyoucluesabout
operatorsimplementedbythelisttype.
Dohelp([])orhelp(list)atthePythoninteractiveprompt.
Dohelp(any_list_instance.some_method),wheresome_method
isoneoftheitemslistedusingdir(any_list_instance).
SeeSequenceTypesstr,unicode,list,tuple,buffer,xrange
http://docs.python.org/lib/typesseq.html
Exercises:
1. Concatenate(add)twoliststogether.
2. Createasinglelistthatcontainstheitemsinaninitiallistrepeated3times.
3. Comparetwolists.
Solutions:
1. Theplusoperator,appliedtotwolistsproducesanewlistthatisaconcatenation
oftwolists:
>>>[11,22]+['aa','bb']
2. Multiplyingalistbyanintegerncreatesanewlistthatrepeatstheoriginallistn
times:
>>>[11,'abc',4.5]*3
3. Thecomparisonoperatorscanbeusedtocomparelists:
>>>[11,22]==[11,22]
>>>[11,22]<[11,33]

3.4.2.3Methodsonlists
Again,usedir()andhelp()tolearnaboutthemethodssupportedbylists.

Page178
APythonBook

Examples:
1. Createtwo(small)lists.Extendthefirstlistwiththeitemsinthesecond.
2. Appendseveralindividualitemstotheendofalist.
3. (a)Insertaitematthebeginningofalist.(b)Insertanitemsomewhereinthe
middleofalist.
4. Popanitemofftheendofalist.
Solutions:
1. Theextendmethodaddselementsfromanotherlist,orotheriterable:
>>>a=[11,22,33,44,]
>>>b=[55,66]
>>>a.extend(b)
>>>a
[11,22,33,44,55,66]
2. Usetheappendmethodonalisttoadd/appendanitemtotheendofalist:
>>>a=['aa',11]
>>>a.append('bb')
>>>a.append(22)
>>>a
['aa',11,'bb',22]
3. Theinsertmethodonalistenablesustoinsertitemsatagivenpositionina
list:
>>>a=[11,22,33,44,]
>>>a.insert(0,'aa')
>>>a
['aa',11,22,33,44]
>>>a.insert(2,'bb')
>>>a
['aa',11,'bb',22,33,44]
But,notethatweuseappendtoadditemsattheendofalist.
4. Thepopmethodonalistreturnsthe"rightmost"itemfromalistandremoves
thatitemfromthelist:
>>>a=[11,22,33,44,]
>>>
>>>b=a.pop()
>>>a
[11,22,33]
>>>b
44
>>>b=a.pop()
>>>a
[11,22]
>>>b
33

Page179
APythonBook

Notethattheappendandpopmethodstakentogethercanbeusedtoimplement
astack,thatisaLIFO(lastinfirstout)datastructure.

3.4.2.4Listcomprehensions
Alistcomprehensionisaconvenientwaytoproducealistfromaniterable(asequence
orotherobjectthatcanbeiteratedover).
Initssimplestform,alistcomprehensionresemblestheheaderlineofaforstatement
insidesquarebrackets.However,inalistcomprehension,theforstatementheaderis
prefixedwithanexpressionandsurroundedbysquarebrackets.Hereisatemplate:
[expr(x)forxiniterable]
where:
expr(x)isanexpression,usually,butnotalways,containingx.
iterableissomeiterable.Aniterablemaybeasequence(forexample,alist,a
string,atuple)oranunorderedcollectionoraniterator(somethingoverwhichwe
caniterateorapplyaforstatementto).
Hereisanexample:
>>>a=[11,22,33,44]
>>>b=[x*2forxina]
>>>b
[22,44,66,88]
Exercises:
1. Giventhefollowinglistofstrings:
names=['alice','bertrand','charlene']
producethefollowinglists:(1)alistofalluppercasenames;(2)alistof
capitalized(firstletteruppercase);
2. Giventhefollowingfunctionwhichcalculatesthefactorialofanumber:
deft(n):
ifn<=1:
returnn
else:
returnn*t(n1)
andthefollowinglistofnumbers:
numbers=[2,3,4,5]
createalistofthefactorialsofeachofthenumbersinthelist.
Solutions:
1. Forourexpressioninalistcomprehension,usetheupperandcapitalize

Page180
APythonBook

methods:
>>>names=['alice','bertrand','charlene']
>>>[name.upper()fornameinnames]
['ALICE','BERTRAND','CHARLENE']
>>>[name.capitalize()fornameinnames]
['Alice','Bertrand','Charlene']
2. Theexpressioninourlistcomprehensioncallsthefactorialfunction:
deft(n):
ifn<=1:
returnn
else:
returnn*t(n1)

deftest():
numbers=[2,3,4,5]
factorials=[t(n)forninnumbers]
print'factorials:',factorials

if__name__=='__main__':
test()
Alistcomprehensioncanalsocontainanifclause.Hereisatemplate:
[expr(x)forxiniterableifpred(x)]
where:
pred(x)isanexpressionthatevaluatestoatrue/falsevalue.Valuesthatcount
asfalsearenumericzero,False,None,andanyemptycollection.Allother
valuescountastrue.
Onlyvaluesforwhichtheifclauseevaluatestotrueareincludedincreatingtheresulting
list.
Examples:
>>>a=[11,22,33,44]
>>>b=[x*3forxinaifx%2==0]
>>>b
[66,132]
Exercises:
1. Giventwolists,generatealistofallthestringsinthefirstlistthatarenotinthe
secondlist.Herearetwosamplelists:
names1=['alice','bertrand','charlene','daniel']
names2=['bertrand','charlene']
Solutions:
1. Theifclauseofourlistcomprehensionchecksforcontainmentinthelistnames2:

Page181
APythonBook

deftest():
names1=['alice','bertrand','charlene',
'daniel']
names2=['bertrand','charlene']
names3=[namefornameinnames1ifnamenotin
names2]
print'names3:',names3

if__name__=='__main__':
test()
Whenrun,thisscriptprintsoutthefollowing:
names3:['alice','daniel']

3.4.3Strings
Astringisanorderedsequenceofcharacters.Hereareafewcharacteristicsofstrings:
Astringhasalength.Getthelengthwiththelen()builtinfunction.
Astringisindexable.Getasinglecharacteratapositioninastringwiththe
squarebracketoperator,forexamplemystring[5].
Youcanretrieveaslice(substring)ofastringwithasliceoperation,forexample
mystring[5:8].
Createstringswithsinglequotesordoublequotes.Youcanputsinglequotesinside
doublequotesandyoucanputdoublequotesinsidesinglequotes.Youcanalsoescape
characterswithabackslash.
Exercises:
1. Createastringcontainingasinglequote.
2. Createastringcontainingadoublequote.
3. Createastringcontainingbothasinglequoteadoublequote.
Solutions:
1. Createastringwithdoublequotestoincludesinglequotesinsidethestring:
>>>str1="thatisjerry'sball"
2. Createastringenclosedwithsinglequotesinordertoincludedoublequotes
insidethestring:
>>>str1='say"goodbye",bullwinkle'
3. Takeyourchoice.Escapeeitherthesinglequotesorthedoublequoteswitha
backslash:
>>>str1='say"hello"tojerry\'smom'
>>>str2="say\"hello\"tojerry'smom"
>>>str1
'say"hello"tojerry\'smom'

Page182
APythonBook

>>>str2
'say"hello"tojerry\'smom'
Triplequotesenableyoutocreateastringthatspansmultiplelines.Usethreesingle
quotesorthreedoublequotestocreateasinglequotedstring.
Examples:
1. Createatriplequotedstringthatcontainssingleanddoublequotes.
Solutions:
1. Usetriplesinglequotesortripledoublequotestocreatemultilinestrings:
String1='''Thisstringextends
acrossseverallines.And,soithas
endoflinecharactersinit.
'''

String2="""
Thisstringbeginsandendswithanendofline
character.Itcanhaveboth'single'
quotesand"double"quotesinit.
"""

deftest():
printString1
printString2

if__name__=='__main__':
test()

3.4.3.1Characters
Pythondoesnothaveadistinctcharactertype.InPython,acharacterisastringoflength
1.Youcanusetheord()andchr()builtinfunctionstoconvertfromcharacterto
integerandback.
Exercises:
1. Createacharacter"a".
2. Createacharacter,thenobtainitsintegerrepresentation.
Solutions:
1. Thecharacter"a"isaplainstringoflength1:
>>>x='a'
2. Theintegerequivalentoftheletter"A":
>>>x="A"
>>>ord(x)
65

Page183
APythonBook

3.4.3.2Operatorsonstrings
Youcanconcatenatestringswiththe"+"operator.
Youcancreatemultipleconcatenatedcopiesofastringwiththe"*"operator.
And,augmentedassignment(+=and*=)alsowork.
Examples:
>>>'cat'+'and'+'dog'
'catanddog'
>>>'#'*40
'########################################'
>>>
>>>s1='flower'
>>>s1+='s'
>>>s1
'flowers'
Exercises:
1. Giventhesestrings:
>>>s1='abcd'
>>>s2='efgh'
createanewstringcomposedofthefirststringfollowedby(concatenatedwith)
thesecond.
2. Createasinglestringcontaining5copiesofthestring'abc'.
3. Usethemultiplicationoperatortocreatea"line"of50dashes.
4. Herearethecomponentsofapathtoafileonthefilesystem:"home",
"myusername","Workdir","notes.txt".Concatenatethesetogetherseparating
themwiththepathseparatortoformacompletepathtothatfile.(Notethatifyou
usethebackslashtoseparatecomponentsofthepath,youwillneedtousea
doublebackslash,becausethebackslashistheescapecharacterinstrings.
Solutions:
1. Theplus(+)operatorappliedtoastringcanbeusedtoconcatenatestrings:
>>>s3=s1+s2
>>>s3
'abcdefgh'
2. Themultiplicationoperator(*)appliedtoastringcreatesanewstringthat
concatenatesastringwithitselfsomenumberoftimes:
>>>s1='abc'*5
>>>s1
'abcabcabcabcabc'
3. Themultiplicationoperator(*)appliedtoastringcanbeusedtocreatea

Page184
APythonBook

"horizontaldividerline":
>>>s1=''*50
>>>prints1

4. Thesepmemberoftheosmodulegivesusaplatformindependentwayto
constructpaths:
>>>importos
>>>
>>>a=["home","myusername","Workdir","notes.txt"]
>>>path=a[0]+os.sep+a[1]+os.sep+a[2]+
os.sep+a[3]
>>>path
'home/myusername/Workdir/notes.txt'
And,amoreconcisesolution:
>>>importos
>>>a=["home","myusername","Workdir","notes.txt"]
>>>os.sep.join(a)
'home/myusername/Workdir/notes.txt'
Notes:
Notethatimportingtheosmoduleandthenusingos.sepfromthatmodule
givesusaplatformindependentsolution.
Ifyoudodecidetocodethepathseparatorcharacterexplicitlyandifyouare
onMSWindowswherethepathseparatoristhebackslash,thenyouwillneed
touseadoublebackslash,becausethatcharacteristheescapecharacter.

3.4.3.3Methodsonstrings
Stringsupportavarietyofoperations.Youcanobtainalistofthesemethodsbyusingthe
dir()builtinfunctiononanystring:
>>>dir("")
['__add__','__class__','__contains__','__delattr__','__doc__',
'__eq__','__ge__','__getattribute__','__getitem__',
'__getnewargs__','__getslice__','__gt__','__hash__','__init__',
'__le__','__len__','__lt__','__mod__','__mul__','__ne__',
'__new__','__reduce__','__reduce_ex__','__repr__','__rmod__',
'__rmul__','__setattr__','__str__','capitalize','center',
'count','decode','encode','endswith','expandtabs','find',
'index','isalnum','isalpha','isdigit','islower','isspace',
'istitle','isupper','join','ljust','lower','lstrip',
'partition','replace','rfind','rindex','rjust','rpartition',
'rsplit','rstrip','split','splitlines','startswith','strip',
'swapcase','title','translate','upper','zfill']
And,youcangethelponanyspecificmethodbyusingthehelp()builtinfunction.
Hereisanexample:

Page185
APythonBook

>>>help("".strip)
Helponbuiltinfunctionstrip:

strip(...)
S.strip([chars])>stringorunicode

ReturnacopyofthestringSwithleadingandtrailing
whitespaceremoved.
IfcharsisgivenandnotNone,removecharactersinchars
instead.
Ifcharsisunicode,Swillbeconvertedtounicodebefore
stripping
Exercises:
1. Stripallthewhitespacecharactersofftherightendofastring.
2. Centerashortstringwithinalongerstring,thatis,padashortstringwithblank
charactersonbothrightandlefttocenterit.
3. Convertastringtoalluppercase.
4. Splitastringintoalistof"words".
5. (a)Jointhestringsinalistofstringstoformasinglestring.(b)Ditto,butputa
newlinecharacterbetweeneachoriginalstring.
Solutions:
1. Therstrip()methodstripswhitespaceofftherightsideofastring:
>>>s1='sometext\n'
>>>s1
'sometext\n'
>>>s2=s1.rstrip()
>>>s2
'sometext'
2. Thecenter(n)methodcentersastringwithinapaddedstringofwidthn:
>>>s1='Dave'
>>>s2=s1.center(20)
>>>s2
'Dave'
3. Theupper()methodproducesanewstringthatconvertsallalphacharactersin
theoriginaltouppercase:
>>>s1='Banana'
>>>s1
'Banana'
>>>s2=s1.upper()
>>>s2
'BANANA'
4. Thesplit(sep)methodproducesalistofstringsthatareseparatedbysepin
theoriginalstring.Ifsepisomitted,whitespaceistreatedastheseparator:

Page186
APythonBook

>>>s1="""howdoesitfeel
...tobeonyourown
...nodirectionsknown
...likearollingstone
..."""
>>>words=s1.split()
>>>words
['how','does','it','feel','to','be','on','your',
'own','no',
'directions','known','like','a','rolling','stone']
Notethatthesplit()functioninthere(regularexpression)moduleisuseful
whentheseparatorismorecomplexthanwhitespaceorasinglecharacter.
5. Thejoin()methodconcatenatesstringsfromalistofstringstoformasingle
string:
>>>lines=[]
>>>lines.append('howdoesitfeel')
>>>lines.append('tobeonyourown')
>>>lines.append('nodirectionsknown')
>>>lines.append('likearollingstone')
>>>lines
['howdoesitfeel','tobeonyourown','no
directionsknown',
'likearollingstone']
>>>s1=''.join(lines)
>>>s2=''.join(lines)
>>>s3='\n'.join(lines)
>>>s1
'howdoesitfeeltobeonyourownnodirections
knownlikearollingstone'
>>>s2
'howdoesitfeeltobeonyourownnodirectionsknown
likearollingstone'
>>>s3
'howdoesitfeel\ntobeonyourown\nnodirections
known\nlikearollingstone'
>>>prints3
howdoesitfeel
tobeonyourown
nodirectionsknown
likearollingstone

3.4.3.4Rawstrings
Rawstringsgiveusaconvenientwaytoincludethebackslashcharacterinastring
withoutescaping(withanadditionalbackslash).Rawstringslooklikeplainliteral
strings,butareprefixedwithan"r"or"R".SeeStringliterals
http://docs.python.org/reference/lexical_analysis.html#stringliterals
Excercises:

Page187
APythonBook

1. Createastringthatcontainsabackslashcharacterusingbothplainliteralstring
andarawstring.
Solutions:
1. Weusean"r"prefixtodefinearawstring:
>>>print'abc\\def'
abc\def
>>>printr'abc\def'
abc\def

3.4.3.5Unicodestrings
Unicodestringsgiveusaconsistentwaytoprocesscharacterdatafromavarietyof
characterencodings.
Excercises:
1. Createseveralunicodestrings.Useboththeunicodeprefixcharacter("u")andthe
unicodetype(unicode(some_string)).
2. Convertastring(possiblyfromanothernonasciiencoding)tounicode.
3. Convertaunicodestringtoanotherencoding,forexample,utf8.
4. Testastringtodetermineifitisunicode.
5. Createastringthatcontainsaunicodecharacter,thatis,acharacteroutsidethe
asciicharacterset.
Solutions:
1. Wecanrepresentunicodestringwitheitherthe"u"prefixorwithacalltothe
unicodetype:
defexercise1():
a=u'abcd'
printa
b=unicode('efgh')
printb
2. Weconvertastringfromanothercharacterencodingintounicodewiththe
decode()stringmethod:
importsys

defexercise2():
a='abcd'.decode('utf8')
printa
b='abcd'.decode(sys.getdefaultencoding())
printb
3. Wecanconvertaunicodestringtoanothercharacterencodingwiththe
encode()stringmethod:
importsys

Page188
APythonBook

defexercise3():
a=u'abcd'
printa.encode('utf8')
printa.encode(sys.getdefaultencoding())
4. Herearetwowaystocheckthetypeofastring:
importtypes

defexercise4():
a=u'abcd'
printtype(a)istypes.UnicodeType
printtype(a)istype(u'')
5. Wecanencodeunicodecharactersinastringinseveralways,forexample,(1)by
definingautf8stringandconvertingittounicodeor(2)definingastringwithan
embeddedunicodecharacteror(3)concatenatingaunicodecharacherintoa
string:
defexercise5():
utf8_string='IvanKrsti\xc4\x87'
unicode_string=utf8_string.decode('utf8')
printunicode_string.encode('utf8')
printlen(utf8_string)
printlen(unicode_string)
unicode_string=u'aa\u0107bb'
printunicode_string.encode('utf8')
unicode_string='aa'+unichr(263)+'bb'
printunicode_string.encode('utf8')
Guidanceforuseofencodingsandunicode:
1. Convert/decodefromanexternalencodingtounicodeearly:
my_source_string.decode(encoding)
2. Doyourwork(Pythonprocessing)inunicode.
3. Convert/encodetoanexternalencodinglate(forexample,justbeforesavingtoan
externalfile):
my_unicode_string.encode(encoding)
Formoreinformation,see:
UnicodeInPython,CompletelyDemystifiedhttp://farmdev.com/talks/unicode/
UnicodeHowtohttp://www.amk.ca/python/howto/unicode.
PEP100:PythonUnicodeIntegration
http://www.python.org/dev/peps/pep0100/
4.8codecsCodecregistryandbaseclasses
http://docs.python.org/lib/modulecodecs.html
4.8.2EncodingsandUnicode

Page189
APythonBook

http://docs.python.org/lib/encodingsoverview.html
4.8.3StandardEncodingshttp://docs.python.org/lib/standardencodings.html
ConvertingUnicodeStringsto8bitStrings
http://effbot.org/zone/unicodeconvert.htm

3.4.4Dictionaries
Adictionaryisanunorderedcollectionofkeyvaluepairs.
Adictionaryhasalength,specificallythenumberofkeyvaluepairs.
Adictionaryprovidesfastlookupbykey.
Thekeysmustbeimmutableobjecttypes.

3.4.4.1Literalrepresentationofdictionaries
Curleybracketsareusedtorepresentadictionary.Eachpairinthedictionaryis
representedbyakeyandvalueseparatedbyacolon.Multiplepairsareseparatedby
comas.Forexample,hereisanemptydictionaryandseveraldictionariescontaining
key/valuepairs:
In[4]:d1={}
In[5]:d2={'width':8.5,'height':11}
In[6]:d3={1:'RED',2:'GREEN',3:'BLUE',}
In[7]:d1
Out[7]:{}
In[8]:d2
Out[8]:{'height':11,'width':8.5}
In[9]:d3
Out[9]:{1:'RED',2:'GREEN',3:'BLUE'}
Notes:
Acommaafterthelastpairisoptional.SeetheREDGREENBLUEexample
above.
Stringsandintegersworkaskeys,sincetheyareimmutable.Youmightalsowant
tothinkabouttheuseoftuplesofintegersaskeysinadictionaryusedto
representasparsearray.
Exercises:
1. Defineadictionarythathasthefollowingkeyvaluepairs:
2. Defineadictionarytorepresentthe"enum"daysoftheweek:Sunday,Monday,
Tuesday,...
Solutions:
1. Adictionarywhosekeysandvaluesarestringscanbeusedtorepresentthistable:

Page190
APythonBook

vegetables={
'Eggplant':'Purple',
'Tomato':'Red',
'Parsley':'Green',
'Lemon':'Yellow',
'Pepper':'Green',
}
Notethattheopencurlybracketenablesustocontinuethisstatementacross
multiplelineswithoutusingabackslash.
2. Wemightusestringsforthenamesofthedaysoftheweekaskeys:
DAYS={
'Sunday':1,
'Monday':2,
'Tuesday':3,
'Wednesday':4,
'Thrusday':5,
'Friday':6,
'Saturday':7,
}

3.4.4.2Operatorsondictionaries
Dictionariessupportthefollowing"operators":
Lengthlen(d)returnsthenumberofpairsinadictionary.
IndexingYoucanbothsetandgetthevalueassociatedwithakeybyusingthe
indexingoperator[].Examples:
In[12]:d3[2]
Out[12]:'GREEN'
In[13]:d3[0]='WHITE'
In[14]:d3[0]
Out[14]:'WHITE'
TestforkeyTheinoperatortestsfortheexistenceofakeyinadictionary.
Example:
In[6]:trees={'poplar':'deciduous','cedar':
'evergreen'}
In[7]:if'cedar'intrees:
...:print'Thecedaris%s'%
(trees['cedar'],)
...:
Thecedarisevergreen
Exercises:
1. Createanemptydictionary,thenusetheindexingoperator[]toinsertthe
followingnamevaluepairs:
"red""255:0:0"

Page191
APythonBook

"green""0:255:0"
"blue""0:0:255"
2. Printoutthenumberofitemsinyourdictionary.
Solutions:
1. Wecanuse"[]"tosetthevalueofakeyinadictionary:
deftest():
colors={}
colors["red"]="255:0:0"
colors["green"]="0:255:0"
colors["blue"]="0:0:255"
print'Thevalueofredis"%s"'%
(colors['red'],)
print'Thecolorsdictionarycontains%ditems.'%
(len(colors),)

test()
Whenwerunthis,wesee:
Thevalueofredis"255:0:0"
Thecolorsdictionarycontains3items.
2. Thelen()builtinfunctiongivesusthenumberofitemsinadictionary.Seethe
previoussolutionforanexampleofthis.

3.4.4.3Methodsondictionaries
Hereisatablethatdescribesthemethodsapplicabletodictionarys:
Operation Result
len(a) thenumberofitemsina
a[k] theitemofawithkeyk
a[k]=v seta[k]tov
dela[k] removea[k]froma
a.clear() removeallitemsfroma
a.copy() a(shallow)copyofa
kina Trueifahasakeyk,elseFalse
knotina equivalenttonotkina
a.has_key(k) equivalenttokina,usethatforminnewcode
a.items() acopyofa'slistof(key,value)pair

Page192
APythonBook

Operation Result

a.keys() acopyofa'slistofkeys
a.update([b]) updatesawithkey/valuepairsfromb,overwritingexisting
keys,returnsNone
a.fromkeys(seq[,value]) createsanewdictionarywithkeysfromseqandvaluessetto
value
a.values() acopyofa'slistofvalues
a.get(k[,x]) a[k]ifkina,elsex)
a.setdefault(k[,x]) a[k]ifkina,elsex(alsosettingit)
a.pop(k[,x]) a[k]ifkina,elsex(andremovek)(8)
a.popitem() removeandreturnanarbitrary(key,value)pair
a.iteritems() returnaniteratorover(key,value)pairs
a.iterkeys() returnaniteratoroverthemapping'skeys
a.itervalues() returnaniteratoroverthemapping'svalues

YoucanalsofindthistableatthestandarddocumentationWebsiteinthe"Python
LibraryReference":MappingTypesdicthttp://docs.python.org/lib/typesmapping.html
Exercises:
1. Printthekeysandvaluesintheabove"vegetable"dictionary.
2. Printthekeysandvaluesintheabove"vegetable"dictionarywiththekeysin
alphabeticalorder.
3. Testfortheoccuranceofakeyinadictionary.
Solutions:
1. Wecanusethed.items()methodtoretrievealistoftuplescontaining
keyvaluepairs,thenuseunpackingtocapturethekeyandvalue:
Vegetables={
'Eggplant':'Purple',
'Tomato':'Red',
'Parsley':'Green',
'Lemon':'Yellow',
'Pepper':'Green',
}

Page193
APythonBook

deftest():
forkey,valueinVegetables.items():
print'key:',key,'value:',value

test()
2. Weretrievealistofkeyswiththekeys()method,thesortitwiththelist
sort()method:
Vegetables={
'Eggplant':'Purple',
'Tomato':'Red',
'Parsley':'Green',
'Lemon':'Yellow',
'Pepper':'Green',
}

deftest():
keys=Vegetables.keys()
keys.sort()
forkeyinkeys:
print'key:',key,'value:',Vegetables[key]

test()
3. Totestfortheexistenceofakeyinadictionary,wecanuseeitherthein
operator(preferred)orthed.has_key()method(oldstyle):
Vegetables={
'Eggplant':'Purple',
'Tomato':'Red',
'Parsley':'Green',
'Lemon':'Yellow',
'Pepper':'Green',
}

deftest():
if'Eggplant'inVegetables:
print'wehave%segplants'%
Vegetables['Eggplant']
if'Banana'notinVegetables:
print'yeswehavenobananas'
ifVegetables.has_key('Parsley'):
print'wehaveleafy,%sparsley'%
Vegetables['Parsley']

test()
Whichwillprintout:
wehavePurpleegplants
yeswehavenobananas
wehaveleafy,Greenparsley

Page194
APythonBook

3.4.5Files
APythonfileobjectrepresentsafileonafilesystem.
Afileobjectopenforreadingatextfileisiterable.Whenweiterateoverit,itproduces
thelinesinthefile.
Afilemaybeopenedinthesemodes:
'r'readmode.Thefilemustexist.
'w'writemode.Thefileiscreated;anexistingfileisoverwritten.
'a'appendmode.Anexistingfileisopenedforwriting(attheendofthefile).A
fileiscreatedifitdoesnotexist.
Theopen()builtinfunctionisusedtocreateafileobject.Forexample,thefollowing
code(1)opensafileforwriting,then(2)forreading,then(3)forappending,andfinally
(4)forreadingagain:
deftest(infilename):
#1.Openthefileinwritemode,whichcreatesthefile.
outfile=open(infilename,'w')
outfile.write('line1\n')
outfile.write('line2\n')
outfile.write('line3\n')
outfile.close()
#2.Openthefileforreading.
infile=open(infilename,'r')
forlineininfile:
print'Line:',line.rstrip()
infile.close()
#3.Openthefileinappendmode,andaddalinetotheendof
#thefile.
outfile=open(infilename,'a')
outfile.write('line4\n')
outfile.close()
print''*40
#4.Openthefileinreadmodeoncemore.
infile=open(infilename,'r')
forlineininfile:
print'Line:',line.rstrip()
infile.close()

test('tmp.txt')
Exercises:
1. Openatextfileforreading,thenreadtheentirefileasasinglestring,andthen
splitthecontentonnewlinecharacters.
2. Openatextfileforreading,thenreadtheentirefileasalistofstrings,whereeach
stringisonelineinthefile.
3. Openatextfileforreading,theniterateofeachlineinthefileandprintitout.

Page195
APythonBook

Solutions:
1. Usetheopen()builtinfunctiontoopenthefileandcreateafileobject.Usethe
read()methodonthefileobjecttoreadtheentirefile.Usethesplit()or
splitlines()methodstosplitthefileintolines:
>>>infile=open('tmp.txt','r')
>>>content=infile.read()
>>>infile.close()
>>>lines=content.splitlines()
>>>printlines
['line1','line2','line3','']
2. Thef.readlines()methodreturnsalistoflinesinafile:
>>>infile=open('tmp.txt','r')
>>>lines=infile.readlines()
>>>infile.close()
>>>printlines
['line1\n','line2\n','line3\n']
3. Sinceafileobject(openforreading)isitselfaniterator,wecaniterateoveritina
forstatement:
"""
Testiterationoveratextfile.
Usage:
pythontest.pyin_file_name
"""

importsys

deftest(infilename):
infile=open(infilename,'r')
forlineininfile:
#Stripoffthenewlinecharacterandany
whitespaceon
#theright.
line=line.rstrip()
#Printonlynonblanklines.
ifline:
printline
infile.close()

defmain():
args=sys.argv[1:]
iflen(args)!=1:
print__doc__
sys.exit(1)
infilename=args[0]
test(infilename)

if__name__=='__main__':
main()

Page196
APythonBook

Notes:
Thelasttwolinesofthissolutioncheckthe__name__attributeofthe
moduleitselfsothatthemodulewillrunasascriptbutwillnotrunwhenthe
moduleisimportedbyanothermodule.
The__doc__attributeofthemodulegivesusthemodule'sdocstring,which
isthestringdefinedatthetopofthemodule.
sys.argvgivesusthecommandline.And,sys.argv[1:]chopsoffthe
programname,leavinguswiththecommanlinearguments.

3.4.6Afewmiscellaneousdatatypes

3.4.6.1None
Noneisasingleton.ThereisonlyoneinstanceofNone.Usethisvaluetoindicatethe
absenceofanyother"real"value.
TestforNonewiththeidentityoperatoris.
Exercises:
1. Createalist,someofwhoseelementsareNone.Thenwriteaforloopthat
countsthenumberofoccurancesofNoneinthelist.
Solutions:
1. TheidentityoperatorsisandisnotcanbeusedtotestforNone:
>>>a=[11,None,'abc',None,{}]
>>>a
[11,None,'abc',None,{}]
>>>count=0
>>>foritemina:
...ifitemisNone:
...count+=1
...
>>>
>>>printcount
2

3.4.6.2ThebooleansTrueandFalse
PythonhasthetwobooleanvaluesTrueandFalse.Manycomparisonoperatorsreturn
TrueandFalse.
Examples:
1. Whatvalueisreturnedby3>2?
Answer:ThebooleanvalueTrue.
2. Giventhesevariabledefinitions:

Page197
APythonBook

x=3
y=4
z=5
Whatdoesthefollowingprintout:
printy>xandz>y
AnswerPrintsout"True"

3.5Statements

3.5.1Assignmentstatement
Theassignmentstatementusestheassignmentoperator=.
Theassignmentstatementisabindingstatement:itbindsavaluetoanamewithina
namespace.
Exercises:
1. Bindthevalue"eggplant"tothevariablevegetable.
Solutions:
1.The=operatorisanassignmentstatementthatbindsavaluetoavariable:
>>>vegetable="eggplant"
Thereisalsoaugmentedassignmentusingtheoperators+=,=,*=,/=,etc.
Exercises:
1. Useaugmentedassignmenttoincrementthevalueofaninteger.
2. Useaugmentedassignmenttoappendcharacterstotheendofastring.
3. Useaugmentedassignmenttoappendtheitemsinonelisttoanother.
4. Useaugmentedassignmenttodecrementavariablecontaininganintegerby1.
Solutions:
1. The+=operatorincrementsthevalueofaninteger:
>>>count=0
>>>count+=1
>>>count
1
>>>count+=1
>>>count
2
2. The+=operatorappendscharacterstotheendofastring:
>>>buffer='abcde'
>>>buffer+='fgh'

Page198
APythonBook

>>>buffer
'abcdefgh'
3. The+=operatorappendsitemsinonelisttoanother:
In[20]:a=[11,22,33]
In[21]:b=[44,55]
In[22]:a+=b
In[23]:a
Out[23]:[11,22,33,44,55]
1. The=operatordecrementsthevalueofaninteger:
>>>count=5
>>>count
5
>>>count=1
>>>count
4
Youcanalsoassignavalueto(1)anelementofalist,(2)aniteminadictionary,(3)an
attributeofanobject,etc.
Exercises:
1. Createalistofthreeitems,thenassignanewvaluetothe2ndelementinthelist.
2. Createadictionary,thenassignvaluestothekeys"vegetable"and"fruit"inthat
dictionary.
3. Usethefollowingcodetocreateaninstanceofaclass:
classA(object):
pass
a=A()
Thenassignvaluestoanattribuenamedcategoryinthatinstance.
Solutions:
1. Assignmentwiththeindexingoperator[]assignsavaluetoanelementinalist:
>>>trees=['pine','oak','elm']
>>>trees
['pine','oak','elm']
>>>trees[1]='cedar'
>>>trees
['pine','cedar','elm']
2. Assignmentwiththeindexingoperator[]assignsavaluetoanitem(akeyvalue
pair)inadictionary:
>>>foods={}
>>>foods
{}
>>>foods['vegetable']='greenbeans'
>>>foods['fruit']='nectarine'
>>>foods

Page199
APythonBook

{'vegetable':'greenbeans','fruit':'nectarine'}
3. Assignmentalongwiththedereferencingoperator.(dot)enablesustoassigna
valuetoanattributeofanobject:
>>>classA(object):
...pass
...
>>>a=A()
>>>a.category=25
>>>a.__dict__
{'category':25}
>>>a.category
25

3.5.2printstatement
Warning:BeawarethattheprintstatementwillgoawayinPythonversion3.0.Itwill
bereplacedbythebuiltinprint()function.
Theprintstatementsendsoutputtostandardoutput.Itprovidesasomewhatmore
convenientwayofproducingoutputthanusingsys.stdout.write().
Theprintstatementtakesaseriesofzeroormoreobjectsseparatedbycommas.Zero
objectsproducesablankline.
Theprintstatementnormallyaddsanewlineattheendofitsoutput.Toeliminatethat,
addacommaattheend.
Exercises:
1. Printasinglestring.
2. Printthreestringsusingasingleprintstatement.
3. Givenavariablenamecontainingastring,printoutthestringMynameis
"xxxx".,wherexxxxisreplacebythevalueofname.Usethestringformatting
operator.
Solutions:
1. Wecanprintaliteralstring:
>>>print'Hello,there'
Hello,there
2. Wecanprintliteralsandthevalueofvariables:
>>>description='cute'
>>>print'Iama',description,'kid.'
Iamacutekid.
3. Thestringformattingoperatorgivesmorecontroloverformattingoutput:
>>>name='Alice'

Page200
APythonBook

>>>print'Mynameis"%s".'%(name,)
Mynameis"Alice".

3.5.3if:statementexercises
Theifstatementisacompoundstatementthatenablesustoconditionallyexecute
blocksofcode.
Theifstatementalsohasoptionalelif:andelse:clauses.
Theconditioninanif:orelif:clausecanbeanyPythonexpression,inotherwords,
somethingthatreturnsavalue(evenifthatvalueisNone).
Intheconditioninanif:orelif:clause,thefollowingvaluescountas"false":
False
None
Numericzero
Anemptycollection,forexampleanemptylistordictionary
Anemptystring(astringoflengthzero)
Allothervaluescountastrue.
Exercises:
1. Giventhefollowinglist:
>>>bananas=['banana1','banana2','banana3',]
Printonemessageifitisanemptylistandanothermessgeifitisnot.
2. HereisonewayofdefiningaPythonequivalentofan"enum":
NO_COLOR,RED,GREEN,BLUE=range(4)
Writeanif:statementwhichimplementstheeffectofa"switch"statementin
Python.Printoutauniquemessageforeachcolor.
Solutions:
1. Wecantestforanemptyornonemptylist:
>>>bananas=['banana1','banana2','banana3',]
>>>ifnotbananas:
...print'yes,wehavenobananas'
...else:
...print'yes,wehavebananas'
...
yes,wehavebananas
2. Wecansimulatea"switch"statementusingif:elif:...:
NO_COLOR,RED,GREEN,BLUE=range(4)

deftest(color):

Page201
APythonBook

ifcolor==RED:
print"It'sred."
elifcolor==GREEN:
print"It'sgreen."
elifcolor==BLUE:
print"It'sblue."

defmain():
color=BLUE
test(color)

if__name__=='__main__':
main()
Which,whenrunprintsoutthefollowing:
It'sblue.

3.5.4for:statementexercises
Thefor:statementisthePythonwaytoiterateoverandprocesstheelementsofa
collectionorotheriterable.
Thebasicformofthefor:statementisthefollowing:
forXinY:
statement
o
o
o
where:
Xissomethingthatcanbeassignedto.ItissomethingtowhichPythoncanbinda
value.
Yissomecollectionorotheriterable.
Exercises:
1. Createalistofintegers.Useafor:statementtoprintouteachintegerinthelist.
2. Createastring.printouteachcharacterinthestring.
Solutions:
1. Thefor:statementcaniterateovertheitemsinalist:
In[13]:a=[11,22,33,]
In[14]:forvalueina:
....:print'value:%d'%value
....:
....:
value:11
value:22
value:33

Page202
APythonBook

2. Thefor:statementcaniterateoverthecharactersinastring:
In[16]:b='chocolate'
In[17]:forchr1inb:
....:print'character:%s'%chr1
....:
....:
character:c
character:h
character:o
character:c
character:o
character:l
character:a
character:t
character:e
Notes:
Inthesolution,Iusedthevariablenamechr1ratherthanchrsoasnotto
overwritethenameofthebuiltinfunctionchr().
Whenweneedasequentialindex,wecanusetherange()builtinfunctiontocreatea
listofintegers.And,thexrange()builtinfunctionproducesaninteratorthatproduces
asequenceofintegerswithoutcreatingtheentirelist.Toiterateoveralargesequenceof
integers,usexrange()insteadofrange().
Exercises:
1. Printouttheintegersfrom0to5insequence.
2. Computethesumofalltheintegersfrom0to99999.
3. Giventhefollowinggeneratorfunction:
importurllib

Urls=[
'http://yahoo.com',
'http://python.org',
'http://gimp.org',#TheGNUimagemanipulation
program
]

defwalk(url_list):
forurlinurl_list:
f=urllib.urlopen(url)
stuff=f.read()
f.close()
yieldstuff
Writeafor:statementthatusesthisiteratorgeneratortoprintthelengthsofthe
contentateachoftheWebpagesinthatlist.
Solutions:
1. Therange()builtinfunctiongivesusasequencetoiterateover:

Page203
APythonBook

In[5]:foridxinrange(6):
...:print'idx:%d'%idx
...:
...:
idx:0
idx:1
idx:2
idx:3
idx:4
idx:5
2. Sincethatsequenceisabitlarge,we'llusexrange()insteadofrange():
In[8]:count=0
In[9]:forninxrange(100000):
...:count+=n
...:
...:
In[10]:count
Out[10]:4999950000
3. Thefor:statementenablesustoiterateoveriterablesaswellascollections:
importurllib

Urls=[
'http://yahoo.com',
'http://python.org',
'http://gimp.org',#TheGNUimagemanipulation
program
]

defwalk(url_list):
forurlinurl_list:
f=urllib.urlopen(url)
stuff=f.read()
f.close()
yieldstuff

deftest():
forurlinwalk(Urls):
print'length:%d'%(len(url),)

if__name__=='__main__':
test()
WhenIranthisscript,itprintsthefollowing:
length:9562
length:16341
length:12343
Ifyouneedanindexwhileiteratingoverasequence,considerusingtheenumerate()
builtinfunction.

Page204
APythonBook

Exercises:
1. Giventhefollowingtwolistsofintegersofthesamelength:
a=[1,2,3,4,5]
b=[100,200,300,400,500]
Addthevaluesinthefirstlisttothecorrespondingvaluesinthesecondlist.
Solutions:
1. Theenumerate()builtinfunctiongivesusanindexandvaluesfroma
sequence.Sinceenumerate()givesusaninteratorthatproducesasequenceof
twotuples,wecanunpackthosetuplesintoindexandvaluevariablesinthe
headerlineoftheforstatement:
In[13]:a=[1,2,3,4,5]
In[14]:b=[100,200,300,400,500]
In[15]:
In[16]:foridx,valueinenumerate(a):
....:b[idx]+=value
....:
....:
In[17]:b
Out[17]:[101,202,303,404,505]

3.5.5while:statementexercises
Awhile:statementexecutesablockofcoderepeatedlyaslongasaconditionistrue.
Hereisatemplateforthewhile:statement:
whilecondition:
statement
o
o
o
Where:
conditionisanexpression.Theexpressionissomethingthatreturnsavalue
whichcanbeinterpretedastrueorfalse.
Exercises:
1. Writeawhile:loopthatdoublesallthevaluesinalistofintegers.
Solutions:
1. Awhile:loopwithanindexvariablecanbeusedtomodifyeachelementofa
list:
deftest_while():
numbers=[11,22,33,44,]
print'before:%s'%(numbers,)

Page205
APythonBook

idx=0
whileidx<len(numbers):
numbers[idx]*=2
idx+=1
print'after:%s'%(numbers,)
But,noticethatthistaskiseasierusingthefor:statementandthebuiltin
enumerate()function:
deftest_for():
numbers=[11,22,33,44,]
print'before:%s'%(numbers,)
foridx,iteminenumerate(numbers):
numbers[idx]*=2
print'after:%s'%(numbers,)

3.5.6breakandcontinuestatements
Thecontinuestatementskipstheremainderofthestatementsinthebodyofaloop
andstartsimmediatelyatthetopoftheloopagain.
Abreakstatementinthebodyofaloopterminatestheloop.Itexitsfromthe
immediatelycontainingloop.
breakandcontinuecanbeusedinbothfor:andwhile:statements.
Exercises:
1. Writeafor:loopthattakesalistofintegersandtripleseachintegerthatiseven.
Usethecontinuestatement.
2. Writealoopthattakesalistofintegersandcomputesthesumofalltheintegers
upuntilazeroisfoundinthelist.Usethebreakstatement.
Solutions:
1. Thecontinuestatementenablesusto"skip"itemsthatsatisfyaconditionor
test:
deftest():
numbers=[11,22,33,44,55,66,]
print'before:%s'%(numbers,)
foridx,iteminenumerate(numbers):
ifitem%2!=0:
continue
numbers[idx]*=3
print'after:%s'%(numbers,)

test()
2. Thebreakstatementenablesustoexitfromaloopwhenwefindazero:
deftest():
numbers=[11,22,33,0,44,55,66,]

Page206
APythonBook

print'numbers:%s'%(numbers,)
sum=0
foriteminnumbers:
ifitem==0:
break
sum+=item
print'sum:%d'%(sum,)

test()

3.5.7Exceptionsandthetry:except:andraisestatements
Thetry:except:statementenablesustocatchanexceptionthatisthrownfrom
withinablockofcode,orfromcodecalledfromanydepthwithingthatblock.
Theraisestatementenablesustothrowanexception.
Anexceptionisaclassoraninstanceofanexceptionclass.Ifanexceptionisnotcaught,
itresultsinatracebackandterminationoftheprogram.
Thereisasetofstandardexceptions.Youcanlearnaboutthemhere:BuiltinExceptions
http://docs.python.org/lib/moduleexceptions.html.
Youcandefineyourownexceptionclasses.Todoso,createanemptysubclassofthe
classException.Definingyourownexceptionwillenableyou(orothers)tothrow
andthencatchthatspecificexceptiontypewhileignoreothersexceptions.
Exercises:
1. Writeatry:except:statementthatattemptstoopenafileforreadingand
catchestheexceptionthrownwhenthefiledoesnotexist.
Question:Howdoyoufindoutthenameoftheexceptionthatisthrownforan
input/outputerrorsuchasthefailuretoopenafile?
2. Defineanexceptionclass.Thenwriteatry:except:statementinwhichyou
throwandcatchthatspecificexception.
3. Defineanexceptionclassanduseittoimplementamultilevelbreakfroman
innerloop,bypassinganouterloop.
Solutions:
1. UsethePythoninteractiveinterpretertolearntheexceptiontypethrownwhena
I/Oerroroccurs.Example:
>>>infile=open('xx_nothing__yy.txt','r')
Traceback(mostrecentcalllast):
File"<stdin>",line1,in<module>
IOError:[Errno2]Nosuchfileordirectory:
'xx_nothing__yy.txt'
>>>

Page207
APythonBook

Inthiscase,theexceptiontypeisIOError.
Now,writeatry:except:blockwhichcatchesthatexception:
deftest():
infilename='nothing_noplace.txt'
try:
infile=open(infilename,'r')
forlineininfile:
printline
exceptIOError,exp:
print'cannotopenfile"%s"'%infilename

test()
2. WedefineaexceptionclassasasubclassofclassException,thenthrowit
(withtheraisestatement)andcatchit(withatry:except:statement):
classSizeError(Exception):
pass

deftest_exception(size):
try:
ifsize<=0:
raiseSizeError,'sizemustbegreaterthan
zero'
#Produceadifferenterrortoshowthatit
willnotbecaught.
x=y
exceptSizeError,exp:
print'%s'%(exp,)
print'goodbye'

deftest():
test_exception(1)
print''*40
test_exception(1)

test()
Whenwerunthisscript,itproducesthefollowingoutput:
$pythonworkbook027.py
sizemustbegreaterthanzero
goodbye

Traceback(mostrecentcalllast):
File"workbook027.py",line20,in<module>
test()
File"workbook027.py",line18,intest
test_exception(1)
File"workbook027.py",line10,intest_exception
x=y
NameError:globalname'y'isnotdefined

Page208
APythonBook

Notes:
Ourexcept:clausecaughttheSizeError,butallowedtheNameError
tobeuncaught.
3. WedefineasubclassofofclassException,thenraiseitinaninnerloopand
catchitoutsideofanouterloop:
classBreakException1(Exception):
pass

deftest():
a=[11,22,33,44,55,66,]
b=[111,222,333,444,555,666,]
try:
forxina:
print'outerx:%d'%x
foryinb:
ifx>22andy>444:
raiseBreakException1('leaving
innerloop')
print'innery:%d'%y
print'outerafter'
print''*40
exceptBreakException1,exp:
print'outofloopexp:%s'%exp

test()
Hereiswhatthisprintsoutwhenrun:
outerx:11
innery:111
innery:222
innery:333
innery:444
innery:555
innery:666
outerafter

outerx:22
innery:111
innery:222
innery:333
innery:444
innery:555
innery:666
outerafter

outerx:33
innery:111
innery:222
innery:333
innery:444
outofloopexp:leavinginnerloop

Page209
APythonBook

3.6Functions
Afunctionhasthesecharacteristics:
Itgroupsablockofcodetogethersothatwecancallitbyname.
Itenablesustopassvaluesintothethefunctionwhenwecallit.
Itcanreturnsavalue(evenifNone).
Whenafunctioniscalled,ithasitsownnamespace.Variablesinthefunctionare
localtothefunction(anddisappearwhenthefunctionexits).
Afunctionisdefinedwiththedef:statement.Hereisasimpleexample/template:
deffunction_name(arg1,arg2):
local_var1=arg1+1
local_var2=arg2*2
returnlocal_var1+local_var2
And,hereisanexampleofcallingthisfunction:
result=function_name(1,2)
Hereareafewnotesofexplanation:
Theabovedefinesafunctionwhosenameisfunction_name.
Thefunctionfunction_namehastwoarguments.Thatmeansthatwecanand
mustpassinexactlytwovalueswhenwecallit.
Thisfunctionhastwolocalvariables,local_var1andlocal_var2.These
variablesarelocalinthesensethatafterwecallthisfunction,thesetwovariables
arenotavailableinthelocationofthecaller.
Whenwecallthisfunction,itreturnsonevalue,specificallythesumof
local_var1andlocal_var2.
Exercises:
1. Writeafunctionthattakesalistofintegersasanargument,andreturnsthesum
oftheintegersinthatlist.
Solutions:
1. Thereturnstatementenablesustoreturnavaluefromafunction:
deflist_sum(values):
sum=0
forvalueinvalues:
sum+=value
returnsum

deftest():
a=[11,22,33,44,]
printlist_sum(a)

if__name__=='__main__':

Page210
APythonBook

test()

3.6.1Optionalargumentsanddefaultvalues
Youcanprovideadefaultvalueforanargumenttoafunction.
Ifyoudo,thatargumentisoptional(whenthefunctioniscalled).
Hereareafewthingstolearnaboutoptionalarguments:
Provideadefaultvaluewithanequalsignandavalue.Example:
defsample_func(arg1,arg2,arg3='empty',arg4=0):
Allparameterswithdefaultvaluesmustbeafter(totherightof)normal
parameters.
Donotuseamutableobjectasadefaultvalue.Becausethedef:statementis
evaluatedonlyonceandnoteachtimethefunctioniscalled,themutableobject
mightbesharedacrossmultiplecallstothefunction.Donotdothis:
defsample_func(arg1,arg2=[]):
Instead,dothis:
defsample_func(arg1,arg2=None):
ifarg2isNone:
arg2=[]
Hereisanexamplethatillustrateshowthismightgowrong:
defadder(a,b=[]):
b.append(a)
returnb

deftest():
printadder('aaa')
printadder('bbb')
printadder('ccc')

test()
Which,whenexecuted,displaysthefollowing:
['aaa']
['aaa','bbb']
['aaa','bbb','ccc']
Exercises:
1. Writeafunctionthatwritesastringtoafile.Thefunctiontakestwoarguments:
(1)afilethatisopenforoutputand(2)astring.Givethesecondargument(the
string)adefaultvaluesothatwhenthesecondargumentisomitted,anempty,
blanklineiswrittentothefile.

Page211
APythonBook

2. Writeafunctionthattakesthefollowingarguments:(1)aname,(2)avalue,and
(3)andoptionaldictionary.Thefunctionaddsthevaluetothedictionaryusingthe
nameasakeyinthedictionary.
Solutions:
1. Wecanpassafileaswewouldanyotherobject.And,wecanuseanewline
characterasadefaultparametervalue:
importsys

defwriter(outfile,msg='\n'):
outfile.write(msg)

deftest():
writer(sys.stdout,'aaaaa\n')
writer(sys.stdout)
writer(sys.stdout,'bbbbb\n')

test()
Whenrunfromthecommandline,thisprintsoutthefollowing:
aaaaa

bbbbb

2. Inthissolutionwearecarefulnottouseamutableobjectasadefaultvalue:
defadd_to_dict(name,value,dic=None):
ifdicisNone:
dic={}
dic[name]=value
returndic

deftest():
dic1={'albert':'cute',}
printadd_to_dict('barry','funny',dic1)
printadd_to_dict('charlene','smart',dic1)
printadd_to_dict('darryl','outrageous')
printadd_to_dict('eddie','friendly')

test()
Ifwerunthisscript,wesee:
{'barry':'funny','albert':'cute'}
{'barry':'funny','albert':'cute','charlene':
'smart'}
{'darryl':'outrageous'}
{'eddie':'friendly'}
Notes:
It'simportantthatthedefaultvalueforthedictionaryisNoneratherthanan
emptydictionary,forexample({}).Rememberthatthedef:statementis

Page212
APythonBook

evaluatedonlyonce,whichresultsinasingledictionary,whichwouldbe
sharedbyallcallersthatdonotprovideadictionaryasanargument.

3.6.2Passingfunctionsasarguments
Afunction,likeanyotherobject,canbepassedasanargumenttoafunction.Thisisdue
thethefactthatalmostall(maybeall)objectsinPythonare"firstclassobjects".Afirst
classobjectisonewhichwecan:
1. Storeinadatastructure(e.g.alist,adictionary,...).
2. Passtoafunction.
3. Returnfromafunction.
Exercises:
1. Writeafunctionthattakesthreearguments:(1)aninputfile,(2)anoutputfile,
and(3)afilterfunction:
Argument1isafileopenedforreading.
Argument2isafileopenedforwriting.
Argument3isafunctionthattakesasingleargument(astring),performsa
transformationonthatstring,andreturnsthetransformedstring.
Theabovefunctionshouldreadeachlineintheinputtextfile,passthatline
throughthefilterfunction,thenwritethat(possibly)transformedlinetothe
outputfile.
Now,writeoneormore"filterfunctions"thatcanbepassedtothefunction
describedabove.
Solutions:
1. Thisscriptaddsorremovescommentcharacterstothelinesofafile:
importsys

deffilter(infile,outfile,filterfunc):
forlineininfile:
line=filterfunc(line)
outfile.write(line)

defadd_comment(line):
line='##%s'%(line,)
returnline

defremove_comment(line):
ifline.startswith('##'):
line=line[3:]
returnline

defmain():
filter(sys.stdin,sys.stdout,add_comment)

Page213
APythonBook

if__name__=='__main__':
main()
Runningthismightproducesomethinglikethefollowing(noteforMSWindows
users:usetypeinsteadofcat):
$cattmp.txt
line1
line2
line3
$cattmp.txt|pythonworkbook005.py
##line1
##line2
##line3

3.6.3Extraargsandkeywordargs
Additionalpositionalargumentspassedtoafunctionthatarenotspecifiedinthefunction
definition(thedef:statement``),arecollectedinanargumentprecededbyasingle
asterisk.Keywordargumentspassedtoafunctionthatarenotspecifiedinthefunction
definitioncanbecollectedinadictionaryandpassedtoanargumentprecededbya
doubleasterisk.
Examples:
1. Writeafunctionthattakesonepositionalargument,oneargumentwithadefault
value,andalsoextraargsandkeywordargs.
2. Writeafunctionthatpassesallitsarguments,nomatterhowmany,toacallto
anotherfunction.
Solutions:
1. Weuse*argsand**kwargstocollectextraargumentsandextrakeyword
arguments:
defshow_args(x,y=1,*args,**kwargs):
print''*40
print'x:',x
print'y:',y
print'args:',args
print'kwargs:',kwargs

deftest():
show_args(1)
show_args(x=2,y=3)
show_args(y=5,x=4)
show_args(4,5,6,7,8)
show_args(11,y=44,a=55,b=66)

test()

Page214
APythonBook

Runningthisscriptproducesthefollowing:
$pythonworkbook006.py

x:1
y:1
args:()
kwargs:{}

x:2
y:3
args:()
kwargs:{}

x:4
y:5
args:()
kwargs:{}

x:4
y:5
args:(6,7,8)
kwargs:{}

x:11
y:44
args:()
kwargs:{'a':55,'b':66}
Notes:
Thespellingofargsandkwargsisnotfixed,butthe
2. Weuseargsandkwargstocatchandpassonallarguments:
deffunc1(*args,**kwargs):
print'args:%s'%(args,)
print'kwargs:%s'%(kwargs,)

deffunc2(*args,**kwargs):
print'before'
func1(*args,**kwargs)
print'after'

deftest():
func2('aaa','bbb','ccc',arg1='ddd',arg2='eee')

test()
Whenwerunthis,itprintsthefollowing:
before
args:('aaa','bbb','ccc')
kwargs:{'arg1':'ddd','arg2':'eee'}
after

Page215
APythonBook

Notes:
Inafunctioncall,the*operatorunrollsalistintoindividualpositional
arguments,andthe**operatorunrollsadictionaryintoindividualkeyword
arguments.

3.6.3.1Orderofarguments(positional,extra,andkeywordargs)
Inafunctiondefinition,argumentsmustappearinthefollowingorder,fromlefttoright:
1. Positional(normal,plain)arguments
2. Argumentswithdefaultvalues,ifany
3. Extraargumentsparameter(procededbysingleasterisk),ifpresent
4. Keywordargumentsparameter(procededbydoubleasterisk),ifpresent
Inafunctioncall,argumentsmustappearinthefollowingorder,fromlefttoright:
1. Positional(plain)arguments
2. Extraarguments,ifpresent
3. Keywordarguments,ifpresent

3.6.4Functionsandducktypingandpolymorphism
Iftheargumentsandreturnvalueofafunctionsatisfysomedescription,thenwecansay
thatthefunctionispolymorphicwithrespecttothatdescription.
Ifthesomeofthemethodsofanobjectsatisfysomedescription,thenwecansaythatthe
objectispolymorphicwithrespecttothatdescription.
Basically,whatthisdoesistoenableustouseafunctionoranobjectanywherethat
functionsatisfiestherequirementsgivenbyadescription.
Exercises:
1. Implementafunctionthattakestwoarguments:afunctionandanobject.It
appliesthefunctionargumenttotheobject.
2. Implementafunctionthattakestwoarguments:alistoffunctionsandanobject.
Itapplieseachfunctioninthelisttotheargument.
Solutions:
1. Wecanpassafunctionasanargumenttoafunction:
deffancy(obj):
print'fancyfancy%sfancyfancy'%(obj,)

defplain(obj):
print'plain%splain'%(obj,)

defshow(func,obj):
func(obj)

Page216
APythonBook

defmain():
a={'aa':11,'bb':22,}
show(fancy,a)
show(plain,a)

if__name__=='__main__':
main()
2. Wecanalsoputfunctions(functionobjects)inadatastructure(forexample,a
list),andthenpassthatdatastructuretoafunction:
deffancy(obj):
print'fancyfancy%sfancyfancy'%(obj,)

defplain(obj):
print'plain%splain'%(obj,)

Func_list=[fancy,plain,]

defshow(funcs,obj):
forfuncinfuncs:
func(obj)

defmain():
a={'aa':11,'bb':22,}
show(Func_list,a)

if__name__=='__main__':
main()
NoticethatPythonsupportspolymorphism(withor)withoutinheritance.Thistypeof
polymorphismisenabledbywhatiscalledducktyping.Formoreonthissee:Duck
typinghttp://en.wikipedia.org/wiki/Duck_typingatWikipedia.

3.6.5Recursivefunctions
Arecursivefunctionisafunctionthatcallsitself.
Arecursivefunctionmusthavealimitingcondition,orelseitwillloopendlessly.
Eachrecursivecallconsumesspaceonthefunctioncallstack.Therefore,thenumberof
recursionsmusthavesomereasonableupperbound.
Exercises:
1. Writearecursivefunctionthatprintsinformationabouteachnodeinthe
followingtreestructuredatastructure:
Tree={
'name':'animals',
'left_branch':{

Page217
APythonBook

'name':'birds',
'left_branch':{
'name':'seedeaters',
'left_branch':{
'name':'housefinch',
'left_branch':None,
'right_branch':None,
},
'right_branch':{
'name':'whitecrownedsparrow',
'left_branch':None,
'right_branch':None,
},
},
'right_branch':{
'name':'insecteaters',
'left_branch':{
'name':'hermitthrush',
'left_branch':None,
'right_branch':None,
},
'right_branch':{
'name':'blackheadedphoebe',
'left_branch':None,
'right_branch':None,
},
},
},
'right_branch':None,
}
Solutions:
1. Wewritearecursivefunctiontowalkthewholetree.Therecursivefunctioncalls
itselftoprocesseachchildofanodeinthetree:
Tree={
'name':'animals',
'left_branch':{
'name':'birds',
'left_branch':{
'name':'seedeaters',
'left_branch':{
'name':'housefinch',
'left_branch':None,
'right_branch':None,
},
'right_branch':{
'name':'whitecrownedsparrow',
'left_branch':None,
'right_branch':None,
},
},

Page218
APythonBook

'right_branch':{
'name':'insecteaters',
'left_branch':{
'name':'hermitthrush',
'left_branch':None,
'right_branch':None,
},
'right_branch':{
'name':'blackheadedphoebe',
'left_branch':None,
'right_branch':None,
},
},
},
'right_branch':None,
}

Indents=[''*idxforidxinrange(10)]

defwalk_and_show(node,level=0):
ifnodeisNone:
return
print'%sname:%s'%(Indents[level],node['name'],
)
level+=1
walk_and_show(node['left_branch'],level)
walk_and_show(node['right_branch'],level)

deftest():
walk_and_show(Tree)

if__name__=='__main__':
test()
Notes:
Later,youwilllearnhowtocreateequivalentdatastructuresusingclassesand
OOP(objectorientedprogramming).FormoreonthatseeRecursivecallsto
methodsinthisdocument.

3.6.6Generatorsanditerators
The"iteratorprotocol"defineswhataniteratorobjectmustdoinordertobeusableinan
"iteratorcontext"suchasaforstatement.Theiteratorprotocolisdescribedinthe
standardlibraryreference:IteratorTypeshttp://docs.python.org/lib/typeiter.html
Aneasywaytodefineanobjectthatobeystheiteratorprotocolistowriteagenerator
function.Ageneratorfunctionisafunctionthatcontainsoneormoreyieldstatements.
Ifafunctioncontainsatleastoneyieldstatement,thenthatfunctionwhencalled,
returnsgeneratoriterator,whichisanobjectthatobeystheiteratorprotocol,i.e.it'san
iteratorobject.

Page219
APythonBook

NotethatinrecentversionsofPython,yieldisanexpression.Thisenablestheconsumer
tocommunicatebackwiththeproducer(thegeneratoriterator).Formoreonthis,see
PEP:342CoroutinesviaEnhancedGenerators
http://www.python.org/dev/peps/pep0342/.
Exercises:
1. ImplementageneratorfunctionThegeneratorproducedshouldyieldall
valuesfromalist/iterablethatsatisfyapredicate.Itshouldapplythetransforms
beforereturneachvalue.Thefunctiontakesthesearguments:
1. valuesAlistofvalues.Actually,itcouldbeanyiterable.
2. predicateAfunctionthattakesasingleargument,performsateston
thatvalue,andreturnsTrueorFalse.
3. transforms(optional)Alistoffunctions.Applyeachfunctioninthislist
andreturnstheresultingvalue.So,forexample,ifthefunctioniscalledlike
this:
result=transforms([11,22],p,[f,g])
thentheresultinggeneratormightreturn:
g(f(11))
2. ImplementageneratorfunctionthattakesalistofURLsasitsargumentand
generatesthecontentsofeachWebpage,onebyone(thatis,itproducesa
sequenceofstrings,theHTMLpagecontents).
Solutions:
1. Hereistheimplementationofafunctionwhichcontainsyield,and,therefore,
producesagenerator:
#!/usr/bin/envpython
"""
filter_and_transform

filter_and_transform(content,test_func,
transforms=None)

Returnageneratorthatreturnsitemsfromcontent
afterapplying
thefunctionsintransformsiftheitemsatisfies
test_func.

Arguments:

1.``values``Alistofvalues

2.``predicate``Afunctionthattakesasingle
argument,
performsatestonthatvalue,andreturnsTrue

Page220
APythonBook

orFalse.

3.``transforms``(optional)Alistoffunctions.
Applyeach
functioninthislistandreturnstheresulting
value.So,
forexample,ifthefunctioniscalledlike
this::

result=filter_and_transforms([11,22],p,[f,
g])

thentheresultinggeneratormightreturn::

g(f(11))
"""

deffilter_and_transform(content,test_func,
transforms=None):
forxincontent:
iftest_func(x):
iftransformsisNone:
yieldx
elifisiterable(transforms):
forfuncintransforms:
x=func(x)
yieldx
else:
yieldtransforms(x)

defisiterable(x):
flag=True
try:
x=iter(x)
exceptTypeError,exp:
flag=False
returnflag

defiseven(n):
returnn%2==0

deff(n):
returnn*2

defg(n):
returnn**2

deftest():
data1=[11,22,33,44,55,66,77,]
forvalinfilter_and_transform(data1,iseven,f):
print'val:%d'%(val,)
print''*40
forvalinfilter_and_transform(data1,iseven,[f,

Page221
APythonBook

g]):
print'val:%d'%(val,)
print''*40
forvalinfilter_and_transform(data1,iseven):
print'val:%d'%(val,)

if__name__=='__main__':
test()
Notes:
Becausefunctionfilter_and_transformcontainsyield,when
called,itreturnsaniteratorobject,whichwecanuseinaforstatement.
Thesecondparameteroffunctionfilter_and_transformtakesany
functionwhichtakesasingleargumentandreturnsTrueorFalse.Thisisan
exampleofpolymorphismand"ducktyping"(seeDuckTyping
http://en.wikipedia.org/wiki/Duck_typing).Ananalogousclaimcanbemade
aboutthethirdparameter.
2. Thefollowingfunctionusestheurllibmoduleandtheyieldfunctionto
generatethecontentsofasequenceofWebpages:
importurllib

Urls=[
'http://yahoo.com',
'http://python.org',
'http://gimp.org',#TheGNUimagemanipulation
program
]

defwalk(url_list):
forurlinurl_list:
f=urllib.urlopen(url)
stuff=f.read()
f.close()
yieldstuff

deftest():
forxinwalk(Urls):
print'length:%d'%(len(x),)

if__name__=='__main__':
test()
WhenIrunthis,Isee:
$pythongenerator_example.py
length:9554
length:16748
length:11487

Page222
APythonBook

3.7Objectorientedprogrammingandclasses
ClassesprovidePython'swaytodefinenewdatatypesandtodoOOP(objectoriented
programming).
Ifyouhavemadeitthisfar,youhavealreadyusedlotsofobjects.Youhavebeena
"consumer"ofobjectsandtheirservices.Now,youwilllearnhowtodefineand
implementnewkindsofobjects.Youwillbecomea"producer"ofobjects.Youwill
definenewclassesandyouwillimplementthecapabilities(methods)ofeachnewclass.
Aclassisdefinedwiththeclassstatement.Thefirstlineofaclassstatementisa
header(ithasacolonattheend),anditspecifiesthenameoftheclassbeingdefinedand
an(optional)superclass.Andthatheaderintroducesacompoundstatement:specifically,
thebodyoftheclassstatementwhichcontainsindented,nestedstatements,
importantly,defstatementsthatdefinethemethodsthatcanbecalledoninstancesofthe
objectsimplementedbythisclass.
Exercises:
1. Defineaclasswithonemethodshow.Thatmethodshouldprintout"Hello".
Then,createaninstanceofyourclass,andcalltheshowmethod.
Solutions:
1. Asimpleinstancemethodcanhavetheselfparameterandnoothers:
classDemo(object):
defshow(self):
print'hello'

deftest():
a=Demo()
a.show()

test()
Notes:
Noticethatweuseobjectasasuperclass,becausewewanttodefinean
"newstyle"classandbecausethereisnootherclassthatwewantasa
superclass.Seethefollowingformoreinformationonnewstyleclasses:
NewstyleClasseshttp://www.python.org/doc/newstyle/.
InPython,wecreateaninstanceofaclassbycallingtheclass,thatis,we
applythefunctioncalloperator(parentheses)totheclass.

3.7.1Theconstructor
Aclasscandefinemethodswithspecialnames.Youhaveseemsomeofthesebefore.
Thesenamesbeginandendwithadoubleunderscore.

Page223
APythonBook

Oneimportantspecialnameis__init__.It'stheconstructorforaclass.Itiscalled
eachtimeaninstanceoftheclassiscreated.Implementingthismethodinaclassgivesus
achancetoinitializeeachinstanceofourclass.
Exercises:
1. ImplementaclassnamedPlantthathasaconstructorwhichinitializestwo
instancevariables:nameandsize.Also,inthisclass,implementamethod
namedshowthatprintsoutthevaluesoftheseinstancevariables.Createseveral
instancesofyourclassand"show"them.
2. ImplementaclassnameNodethathastwoinstancevariables:dataand
children,wheredataisany,arbitraryobjectandchildrenisalistofchild
Nodes.Alsoimplementamethodnamedshowthatrecursivelydisplaysthe
nodesina"tree".Createaninstanceofyourclassthatcontainsseveralchild
instancesofyourclass.Calltheshowmethodontheroot(topmost)objectto
showthetree.
Solutions:
1. Theconstructorforaclassisamethodwiththespecialname__init__:
classPlant(object):
def__init__(self,name,size):
self.name=name
self.size=size
defshow(self):
print'name:"%s"size:%d'%(self.name,
self.size,)

deftest():
p1=Plant('Eggplant',25)
p2=Plant('Tomato',36)
plants=[p1,p2,]
forplantinplants:
plant.show()

test()
Notes:
Ourconstructortakestwoarguments:nameandsize.Itsavesthosetwo
valuesasinstancevariables,thatisinattributesoftheinstance.
Theshow()methodprintsoutthevalueofthosetwoinstancevariables.
2. Itisagoodideatoinitializeallinstancevariablesintheconstructor.Thatenables
someonereadingourcodetolearnaboutalltheinstancevariablesofaclassby
lookinginasinglelocation:
#simple_node.py

Indents=[''*nforninrange(10)]

Page224
APythonBook

classNode(object):
def__init__(self,name=None,children=None):
self.name=name
ifchildrenisNone:
self.children=[]
else:
self.children=children
defshow_name(self,indent):
print'%sname:"%s"'%(Indents[indent],
self.name,)
defshow(self,indent=0):
self.show_name(indent)
indent+=1
forchildinself.children:
child.show(indent)

deftest():
n1=Node('N1')
n2=Node('N2')
n3=Node('N3')
n4=Node('N4')
n5=Node('N5',[n1,n2,])
n6=Node('N6',[n3,n4,])
n7=Node('N7',[n5,n6,])
n7.show()

if__name__=='__main__':
test()
Notes:
Noticethatwedonotusetheconstructorforalist([])asadefaultvaluefor
thechildrenparameteroftheconstructor.Alistismutableandwouldbe
createdonlyonce(whentheclassstatementisexecuted)andwouldbeshared.

3.7.2InheritanceImplementingasubclass
Asubclassextendsorspecializesasuperclassbyaddingadditionalmethodstothe
superclassandbyoverridingmethods(withthesamename)thatalreadyexistinthe
superclass.
Exercises:
1. ExtendyourNodeexerciseabovebyaddingtwoadditionalsubclassesofthe
Nodeclass,onenamedPlantandtheothernamedAnimal.ThePlantclass
alsohasaheightinstancevariableandtheAnimalclassalsohasacolor
instancevariable.
Solutions:
1. WecanimportourpreviousNodescript,thenimplementclassesthathavethe
Nodeclassasasuperclass:

Page225
APythonBook

fromsimple_nodeimportNode,Indents

classPlant(Node):
def__init__(self,name,height=1,children=None):
Node.__init__(self,name,children)
self.height=height
defshow(self,indent=0):
self.show_name(indent)
print'%sheight:%s'%(Indents[indent],
self.height,)
indent+=1
forchildinself.children:
child.show(indent)

classAnimal(Node):
def__init__(self,name,color='nocolor',
children=None):
Node.__init__(self,name,children)
self.color=color
defshow(self,indent=0):
self.show_name(indent)
print'%scolor:"%s"'%(Indents[indent],
self.color,)
indent+=1
forchildinself.children:
child.show(indent)

deftest():
n1=Animal('scrubjay','grayblue')
n2=Animal('raven','black')
n3=Animal('americankestrel','brown')
n4=Animal('redshoulderedhawk','brownand
gray')
n5=Animal('corvid','none',[n1,n2,])
n6=Animal('raptor',children=[n3,n4,])
n7a=Animal('bird',children=[n5,n6,])
n1=Plant('valleyoak',50)
n2=Plant('canyonliveoak',40)
n3=Plant('jefferypine',120)
n4=Plant('ponderosapine',140)
n5=Plant('oak',children=[n1,n2,])
n6=Plant('conifer',children=[n3,n4,])
n7b=Plant('tree',children=[n5,n6,])
n8=Node('birdsandtrees',[n7a,n7b,])
n8.show()

if__name__=='__main__':
test()
Notes:
TheshowmethodinclassPlantcallstheshow_namemethodinits
superclassusingself.show_name(...).Pythonsearchesupthe

Page226
APythonBook

inheritancetreetofindtheshow_namemethodinclassNode.
Theconstructor(__init__)inclassesPlantandAnimaleachcallthe
constructorinthesuperclassbyusingthenameofthesuperclass.Whythe
difference?Because,if(inthePlantclass,forexample)itused
self.__init__(...)itwouldbecallingthe__init__inthePlant
class,itself.So,itbypassesitselfbyreferencingtheconstructorinthe
superclassdirectly.
Thisexercisealsodemonstrates"polymorphism"Theshowmethodis
calledanumberoftimes,butwhichimplementationexecutesdependson
whichinstanceitiscalledon.Callingontheshowmethodonaninstanceof
classPlantresultsinacalltoPlant.show.Callingtheshowmethodon
aninstanceofclassAnimalresultsinacalltoAnimal.show.Andsoon.It
isimportantthateachshowmethodtakesthecorrectnumberofarguments.

3.7.3Classesandpolymorphism
Pythonalsosupportsclassbasedpolymorphism,whichwas,bytheway,demonstratedin
thepreviousexample.
Exercises:
1. Writethreeclasses,eachofwhichimplementashow()methodthattakesone
argument,astring.Theshowmethodshouldprintoutthenameoftheclassand
themessage.Thencreatealistofinstancesandcalltheshow()methodoneach
objectinthelist.
Solution:
1. Weimplementthreesimpleclassesandthencreatealistofinstancesofthese
classes:
classA(object):
defshow(self,msg):
print'classAmsg:"%s"'%(msg,)

classB(object):
defshow(self,msg):
print'classBmsg:"%s"'%(msg,)

classC(object):
defshow(self,msg):
print'classCmsg:"%s"'%(msg,)

deftest():
objs=[A(),B(),C(),A(),]
foridx,objinenumerate(objs):
msg='message#%d'%(idx+1,)
obj.show(msg)

Page227
APythonBook

if__name__=='__main__':
test()
Notes:
Wecancalltheshow()methodinanyobjectinthelistobjsaslongaswe
passinasingleparameter,thatis,aslongasweobeytherequirementsof
ducktyping.Wecandothisbecauseallobjectsinthatlistimplementa
show()method.
Inastaticallytypedlanguage,thatisalanguagewherethetypeis(also)
presentinthevariable,alltheinstancesinexamplewouldhavetodescend
fromacommonsuperclassandthatsuperclasswouldhavetoimplementa
show()method.Pythondoesnotimposethisrestriction.And,because
variablesarenotnottypedinPython,perhapsthatwouldnotevenpossible.
Noticethatthisexampleofpolymorphismworkseventhoughthesethree
classes(A,B,andC)arenotrelated(forexample,inaclasshierarchy).All
thatisrequiredforpolymorphismtoworkinPythonisforthemethodnames
tobethesameandtheargumentstobecompatible.

3.7.4Recursivecallstomethods
Amethodinaclasscanrecusivelycallitself.Thisisverysimilartothewayinwhichwe
implementedrecursivefunctionssee:Recursivefunctions.
Exercises:
1. ReimplementthebinarytreeofanimalsandbirdsdescribedinRecursive
functions,butthistime,useaclasstorepresenteachnodeinthetree.
2. Solvethesameproblem,butthistimeimplementatreeinwhicheachnodecan
haveanynumberofchildren(ratherthanexactly2children).
Solutions:
1. Weimplementaclasswiththreeinstancevariables:(1)name,(2)leftbranch,and
(3)rightbranch.Then,weimplementashow()methodthatdisplaysthename
andcallsitselftoshowthechildrenineachsubtree:
Indents=[''*idxforidxinrange(10)]

classAnimalNode(object):

def__init__(self,name,left_branch=None,
right_branch=None):
self.name=name
self.left_branch=left_branch
self.right_branch=right_branch

defshow(self,level=0):
print'%sname:%s'%(Indents[level],

Page228
APythonBook

self.name,)
level+=1
ifself.left_branchisnotNone:
self.left_branch.show(level)
ifself.right_branchisnotNone:
self.right_branch.show(level)

Tree=AnimalNode('animals',
AnimalNode('birds',
AnimalNode('seedeaters',
AnimalNode('housefinch'),
AnimalNode('whitecrownedsparrow'),
),
AnimalNode('insecteaters',
AnimalNode('hermitthrush'),
AnimalNode('blackheadedphoebe'),
),
),
None,
)

deftest():
Tree.show()

if__name__=='__main__':
test()
2. Insteadofusingaleftbranchandarightbranch,inthissolutionweusealistto
representthechildrenofanode:
classAnimalNode(object):
def__init__(self,data,children=None):
self.data=data
ifchildrenisNone:
self.children=[]
else:
self.children=children

defshow(self,level=''):
print'%sdata:%s'%(level,self.data,)
level+=''
forchildinself.children:
child.show(level)

Tree=AnimalNode('animals',[
AnimalNode('birds',[
AnimalNode('seedeaters',[
AnimalNode('housefinch'),
AnimalNode('whitecrownedsparrow'),
AnimalNode('lessergoldfinch'),
]),
AnimalNode('insecteaters',[
AnimalNode('hermitthrush'),

Page229
APythonBook

AnimalNode('blackheadedphoebe'),
]),
])
])

deftest():
Tree.show()

if__name__=='__main__':
test()
Notes:
Werepresentthechildrenofanodeasalist.Eachnode"hasa"listof
children.
Noticethatbecausealistismutable,wedonotusealistconstructor([])in
theinitializerofthemethodheader.Instead,weuseNone,thenconstructan
emptylistinthebodyofthemethodifnecessary.SeesectionOptional
argumentsanddefaultvaluesformoreonthis.
We(recursively)calltheshowmethodforeachnodeinthechildrenlist.
Sinceanodewhichhasnochildren(aleafnode)willhaveanempty
childrenlist,thisprovidesalimitconditionforourrecursion.

3.7.5Classvariables,classmethods,andstaticmethods
Aclassvariableisonewhosesinglevalueissharedbyallinstancesoftheclassand,in
fact,issharedbyallwhohaveaccesstotheclass(object).
"Normal"methodsareinstancemethods.Aninstancemethodreceivestheinstanceasits
firstargument.Ainstancemethodisdefinedbyusingthedefstatementinthebodyofa
classstatement.
Aclassmethodreceivestheclassasitsfirstargument.Aclassmethodisdefinedby
defininganormal/instancemethod,thenusingtheclassmethodbuiltinfunction.For
example:
classASimpleClass(object):
description='asimpleclass'
defshow_class(cls,msg):
print'%s:%s'%(cls.description,msg,)
show_class=classmethod(show_class)
Astaticmethoddoesnotreceiveanythingspecialasitsfirstargument.Astaticmethodis
definedbydefininganormal/instancemethod,thenusingthestaticmethodbuiltin
function.Forexample:
classASimpleClass(object):
description='asimpleclass'
defshow_class(msg):

Page230
APythonBook

print'%s:%s'%(ASimpleClass.description,msg,)
show_class=staticmethod(show_class)
Ineffect,bothclassmethodsandstaticmethodsaredefinedbycreatinganormal
(instance)method,thencreatingawrapperobject(aclassmethodorstaticmethod)using
theclassmethodorstaticmethodbuiltinfunction.
Exercises:
1. Implementaclassthatkeepsarunningtotalofthenumberofinstancescreated.
2. Implementanothersolutiontothesameproblem(aclassthatkeepsarunning
totalofthenumberofinstances),butthistimeuseastaticmethodinsteadofa
classmethod.
Solutions:
1. Weuseaclassvariablenamedinstance_count,ratherthananinstance
variable,tokeeparunningtotalofinstances.Then,weincrementthatvariable
eachtimeaninstanceiscreated:
classCountInstances(object):

instance_count=0

def__init__(self,name='noname'):
self.name=name
CountInstances.instance_count+=1

defshow(self):
print'name:"%s"'%(self.name,)

defshow_instance_count(cls):
print'instancecount:%d'%
(cls.instance_count,)
show_instance_count=
classmethod(show_instance_count)

deftest():
instances=[]
instances.append(CountInstances('apple'))
instances.append(CountInstances('banana'))
instances.append(CountInstances('cherry'))
instances.append(CountInstances())
forinstanceininstances:
instance.show()
CountInstances.show_instance_count()

if__name__=='__main__':
test()
Notes:

Page231
APythonBook

Whenwerunthisscript,itprintsoutthefollowing:
name:"apple"
name:"banana"
name:"cherry"
name:"noname"
instancecount:4
Thecalltotheclassmethodbuiltinfunctioneffectivelywrapsthe
show_instance_countmethodinaclassmethod,thatis,inamethod
thattakesaclassobjectasitsfirstargumentratherthananinstanceobject.To
readmoreaboutclassmethod,gotoBuiltinFunctions
http://docs.python.org/lib/builtinfuncs.htmlandsearchfor"classmethod".
2. Astaticmethodtakesneitheraninstance(self)noraclassasitsfirst
paramenter.And,staticmethodiscreatedwiththestaticmethod()builtin
function(ratherthanwiththeclassmethod()builtin):
classCountInstances(object):

instance_count=0

def__init__(self,name='noname'):
self.name=name
CountInstances.instance_count+=1

defshow(self):
print'name:"%s"'%(self.name,)

defshow_instance_count():
print'instancecount:%d'%(
CountInstances.instance_count,)
show_instance_count=
staticmethod(show_instance_count)

deftest():
instances=[]
instances.append(CountInstances('apple'))
instances.append(CountInstances('banana'))
instances.append(CountInstances('cherry'))
instances.append(CountInstances())
forinstanceininstances:
instance.show()
CountInstances.show_instance_count()

if__name__=='__main__':
test()

3.7.5.1Decoratorsforclassmethodandstaticmethod
Adecoratorenablesustodowhatwedidinthepreviousexamplewithasomewhat
simplersyntax.

Page232
APythonBook

Forsimplecases,thedecoratorsyntaxenablesustodothis:
@functionwrapper
defmethod1(self):
o
o
o
insteadofthis:
defmethod1(self):
o
o
o
method1=functionwrapper(method1)
So,wecanwritethis:
@classmethod
defmethod1(self):
o
o
o
insteadofthis:
defmethod1(self):
o
o
o
method1=classmethod(method1)
Exercises:
1. ImplementtheCountInstancesexampleabove,butuseadecoratorrather
thantheexplicitcalltoclassmethod.
Solutions:
1. Adecoratorisaneasierandcleanerwaytodefineaclassmethod(orastatic
method):
classCountInstances(object):

instance_count=0

def__init__(self,name='noname'):
self.name=name
CountInstances.instance_count+=1

defshow(self):
print'name:"%s"'%(self.name,)

@classmethod

Page233
APythonBook

defshow_instance_count(cls):
print'instancecount:%d'%
(cls.instance_count,)
#Notethatthefollowinglinehasbeenreplacedby
#theclassmethoddecorator,above.
#show_instance_count=
classmethod(show_instance_count)

deftest():
instances=[]
instances.append(CountInstances('apple'))
instances.append(CountInstances('banana'))
instances.append(CountInstances('cherry'))
instances.append(CountInstances())
forinstanceininstances:
instance.show()
CountInstances.show_instance_count()

if__name__=='__main__':
test()

3.8AdditionalandAdvancedTopics

3.8.1Decoratorsandhowtoimplementthem
Decoratorscanbeusedto"wrap"afunctionwithanotherfunction.
Whenimplementingadecorator,itishelpfultorememberthatthefollowingdecorator
application:
@dec
deffunc(arg1,arg2):
pass
isequivalentto:
deffunc(arg1,arg2):
pass
func=dec(func)
Therefore,toimplementadecorator,wewriteafunctionthatreturnsafunctionobject,
sincewereplacethevalueoriginallyboundtothefunctionwiththisnewfunctionobject.
Itmaybehelpfultotaketheviewthatwearecreatingafunctionthatisawrapperforthe
originalfunction.
Exercises:
1. Writeadecoratorthatwritesamessagebeforeandafterexecutingafunction.
Solutions:

Page234
APythonBook

1. Afunctionthatcontainsandreturnsaninnerfunctioncanbeusedtowrapa
function:
deftrace(func):
definner(*args,**kwargs):
print'>>'
func(*args,**kwargs)
print'<<'
returninner

@trace
deffunc1(x,y):
print'x:',x,'y:',y
func2((x,y))

@trace
deffunc2(content):
print'content:',content

deftest():
func1('aa','bb')

test()
Notes:
Yourinnerfunctioncanuse*argsand**kwargstoenableittocall
functionswithanynumberofarguments.

3.8.1.1Decoratorswitharguments
Decoratorscanalsotakearguments.
Thefollowingdecoratorwitharguments:
@dec(argA,argB)
deffunc(arg1,arg2):
pass
isequivalentto:
deffunc(arg1,arg2):
pass
func=dec(argA,argB)(func)
Becausethedecorator'sargumentsarepassedtotheresultofcallingthedecoratoronthe
decoratedfunction,youmayfinditusefultoimplementadecoratorwithargumentsusing
afunctioninsideafunctioninsideafunction.
Exercises:
1. Writeandtestadecoratorthattakesoneargument.Thedecoratorprintsa
messagealongwiththevalueoftheargumentbeforeandafterenteringthe

Page235
APythonBook

decoratedfunction.
Solutions:
1. Implementthisdecoratorthattakesargumentswithafunctioncontaininganested
functionwhichinturncontainsanestedfunction:
deftrace(msg):
definner1(func):
definner2(*args,**kwargs):
print'>>[%s]'%(msg,)
retval=func(*args,**kwargs)
print'<<[%s]'%(msg,)
returnretval
returninner2
returninner1

@trace('tracingfunc1')
deffunc1(x,y):
print'x:',x,'y:',y
result=func2((x,y))
returnresult

@trace('tracingfunc2')
deffunc2(content):
print'content:',content
returncontent*3

deftest():
result=func1('aa','bb')
print'result:',result

test()

3.8.1.2Stackeddecorators
Decoratorscanbe"stacked".
Thefollowingstackeddecorators:
@dec2
@dec1
deffunc(arg1,arg2,...):
pass
areequivalentto:
deffunc(arg1,arg2,...):
pass
func=dec2(dec1(func))
Exercises:
1. Implementadecorator(asabove)thattracescallstoadecoratedfunction.Then

Page236
APythonBook

"stack"thatwithanotherdecoratorthatprintsahorizontallineofdashesbefore
andaftercallingthefunction.
2. Modifyyoursolutiontotheaboveexercisesothatthedecoratorthatprintsthe
horizontallinetakesoneargument:acharacter(orcharacters)thatcanberepeated
toproduceahorizontalline/separator.
Solutions:
1. Reuseyourtracingfunctionfromthepreviousexercise,thenwriteasimple
decoratorthatprintsarowofdashes:
deftrace(msg):
definner1(func):
definner2(*args,**kwargs):
print'>>[%s]'%(msg,)
retval=func(*args,**kwargs)
print'<<[%s]'%(msg,)
returnretval
returninner2
returninner1

defhorizontal_line(func):
definner(*args,**kwargs):
print''*50
retval=func(*args,**kwargs)
print''*50
returnretval
returninner

@trace('tracingfunc1')
deffunc1(x,y):
print'x:',x,'y:',y
result=func2((x,y))
returnresult

@horizontal_line
@trace('tracingfunc2')
deffunc2(content):
print'content:',content
returncontent*3

deftest():
result=func1('aa','bb')
print'result:',result

test()
2. Onceagain,adecoratorwithargumentscanbeimplementedwithafunction
nestedinsideafunctionwhichisnestedinsideafunction.Thisremainsthesame
whetherthedecoratorisusedasastackeddecoratorornot.Hereisasolution:
deftrace(msg):

Page237
APythonBook

definner1(func):
definner2(*args,**kwargs):
print'>>[%s]'%(msg,)
retval=func(*args,**kwargs)
print'<<[%s]'%(msg,)
returnretval
returninner2
returninner1

defhorizontal_line(line_chr):
definner1(func):
definner2(*args,**kwargs):
printline_chr*15
retval=func(*args,**kwargs)
printline_chr*15
returnretval
returninner2
returninner1

@trace('tracingfunc1')
deffunc1(x,y):
print'x:',x,'y:',y
result=func2((x,y))
returnresult

@horizontal_line('<**>')
@trace('tracingfunc2')
deffunc2(content):
print'content:',content
returncontent*3

deftest():
result=func1('aa','bb')
print'result:',result

test()

3.8.1.3Morehelpwithdecorators
Thereismoreaboutdecoratorshere:
Pythonsyntaxandsemantics
http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decoratorsat
Wikipedia.
PythonDecoratorLibraryhttp://wiki.python.org/moin/PythonDecoratorLibrary
atthePythonWikihaslotsofsamplecode.
PEP318DecoratorsforFunctionsandMethods
http://www.python.org/dev/peps/pep0318/istheformalproposaland
specificationforPythondecorators.

Page238
APythonBook

3.8.2Iterables

3.8.2.1AfewpreliminariesonIterables
Definition:iterable(adjective)thatwhichcanbeiteratedover.
Agoodtestofwhethersomethingisiterableiswhetheritcanbeusedinafor:
statement.Forexample,ifwecanwriteforiteminX:,thenXisiterable.Hereis
anothersimpletest:
defisiterable(x):
try:
y=iter(x)
exceptTypeError,exp:
returnFalse
returnTrue
Somekindsofiterables:
ContainersWecaniterateoverlists,tuples,dictionaries,sets,strings,andother
containers.
Somebuiltin(noncontainer)typesExamples:
Atextfileopeninreadmodeisiterable:ititeratesoverthelinesinthefile.
ThexrangetypeSeeXRangeType
http://docs.python.org/lib/typesseqxrange.html.It'susefulwhenyouwanta
largesequenceofintegerstoiterateover.
Instancesofclassesthatobeytheiteratorprotocol.Foradescriptionoftheiterator
protocol,seeIteratorTypeshttp://docs.python.org/lib/typeiter.html.Hint:Type
dir(obj)andlookfor"__iter__"and"next".
GeneratorsAnobjectreturnedbyanyfunctionormethodthatcontainsyield.
Exercises:
1. Implementaclasswhoseinstancesareinterable.Theconstructortakesalistof
URLsasitsargument.Aninstanceofthisclass,wheniteratedover,generatesthe
contentoftheWebpageatthataddress.
Solutions:
1. Weimplementaclassthathas__iter__()andnext()methods:
importurllib

classWebPages(object):
def__init__(self,urls):
self.urls=urls
self.current_index=0
def__iter__(self):
self.current_index=0
returnself

Page239
APythonBook

defnext(self):
ifself.current_index>=len(self.urls):
raiseStopIteration
url=self.urls[self.current_index]
self.current_index+=1
f=urllib.urlopen(url)
content=f.read()
f.close()
returncontent

deftest():
urls=[
'http://www.python.org',
'http://en.wikipedia.org/',

'http://en.wikipedia.org/wiki/Python_(programming_langu
age)',
]
pages=WebPages(urls)
forpageinpages:
print'length:%d'%(len(page),)
pages=WebPages(urls)
print''*50
page=pages.next()
print'length:%d'%(len(page),)
page=pages.next()
print'length:%d'%(len(page),)
page=pages.next()
print'length:%d'%(len(page),)
page=pages.next()
print'length:%d'%(len(page),)

test()

3.8.2.2Morehelpwithiterables
TheitertoolsmoduleinthePythonstandardlibraryhashelpersforiterators:
http://docs.python.org/library/itertools.html#moduleitertools

3.9ApplicationsandRecipes

3.9.1XMLSAX,minidom,ElementTree,Lxml
Exercises:
1. SAXParseanXMLdocumentwithSAX,thenshowsomeinformation(tag,
attributes,characterdata)foreachelement.
2. MinidomParseanXMLdocumentwithminidom,thenwalktheDOMtree
andshowsomeinformation(tag,attributes,characterdata)foreachelement.

Page240
APythonBook

HereisasampleXMLdocumentthatyoucanuseforinput:
<?xmlversion="1.0"?>
<people>
<personid="1"value="abcd"ratio="3.2">
<name>Alberta</name>
<interest>gardening</interest>
<interest>reading</interest>
<category>5</category>
</person>
<personid="2">
<name>Bernardo</name>
<interest>programming</interest>
<category></category>
<agent>
<firstname>Darren</firstname>
<lastname>Diddly</lastname>
</agent>
</person>
<personid="3"value="efgh">
<name>Charlie</name>
<interest>people</interest>
<interest>cats</interest>
<interest>dogs</interest>
<category>8</category>
<promoter>
<firstname>David</firstname>
<lastname>Donaldson</lastname>
<client>
<fullname>ArnoldApplebee</fullname>
<refid>10001</refid>
</client>
</promoter>
<promoter>
<firstname>Edward</firstname>
<lastname>Eddleberry</lastname>
<client>
<fullname>ArnoldApplebee</fullname>
<refid>10001</refid>
</client>
</promoter>
</person>
</people>
3. ElementTreeParseanXMLdocumentwithElementTree,thenwalktheDOM
treeandshowsomeinformation(tag,attributes,characterdata)foreachelement.
4. lxmlParseanXMLdocumentwithlxml,thenwalktheDOMtreeandshow
someinformation(tag,attributes,characterdata)foreachelement.
5. ModifydocumentwithElementTreeUseElementTreetoreadadocument,then
modifythetree.Showthecontentsofthetree,andthenwriteoutthemodified
document.
6. XPathlxmlsupportsXPath.UsetheXPathsupportinlxmltoaddresseachof

Page241
APythonBook

thefollowingintheaboveXMLinstancedocument:
Thetextinallthenameelements
Thevaluesofalltheidattributes
Solutions:
1. WecanusetheSAXsupportinthePythonstandardlibrary:
#!/usr/bin/envpython

"""
ParseandXMLwithSAX.Displayinfoabouteach
element.

Usage:
pythontest_sax.pyinfilename
Examples:
pythontest_sax.pypeople.xml
"""

importsys
fromxml.saximportmake_parser,handler

classTestHandler(handler.ContentHandler):
def__init__(self):
self.level=0

defshow_with_level(self,value):
print'%s%s'%(''*self.level,value,)

defstartDocument(self):
self.show_with_level('Documentstart')
self.level+=1

defendDocument(self):
self.level=1
self.show_with_level('Documentend')

defstartElement(self,name,attrs):
self.show_with_level('startelementname:
"%s"'%(name,))
self.level+=1

defendElement(self,name):
self.level=1
self.show_with_level('endelementname:
"%s"'%(name,))

defcharacters(self,content):
content=content.strip()
ifcontent:
self.show_with_level('characters:"%s"'%
(content,))

Page242
APythonBook

deftest(infilename):
parser=make_parser()
handler=TestHandler()
parser.setContentHandler(handler)
parser.parse(infilename)

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]
iflen(args)!=1:
usage()
infilename=args[0]
test(infilename)

if__name__=='__main__':
main()
2. Theminidommodulecontainsaparse()functionthatenablesustoreadan
XMLdocumentandcreateaDOMtree:
#!/usr/bin/envpython

"""ProcessanXMLdocumentwithminidom.

Showthedocumenttree.

Usage:
pythonminidom_walk.py[options]infilename
"""

importsys
fromxml.domimportminidom

defshow_tree(doc):
root=doc.documentElement
show_node(root,0)

defshow_node(node,level):
count=0
ifnode.nodeType==minidom.Node.ELEMENT_NODE:
show_level(level)
print'tag:%s'%(node.nodeName,)
forkeyinnode.attributes.keys():
attr=node.attributes.get(key)
show_level(level+1)
print'attributename:%svalue:"%s"'%
(attr.name,
attr.value,)
if(len(node.childNodes)==1and
node.childNodes[0].nodeType==

Page243
APythonBook

minidom.Node.TEXT_NODE):
show_level(level+1)
print'data:"%s"'%
(node.childNodes[0].data,)
forchildinnode.childNodes:
count+=1
show_node(child,level+1)
returncount

defshow_level(level):
forxinrange(level):
print'',

deftest():
args=sys.argv[1:]
iflen(args)!=1:
print__doc__
sys.exit(1)
docname=args[0]
doc=minidom.parse(docname)
show_tree(doc)

if__name__=='__main__':
#importpdb;pdb.set_trace()
test()
3. ElementTreeenablesustoparseanXMLdocumentandcreateaDOMtree:
#!/usr/bin/envpython

"""ProcessanXMLdocumentwithelementtree.

Showthedocumenttree.

Usage:
pythonelementtree_walk.py[options]infilename
"""

importsys
fromxml.etreeimportElementTreeasetree

defshow_tree(doc):
root=doc.getroot()
show_node(root,0)

defshow_node(node,level):
show_level(level)
print'tag:%s'%(node.tag,)
forkey,valueinnode.attrib.iteritems():
show_level(level+1)
print'attributename:%svalue:"%s"'%
(key,value,)
ifnode.text:
text=node.text.strip()

Page244
APythonBook

show_level(level+1)
print'text:"%s"'%(node.text,)
ifnode.tail:
tail=node.tail.strip()
show_level(level+1)
print'tail:"%s"'%(tail,)
forchildinnode.getchildren():
show_node(child,level+1)

defshow_level(level):
forxinrange(level):
print'',

deftest():
args=sys.argv[1:]
iflen(args)!=1:
print__doc__
sys.exit(1)
docname=args[0]
doc=etree.parse(docname)
show_tree(doc)

if__name__=='__main__':
#importpdb;pdb.set_trace()
test()
4. lxmlenablesustoparseanXMLdocumentandcreateaDOMtree.Infact,since
lxmlattemptstomimictheElementTreeAPI,ourcodeisverysimilartothatin
thesolutiontotheElementTreeexercise:
#!/usr/bin/envpython

"""ProcessanXMLdocumentwithelementtree.

Showthedocumenttree.

Usage:
pythonlxml_walk.py[options]infilename
"""

#
#Imports:
importsys
fromlxmlimportetree

defshow_tree(doc):
root=doc.getroot()
show_node(root,0)

defshow_node(node,level):
show_level(level)
print'tag:%s'%(node.tag,)
forkey,valueinnode.attrib.iteritems():

Page245
APythonBook

show_level(level+1)
print'attributename:%svalue:"%s"'%
(key,value,)
ifnode.text:
text=node.text.strip()
show_level(level+1)
print'text:"%s"'%(node.text,)
ifnode.tail:
tail=node.tail.strip()
show_level(level+1)
print'tail:"%s"'%(tail,)
forchildinnode.getchildren():
show_node(child,level+1)

defshow_level(level):
forxinrange(level):
print'',

deftest():
args=sys.argv[1:]
iflen(args)!=1:
print__doc__
sys.exit(1)
docname=args[0]
doc=etree.parse(docname)
show_tree(doc)

if__name__=='__main__':
#importpdb;pdb.set_trace()
test()
5. WecanmodifytheDOMtreeandwriteitouttoanewfile:
#!/usr/bin/envpython

"""ProcessanXMLdocumentwithelementtree.

Showthedocumenttree.
Modifythedocumenttreeandthenshowitagain.
WritethemodifiedXMLtreetoanewfile.

Usage:
pythonelementtree_walk.py[options]infilename
outfilename
Options:
h,helpDisplaythishelpmessage.
Example:
pythonelementtree_walk.pymyxmldoc.xml
myotherxmldoc.xml
"""

importsys
importos
importgetopt

Page246
APythonBook

importtime

#UseElementTree.
fromxml.etreeimportElementTreeasetree
#OruncommenttouseLxml.
#fromlxmlimportetree

defshow_tree(doc):
root=doc.getroot()
show_node(root,0)

defshow_node(node,level):
show_level(level)
print'tag:%s'%(node.tag,)
forkey,valueinnode.attrib.iteritems():
show_level(level+1)
print'attributename:%svalue:"%s"'%
(key,value,)
ifnode.text:
text=node.text.strip()
show_level(level+1)
print'text:"%s"'%(node.text,)
ifnode.tail:
tail=node.tail.strip()
show_level(level+1)
print'tail:"%s"'%(tail,)
forchildinnode.getchildren():
show_node(child,level+1)

defshow_level(level):
forxinrange(level):
print'',

defmodify_tree(doc,tag,attrname,attrvalue):
root=doc.getroot()
modify_node(root,tag,attrname,attrvalue)

defmodify_node(node,tag,attrname,attrvalue):
ifnode.tag==tag:
node.attrib[attrname]=attrvalue
forchildinnode.getchildren():
modify_node(child,tag,attrname,attrvalue)

deftest(indocname,outdocname):
doc=etree.parse(indocname)
show_tree(doc)
print''*50
date=time.ctime()
modify_tree(doc,'person','date',date)
show_tree(doc)
write_output=False
ifos.path.exists(outdocname):
response=raw_input('Outputfile(%s)exists.

Page247
APythonBook

Overwrite?(y/n):'%
outdocname)
ifresponse=='y':
write_output=True
else:
write_output=True
ifwrite_output:
doc.write(outdocname)
print'WrotemodifiedXMLtreeto%s'%
outdocname
else:
print'Didnotwriteoutputfile.'

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]
try:
opts,args=getopt.getopt(args,'h',['help',
])
except:
usage()
foropt,valinopts:
ifoptin('h','help'):
usage()
iflen(args)!=2:
usage()
indocname=args[0]
outdocname=args[1]
test(indocname,outdocname)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Notes:
TheabovesolutioncontainsanimportstatementforElementTreeand
anotherforlxml.Theoneforlxmliscommentedout,butyoucouldchange
thatifyouwishtouselxmlinsteadofElementTree.Thissolutionwillwork
thesamewaywitheitherElementTreeorlxml.
6. WhenweparseandXMLdocumentwithlxml,eachelement(node)hasan
xpath()method.
#test_xpath.py

fromlxmlimportetree

deftest():
doc=etree.parse('people.xml')
root=doc.getroot()

Page248
APythonBook

printroot.xpath("//name/text()")
printroot.xpath("//@id")

test()
And,whenweruntheabovecode,hereiswhatwesee:
$pythontest_xpath.py
['Alberta','Bernardo','Charlie']
['1','2','3']
FormoreonXPathsee:XMLPathLanguage(XPath)
http://www.w3.org/TR/xpath

3.9.2Relationaldatabaseaccess
YoucanfindinformationaboutdatabaseprogramminginPythonhere:Database
Programminghttp://wiki.python.org/moin/DatabaseProgramming/.
FordatabaseaccessweusethePythonDatabaseAPI.Youcanfindinformationaboutit
here:PythonDatabaseAPISpecificationv2.0
http://www.python.org/dev/peps/pep0249/.
TousethedatabaseAPIwedothefollowing:
1. Usethedatabaseinterfacemoduletocreateaconnectionobject.
2. Usetheconnectionobjecttocreateacursorobject.
3. UsethecursorobjecttoexecuteanSQLquery.
4. Retrieverowsfromthecursorobject,ifneeded.
5. Optionally,commitresultstothedatabase.
6. Closetheconnectionobject.
Ourexamplesusethegadflydatabase,whichiswritteninPython.Ifyouwanttouse
gadfly,youcanfindithere:http://gadfly.sourceforge.net/.gadflyisareasonable
choiceifyouwantaneasytousedatabaseonyourlocalmachine.
Anotherreasonablechoiceforalocaldatabaseissqlite3,whichisinthePython
standardlibrary.HereisadescriptivequotefromtheSQLiteWebsite:
"SQLiteisasoftwarelibrarythatimplementsaselfcontained,
serverless,zeroconfiguration,transactionalSQLdatabaseengine.
SQLiteisthemostwidelydeployedSQLdatabaseengineintheworld.
ThesourcecodeforSQLiteisinthepublicdomain."
Youcanlearnaboutithere:
sqlite3DBAPI2.0interfaceforSQLitedatabases
http://docs.python.org/library/sqlite3.html
SQLitehomepagehttp://www.sqlite.org/

Page249
APythonBook

Thepysqlitewebpagehttp://oss.itsystementwicklung.de/trac/pysqlite/
Ifyouwantorneedtouseanother,enterpriseclassdatabase,forexamplePostgreSQL,
MySQL,Oracle,etc.,youwillneedaninterfacemoduleforyourspecificdatabase.You
canfindinformationaboutdatabaseinterfacemoduleshere:Databaseinterfaces
http://wiki.python.org/moin/DatabaseInterfaces
Excercises:
1. Writeascriptthatretrievesalltherowsinatableandprintseachrow.
2. Writeascriptthatretrievesalltherowsinatable,thenusesthecursorasan
iteratortoprinteachrow.
3. Writeascriptthatusesthecursor'sdescriptionattributetoprintoutthename
andvalueofeachfieldineachrow.
4. Writeascriptthatperformsseveraloftheabovetasks,butusessqlite3instead
ofgadfly.
Solutions:
1. WecanexecuteaSQLqueryandthenretrievealltherowswith
fetchall():
importgadfly

deftest():
connection=gadfly.connect("dbtest1",
"plantsdbdir")
cur=connection.cursor()
cur.execute('select*fromplantsdborderby
p_name')
rows=cur.fetchall()
forrowinrows:
print'2.row:',row
connection.close()

test()
2. Thecursoritselfisaniterator.Ititeratesovertherowsreturnedbyaquery.So,
weexecuteaSQLqueryandthenweusethecursorinafor:statement:
importgadfly

deftest():
connection=gadfly.connect("dbtest1",
"plantsdbdir")
cur=connection.cursor()
cur.execute('select*fromplantsdborderby
p_name')
forrowincur:
printrow
connection.close()

Page250
APythonBook

test()
3. Thedescriptionattributeinthecursorisacontainerthathasanitemdescribing
eachfield:
importgadfly

deftest():
cur.execute('select*fromplantsdborderby
p_name')
forfieldincur.description:
print'field:',field
rows=cur.fetchall()
forrowinrows:
foridx,fieldinenumerate(row):
content='%s:"%s"'%
(cur.description[idx][0],field,)
printcontent,
print
connection.close()

test()
Notes:
ThecommaattheendoftheprintstatementtellsPythonnottoprinta
newline.
Thecur.descriptionisasequencecontaininganitemforeachfield.
Afterthequery,wecanextractadescriptionofeachfield.
4. Thesolutionsusingsqlite3areverysimilartothoseusinggadfly.For
informationonsqlite3,see:sqlite3DBAPI2.0interfaceforSQLite
databaseshttp://docs.python.org/library/sqlite3.html#modulesqlite3.
#!/usr/bin/envpython

"""
Performoperationsonsqlite3(plants)database.

Usage:
pythonpy_db_api.pycommand[arg1,...]
Commands:
createcreatenewdatabase.
showshowcontentsofdatabase.
addaddrowtodatabase.Requires3args(name,
descrip,rating).
deleteremoverowfromdatabase.Requires1arg
(name).
Examples:
pythontest1.pycreate
pythontest1.pyshow
pythontest1.pyaddcrenshaw"Themostsucculent
melon"10
pythontest1.pydeletelemon

Page251
APythonBook

"""

importsys
importsqlite3

Values=[
('lemon','brightandyellow','7'),
('peach','succulent','9'),
('banana','smoothandcreamy','8'),
('nectarine','tangyandtasty','9'),
('orange','sweetandtangy','8'),
]

Field_defs=[
'p_namevarchar',
'p_descripvarchar',
#'p_ratinginteger',
'p_ratingvarchar',
]

defcreatedb():
connection=sqlite3.connect('sqlite3plantsdb')
cursor=connection.cursor()
q1="createtableplantsdb(%s)"%(',
'.join(Field_defs))
print'createq1:%s'%q1
cursor.execute(q1)
q1="createindexindex1onplantsdb(p_name)"
cursor.execute(q1)
q1="insertintoplantsdb(p_name,p_descrip,
p_rating)values('%s','%s',%s)"
forspecinValues:
q2=q1%spec
print'q2:"%s"'%q2
cursor.execute(q2)
connection.commit()
showdb1(cursor)
connection.close()

defshowdb():
connection,cursor=opendb()
showdb1(cursor)
connection.close()

defshowdb1(cursor):
cursor.execute("select*fromplantsdborderby
p_name")
hr()
description=cursor.description

Page252
APythonBook

printdescription
print'description:'
forrowdescriptionindescription:
print'%s'%(rowdescription,)
hr()
rows=cursor.fetchall()
printrows
print'rows:'
forrowinrows:
print'%s'%(row,)
hr()
print'content:'
forrowinrows:
descrip=row[1]
name=row[0]
rating='%s'%row[2]
print'%s%s%s'%(
name.ljust(12),descrip.ljust(30),
rating.rjust(4),)

defaddtodb(name,descrip,rating):
try:
rating=int(rating)
exceptValueError,exp:
print'Error:ratingmustbeinteger.'
return
connection,cursor=opendb()
cursor.execute("select*fromplantsdbwherep_name
='%s'"%name)
rows=cursor.fetchall()
iflen(rows)>0:
ql="updateplantsdbsetp_descrip='%s',
p_rating='%s'wherep_name='%s'"%(
descrip,rating,name,)
print'ql:',ql
cursor.execute(ql)
connection.commit()
print'Updated'
else:
cursor.execute("insertintoplantsdbvalues
('%s','%s','%s')"%(
name,descrip,rating))
connection.commit()
print'Added'
showdb1(cursor)
connection.close()

defdeletefromdb(name):
connection,cursor=opendb()
cursor.execute("select*fromplantsdbwherep_name
='%s'"%name)

Page253
APythonBook

rows=cursor.fetchall()
iflen(rows)>0:
cursor.execute("deletefromplantsdbwhere
p_name='%s'"%name)
connection.commit()
print'Plant(%s)deleted.'%name
else:
print'Plant(%s)doesnotexist.'%name
showdb1(cursor)
connection.close()

defopendb():
connection=sqlite3.connect("sqlite3plantsdb")
cursor=connection.cursor()
returnconnection,cursor

defhr():
print''*60

defusage():
print__doc__
sys.exit(1)

defmain():
args=sys.argv[1:]
iflen(args)<1:
usage()
cmd=args[0]
ifcmd=='create':
iflen(args)!=1:
usage()
createdb()
elifcmd=='show':
iflen(args)!=1:
usage()
showdb()
elifcmd=='add':
iflen(args)<4:
usage()
name=args[1]
descrip=args[2]
rating=args[3]
addtodb(name,descrip,rating)
elifcmd=='delete':
iflen(args)<2:
usage()
name=args[1]
deletefromdb(name)
else:

Page254
APythonBook

usage()

if__name__=='__main__':
main()

3.9.3CSVcommaseparatedvaluefiles
ThereissupportforparsingandgeneratingCSVfilesinthePythonstandardlibrary.See:
csvCSVFileReadingandWriting
http://docs.python.org/library/csv.html#modulecsv.
Exercises:
1. ReadaCSVfileandprintthefieldsincolumns.Hereisasamplefiletouseas
input:
#namedescriptionrating
Lemon,Brightyellowandtart,5
Eggplant,Purpleandshiny,6
Tangerine,Succulent,8
Solutions:
1. UsetheCSVmoduleinthePythonstandardlibrarytoreadaCSVfile:
"""
ReadaCSVfileandprintthecontentsincolumns.
"""

importcsv

deftest(infilename):
infile=open(infilename)
reader=csv.reader(infile)
print'===============
======'
print'NameDescription
Rating'
print'===============
======'
forfieldsinreader:
iflen(fields)==3:
line='%s%s%s'%(fields[0].ljust(20),
fields[1].ljust(40),
fields[2].ljust(4))
printline
infile.close()

defmain():
infilename='csv_report.csv'
test(infilename)

Page255
APythonBook

if__name__=='__main__':
main()
And,whenrun,hereiswhatitdisplays:
===============
======
NameDescription
Rating
===============
======
LemonBrightyellowandtart
5
EggplantPurpleandshiny
6
TangerineSucculent
8

3.9.4YAMLandPyYAML
YAMLisastructuredtextdatarepresentationformat.Itusesindentationtoindicate
nesting.HereisadescriptionfromtheYAMLWebsite:
"YAML:YAMLAin'tMarkupLanguage
"WhatItIs:YAMLisahumanfriendlydataserializationstandardfor
allprogramminglanguages."
YoucanlearnmoreaboutYAMLandPyYAMLhere:
TheOfficialYAMLWebSitehttp://yaml.org/
PyYAML.orgthehomeofvariousYAMLimplementationsforPython
http://pyyaml.org/
TheYAML1.2specificationhttp://yaml.org/spec/1.2/
Exercises:
1. ReadthefollowingsampleYAMLdocument.Printouttheinformationinit:
american:
BostonRedSox
DetroitTigers
NewYorkYankees
national:
NewYorkMets
ChicagoCubs
AtlantaBraves
2. LoadtheYAMLdatausedinthepreviousexercise,thenmakeamodification(for
example,add"SanFranciscoGiants"totheNationalLeague),thendumpthe
modifieddatatoanewfile.
Solutions:

Page256
APythonBook

1. PrintingoutinformationfromYAMLisas"simple"asprintingoutaPythondata
structure.Inthissolution,weusetheprettyprinterfromthePythonstandard
library:
importyaml
importpprint

deftest():
infile=open('test1.yaml')
data=yaml.load(infile)
infile.close()
pprint.pprint(data)

test()
Wecould,alternatively,readinandthen"load"fromastring:
importyaml
importpprint

deftest():
infile=open('test1.yaml')
data_str=infile.read()
infile.close()
data=yaml.load(data_str)
pprint.pprint(data)

test()
2. TheYAMLdump()functionenablesustodumpdatatoafile:
importyaml
importpprint

deftest():
infile=open('test1.yaml','r')
data=yaml.load(infile)
infile.close()
data['national'].append('SanFranciscoGiants')
outfile=open('test1_new.yaml','w')
yaml.dump(data,outfile)
outfile.close()

test()
Notes:
IfwewanttoproducethestandardYAML"block"styleratherthanthe"flow"
format,thenwecoulduse:
yaml.dump(data,outfile,default_flow_style=False)

Page257
APythonBook

3.9.5Json
HereisaquotefromWikipediaentryforJson:
"JSON(pronounced'Jason'),shortforJavaScriptObjectNotation,isa
lightweightcomputerdatainterchangeformat.Itisatextbased,
humanreadableformatforrepresentingsimpledatastructuresand
associativearrays(calledobjects)."
TheJsontextrepresentationlooksverysimilartoPythonliteralrepresentationofPython
builtindatatypes(forexample,lists,dictionaries,numbers,andstrings).
LearnmoreaboutJsonandPythonsupportforJsonhere:
IntroducingJSONhttp://json.org/
JsonatWikipediahttp://en.wikipedia.org/wiki/Json
pythonjsonhttp://pypi.python.org/pypi/pythonjson
simplejsonhttp://pypi.python.org/pypi/simplejson
Excercises:
1. WriteaPythonscript,usingyourfavoritePythonJsonimplementation(for
examplepythonjsonorsimplejson),thatdumpsthefollowingdata
structuretoafile:
Data={
'rockandroll':
['Elis','TheBeatles','TheRollingStones',],
'country':
['WillieNelson','HankWilliams',]
}
2. WriteaPythonscriptthatreadsJsondatafromafileandloadsitintoPythondata
structures.
Solutions:
1. ThissolutionusessimplejsontostoreaPythondatastructureencodedasJson
inafile:
importsimplejsonasjson

Data={
'rockandroll':
['Elis','TheBeatles','TheRollingStones',],
'country':
['WillieNelson','HankWilliams',]
}

deftest():
fout=open('tmpdata.json','w')
content=json.dumps(Data)
fout.write(content)

Page258
APythonBook

fout.write('\n')
fout.close()

test()
2. Wecanreadthefileintoastring,thendecodeitfromJson:
importsimplejsonasjson

deftest():
fin=open('tmpdata.json','r')
content=fin.read()
fin.close()
data=json.loads(content)
printdata

test()
Notethatyoumaywantsomecontroloverindentation,characterencoding,etc.For
simplejson,youcanlearnaboutthathere:simplejsonJSONencoderanddecoder
http://simplejson.googlecode.com/svn/tags/simplejson2.0.1/docs/index.html.

Page259
APythonBook

4Part4GeneratingPythonBindingsforXML
ThissectiondiscussesaspecificPythontool,specificallyaPythoncodegeneratorthat
generatesPythonbindingsforXMLfiles.
Thus,thissectionwillhelpyouinthefollowingways:
1. Itwillhelpyoulearntouseaspecifictool,namelygenerateDS.py,that
generatesPythoncodetobeusedtoprocessXMLinstancedocumentsofa
particulardocumenttype.
2. Itwillhelpyougainmoreexperiencewithreading,modifyingandusingPython
code.

4.1Introduction
Additionalinformation:
Ifyouplantoworkthroughthistutorial,youmayfindithelpfultolookatthe
samplecodethataccompaniesthistutorial.Youcanfinditinthedistribution
under:
tutorial/
tutorial/Code/
YoucanfindadditionalinformationaboutgenerateDS.pyhere:
http://http://www.davekuhlman.org/#generatedspy
Thatdocumentationisalsoincludedinthedistribution.
generateDS.pygeneratesPythondatastructures(forexample,classdefinitions)from
anXMLschemadocument.ThesedatastructuresrepresenttheelementsinanXML
documentdescribedbytheXMLschema.generateDS.pyalsogeneratesparsersthat
loadanXMLdocumentintothosedatastructures.Inaddition,aseparatefilecontaining
subclasses(stubs)isoptionallygenerated.Theusercanaddmethodstothesubclassesin
ordertoprocessthecontentsofanXMLdocument.
ThegeneratedPythoncodecontains:
AclassdefinitionforeachelementdefinedintheXMLschemadocument.
Amainanddriverfunctionthatcanbeusedtotestthegeneratedcode.
AparserthatwillreadanXMLdocumentwhichsatisfiestheXMLschemafrom
whichtheparserwasgenerated.Theparsercreatesandpopulatesatreestructure
ofinstancesofthegeneratedPythonclasses.
MethodsineachclasstoexporttheinstancebackouttoXML(methodexport)
andtoexporttheinstancetoaliteralrepresentingthePythondatastructure

Page260
APythonBook

(methodexportLiteral).
Eachgeneratedclasscontainsthefollowing:
Aconstructormethod(__init__),withmembervariableinitializers.
Methodswithnamesget_xyzandset_xyzforeachmembervariable"xyz"
or,ifthemembervariableisdefinedwithmaxOccurs="unbounded",
methodswithnamesget_xyz,set_xyz,add_xyz,andinsert_xyz.
(Note:Ifyouusetheuseoldgettersetter,thenyouwillget
methodswithnameslikegetXyzandsetXyz.)
Abuildmethodthatcanbeusedtopopulateaninstanceoftheclassfroma
nodeinanElementTreeorLxmltree.
Anexportmethodthatwillwritetheinstance(andanynestedsubinstances)to
afileobjectasXMLtext.
AnexportLiteralmethodthatwillwritetheinstance(andanynested
subinstances)toafileobjectasPythonliterals(text).
Thegeneratedsubclassfilecontainsone(sub)classdefinitionforeachdata
representationclass.Ifthesubclassfileisused,thentheparsercreatesinstancesofthe
subclasses(insteadofcreatinginstancesofthesuperclasses).Thisenablestheuserto
extendthesubclasseswith"treewalk"methods,forexample,thatprocessthecontentsof
theXMLfile.Theusercanalsogenerateandextendmultiplesubclassfileswhichusea
single,commonsuperclassfile,thusimplementinganumberofdifferentprocessesonthe
sameXMLdocumenttype.
ThisdocumentintroducestheusertogenerateDS.pyandwalkstheuserthrough
severalexamplesthatshowhowtogeneratePythoncodeandhowtousethatgenerated
code.

4.2Generatingthecode
Note:Thesamplefilesusedbelowareunderthetutorial/Code/directory.
Usethefollowingtogethelp:
$generateDS.pyhelp
I'llassumethatgenerateDS.pyisinadirectoryonyourpath.Ifnot,youshoulddo
whateverisnecessarytomakeitaccessibleandexecutable.
HereisasimpleXMLschemadocument:
And,hereishowyoumightgenerateclassesandsubclassesthatprovidedatabindings(a
PythonAPI)forthedefinitionsinthatschema:
$generateDS.pyopeople_api.pyspeople_sub.pypeople.xsd

Page261
APythonBook

And,ifyouwanttoautomaticallyoverwritethegeneratedPythonfiles,usethef
commandlineflagtoforceoverwritewithoutasking:
$generateDS.pyfopeople_api.pyspeople_sub.pypeople.xsd
And,tohardwirethesubclassfilesothatitimportstheAPImodule,usethesuper
commandlinefile.Example:
$generateDS.pyopeople_api.pypeople.xsd
$generateDS.pyspeople_appl1.pysuper=people_apipeople.xsd
Or,dobothatthesametimewiththefollowing:
$generateDS.pyopeople_api.pyspeople_appl1.py
super=people_apipeople.xsd
And,foryoursecondapplication:
$generateDS.pyspeople_appl2.pysuper=people_apipeople.xsd
Ifyoutakealookinsidethesetwo"application"files,youwillseeandimportstatement
likethefollowing:
import???assupermod
Ifyouhadnotusedthesupercommandlineoptionwhengeneratingthe
"application"files,thenyoucouldmodifythatstatementyourself.Thesuper
commandlineoptiondoesthisforyou.
YoucanalsousetheThegraphicalfrontendtoconfigureoptionsandsavethemina
sessionfile,thenusethatsessionfilewithgenerateDS.pytospecifyyourcommand
lineoptions.Forexample:
$generateDS.pysession=test01.session
Youcantestthegeneratedcodebyrunningit.Trysomethinglikethefollowing:
$pythonpeople_api.pypeople.xml
or:
$pythonpeople_appl1.pypeople.xml
Whydoesthiswork?WhycanwerunthegeneratedcodeasaPythonscript?Ifyou
lookatthegeneratedcode,downneartheendofthefileyou'llfindamain()function
thatcallsafunctionnamedparse().Theparsefunctiondoesthefollowing:
1. ParsesyourXMLinstancedocument.
2. UsesyourgeneratedAPItobuildatreeofinstancesofthegeneratedclasses.
3. Usestheexport()methodsinthattreeofinstancestoprintout(export)XML

Page262
APythonBook

thatrepresentsyourgeneratedtreeofinstances.
Exceptforsomeindentation(ignorablewhitespace),thisexportedXMLshouldbethe
sameastheoriginalXMLdocument.So,thatgivesyouareasonablythoroughtestof
yourgeneratedcode.
And,thecodeinthatparse()functiongivesyouahintofhowyoumightbuildyour
ownapplicationspecificcodethatusesthegeneratedAPI(thosegeneratedPython
classes).

4.3UsingthegeneratedcodetoparseandexportanXMLdocument
Nowthatyouhavegeneratedcodeforyourdatamodel,youcantestitbyrunningitasan
application.SupposethatyouhaveanXMLinstancedocumentpeople1.xmlthat
satisfiesyourschema.Thenyoucanparsethatinstancedocumentandexportit(printit
out)withsomethinglikethefollowing:
$pythonpeople_api.pypeople1.xml
And,ifyouhaveusedthesupercommandlineoption,asIhaveabove,toconnect
yoursubclassfilewiththesuperclass(API)file,thenyoucouldusethefollowingtodo
thesamething:
$pythonpeople_appl1.pypeople1.xml

4.4Somecommandlineoptionsyoumightwanttoknow
Youmaywanttomerelyskimthissectionfornow,thenlaterreferbacktoitwhensome
oftheseoptionsareareusedlaterinthistutorial.Also,rememberthatyoucanget
informationaboutmorecommandlineoptionsusedbygenerateDS.pybytyping:
$pythongenerateDS.pyhelp
andbyreadingthedocumentathttp://www.davekuhlman.org/#generatedspy
o
Generatethesuperclassmodule.Thisisthemodulethatcontainstheimplementation
ofeachclassforeachelementtype.So,youcanthinkofthisastheimplementationof
the"databindings"ortheAPIforXMLdocumentsofthetypedefinedbyyourXML
schema.
s
Generatethesubclassmodule.Youmightormightnotneedthese.Ifyouintendto
writesomeapplicationspecificcode,youmightwanttoconsiderstartingwiththese
skeletonclassesandaddyourapplicationcodethere.

Page263
APythonBook

super
Thisoptioninsertsthenameofthesuperclassmoduleintoanimportstatementin
thesubclassfile(generatedwith"s").Ifyouknowthenameofthesuperclassfilein
advance,youcanusethisoptiontoenablethesubclassfiletoimportthesuperclass
moduleautomatically.Ifyoudonotusethisoption,youwillneedtoeditthesubclass
modulewithyourtexteditorandmodifytheimportstatementnearthetop.
rootelement="elementname"
UsethisoptiontotellgenerateDS.pywhichoftheelementsdefinedinyourXM
schemaisthe"root"element.Therootelementistheoutermost(toplevel)element
inXMLinstancedocumentsdefinedbythisschema.Ineffect,thistellsyour
generatedmoduleswhichelementtouseastherootelementwhenparsingand
exportingdocuments.
generateDS.pyattemptstoguesstherootelement,usuallythefirstelement
definedinyourXMLschema.Usethisoptionwhenthatdefaultisnotwhatyouwant.
memberspecs=list|dict
Supposeyouwanttowritesomecodethatcanbegenericallyappliedtoelementsof
differentkinds(elementtypesimplementedbyseveraldifferentgeneratedclasses.If
so,itmightbehelpfultohavealistordictionaryspecifyinginformationabouteach
memberdataitemineachclass.Thisoptiondoesthatbygeneratingalistora
dictionary(withthememberdataitemnameaskey)ineachgeneratedclass.Takea
lookatthegeneratedcodetolearnaboutit.Inparticular,lookatthegeneratedlistor
dictionaryinaclassforanyelementtypeandalsoatthedefinitionoftheclass
_MemberSpecgeneratednearthetopoftheAPImodule.
version
AskgenerateDS.pytotellyouwhatversionitis.Thisishelpfulwhenyouwant
toaskaboutaproblem,forexampleatthegeneratedsusersemaillist
(https://lists.sourceforge.net/lists/listinfo/generatedsusers),andwanttospecifywhich
versionyouareusing.

4.5Thegraphicalfrontend
ThereisalsoapointandclickwaytorungenerateDS.Itenablesyoutospecifythe
optionsneededbygenerateDS.pythroughagraphicalinterface,thentorun
generateDS.pywiththoseoptions.Italso
Youcanrunit,ifyouhaveinstalledgenerateDS,bytypingthefollowingata
commandline:

Page264
APythonBook

$generateds_gui.py
Afterconfiguringoptions,youcansavethoseoptionsina"session"file,whichcanbe
loadedlater.LookundertheFilemenuforsaveandloadcommandsandalsoconsider
usingthe"session"commandlineoption.
AlsonotethatgenerateDS.pyitselfsupportsa"session"commandlineoptionthat
enablesyoutorungenerateDS.pywiththeoptionsthatyouspecifiedandsavedwith
thegraphicalfrontend.

4.6Addingapplicationspecificbehavior
generateDS.pygeneratesPythoncodewhich,withnomodification,willparseand
thenexportanXMLdocumentdefinedbyyourschema.However,youarelikelytowant
togobeyondthat.Inmanysituationsyouwillwanttoconstructacustomapplicationthat
processesyourXMLdocumentsusingthegeneratedcode.

4.6.1Implementingcustomsubclasses
Onestrategyistogenerateasubclassfileandtoaddyourapplicationspecificcodeto
that.Generatethesubclassfilewiththe"s"commandlineflag:
$generateDS.pysmyapp.pypeople.xsd
Nowaddsomeapplicationspecificcodetomyapp.py,forexample,ifyouareusingthe
included"people"samplefiles:
classpeopleTypeSub(supermod.people):
def__init__(self,comments=None,person=None,programmer=None,
python_programmer=None,java_programmer=None):
supermod.people.__init__(self,comments,person,programmer,
python_programmer,
java_programmer)
deffancyexport(self,outfile):
outfile.write('Startingfancyexport')
forpersoninself.get_person():
person.fancyexport(outfile)
supermod.people.subclass=peopleTypeSub
#endclasspeopleTypeSub

classpersonTypeSub(supermod.person):
def__init__(self,vegetable=None,fruit=None,ratio=None,
id=None,value=None,
name=None,interest=None,category=None,agent=None,
promoter=None,
description=None):
supermod.person.__init__(self,vegetable,fruit,ratio,id,
value,

Page265
APythonBook

name,interest,category,agent,promoter,description)
deffancyexport(self,outfile):
outfile.write('Fancypersonexportname:%s'%
self.get_name(),)
supermod.person.subclass=personTypeSub
#endclasspersonTypeSub

4.6.2Usingthegenerated"API"fromyourapplication
Inthisapproachyoumightdothingslikethefollowing:
importyourgeneratedclasses.
Createinstancesofthoseclasses.
Linkthoseinstances,forexampleput"children"insideofaparent,oraddoneor
moreinstancestoaparentthatcancontainalistofobjects(think"maxOccurs"
greaterthan1inyourschema)
GettoknowthegeneratedexportAPIbyinspectingthegeneratedcodeinthesuperclass
file.That'sthefilegeneratedwiththe"o"commandlineflag.
Whattolookfor:
Lookattheargumentstotheconstructor(__init__)tolearnhowtoinitialize
aninstance.
Lookatthe"getters"and"setters"(methodsnamegetxxxandsetxxx,tolearn
howtomodifymembervariables.
Lookforamethodnamedaddxxxformembersthatarelists.Thesecorrespond
tomembersdefinedwithmaxOccurs="n",wheren>1.
Lookatthebuildmethods:build,buildChildren,and
buildAttributes.Thesewillgiveyouinformationabouthowtoconstruct
eachofthemembersofagivenelement/class.
Now,youcanimportyourgeneratedAPImodule,anduseittoconstructandmanipulate
objects.Hereisanexampleusingcodegeneratedwiththe"people"schema:
importsys
importpeople_apiasapi

deftest(names):
people=api.peopleType()
forcount,nameinenumerate(names):
id='%d'%(count+1,)
person=api.personType(name=name,id=id)
people.add_person(person)
people.export(sys.stdout,0)

test(['albert','betsy','charlie'])
Runthisandyoumightseesomethinglikethefollowing:

Page266
APythonBook

$pythontmp.py
<people>
<personid="1">
<name>albert</name>
</person>
<personid="2">
<name>betsy</name>
</person>
<personid="3">
<name>charlie</name>
</person>
</people>

4.6.3Acombinedapproach
Note:Youcanfindexamplesofthecodeinthissectioninthesefiles:

tutorial/Code/upcase_names.py
tutorial/Code/upcase_names_appl.py
Herearetherelevant,modifiedsubclasses(upcase_names_appl.py):
importpeople_apiassupermod

classpeopleTypeSub(supermod.peopleType):
def__init__(self,comments=None,person=None,
specialperson=None,programmer=None,python_programmer=None,
java_programmer=None):
super(peopleTypeSub,self).__init__(comments,person,
specialperson,programmer,python_programmer,java_programmer,)
defupcase_names(self):
forpersoninself.get_person():
person.upcase_names()
supermod.peopleType.subclass=peopleTypeSub
#endclasspeopleTypeSub

classpersonTypeSub(supermod.personType):
def__init__(self,vegetable=None,fruit=None,ratio=None,
id=None,value=None,name=None,interest=None,category=None,
agent=None,promoter=None,description=None,range_=None,
extensiontype_=None):
super(personTypeSub,self).__init__(vegetable,fruit,ratio,
id,value,name,interest,category,agent,promoter,description,
range_,extensiontype_,)
defupcase_names(self):
self.set_name(self.get_name().upper())
supermod.personType.subclass=personTypeSub
#endclasspersonTypeSub
Notes:
Theseclassesweregeneratedwiththe"s"commandlineoption.Theyare

Page267
APythonBook

subclassesofclassesinthemodulepeople_api,whichwasgeneratedwiththe
"o"commandlineoption.
Theonlymodificationtotheskeletonsubclassesistheadditionofthetwo
methodsnamedupcase_names().
InthesubclasspeopleTypeSub,themethodupcase_names()merelywalk
overitsimmediatechildren.
InthesubclasspersonTypeSub,themethodupcase_names()justconverts
thevalueofits"name"membertouppercase.
Hereistheapplicationitself(upcase_names.py):
importsys
importupcase_names_applasappl

defcreate_people(names):
people=appl.peopleTypeSub()
forcount,nameinenumerate(names):
id='%d'%(count+1,)
person=appl.personTypeSub(name=name,id=id)
people.add_person(person)
returnpeople

defmain():
names=['albert','betsy','charlie']
people=create_people(names)
print'Before:'
people.export(sys.stdout,1)
people.upcase_names()
print''*50
print'After:'
people.export(sys.stdout,1)

main()
Notes:
Thecreate_people()functioncreatesapeopleTypeSubinstancewith
severalpersonTypeSubinstancesinsideit.
And,whenyourunthisminiapplication,hereiswhatyoumightsee:
$pythonupcase_names.py
Before:
<people>
<personid="1">
<name>albert</name>
</person>
<personid="2">
<name>betsy</name>
</person>
<personid="3">
<name>charlie</name>

Page268
APythonBook

</person>
</people>

After:
<people>
<personid="1">
<name>ALBERT</name>
</person>
<personid="2">
<name>BETSY</name>
</person>
<personid="3">
<name>CHARLIE</name>
</person>
</people>

4.7Specialsituationsanduses

4.7.1Generic,typeindependentprocessing
Therearetimeswhenyouwouldliketoimplementafunctionormethodthatcanperform
operationsonavarietyofmembersandthatneedstypeinformationabouteachmember.
Youcangethelpwiththisbygeneratingyourcodewiththe"memberspecs"command
lineoption.Whenyouusethisoption,generateDS.pyaddalistoradictionary
containinganitemforeachmember.Ifyouwantalist,thenuse"memberspecs=list",
andifyouwantadictionary,withmembernamesaskeys,thenuse
"memberspecs=dict".
HereisanexampleInthisexample,wewalkthedocument/instancetreeandconvert
allstringsimpletypestouppercase.
Hereisaschema(Code/member_specs.xsd):
<?xmlversion="1.0"?>
<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:elementname="contactlist"type="contactlistType"/>

<xs:complexTypename="contactlistType">
<xs:sequence>
<xs:elementname="description"type="xs:string"/>
<xs:elementname="contact"type="contactType"
maxOccurs="unbounded"/>
</xs:sequence>
<xs:attributename="locator"type="xs:string"/>
</xs:complexType>

<xs:complexTypename="contactType">

Page269
APythonBook

<xs:sequence>
<xs:elementname="firstname"type="xs:string"/>
<xs:elementname="lastname"type="xs:string"/>
<xs:elementname="interest"type="xs:string"
maxOccurs="unbounded"/>
<xs:elementname="category"type="xs:integer"/>
</xs:sequence>
<xs:attributename="id"type="xs:integer"/>
<xs:attributename="priority"type="xs:float"/>
<xs:attributename="colorcode"type="xs:string"/>
</xs:complexType>

</xs:schema>

4.7.1.1Step1generatethebindings
Wegeneratecodewiththefollowingcommandline:
$generateDS.pyf\
omember_specs_api.py\
smember_specs_upper.py\
super=member_specs_api\
memberspecs=list\
member_specs.xsd
Notes:
Wegeneratethememberspecificationsasalistwiththecommandlineoption
memberspecs=list.
Wegeneratean"application"modulewiththescommandlineoption.We'llput
ourapplicationspecificcodeinmember_specs_upper.py.

4.7.1.2Step2addapplicationspecificcode
And,hereisthesubclassfile(member_specs_upper.py,generatedwiththe"s"
commandlineoption),towhichwehaveaddedabitofcodethatconvertsanystringtype
memberstouppercase.Youcanthinkofthismoduleasaspecial"application"ofthe
generatedclasses.
#!/usr/bin/envpython

#
#member_specs_upper.py
#

#
#GeneratedTueNov915:54:472010bygenerateDS.pyversion2.2a.
#

importsys

Page270
APythonBook

importmember_specs_apiassupermod

etree_=None
Verbose_import_=False
(XMLParser_import_none,XMLParser_import_lxml,
XMLParser_import_elementtree
)=range(3)
XMLParser_import_library=None
try:
#lxml
fromlxmlimportetreeasetree_
XMLParser_import_library=XMLParser_import_lxml
ifVerbose_import_:
print("runningwithlxml.etree")
exceptImportError:
try:
#cElementTreefromPython2.5+
importxml.etree.cElementTreeasetree_
XMLParser_import_library=XMLParser_import_elementtree
ifVerbose_import_:
print("runningwithcElementTreeonPython2.5+")
exceptImportError:
try:
#ElementTreefromPython2.5+
importxml.etree.ElementTreeasetree_
XMLParser_import_library=XMLParser_import_elementtree
ifVerbose_import_:
print("runningwithElementTreeonPython2.5+")
exceptImportError:
try:
#normalcElementTreeinstall
importcElementTreeasetree_
XMLParser_import_library=
XMLParser_import_elementtree
ifVerbose_import_:
print("runningwithcElementTree")
exceptImportError:
try:
#normalElementTreeinstall
importelementtree.ElementTreeasetree_
XMLParser_import_library=
XMLParser_import_elementtree
ifVerbose_import_:
print("runningwithElementTree")
exceptImportError:
raiseImportError("FailedtoimportElementTree
fromanyknownplace")

defparsexml_(*args,**kwargs):
if(XMLParser_import_library==XMLParser_import_lxmland
'parser'notinkwargs):
#UsethelxmlElementTreecompatibleparsersothat,e.g.,

Page271
APythonBook

#weignorecomments.
kwargs['parser']=etree_.ETCompatXMLParser()
doc=etree_.parse(*args,**kwargs)
returndoc

#
#Globals
#

ExternalEncoding='ascii'

#
#Utilityfuntionsneededineachgeneratedclass.
#

defupper_elements(obj):
foriteminobj.member_data_items_:
ifitem.get_data_type()=='xs:string':
name=remap(item.get_name())
val1=getattr(obj,name)
ifisinstance(val1,list):
foridx,val2inenumerate(val1):
val1[idx]=val2.upper()
else:
setattr(obj,name,val1.upper())

defremap(name):
newname=name.replace('','_')
returnnewname

#
#Datarepresentationclasses
#

classcontactlistTypeSub(supermod.contactlistType):
def__init__(self,locator=None,description=None,contact=None):
super(contactlistTypeSub,self).__init__(locator,
description,contact,)
defupper(self):
upper_elements(self)
forchildinself.get_contact():
child.upper()
supermod.contactlistType.subclass=contactlistTypeSub
#endclasscontactlistTypeSub

classcontactTypeSub(supermod.contactType):
def__init__(self,priority=None,color_code=None,id=None,
first_name=None,last_name=None,interest=None,category=None):
super(contactTypeSub,self).__init__(priority,color_code,
id,first_name,last_name,interest,category,)
defupper(self):

Page272
APythonBook

upper_elements(self)
supermod.contactType.subclass=contactTypeSub
#endclasscontactTypeSub

defget_root_tag(node):
tag=supermod.Tag_pattern_.match(node.tag).groups()[1]
rootClass=None
ifhasattr(supermod,tag):
rootClass=getattr(supermod,tag)
returntag,rootClass

defparse(inFilename):
doc=parsexml_(inFilename)
rootNode=doc.getroot()
rootTag,rootClass=get_root_tag(rootNode)
ifrootClassisNone:
rootTag='contactlist'
rootClass=supermod.contactlistType
rootObj=rootClass.factory()
rootObj.build(rootNode)
#EnablePythontocollectthespaceusedbytheDOM.
doc=None
sys.stdout.write('<?xmlversion="1.0"?>\n')
rootObj.export(sys.stdout,0,name_=rootTag,
namespacedef_='')
doc=None
returnrootObj

defparseString(inString):
fromStringIOimportStringIO
doc=parsexml_(StringIO(inString))
rootNode=doc.getroot()
rootTag,rootClass=get_root_tag(rootNode)
ifrootClassisNone:
rootTag='contactlist'
rootClass=supermod.contactlistType
rootObj=rootClass.factory()
rootObj.build(rootNode)
#EnablePythontocollectthespaceusedbytheDOM.
doc=None
sys.stdout.write('<?xmlversion="1.0"?>\n')
rootObj.export(sys.stdout,0,name_=rootTag,
namespacedef_='')
returnrootObj

defparseLiteral(inFilename):
doc=parsexml_(inFilename)
rootNode=doc.getroot()
rootTag,rootClass=get_root_tag(rootNode)

Page273
APythonBook

ifrootClassisNone:
rootTag='contactlist'
rootClass=supermod.contactlistType
rootObj=rootClass.factory()
rootObj.build(rootNode)
#EnablePythontocollectthespaceusedbytheDOM.
doc=None
sys.stdout.write('#frommember_specs_apiimport*\n\n')
sys.stdout.write('importmember_specs_apiasmodel_\n\n')
sys.stdout.write('rootObj=model_.contact_list(\n')
rootObj.exportLiteral(sys.stdout,0,name_="contact_list")
sys.stdout.write(')\n')
returnrootObj

USAGE_TEXT="""
Usage:python???.py<infilename>
"""

defusage():
printUSAGE_TEXT
sys.exit(1)

defmain():
args=sys.argv[1:]
iflen(args)!=1:
usage()
infilename=args[0]
root=parse(infilename)

if__name__=='__main__':
#importpdb;pdb.set_trace()
main()
Notes:
Weaddthefunctionsupper_elementsandremapthatweuseineach
generatedclass.
Noticehowthefunctionupper_elementscallsthefunctionremaponlyon
thosememberswhosetypeisxs:string.
Ineachgenerated(sub)class,weaddthemethodsthatwalktheDOMtreeand
applythemethod(upper)thattransformseachxs:stringvalue.

4.7.1.3Step3writeatest/driverharness
Hereisatestdriver(member_specs_test.py)forour(mini)application:
#!/usr/bin/envpython

Page274
APythonBook

#
#member_specs_test.py
#

importsys
importmember_specs_apiassupermod
importmember_specs_upper

defprocess(inFilename):
doc=supermod.parsexml_(inFilename)
rootNode=doc.getroot()
rootClass=member_specs_upper.contactlistTypeSub
rootObj=rootClass.factory()
rootObj.build(rootNode)
#EnablePythontocollectthespaceusedbytheDOM.
doc=None
sys.stdout.write('<?xmlversion="1.0"?>\n')
rootObj.export(sys.stdout,0,name_="contactlist",
namespacedef_='')
rootObj.upper()
sys.stdout.write(''*60)
sys.stdout.write('\n')
rootObj.export(sys.stdout,0,name_="contactlist",
namespacedef_='')
returnrootObj

USAGE_MSG="""\
Synopsis:
Sampleapplicationusingclassesandsubclassesgeneratedby
generateDS.py
Usage:
pythonmember_specs_test.pyinfilename
"""

defusage():
printUSAGE_MSG
sys.exit(1)

defmain():
args=sys.argv[1:]
iflen(args)!=1:
usage()
infilename=args[0]
process(infilename)

if__name__=='__main__':
main()
Notes:
Wecopythefunctionparse()fromourgeneratedcodetoserveasamodelfor

Page275
APythonBook

ourfunctionprocess().
AfterparsinganddisplayingtheXMLinstancedocument,wecallmethod
upper()inthegeneratedclasscontactlistTypeSubinordertowalkthe
DOMtreeandtransformeachxs:stringtouppercase.

4.7.1.4Step4runthetestapplication
Wecanusethefollowingcommandlinetorunourapplication:
$pythonmember_specs_test.pymember_specs_data.xml
Whenwerunourapplication,hereistheoutput:
$pythonmember_specs_test.pymember_specs_data.xml
<?xmlversion="1.0"?>
<contactlistlocator="http://www.rexx.com/~dkuhlman">
<description>Mylistofcontacts</description>
<contactpriority="0.050000"colorcode="red"id="1">
<firstname>arlene</firstname>
<lastname>Allen</lastname>
<interest>traveling</interest>
<category>2</category>
</contact>
</contactlist>

<contactlistlocator="HTTP://WWW.REXX.COM/~DKUHLMAN">
<description>MYLISTOFCONTACTS</description>
<contactpriority="0.050000"colorcode="RED"id="1">
<firstname>ARLENE</firstname>
<lastname>ALLEN</lastname>
<interest>TRAVELING</interest>
<category>2</category>
</contact>
</contactlist>
Notes:
Theoutputaboveshowsbothbeforeandafterversionofexportingtheparsed
XMLinstancedocument.

4.8Somehints
Thefollowinghintsareofferedforconvenience.Youcandiscoverthemforyourself
rathereasilybyinspectingthegeneratedcode.

4.8.1ChildrendefinedwithmaxOccursgreaterthan1
IfachildelementisdefinedintheXMLschemawithmaxOccurs="unbounded"or
avalueofmaxOccursgreaterthan1,thenaccesstothechildisthroughalist.

Page276
APythonBook

4.8.2Childrendefinedwithsimplenumerictypes
Ifachildelementisdefinedasanumerictypesuchasxs:integer,xs:float,or
xs:doubleorasasimpletypethatis(ultimately)basedonanumerictype,thenthe
valueisstored(inthePythonobject)asaPythondatatype(int,float,etc).

4.8.3Thetypeofanelement'scharactercontent
But,whentheelementitselfisdefinedasmixed="true"ortheelementarestrictionof
andhasasimple(numeric)asabase,thenthevalueOf_instancevariableholdsthe
charactercontentanditisalwaysastring,thatisitisnotconverted.

4.8.4Constructorsandtheirdefaultvalues
Allparameterstotheconstructorsofgeneratedclasseshavedefaultparameters.
Therefore,youcancreatean"empty"instanceofanyelementbycallingtheconstructor
withnoparameters.
Forexample,supposewehavethefollowingXMLschema:
<?xmlversion="1.0"?>
<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:elementname="plantlist"type="PlantList"/>

<xs:complexTypename="PlantType">
<xs:sequence>
<xs:elementname="description"type="xs:string"/>
<xs:elementname="catagory"type="xs:integer"/>
<xs:elementname="fertilizer"type="FertilizerType"
maxOccurs="unbounded"/>
</xs:sequence>
<xs:attributename="identifier"type="xs:string"/>
</xs:complexType>

<xs:complexTypename="FertilizerType">
<xs:sequence>
<xs:elementname="name"type="xs:string"/>
<xs:elementname="description"type="xs:string"/>
</xs:sequence>
<xs:attributename="id"type="xs:integer"/>
</xs:complexType>

</xs:schema>
And,supposewegenerateamodulewiththefollowingcommandline:
$./generateDS.pyogarden_api.pygarden.xsd

Page277
APythonBook

Then,fortheelementnamedPlantTypeinthegeneratedmodulenamed
garden_api.py,youcancreateaninstanceasfollows:
>>>importgarden_api
>>>plant=garden_api.PlantType()
>>>importsys
>>>plant.export(sys.stdout,0)
<PlantType/>

Page278

You might also like