://avxhome.se/blogs/crazy Slim The Python Book Ultimate Guide To Coding With 2015

291321612-The-Python-Book-The-Ultimate-Guide-to-Coding-With-Python-2015

User Manual:

Open the PDF directly: View PDF PDF.
Page Count: 180

Download://avxhome.se/blogs/crazy-slim The Python Book - Ultimate Guide To Coding With 2015
Open PDF In BrowserView PDF
NE
W
The ultimate guide to coding with Python

Pi 2

projects
inside

Learn to use Pythont Program games t Get creative with Pi

Welcome to

Python
The

Python is an incredibly versatile, expansive language which, due to its similarity to everyday
language, is surprisingly easy to learn even for inexperienced programmers. It has seen a
huge increase in popularity since the release and rise of the Raspberry Pi, for which Python
is the officially recognised programming language. In The Python Book, you’ll find plenty
of creative projects to help you get to grips with the combination of your Raspberry Pi and
Python’s powerful functionality, but there are also plenty of tutorials that focus on Python’s
effectiveness away from the Raspberry Pi. You’ll learn all about how to code with Python
from the very beginning with our comprehensive masterclass, then go on to complete
tutorials to consolidate your skills and become fluent in the language while also improving
your computing experience. You’ll learn how to make Python work for you with tutorials
on coding with Django, Flask, Pygame and even more useful third-party applications and
frameworks. Get ready to become a true Python expert with the wealth of information
contained within these pages.

Python
The

Imagine Publishing Ltd
Richmond House
33 Richmond Hill
Bournemouth
Dorset BH2 6EZ
 +44 (0) 1202 586200
Website: www.imagine-publishing.co.uk
Twitter: @Books_Imagine
Facebook: www.facebook.com/ImagineBookazines

Publishing Director
Aaron Asadi
Head of Design
Ross Andrews
Production Editor
Alex Hoskins
Senior Art Editor
Greg Whitaker
Designer
Perry Wardell-Wicks
Printed by
William Gibbons, 26 Planetary Road, Willenhall, West Midlands, WV13 3XT
Distributed in the UK, Eire & the Rest of the World by
Marketforce, Blue Fin Building, 110 Southwark Street, London, SE1 0SU
Tel 0203 148 3300 www.marketforce.co.uk
Distributed in Australia by
Network Services (a division of Bauer Media Group), Level 21 Civic Tower, 66-68 Goulburn Street,
Sydney, New South Wales 2000, Australia Tel +61 2 8667 5288
Disclaimer
The publisher cannot accept responsibility for any unsolicited material lost or damaged in the
post. All text and layout is the copyright of Imagine Publishing Ltd. Nothing in this bookazine may
be reproduced in whole or part without the written permission of the publisher. All copyrights are
recognised and used specifically for the purpose of criticism and review. Although the bookazine has
endeavoured to ensure all information is correct at time of print, prices and availability may change.
This bookazine is fully independent and not affiliated in any way with the companies mentioned herein.
The Python Book © 2015 Imagine Publishing Ltd
ISBN 9781785460609

Part of the

bookazine series

Python
5IF

$POUFOUT

8(FUTUBSUFE

XJUI1ZUIPO

.BTUFSUIFCBTJDTUIFSJHIUXBZ

16
 FTTFOUJBM

DPNNBOET

5IFDPNNBOETZPVOFFEUPLOPX

8PSLXJUI1ZUIPO

$SFBUFXJUI1ZUIPO

74$SFBUFEZOBNJDUFNQMBUFT

108#VJMEUJDUBDUPFXJUI,JWZ

78.BLFFYUFOTJPOTGPS9#.$

112$SFBUFUXPTUFQBVUIFOUJDBUJPO

844DJFOUJöDDPNQVUJOH

1165XJUUFST0"VUIQSPDFTT

88*OTUBOUNFTTBHJOH

1201SPHSBNB4QBDF
*OWBEFSTDMPOF

1SPHSBNOPVHIUTBOEDSPTTFT

6TF+JOKB 'MBTLBOENPSF

6TF5XJMJPGPSTBGFBVUIFOUJDBUJPO

&OIBODF9#.$XJUIUIJTUVUPSJBM

#VJMETJHOJOHSFRVFTUT

(FUUPHSJQTXJUI/VN1Z

(FUDIBUUJOHVTJOH1ZUIPO

943FQMBDFZPVSTIFMM

6TF1ZUIPOGPSZPVSQSJNBSZTIFMM

1ZUIPOFTTFOUJBMT

981ZUIPOGPSTZTUFNBENJOT

26$PEFSPDL QBQFS TDJTTPST

1024DSBQF8JLJQFEJB

1VUCBTJDDPEJOHJOUPBDUJPO

321SPHSBNBIBOHNBOHBNF
6TF1ZUIPOUPNBLFUIFDMBTTJDHBNF

)PX1ZUIPOIFMQTTZTUFNBENJOJTUSBUJPO
6TF#FBVUJGVM4PVQUPSFBEPõ
JOF

74

.BLFUIFCBTJD1JWBEFSTHBNF

124"EEBOJNBUJPOBOETPVOE
&OIBODFZPVS1JWBEFSTHBNF

128.BLFBWJTVBMOPWFM
1SPHSBNBCPPLTUZMFHBNF

120

381MBZQPLFSEJDF

5FTUZPVSMVDLBOEZPVSDPEJOH

44$SFBUFBHSBQIJDBMJOUFSGBDF
"EEJOUFSGBDFUPZPVSQSPKFDUT

50#SJOHHSBQIJDTUPHBNFT
"EEJNBHFTUPTJNQMFHBNFT

56#VJMEBOBQQGPS"OESPJE
.BLFZPVSPXOBQQXJUI,JWZ

62.BLJOHXFCBQQT

6TF1ZUIPOUPDSFBUFPOMJOFBQQT

661ZUIPOUJQT

&TTFOUJBMLOPXMFEHFGPS1ZUIPOVTFST

65IF1ZUIPO#PPL

88

128

144

166

66

148

8FCEFWFMPQNFOU
134%FWFMPQXJUI1ZUIPO

8IZ1ZUIPOJTQFSGFDUGPSUIFXFC

140#VJMEZPVSPXOCMPH

50

1ZUIPO
UJQT

6TF1ZUIPOXJUI1J
1541SPHSBNNJOHJO1ZUIPOPO
3BTQCFSSZ1J
-FBSOIPXUPPQUJNJTFGPS1J

1581SPHSBN.JOFDSBGU1J
1MBZB.JOFDSBGUHBNFPO1J

162#VJMEBO-&%.BUSJY

6TF1JUPDPOUSPMMJHIUTFRVFODFT

1663BTQCFSSZ1JDBSDPNQVUFS

(FUXIFSFZPVSFHPJOHXJUI3BTQCFSSZ1J

#FHJOEFWFMPQJOHZPVSCMPH

144%FMJWFSDPOUFOUUPZPVSCMPH
"EEDPOUFOUUPZPVSTJUF

148&OIBODFZPVSCMPH

$PNQMFUFZPVSCMPHXJUIBEEPOT

i1ZUIPOJTFYQBOTJWF CVUZPVMMCF
BOFYQFSUCFGPSFZPVLOPXJUw
5IF1ZUIPO#PPL7

Get started with Python

Get started
with

Python
Always wanted to have a go at
programming? No more excuses,
because Python is the perfect way to get started!

P

ython is a great programming language for
both beginners and experts. It is designed with
code readability in mind, making it an excellent
choice for beginners who are still getting used to
various programming concepts.
The language is popular and has plenty of libraries
available, allowing programmers to get a lot done with
relatively little code.
You can make all kinds of applications in Python:
you could use the Pygame framework to write
simple 2D games, you could use the GTK

8 The Python Book

libraries to create a windowed application, or you could
try something a little more ambitious like an app such
as creating one using Python’s Bluetooth and Input
libraries to capture the input from a USB keyboard and
relay the input events to an Android phone.
For this tutorial we’re going to be using Python 2.x
since that is the version that is most likely to be installed
on your Linux distribution.
In the following tutorials, you’ll learn how to create
popular games using Python programming. We’ll also
show you how to add sound and AI to these games.

Get started with Python

The Python Book 9

Get started with Python
Hello World

Variables and data types

Let’s get stuck in, and what better way than with the
programmer’s best friend, the ‘Hello World’ application! Start
by opening a terminal. Its current working directory will be your
home directory. It’s probably a good idea to make a directory for
the files we’ll be creating in this tutorial, rather than having them
loose in your home directory. You can create a directory called
Python using the command mkdir Python. You’ll then want to
change into that directory using the command cd Python.
The next step is to create an empty file using the command
‘touch’ followed by the filename. Our expert used the command
touch hello_world.py. The final and most important part of
setting up the file is making it executable. This allows us to run
code inside the hello_world.py file. We do this with the command
chmod +x hello_world.py. Now that we have our file set up, we
can go ahead and open it up in nano, or any text editor of your
choice. Gedit is a great editor with syntax highlighting support
that should be available on any distribution. You’ll be able to
install it using your package manager if you don’t have it already.

A variable is a name in source code that is associated with an
area in memory that you can use to store data, which is then
called upon throughout the code. The data can be one of many
types, including:

[liam@liam-laptop
[liam@liam-laptop
[liam@liam-laptop
[liam@liam-laptop
[liam@liam-laptop

~]$ mkdir Python
~]$ cd Python/
Python]$ touch hello_world.py
Python]$ chmod +x hello_world.py
Python]$ nano hello_world.py

Our Hello World program is very simple, it only needs two lines.
The first line begins with a ‘shebang’ (the symbol #! – also known
as a hashbang) followed by the path to the Python interpreter.
The program loader uses this line to work out what the rest of the
lines need to be interpreted with. If you’re running this in an IDE
like IDLE, you don’t necessarily need to do this.
The code that is actually read by the Python interpreter is only
a single line. We’re passing the value Hello World to the print
function by placing it in brackets immediately after we’ve called
the print function. Hello World is enclosed in quotation marks to
indicate that it is a literal value and should not be interpreted as
source code. As expected, the print function in Python prints any
value that gets passed to it from the console.
You can save the changes you’ve just made to the file in nano
using the key combination Ctrl+O, followed by Enter. Use Ctrl+X
to exit nano.
#!/usr/bin/env python2
print(“Hello World”)

You can run the Hello World program by prefixing
– in this case you’d type:
its filename with ./
./hello_world.py.
[liam@liam-laptop Python]$ ./hello_world.py
Hello World

TIP
If you were using a graphical
editor such as gedit, then
you would only have to do
the last step of making the
file executable. You should
only have to mark the file as
executable once. You can
freely edit the file once it
is executable.

10 The Python Book

Integer

Stores whole numbers

Float

Stores decimal numbers

Boolean

Can have a value of True or False

String

Stores a collection of characters. “Hello
World” is a string

As well as these main data types, there are sequence types
(technically, a string is a sequence type but is so commonly used
we’ve classed it as a main data type):
List

Contains a collection of data in a specific order

Tuple

Contains a collection immutable data in a
specific order

A tuple would be used for something like a co-ordinate,
containing an x and y value stored as a single variable, whereas
a list is typically used to store larger collections. The data
stored in a tuple is immutable because you aren’t able to
change values of individual elements in a tuple. However, you
can do so in a list.
It will also be useful to know about Python’s dictionary
type. A dictionary is a mapped data type. It stores data in
key-value pairs. This means that you access values stored in
the dictionary using that value’s corresponding key, which is
different to how you would do it with a list. In a list, you would
access an element of the list using that element’s index (a
number representing the element’s position in the list).
Let’s work on a program we can use to demonstrate how to
use variables and different data types. It’s worth noting at
this point that you don’t always have to specify data types
in Python. Feel free to create this file in any editor you like.
Everything will work just fine as long as you remember to make
the file executable. We’re going to call ours variables.py.

“A variable is a name
in source code that is
associated with an area in
memory that you can use to
store data”
Interpreted vs compiled languages
An interpreted language such as Python is one where the source
code is converted to machine code and then executed each time the
program runs. This is different from a compiled language such as C,
where the source code is only converted to machine code once – the
resulting machine code is then executed each time the program runs.

Get started with Python
#!/usr/bin/env python2

The following line creates an
integer variable called hello_int
with the # value of 21. Notice
how it doesn’t need to go in
quotation marks

# We create a variable by writing the name of the variable we want followed
# by an equals sign, which is followed by the value we want to store in the
# variable. For example, the following line creates a variable called
# hello_str, containing the string Hello World.
hello_str = “Hello World”
hello_int = 21

The same principal is true of
Boolean values

We create a tuple in the
following way
And a list in this way

hello_bool = True
hello_tuple = (21, 32)
hello_list = [“Hello,”, “this”, “is”, “a”, “list”]
# This list now contains 5 strings. Notice that there are no spaces
# between these strings so if you were to join them up so make a sentence
# you’d have to add a space between each element.

You could also create the
same list in the following way

hello_list = list()
hello_list.append(“Hello,”)
hello_list.append(“this”)
hello_list.append(“is”)
hello_list.append(“a”)
hello_list.append(“list”)
# The first line creates an empty list and the following lines use the append
# function of the list type to add elements to the list. This way of using a
# list isn’t really very useful when working with strings you know of in
# advance, but it can be useful when working with dynamic data such as user
# input. This list will overwrite the first list without any warning as we
# are using the same variable name as the previous list.

We might as well create a
dictionary while we’re at it.
Notice how we’ve aligned the
colons below to make the
code tidy

Notice that there will now be
two exclamation marks when
we print the element

hello_dict = { “first_name” : “Liam”,
“last_name” : “Fraser”,
“eye_colour” : “Blue” }
# Let’s access some elements inside our collections
# We’ll start by changing the value of the last string in our hello_list and
# add an exclamation mark to the end. The “list” string is the 5th element
# in the list. However, indexes in Python are zero-based, which means the
# first element has an index of 0.
print(hello_list[4])
hello_list[4] += “!”
# The above line is the same as
hello_list[4] = hello_list[4] + “!”
print(hello_list[4])

TIP
At this point, it’s worth
explaining that any text in
a Python file that follows
a # character will be
ignored by the interpreter.
This is so you can write
comments in your code.

“Any text in a Python file that follows a #
character will be ignored”

Get started with Python

print(str(hello_tuple[0]))
# We can’t change the value of those elements like we just did with the list
# Notice the use of the str function above to explicitly convert the integer
# value inside the tuple to a string before printing it.
Remember that tuples are
immutable, although we can
access the elements of them
like so

print(hello_dict[“first_name”] + “ “ + hello_dict[“last_name”] + “ has “ +
hello_dict[“eye_colour”] + “ eyes.”)

Let’s create a sentence using the
data in our hello_dict

print(“{0} {1} has {2} eyes.”.format(hello_dict[“first_name”],
hello_dict[“last_name”],
hello_dict[“eye_colour”]))

A tidier way of doing this
would be to use Python’s
string formatter

Control structures
In programming, a control structure is any kind of statement that
can change the path that the code execution takes. For example, a
control structure that decided to end the program if a number was
less than 5 would look something like this:
#!/usr/bin/env python2
import sys # Used for the sys.exit function
int_condition = 5
if int_condition < 6:
sys.exit(“int_condition must be >= 6”)
else:
print(“int_condition was >= 6 - continuing”)

More about a
Python list
A Python list is similar to an
array in other languages. A
list (or tuple) in Python can
contain data of multiple
types, which is not usually
the case with arrays in other
languages. For this reason,
we recommend that you
only store data of the same
type in a list. This should
almost always be the case
anyway due to the nature of
the way data in a list would
be processed.

12 The Python Book

The path that the code takes will depend on the value of
the integer int_condition. The code in the ‘if’ block will only be
executed if the condition is true. The import statement is used
to load the Python system library; the latter provides the exit
function, allowing you to exit the program, printing an error
message. Notice that indentation (in this case four spaces per
indent) is used to indicate which statement a block of code
belongs to.
‘If’ statements are probably the most commonly used control
structures. Other control structures include:
• For statements, which allow you to iterate over items in
collections, or to repeat a piece of code a certain number
of times;
• While statements, a loop that continues while the condition
is true.
We’re going to write a program that accepts user input from the
user to demonstrate how control structures work. We’re calling it
construct.py.
The ‘for’ loop is using a local copy of the current value, which
means any changes inside the loop won’t make any changes
affecting the list. On the other hand however, the ‘while’ loop is
directly accessing elements in the list, so you could change the list
there should you want to do so. We will talk about variable scope in
some more detail later on. The output from the above program is
as follows:

Indentation in detail
As previously mentioned, the level of indentation
dictates which statement a block of code belongs
to. Indentation is mandatory in Python, whereas in
other languages, sets of braces are used to organise
code blocks. For this reason, it is essential that you
use a consistent indentation style. Four spaces
are typically used to represent a single level of
indentation in Python. You can use tabs, but tabs are
not well defined, especially if you happen to open a
file in more than one editor.

“The ‘for‘ loop uses
a local copy, so
changes in the loop
won’t affect the list”
[liam@liam-laptop Python]$ ./construct.py
How many integers? acd
You must enter an integer
[liam@liam-laptop Python]$ ./construct.py
How many integers? 3
Please enter integer 1: t
You must enter an integer
Please enter integer 1: 5
Please enter integer 2: 2
Please enter integer 3: 6
Using a for loop
5
2
6
Using a while loop
5
2
6

#!/usr/bin/env python2

The number of integers we
want in the list

# We’re going to write a program that will ask the user to input an arbitrary
# number of integers, store them in a collection, and then demonstrate how the
# collection would be used with various control structures.
import sys # Used for the sys.exit function
target_int = raw_input(“How many integers? “)
# By now, the variable target_int contains a string representation of
# whatever the user typed. We need to try and convert that to an integer but
# be ready to # deal with the error if it’s not. Otherwise the program will
# crash.
try:
target_int = int(target_int)
except ValueError:
sys.exit(“You must enter an integer”)

A list to store the integers

ints = list()
These are used to keep track
of how many integers we
currently have

If the above succeeds then isint
will be set to true: isint =True

count = 0
# Keep asking for an integer until we have the required number
while count < target_int:
new_int = raw_input(“Please enter integer {0}: “.format(count + 1))
isint = False
try:
new_int = int(new_int)
except:
print(“You must enter an integer”)
# Only carry on if we have an integer. If not, we’ll loop again
# Notice below I use ==, which is different from =. The single equals is an
# assignment operator whereas the double equals is a comparison operator.
if isint == True:
# Add the integer to the collection
ints.append(new_int)
# Increment the count by 1
count += 1

By now, the user has given up or
we have a list filled with integers.
We can loop through these in a
couple of ways. The first is with
a for loop

print(“Using a for loop”)
for value in ints:
print(str(value))

The Python Book 13

Get started with Python
TIP
You can define defaults
for variables if you want
to be able to call the
function without passing
any variables through at
all. You do this by putting
an equals sign after
the variable name. For
example, you can do:
def modify_string
(original=” Default
String”)

# Or with a while loop:
print(“Using a while loop”)
# We already have the total above, but knowing the len function is very
# useful.
total = len(ints)
count = 0
while count < total:
print(str(ints[count]))
count += 1

Functions and variable scope
Functions are used in programming to break processes down into smaller
chunks. This often makes code much easier to read. Functions can also be
reusable if designed in a certain way. Functions can have variables passed
to them. Variables in Python are always passed by value, which means that
a copy of the variable is passed to the function that is only valid in the scope
of the function. Any changes made to the original variable inside the function
will be discarded. However, functions can also return values, so this isn’t
an issue. Functions are defined with the keyword def, followed by the
name of the function. Any variables that can be passed through are put in
brackets following the function’s name. Multiple variables are separated by
commas. The names given to the variables in these brackets are the ones

that they will have in the scope of the function, regardless of what
the variable that’s passed to the function is called. Let’s see this
in action.
The output from the program opposite is as follows:

“Functions are used in
programming to break
processes down in”

#!/usr/bin/env python2
# Below is a function called modify_string,
# that will be called original in the scope
# indented with 4 spaces under the function
# scope.
def modify_string(original):
original += “ that has been modified.”
# At the moment, only the local copy of

We are now outside of
the scope of the modify_
string function, as we
have reduced the level
of indentation
The test string won’t be
changed in this code

which accepts a variable
of the function. Anything
definition is in the

this string has been modified

def modify_string_return(original):
original += “ that has been modified.”
# However, we can return our local copy to the caller. The function
# ends as soon as the return statement is used, regardless of where it
# is in the function.
return original

test_string = “This is a test string”
modify_string(test_string)
print(test_string)
test_string = modify_string_return(test_string)
print(test_string)

However, we can call the
function like this

14 The Python Book

# The function’s return value is stored in the variable test string,
# overwriting the original and therefore changing the value that is
# printed.

(FUTUBSUFEXJUI1ZUIPO
[liam@liam-laptop Python]$ ./functions_and_scope.py
This is a test string
This is a test string that has been modified.
Scope is an important thing to get the hang of, otherwise it can get you
into some bad habits. Let’s write a quick program to demonstrate this. It’s
going to have a Boolean variable called cont, which will decide if a number
will be assigned to a variable in an if statement. However, the variable
hasn’t been defined anywhere apart from in the scope of the if statement.
We’ll finish off by trying to print the variable.
#!/usr/bin/env python2
cont = False
if cont:
var = 1234
print(var)
In the section of code above, Python will convert the integer to a string
before printing it. However, it’s always a good idea to explicitly convert
things to strings – especially when it comes to concatenating strings
together. If you try to use the + operator on a string and an integer, there
will be an error because it’s not explicitly clear what needs to happen.
The + operator would usually add two integers together. Having said that,
Python’s string formatter that we demonstrated earlier is a cleaner way of
doing that. Can you see the problem? Var has only been defined in the scope
of the if statement. This means that we get a very nasty error when we try to
access var.
[liam@liam-laptop Python]$ ./scope.py
Traceback (most recent call last):
File Ŏ./scope.pyŏ, line 8, in 
print var
NameError: name Ăvarā is not defined
If cont is set to True, then the variable will be created and we can access
it just fine. However, this is a bad way to do things. The correct way is to
initialise the variable outside of the scope of the if statement.
#!/usr/bin/env python2
cont = False
var = 0
if cont:
var = 1234
if var != 0:
print(var)
The variable var is defined in a wider scope than the if statement, and
can still be accessed by the if statement. Any changes made to var inside
the if statement are changing the variable defined in the larger scope.
This example doesn’t really do anything useful apart from illustrate the
potential problem, but the worst-case scenario has gone from the program
crashing to printing a zero. Even that doesn’t happen because we’ve added
an extra construct to test the value of var before printing it.

Coding style
It’s worth taking a little time to talk about coding style. It’s simple to write
tidy code. The key is consistency. For example, you should always name
your variables in the same manner. It doesn’t matter if you want to use
camelCase or use underscores as we have. One crucial thing is to use
self-documenting identifiers for variables. You shouldn’t have to guess

Comparison operators
The common comparison operators available in Python include:
<

strictly less than

<=

less than or equal

>

strictly greater than

>=

greater than or equal

==

equal

!=

not equal

what a variable does. The other thing that goes with this is to always
comment your code. This will help anyone else who reads your code,
and yourself in the future. It’s also useful to put a brief summary at
the top of a code file describing what the application does, or a part of
the application if it’s made up of multiple files.

Summary
This article should have introduced you to the basics of programming
in Python. Hopefully you are getting used to the syntax, indentation
and general look and feel of a Python program. The next step is
to learn how to come up with a problem that you want to solve, and
break it down into small enough steps that you can implement in a
programming language.
Google, or any other search engine, is very helpful. If you are stuck
with anything, or have an error message you can’t work out how to
fix, stick it into Google and you should be a lot closer to solving your
problem. For example, if we Google ‘play mp3 file with python’, the
first link takes us to a Stack Overflow thread with a bunch of useful
replies. Don’t be afraid to get stuck in – the real fun of programming is
solving problems one manageable chunk at a time.
Happy programming!

ESSENTIAL

PYTHON
COMMANDS
Python is known as a very
dense language, with lots of
modules capable of doing
almost anything. Here,
we will look at the core
essentials that everyone
needs to know

16 The Python Book

Python has a massive environment of extra modules
that can provide functionality in hundreds of
different disciplines. However, every programming
language has a core set of functionality that everyone
should know in order to get useful work done. Python
is no different in this regard. Here, we will look at
50 commands that we consider to be essential to
programming in Python. Others may pick a slightly
different set, but this list contains the best of the best.
We will cover all of the basic commands, from
importing extra modules at the beginning of a program
to returning values to the calling environment at the
end. We will also be looking at some commands that
are useful in learning about the current session within
Python, like the current list of variables that have been
defined and how memory is being used.

Because the Python environment involves using a lot
of extra modules, we will also look at a few commands
that are strictly outside of Python. We will see how to
install external modules and how to manage multiple
environments for different development projects.
Since this is going to be a list of commands, there is the
assumption that you already know the basics of how
to use loops and conditional structures. This piece is
designed to help you remember commands that you
know you’ve seen before, and hopefully introduce you
to a few that you may not have seen yet.
Although we’ve done our best to pack everything
you could ever need into 50 tips, Python is such an
expansive language that some commands will have
been left out. Make some time to learn about the ones
that we didn’t cover here, once you’ve mastered these.

50 Python commands

02
01

Reloading modules

When a module is first imported, any initialisation functions are run at that time. This may involve
creating data objects, or initiating connections. But, this is only done the first time within a given session.
Importing the same module again won’t re-execute any of the initialisation code. If you want to have this
code re-run, you need to use the reload command. The format is ‘reload(modulename)’. Something to keep
in mind is that the dictionary from the previous import isn’t dumped, but only written over. This means that
any definitions that have changed between the import and the reload are updated correctly. But if you
delete a definition, the old one will stick around and still be accessible. There may be other side effects, so
always use with caution.

Importing modules

The strength of Python is its ability to be
extended through modules. The first step in many
programs is to import those modules that you need.
The simplest import statement is to just call ‘import
modulename’. In this case, those functions and
objects provided are not in the general namespace.
You need to call them using the complete name
(modulename.methodname). You can shorten the
‘modulename’ part with the command ‘import
modulename as mn’. You can skip this issue
completely with the command ‘from modulename
import *’ to import everything from the given module.
Then you can call those provided capabilities directly.
If you only need a few of the provided items, you can
import them selectively by replacing the ‘*’ with the
method or object names.

03

Installing new modules

While most of the commands we are looking at are Python commands
that are to be executed within a Python session, there are a few essential
commands that need to be executed outside of Python. The first of these is pip.
Installing a module involves downloading the source code, and compiling any included
external code. Luckily, there is a repository of hundreds of Python modules available
at http://pypi.python.org. Instead of doing everything manually, you can install a
new module by using the command ‘pip install modulename’. This command will
also do a dependency check and install any missing modules before installing the
one you requested. You may need administrator rights if you want this new module
installed in the global library for your computer. On a Linux machine, you would
simply run the pip command with sudo. Otherwise, you can install it to your
personal library directory by adding the command line option ‘—user’.

“Every programming language out there has a
core set of functionality that everyone should
know in order to get useful work done. Python is
no different”

04

Executing a script

Importing a module does run the code
within the module file, but does it through the
module maintenance code within the Python
engine. This maintenance code also deals with
running initialising code. If you only wish to
take a Python script and execute the raw code
within the current session, you can use the
‘execfile(“filename.py”)’ command, where the
main option is a string containing the Python file
to load and execute. By default, any definitions
are loaded into the locals and globals of the
current session. You can optionally include
two extra parameters the execfile command.
These two options are both dictionaries, one
for a different set of locals and a different set of
globals. If you only hand in one dictionary, it is
assumed to be a globals dictionary. The return
value of this command is None.

05

An enhanced shell

The default interactive shell is provided
through the command ‘python’, but is
rather limited. An enhanced shell is provided by
the command ‘ipython’. It provides a lot of extra
functionality to the code developer. A thorough
history system is available, giving you access to
not only commands from the current session,
but also from previous sessions. There are also
magic commands that provide enhanced ways of
interacting with the current Python session. For
more complex interactions, you can create and use
macros. You can also easily peek into the memory
of the Python session and decompile Python code.
You can even create profiles that allow you to handle
initialisation steps that you may need to do every time
you use iPython.

06

Evaluating code

Sometimes, you may have chunks of
code that are put together programmatically. If
these pieces of code are put together as a string,
you can execute the result with the command
‘eval(“code_string”)’. Any syntax errors within
the code string are reported as exceptions. By
default, this code is executed within the current
session, using the current globals and locals
dictionaries. The ‘eval’ command can also take
two other optional parameters, where you can
provide a different set of dictionaries for the
globals and locals. If there is only one additional
parameter, then it is assumed to be a globals
dictionary. You can optionally hand in a code
object that is created with the compile command
instead of the code string. The return value of this
command is None.

The Python Book 17

07

Asserting values

At some point, we all need to debug
some piece of code we are trying to write. One
of the tools useful in this is the concept of an
assertion. The assert command takes a Python
expression and checks to see if it is true. If so,
then execution continues as normal. If it is not
true, then an AssertionError is raised. This way,
you can check to make sure that invariants
within your code stay invariant. By doing so,
you can check assumptions made within your
code. You can optionally include a second
parameter to the assert command. This second
parameter is Python expression that is executed
if the assertion fails. Usually, this is some type of
detailed error message that gets printed out. Or,
you may want to include cleanup code that tries
to recover from the failed assertion.

08

Mapping functions

A common task that is done in modern
programs is to map a given computation
to an entire list of elements. Python provides the
command ‘map()’ to do just this. Map returns a list of
the results of the function applied to each element of
an iterable object. Map can actually take more than
one function and more than one iterable object. If it
is given more than one function, then a list of tuples
is returned, with each element of the tuple containing
the results from each function. If there is more than
one iterable handed in, then map assumes that the
functions take more than one input parameter, so
it will take them from the given iterables. This has
the implicit assumption that the iterables are all of
the same size, and that they are all necessary as
parameters for the given function.

“While not strictly commands, everyone needs to
know how to deal with loops. The two main types
of loops are a fixed number of iterations loop (for)
and a conditional loop (while)”

10

Filtering

Where the command map returns a result for every element in an iterable, filter only returns a
result if the function returns a True value. This means that you can create a new list of elements where
only the elements that satisfy some condition are used. As an example, if your function checked that
the values were numbers between 0 and 10, then it would create a new list with no negative numbers
and no numbers above 10. This could be accomplished with a for loop, but this method is much
cleaner. If the function provided to filter is ‘None’, then it is assumed to be the identity function. This
means that only those elements that evaluate to True are returned as part of the new list. There are
iterable versions of filter available in the itertools module.

18 The Python Book

Virtualenvs

12

Reductions

Because of the potential complexity of
the Python environment, it is sometimes best to
set up a clean environment within which to install
only the modules you need for a given project. In
this case, you can use the virtualenv command
to initialise such an environment. If you create
a directory named ‘ENV’, you can create a new
environment with the command ‘virtualenv
ENV’. This will create the subdirectories bin, lib
and include, and populate them with an initial
environment. You can then start using this new
environment by sourcing the script ‘ENV/bin/
activate’, which will change several environment
variables, such as the PATH. When you are done,
you can source the script ‘ENV/bin/deactivate’
to reset your shell’s environment back to its
previous condition. In this way, you can have
environments that only have the modules you
need for a given set of tasks.

Loops

While not strictly commands, everyone needs
to know how to deal with loops. The two main
types of loops are a fixed number of iterations loop (for) and
a conditional loop (while). In a for loop, you iterate over some
sequence of values, pulling them off the list one at a time
and putting them in a temporary variable. You continue until
either you have processed every element or you have hit a
break command. In a while loop, you continue going through
the loop as long as some test expression evaluates to True.
While loops can also be exited early by using the break
command, you can also skip pieces of code within either
loop by using a continue command to selectively stop this
current iteration and move on to the next one.

11

09

In many calculations, one of the
computations you need to do is a reduction
operation. This is where you take some list of values
and reduce it down to a single value. In Python, you
can use the command ‘reduce(function, iterable)’ to
apply the reduction function to each pair of elements
in the list. For example, if you apply the summation
reduction operation to the list of the first five
integers, you would get the result ((((1+2)+3)+4)+5).
You can optionally add a third parameter to act as an
initialisation term. It is loaded before any elements
from the iterable, and is returned as a default if the
iterable is actually empty. You can use a lambda
function as the function parameter to reduce to keep
your code as tight as possible. In this case, remember
that it should only take two input parameters.

50 Python commands

is this?
16 What
Everything in Python is an object. You can
check to see what class this object is an instance
of with the command ‘isinstance(object, class)’.
This command returns a Boolean value.

it a subclass?
17 Is
The command ‘issubclass(class1, class2)’
checks to see if class1 is a subclass of class2. If
class1 and class2 are the same, this is returned
as True.

objects
18 Global
You can get a dictionary of the global
symbol table for the current module with the
command ‘globals()’.

objects
19 Local
You can access an updated dictionary
of the current local symbol table by using the
command ‘locals()’.

13

How true is a list?

In some cases, you may have collected a number of elements within a list that can be evaluated
to True or False. For example, maybe you ran a number of possibilities through your computation and
have created a list of which ones passed. You can use the command ‘any(list)’ to check to see whether
any of the elements within your list are true. If you need to check whether all of the elements are True,
you can use the command ‘all(list)’. Both of these commands return a True if the relevant condition is
satisfied, and a False if not. They do behave differently if the iterable object is empty, however. The
command ‘all’ returns a True if the iterable is empty, whereas the command ‘any’ returns a False when
given any empty iterable.

15
14

Enumerating

Sometimes, we need to label the elements
that reside within an iterable object with their
indices so that they can be processed at some later
point. You could do this by explicitly looping through
each of the elements and building an enumerated
list. The enumerate command does this in one line.
It takes an iterable object and creates a list of tuples
as the result. Each tuple has the 0-based index of
the element, along with the element itself. You can
optionally start the indexing from some other value
by including an optional second parameter. As an
example, you could enumerate a list of names with
the command ‘list(enumerate(names, start=1))’. In
this example, we decided to start the indexing at 1
instead of 0.

Casting

Variables in Python don’t have any type
information, and so can be used to store
any type of object. The actual data, however, is of
one type or another. Many operators, like addition,
assume that the input values are of the same type.
Very often, the operator you are using is smart
enough to make the type of conversion that is
needed. If you have the need to explicitly convert
your data from one type to another, there are a class
of functions that can be used to do this conversion
process. The ones you are most likely to use is ‘abs’,
‘bin’, ‘bool’, ‘chr’, ‘complex’, ‘float’, ‘hex’, ‘int’, ‘long’,
‘oct’, and ‘str’. For the number-based conversion
functions, there is an order of precedence where
some types are a subset of others. For example,
integers are “lower” than floats. When converting
up, no changes in the ultimate value should happen.
When converting down, usually some amount of
information is lost. For example, when converting
from float to integer, Python truncates the number
towards zero.

20 Variables
The command ‘vars(dict)’ returns writeable
elements for an object. If you use ‘vars()’, it
behaves like ‘locals()’.

a global
21 Making
A list of names can be interpreted as
globals for the entire code block with the
command ‘global names’.

22 Nonlocals
In Python 3.X, you can access names from
the nearest enclosing scope with the command
‘nonlocal names’ and bind it to the local scope.

23

Raising an exception

When you identify an error condition,
you can use the ‘raise’ command to throw up an
exception. You can include an exception type and
a value.

with an exception
24 Dealing
Exceptions can be caught in a try-except
construction. If the code in the try block raises an
exception, the code in the except block gets run.

methods
25 Static
You can create a statis method, similar
to that in Java or C++, with the command
‘staticmethod(function_name)’.

The Python Book 19

31

26

Ranges

You may need a list of numbers, maybe in
a ‘for’ loop. The command ‘range()’ can create an
iterable list of integers. With one parameter, it
goes from 0 to the given number. You can provide
an optional start number, as well as a step size.
Negative numbers count down.

27 Xranges
One problem with ranges is that all of the
elements need to be calculated up front and
stored in memory. The command ‘xrange()’ takes
the same parameters and provides the same
result, but only calculates the next element as it
is needed.

28 Iterators
Iteration is a very Pythonic way of doing

With modules

The ‘with’ command provides the ability to
wrap a code block with methods defined
by a context manager. This can help clean up code
and make it easier to read what a given piece of
code is supposed to be doing months later. A classic
example of using ‘with’ is when dealing with files.
You could use something like ‘with open(“myfile.
txt”, “r”) as f:’. This will open the file and prepare it for
reading. You can then read the file in the code block
with ‘data=f.read()’. The best part of doing this is that
the file will automatically be closed when the code
block is exited, regardless of the reason. So, even if
the code block throws an exception, you don’t need to
worry about closing the file as part of your exception
handler. If you have a more complicated ‘with’
example, you can create a context manager class to
help out.

32

Printing

The most direct way of getting output
to the user is with the print command.
This will send text out to the console window. If you
are using version 2.X of Python, there are a couple
of ways you can use the print command. The most
common way had been simply call it as ‘print
“Some text”’. You can also use print with the same
syntax that you would use for any other function.
So, the above example would look like ‘print(“Some
text”)’. This is the only form available in version 3.X.
If you use the function syntax, you can add extra
parameters that give you finer control over this
output. For example, you can give the parameter
‘file=myfile.txt’ and get the output from the print
command being dumped into the given text file.
It also will accept any object that has some string
representation available.

“A classic example of using ‘with’ is when dealing
with files. The best part of doing this is that the
file will automatically be closed when the code
block is exited, regardless of the reason”

things. For objects which are not intrinsically
iterable, you can use the command ‘iter(object_
name)’ to essentially wrap your object and provide
an iterable interface for use with other functions
and operators.

lists
29 Sorted
You can use the command ‘sorted(list1)’
to sort the elements of a list. You can give it
a custom comparison function, and for more
complex elements you can include a key function
that pulls out a ranking property from each
element for comparison.

30

33
Summing items

Above, we saw the general reduction
function reduce. A specific type of reduction
operation, summation, is common enough to
warrant the inclusion of a special case, the
command ‘sum(iterable_object)’. You can include
a second parameter here that will provide a
starting value.

20 The Python Book

Memoryview

Sometimes, you need to access the raw data of some object, usually as a buffer of bytes. You
can copy this data and put it into a bytearray, for example. But this means that you will be using extra
memory, and this might not be an option for large objects. The command ‘memoryview(object_name)’
wraps the object handed in to the command and provides an interface to the raw bytes. It gives access
to these bytes an element at a time. In many cases, elements are the size of one byte. But, depending
on the object details, you could end up with elements that are larger than that. You can find out the size
of an element in bytes with the property ‘itemsize’. Once you have your memory view created, you can
access the individual elements as you would get elements from a list (mem_view[1], for example).

50 Python commands

34

Files

When dealing with files, you need to create a file object to interact with it. The file command takes
a string with the file name and location and creates a file object instance. You can then call the file object
methods like ‘open’, ‘read’ and ‘close’, to get data out of the file. If you are doing file processing, you can
also use the ‘readline’ method. When opening a file, there is an explicit ‘open()’ command to simplify the
process. It takes a string with the file name, and an optional parameter that is a string which defines the
mode. The default is to open the file as read-only (‘r’). You can also open it for writing (‘w’) and appending
(‘a’). After opening the file, a file object is returned so that you can further interact with it. You can then read
it, write to it, and finally close it.

35

Yielding

In many cases, a function may need to
yield the context of execution to some other
function. This is the case with generators. The preferred
method for a generator is that it will only calculate the
next value when it is requested through the method
‘next()’. The command ‘yield’ saves the current state of
the generator function, and return execution control
to the calling function. In this way, the saved state of
the generator is reloaded and the generator picks up
where it left off in order to calculate the next requested
value. In this way, you only need to have enough memory
available to store the bare minimum to calculate the
next needed value, rather than having to store all of the
possible values in memory all at once.

37

36

Weak references

39

Threads

You sometimes need to have a reference
to an object, but still be able to destroy it if
needed. A weak reference is one which can
be ignored by the garbage collector. If the only
references left to n object are weak references,
then the garbage collector is allowed to destroy
that object and reclaim the space for other
uses. This is useful in cases where you have
caches or mappings of large datasets that
don’t necessarily have to stay in memory. If an
object that is weakly referenced ends up being
destroyed and you try to access it, it will appear
as a None. You can test for this condition and
then reload the data if you decide that this is a
necessary step.

Pickling data

There are a few different ways of
serialising memory when you need to checkpoint
results to disk. One of these is called pickling.
Pickle is actually a complete module, not just a
single command. To store data on to the hard
drive, you can use the dump method to write
the data out. When you want to reload the same
data at some other point in the future, you can
use the load method to read the data in and
unpickle it. One issue with pickle is its speed, or
lack of it. There is a second module, cPickle, that
provides the same basic functionality. But, since
it is written in C, it can be as much as 1000 times
faster. One thing to be aware of is that pickle does
not store any class information for an object,
but only its instance information. This means
that when you unpickle the object, it may have
different methods and attributes if the class
definition has changed in the interim.

38

Shelving data

While pickling allows you save data and
reload it, sometimes you need more structured
object permanence in your Python session. With the
shelve module, you can create an object store where
essentially anything that can be pickled can be stored
there. The backend of the storage on the drive can be
handled by one of several systems, such as dbm or
gdbm. Once you have opened a shelf, you can read and
write to it using key value pairs. When you are done, you
need to be sure to explicitly close the shelf so that it is
synchronised with the file storage. Because of the way
the data may be stored in the backing database, it is
best to not open the relevant files outside of the shelve
module in Python. You can also open the shelf with
writeback set to True. If so, you can explicitly call the
sync method to write out cached changes.

You can do multiple threads of execution
within Python. The ‘thread()’ command can create a
new thread of execution for you. It follows the same
techniques as those for POSIX threads. When you first
create a thread, you need to hand in a function name,
along with whatever parameters said function needs.
One thing to keep in mind is that these threads behave
just like POSIX threads. This means that almost
everything is the responsibility of the programmer. You
need to handle mutex locks (with the methods ‘acquire’
and ‘release’), as well as create the original mutexes
with the method ‘allocate_lock’. When you are done,
you need to ‘exit’ the thread to ensure that it is properly
cleaned up and no resources get left behind. You also
have fine-grained control over the threads, being able
to set things like the stack size for new threads.

The Python Book 21

50 Python commands

40

Inputting data

Sometimes, you need to collect input
from an end user. The command ‘input()’ can
take a prompt string to display to the user, and
then wait for the user to type a response. Once
the user is done typing and hits the enter key, the
text is returned to your program. If the readline
module was loaded before calling input, then
you will have enhanced line editing and history
functionality. This command passes the text
through eval first, and so may cause uncaught
errors. If you have any doubts, you can use the
command ‘raw_input()’ to skip this problem. This
command simply returns the unchanged string
inputted by the user. Again, you can use the
readline module to get enhanced line editing.

41

Internal variables

For people coming from other programming languages, there is a concept of having certain variables
or methods be only available internally within an object. In Python, there is no such concept. All elements of an
object are accessible. There is a style rule, however, that can mimic this type of behaviour. Any names that start
with an underscore are expected to be treated as if they were internal names and to be kept as private to the
object. They are not hidden, however, and there is no explicit protection for these variables or methods. It is up to
the programmer to honour the intention from the author the class and not alter any of these internal names. You
are free to make these types of changes if it becomes necessary, though.

43
42

Comparing objects

There are several ways to compare objects within Python, with several caveats. The first is that
you can test two things between objects: equality and identity. If you are testing identity, you are testing
to see if two names actually refer to the same instance object. This can be done with the command
‘cmp(obj1, obj2)’. You can also test this condition by using the ‘is’ keyword. For example, ‘obj1 is obj2’. If
you are testing for equality, you are testing to see whether the values in the objects referred to by the
two names are equal. This test is handled by the operator ‘==’, as in ‘obj1 == obj2’. Testing for equality
can become complex for more complicated objects.

22 The Python Book

Slices

While not truly a command, slices are
too important a concept not to mention in this
list of essential commands. Indexing elements
in data structures, like lists, is one of the most
common things done in Python. You can select a
single element by giving a single index value. More
interestingly, you can select a range of elements by
giving a start index and an end index, separated by
a colon. This gets returned as a new list that you can
save in a new variable name. You can even change
the step size, allowing you to skip some number of
elements. So, you could grab every odd element from
the list ‘a’ with the slice ‘a[1::2]’. This starts at index 1,
continues until the end, and steps through the index
values 2 at a time. Slices can be given negative index
values. If you do, then they start from the end of the
list and count backwards.

50 Python commands

“Python is an interpreted language, which means
that the source code that you write needs to be
compiled into a byte code format. This byte code
then gets fed into the actual Python engine”

46

__init__ method

When you create a new class, you can
include a private initialisation method that
gets called when a new instance of the class is
created. This method is useful when the new
object instance needs some data loaded in the
new object.

method
47 __del__
When an instance object is about to be
destroyed, the __del__ method is called. This
gives you the chance to do any kind of cleanup
that may be required. This might be closing files,
or disconnecting network connections. After this
code is completed, the object is finally destroyed
and resources are freed.

44

Lambda expressions

Since objects, and the names that point to them, are truly different things, you can have objects
that have no references to them. One example of this is the lambda expression. With this, you can create
an anonymous function. This allows you use functional programming techniques within Python. The
format is the keyword ‘lambda’, followed by a parameter list, then a colon and the function code. For
example, you could build your own function to square a number with ‘lambda x: x*x’. You can then have a
function that can programmatically create new functions and return them to the calling code. With this
capability, you can create function generators to have self-modifying programs. The only limitation is
that they are limited to a single expression, so you can’t generate very complex functions.

45

Compiling
code objects

Python is an interpreted
language, which means that the source
code that you write needs to be compiled
into a byte code format. This byte code
then gets fed into the actual Python engine
to step through the instructions. Within your program, you may
have the need to take control over the process of converting
code to byte code and running the results. Maybe you wish to
build your own REPL. The command ‘compile()’ takes a string
object that contains a collection of Python code, and returns
an object that represents a byte code translation of this code. This
new object can then be handed in to either ‘eval()’ or ‘exec()’ to be actually
run. You can use the parameter ‘mode=’ to tell compile what kind of code is being
compiled. The ‘single’ mode is a single statement, ‘eval’ is a single expression and
‘exec’ is a whole code block.

48

Exiting your program

There are two pseudo-commands
available to exit from the Python interpreter:
‘exit()’ and quit()’. They both take an optional
parameter which sets the exit code for the
process. If you want to exit from a script, you are
better off using the exit function from the sys
module (‘sys.exit(exit_code)’.

values
49 Return
Functions may need to return some value
to the calling function. Because essentially no
name has a type, this includes functions. So
functions can use the ‘return’ command to return
any object to the caller.

50

String concatenation

We will finish with what most lists start
with – string concatenation. The easiest way to
build up strings is to use the ‘+’ operator. If you
want to include other items, like numbers, you
can use the ‘str()’ casting function to convert it to
a string object.

The Python Book 23

Python

Essentials

26$PEFSPDL QBQFS TDJTTPST
1VUCBTJDDPEJOHJOUPBDUJPO

321SPHSBNBIBOHNBOHBNF
6TF1ZUIPOUPNBLFUIFDMBTTJDHBNF

381MBZQPLFSEJDF

5FTUZPVSMVDLBOEZPVSDPEJOH

44$SFBUFBHSBQIJDBMJOUFSGBDF
"EEJOUFSGBDFUPZPVSQSPKFDUT

50#SJOHHSBQIJDTUPHBNFT
"EEJNBHFTUPTJNQMFHBNFT

56#VJMEBOBQQGPS"OESPJE
.BLFZPVSPXOBQQXJUI,JWZ

62.BLJOHXFCBQQT

6TF1ZUIPOUPDSFBUFPOMJOFBQQT

661ZUIPOUJQT

&TTFOUJBMLOPXMFEHFGPS1ZUIPOVTFST

44

245IF1ZUIPO#PPL

i(FUUPHSJQTXJUI1ZUIPO
BOETUBSUCVJMEJOHPOUIFCBTJDTw
5IF1ZUIPO#PPL25

Python essentials

Allow the Python script
to run in a terminal,
and outside the IDE
Human input in the form
of integers is used for
comparing moves and,
ultimately, playing the game
Use deduction to
determine one of
three outcomes
Loop the code over
again and start
from the beginning

Append to integer
variables to keep track
of scores and more

Code a game of
rock, paper, scissors

Learn how to do some basic Python coding by following
our breakdown of a simple rock, paper, scissors game

Resources
Python 2: www.python.org/download
IDLE: www.python.org/idle

26 The Python Book

This tutorial will guide you through making
a rock, paper, scissors game in Python. The
code applies the lessons from the masterclass –
and expands on what was included there – and
doesn’t require any extra Python modules to run,
like Pygame.
Rock, paper, scissors is the perfect game to
show off a little more about what exactly Python
can do. Human input, comparisons, random
selections and a whole host of loops are used in
making a working version of the game. It’s also

easy enough to adapt and expand as you see
fit, adding rules and results, and even making a
rudimentary AI if you wish.
For this particular tutorial, we also
recommend using IDLE. IDLE is a great Python
IDE that is easily obtainable in most Linux
distributions and is available by default on
Raspbian for Raspberry Pi. It helps you by
highlighting any problems there might be with
your code and allows you to easily run it to make
sure it’s working properly.

Python essentials

01

This section imports the extra Python
functions we’ll need for the code – they’re
still parts of the standard Python libraries, just
not part of the default environment

02

The initial rules of the game are created
here. The three variables we’re using and
their relationship is defined. We also provide a
variable so we can keep score of the games

03

We begin the game code by defining the
start of each round. The end of each play
session comes back through here, whether we
want to play again or not

04

The game is actually contained all in
here, asking for the player input, getting
the computer input and passing these on to get
the results. At the end of that, it then asks if you’d
like to play again

05

Player input is done here. We give the
player information on how to play this
particular version of the game and then allow
their choice to be used in the next step. We also
have something in place in case they enter an
invalid option

06

There are a few things going on when we
show the results. First, we’re putting in a
delay to add some tension, appending a variable
to some printed text, and then comparing what
the player and computer did. Through an if
statement, we choose what outcome to print,
and how to update the scores

07

We now ask for text input on whether
or not someone wants to play again.
Depending on their response, we go back to the
start, or end the game and display the results

The Python Book 27

Python essentials

The breakdown

01

We need to start with the path to the
Python interpreter here. This allows
us to run the program inside a terminal or
otherwise outside of a Python-specific IDE
like IDLE. Note that we’re also using Python 2
rather than Python 3 for this particular script,
which needs to be specified in the code to
make sure it calls upon the correct version
from the system.

02

We’re importing two extra modules on
top of the standard Python code so
we can use some extra functions throughout
the code. We’ll use the random module to
determine what move the computer will throw,
and the time module to pause the running of
the code at key points. The time module can
also be used to utilise dates and times, either
to display them or otherwise.

03

05

06

We’re setting each move to a specific
number so that once a selection is
made by the player during the game, it will be
equated to that specific variable. This makes
the code slightly easier later on, as we won’t
need to parse any text for this particular
function. If you so wish, you can add additional
moves, and this will start here.

01

02

03

04
05
06

04

Here we specify the rules for the game,
and the text representations of each
move for the rest of the code. When called upon,
our script will print the names of any of the three
moves, mainly to tell the player how the computer
moved. These names are only equated to these
variables when they are needed – this way, the
number assigned to each of them is maintained
while it’s needed.

Python modules
There are other modules you can import with
basic Python. Some of the major ones are
shown to the right. There are also many more
that are included as standard with Python.

28 The Python Book

Similar to the way the text names of
the variables are defined and used only
when needed, the rules are done in such a way
that when comparing the results, our variables
are momentarily modified. Further down in the
code we’ll explain properly what’s happening,
but basically after determining whether or
not there’s a tie, we’ll see if the computer’s
move would have lost to the player move. If the
computer move equals the losing throw to the
player’s move, you win.

Very simply, this creates a variable that
can be used throughout the code to
keep track of scores. We need to start it at zero
now so that it exists, otherwise if we defined
it in a function, it would only exist inside that
function. The code adds a point to the computer
or player depending on the outcome of the round,
although we have no scoring for tied games in
this particular version.

string

Perform common string operations

datetime and calendar

Other modules related to time

math

Advanced mathematical functions

json

JSON encoder and decoder

pydoc

Documentation generator and online help system

Python essentials

07

Here we define the actual beginning of the code, with the function
we’ve called ‘start’. It’s quite simple, printing our greeting to the
player and then starting a while loop that will allow us to keep playing the
game as many times as we wish. The pass statement allows the while loop
to stop once we’ve finished, and could be used to perform a number of other
tasks if so wished. If we do stop playing the game, the score function is then
called upon – we’ll go over what that does when we get to it.

08

We’ve kept the game function fairly simple so we can break down
each step a bit more easily in the code. This is called upon from the
start function, and first of all determines the player move by calling upon
the move function below. Once that’s sorted, it sets the computer move. It
uses the random module’s randint function to get an integer between one
and three (1, 3). It then passes the player and computer move, stored as
integers, onto the result function which we use to find the outcome.

07

08

09

10

09

We start the move function off by putting it into
a while loop. The whole point of move is to obtain
an integer between one and three from the player, so the
while loop allows us to account for the player making an
unsupported entry. Next, we are setting the player variable
to be created from the player’s input with raw_input. We’ve
also printed instruction text to go along with it. The ‘\n’ we’ve
used in the text adds a line break; this way, the instructions
appear as a list.

10

The try statement is used to clean up code and
handle errors or other exceptions. We parse what the
player entered by turning it into an integer using int(). We use
the if statement to check if it is either 1, 2, or 3 – if it is, move
returns this value back up to the game function. If it throws
up a ValueError, we use except to do nothing. It prints an error
message and the while loop starts again. This will happen
until an acceptable move is made.

The code in action

The Python Book 29

Python essentials

11

The result function only takes the variables
player and computer for this task, which is
why we set that in result(player, computer). We’re
starting off by having a countdown to the result.
The printed numbers are self-explanatory, but
we’ve also thrown in sleep from the time module
we imported. Sleep pauses the execution of the

code by the number of seconds in the brackets.
We’ve put a one-second pause between counts,
then half a second after that to show the results.

12

To print out what the computer threw,
we’re using string.format(). The {0} in the
printed text is where we’re inserting the move,
which we have previously defined as numbers.
Using names[computer], we’re telling the code to

look up what the text version of the move is called
from the names we set earlier on, and then to
insert that where {0} is.

13

Here we’re simply calling the scores we
set earlier. Using the global function
allows for the variable to be changed and used
outside of the variable, especially after we’ve
appended a number to one of their scores.

11

12
13
14
15

16

14

The way we’re checking the result is
basically through a process of elimination.
Our first check is to see if the move the player
and computer used were the same, which is the
simplest part. We put it in an if statement so that
if it’s true, this particular section of the code ends
here. It then prints our tie message and goes back
to the game function for the next step.

15

If it’s not a tie, we need to keep checking,
as it could still be a win or a loss. Within
the else, we start another if statement. Here,
we use the rules list from earlier to see if the
losing move to the player’s move is the same
as the computer’s. If that’s the case, we print
the message saying so, and add one to the
player_score variable from before.

16

If we get to this point, the player has lost.
We print the losing message, give the
computer a point and it immediately ends the
result function, returning to the game function.

30 The Python Book

The code in action

Python essentials

17

The next section of game calls upon
a play_again function. Like the move
function, we have human input, asking the player
if they would like to play again via a text message
with raw_input, with the simple ‘y/n’ suggestion in
an attempt to elicit an expected response.

18

Giving users an option of y/n like we have
should expect a response in kind. The
if statement checks to see if any of our defined
positive responses have been entered. As Python
doesn’t differentiate between upper or lower
case, we’ve made sure that it accepts both y and
Y. If this is the case, it returns a positive response
to game, which will start it again.

19

If we don’t get an expected response, we
will assume the player does not want to
play again. We’ll print a goodbye message, and
that will end this function. This will also cause
the game function to move onto the next section
and not restart.

17
18
19

20

21

ELIF
IF also has the ELIF (else if) operator, which can
be used in place of the second IF statement
we employed. It’s usually used to keep code
clean, but performs the same function.

20

Going back to the start function, after
game finishes we move onto the results.
This section calls the scores, which are integers,
and then prints them individually after the names
of the players. This is the end of the script, as far
as the player is concerned. Currently, the code
won’t permanently save the scores, but you can
have Python write it to a file to keep if you wish.

21

The final part allows for the script to
be used in two ways. Firstly, we can
execute it in the command line and it will work
fine. Secondly, we can import this into another
Python script, perhaps if you wanted to add it as
a game to a collection. This way, it won’t execute
the code when being imported.

The code in action

The Python Book 31

Python essentials

This section imports the extra Python
functions we’ll need for the code –
they’re still parts of the standard
Python libraries, just not part of the
default environment

We’re again providing variables so we
can keep score of the games played,
and they’re updated each round

Our very basic graphics involve ASCII
art of the game’s stages, printed out
after every turn

Program a
game of
Hangman

#!/usr/bin/env python2

Code listing

from random import *
player_score = 0
computer_score = 0
def hangedman(hangman):
graphic = [
“””
+-------+
|
|
|
|
|
==============
“””,
“””
+-------+
|
|
|
O
|
|
|
===============
“””,
“””

“””,
“””
+-------+
|
|
|
O
|
-||
/ \
|
===============
“””]
print graphic[hangman]
return

Learn how to do some more Python
coding by following our breakdown of a
simple Hangman game

Resources
Python 2: www.python.org/download
IDLE: www.python.org/idle

32 The Python Book

One of the best ways to get to know Python is
by building lots of simple projects so you can
understand a bit more about the programming
language. This time round, we’re looking at
Hangman, a multi-round game relying on if
and while loops and dealing with strings of text
in multiple ways. We’ll be using some of the
techniques we implemented last time as well, so
we can build upon them.
Hangman still doesn’t require the Pygame
set of modules, but it’s a little more advanced

than rock-paper-scissors. We’re playing
around with a lot more variables this time.
However, we’re still looking at comparisons,
random selections and human input, along
with splitting up a string, editing a list and even
displaying rudimentary graphics.
You should continue to use IDLE for these
tutorials. As we’ve mentioned before, its builtin debugging tools are simple yet effective and
it can be used on any Linux system, as well as
the Raspberry Pi.

Python essentials

The actual game starts here, with a while loop to
let you continually play the game until you decide
otherwise, then ending the program

The game rules are decided here, as well as the
setup for the word and keeping track of tries and
incorrect answers

Each round of the game is played here, asking for
an input, then telling you if you were correct or not.
It prints out the graphic and changes any variables
that need to be updated, especially incorrect and
correct guesses

After each round, the code checks if you’ve won or
lost yet – the win condition being that you guessed
the word, or losing if you’ve made six guesses

def start():
print “Let’s play a game of Linux Hangman.”
while game():
pass
scores()

Code listing continued

def game():
dictionary = [“gnu”,”kernel”,”linux”,”mageia”,”penguin”,”ubuntu”]
word = choice(dictionary)
word_length = len(word)
clue = word_length * [“_”]
tries = 6
letters_tried = “”
guesses = 0
letters_right = 0
letters_wrong = 0
global computer_score, player_score
while (letters_wrong != tries) and (“”.join(clue) != word):
letter=guess_letter()
if len(letter)==1 and letter.isalpha():
if letters_tried.find(letter) != -1:
print “You’ve already picked”, letter
else:
letters_tried = letters_tried + letter
first_index=word.find(letter)
if first_index == -1:
letters_wrong +=1
print “Sorry,”,letter,”isn’t what we’re looking for.”
else:
print”Congratulations,”,letter,”is correct.”
for i in range(word_length):
if letter == word[i]:
clue[i] = letter
else:
print “Choose another.”
hangedman(letters_wrong)
print “ “.join(clue)
print “Guesses: “, letters_tried

The human input for the game takes the letter
and turns it into something the code can use. It’s
verified in the previous block of code and then
referred back to if you’ve entered an unsupported
or already used character

The same class as last time, which allows you to
select whether or not you wish to play again

Upon quitting the game, scores are given for the
duration of the play session. We also end the script
with the if __name__ code like before

if letters_wrong == tries:
print “Game Over.”
print “The word was”,word
computer_score += 1
break
if “”.join(clue) == word:
print “You Win!”
print “The word was”,word
player_score += 1
break
return play_again()
def guess_letter():
print
letter = raw_input(“Take a guess at our mystery word:”)
letter.strip()
letter.lower()
print
return letter
def play_again():
answer = raw_input(“Would you like to play again? y/n: “)
if answer in (“y”, “Y”, “yes”, “Yes”, “Of course!”):
return answer
else:
print “Thank you very much for playing our game. See you next time!”

Code highlighting
IDLE automatically highlights the code to make
reading your work that bit easier. It also allows
you to change these colours and highlighting in
IDLE’s Preferences, in case you’re colour blind
or are just used to a different colour scheme
in general.

def scores():
global player_score, computer_score
print “HIGH SCORES”
print “Player: “, player_score
print “Computer: “, computer_score
if __name__ == ‘__main__’:
start()

The Python Book 33

Python essentials

I see ASCII
Here’s a close-up of the seven
stages we’ve used for Hangman’s
graphics. You can change them
yourself, but you need to make
sure the quote marks are all in
the correct place so that the art
is considered a text string to be
printed out.
“””
+-------+
|
|
|
|
|
==============
“””,
“””
+-------+
|
|
|
O
|
|
|
===============
“””,
“””
+-------+
|
|
|
O
|
|
|
|
===============
“””,
“””
+-------+
|
O
|
-|
|
|
|
===============
“””,
“””
+-------+
|
|
|
O
|
-||
|
===============
“””,
“””
+-------+
|
|
|
O
|
-||
/
|
===============
“””,
“””
+-------+
|
|
|
O
|
-||
/ \
|
===============
“””]

34 The Python Book

01 #!/usr/bin/env python2

The rules
Although we’ve moved some of
the rules to the ‘game’ function
this month, you can always put
them back here and call upon
them using the global variable, as
we would do with the scores. For
the words, you could also create a
separate file and import them like
the random module.

02 from random import *
03 player_score = 0

computer_score = 0

04 def hangedman(hangman):

graphic = [
“””
+-------+
|
|
|
|
|
==============
“””,
“””
05 def start():

print “Let’s play a game of Linux Hangman.”
while game():
pass
scores()

01

We begin by using this line to enter the path
to the Python interpreter. This allows us to
run the program inside a terminal or otherwise outside
of a Python-specific IDE like IDLE. Note that we’re
also using Python 2 for this particular script, as it is
installed by default on most Linux systems and will
therefore ensure compatibility.

02

We’re importing the ‘random’ module slightly
differently this time, importing the actual
names of the functions from random rather than just
the module itself. This allows us to use the functions
without having syntax like random.function. The
asterisk imports all the functions from random,
although you can switch that for specific names of
any of random’s functions. We’ll be using the random
function to select a word for the player to guess.

03

Very simply, this creates a variable that can
be used throughout the code to keep track
of scores. We need to start it at zero now so that it
exists; otherwise if we defined it in a function, it would

only exist inside that function. The code adds a point
to the computer or player depending on the outcome
of the round.

04

Our simple graphics consist of a series of
ASCII hanging man stages. We’re storing
these in a function as a list of separate string objects
so we can call upon them by passing on the number of
incorrect guesses to it. There are seven graphics in all,
like in the pen-and-paper version. We also include the
print command with the function, so when it’s called it
will completely handle the selection and display of the
hanging man, with the first one being printed after the
first letter is guessed.

05

Here we define the actual beginning of the
code, with the function we’ve called ‘start’.
It’s quite simple, printing our greeting to the player
and then starting a while loop that will allow us to keep
playing the game as many times as we wish. The pass
statement allows the while loop to stop once we’ve
finished, and could be used to perform a number

Python essentials

06 def game():

dictionary = [“gnu”,”kernel”,”linux”,”mageia”,”penguin”,”ubuntu”] 07
word = choice(dictionary)
word_length = len(word)
clue = word_length * [“_”]
08 tries = 6
letters_tried = “”
guesses = 0
letters_right = 0
letters_wrong = 0
global computer_score, player_score
09 while (letters_wrong != tries) and (“”.join(clue) != word):
letter=guess_letter() 10

if len(letter)==1 and letter.isalpha():
if letters_tried.find(letter) != -1:
print “You’ve already picked”, letter
of other tasks if so wished. If we do stop playing the
game, the score function is then called upon –we’ll go
over what that does when we get to it.

06

We have put a majority of the game code
in the ‘game’ function this time around, as
there’s not as much that needs to be split up. You can
split it up further if you wish, using the style of code
from last issue, if it would make the code cleaner
for you or help you understand the building blocks a
bit more.

07

The first four lines quickly set up the word
for the player to guess. We’ve got a small
selection of words in a list here. However, these can be
imported via HTML or expanded upon. Choice is used
to select a random element from the list, which comes
from the random module we imported. Finally, we
ascertain how long the string is of the word to guess,
and then create the clue variable with a number of
underscores of that length. This is used to display the
word as you build it up from guesses.

08

We start to set up the rules and the individual
variables to keep track of during the game.
There can only be six incorrect guesses before the
hanging man is fully drawn, or in our case displayed,
so we set the tries variable to six. We’ll keep track of
the letters through letters_tried to make sure that not
only will the player know, but also the code for when

it’s checking against letters already played. Finally,
we create empty variables for the number of guesses
made, letters correct and letters incorrect, to make
the code slightly easier. We also import the global
scores here.

09

We’re starting a while loop to perform the
player selection and check the status of the
game. This loop continues until the player wins or loses.
It starts by checking if all the tries have been used up
by seeing if letters_wrong is not equal to tries. As each
try will only add one point to wrong, it will never go
above six. It then concatenates ‘clue’ and sees if it’s the
same as the word the computer selected. If both these
statements are true, it goes on to the next turn.

Indentations
While IDLE will keep track of the
indents in the code, if you’re using
a text editor to write some Python,
you’ll have to make sure you’re
using them correctly. Python is
very sensitive to whether or not
indents are used correctly, and it
does aid in readability as well.

10

We call upon the function we’re using to
input a letter and give it the variable ‘letter’.
We check what it returns by first of all making sure
it’s only a single letter, with len(letter), then by
using isalpha to see if it’s one of the 26 letters of the
alphabet. If these conditions are satisfied, we start
a new if statement to make sure it’s a new guess,
and tell the player if it’s already been chosen so they
can start again. If all this is acceptable, we move on
to the next section of the code to see if it’s a correct
guess or not.

The Python Book 35

Python essentials

Continuation

11 else:

This code is still part of the
game function we started on the
previous page, so make sure your
indentations are in alignment if
you’re not using an IDE. If you plan
to split this code up, we’d suggest
starting with the word selection
and results.

letters_tried = letters_tried + letter
first_index=word.find(letter)
if first_index == -1:
letters_wrong +=1
print “Sorry,”,letter,”isn’t what we’re looking for.”
else:
print”Congratulations,”,letter,”is correct.” 12
for i in range(word_length):
13
if letter == word[i]:
clue[i] = letter
else:
print “Choose another.” 14
hangedman(letters_wrong)
print “ “.join(clue)
print “Guesses: “, letters_tried
15 if letters_wrong == tries:

print “Game Over.”
print “The word was”,word
computer_score += 1
break
if “”.join(clue) == word:
print “You Win!”
print “The word was”,word
player_score += 1
break
return play_again() 16
elimination, we first print out a message to let
the player know that they’ve been successful and
then make a record of it.

11

If it’s a new letter that we find acceptable,
the first thing we do is add it to the list
of letters tried. This is done simply by adding
the strings together. We then use the find
command to search the word string for the letter
entered, which will then return a number of the
placement of the letter in the string. If it doesn’t
find the letter, it returns a -1 value, which we use
in the next if statement to see if the first_index
variable is -1. If so, it adds one to the number of
letters_wrong and then prints a message to let
the player know that it was an incorrect guess.

12

If we’ve got this far and the letter is not
incorrect, than we can only assume
it is correct. Through this simple process of

36 The Python Book

13

We’re going to start a small loop here so
we can update the clue with the correct
letter we’ve added. We use the range function to
tell the code how many times we wish to iterate
over the clue by using the word_length variable.
We then check to see which letter in the word
has been guessed correctly and change that
specific part of the clue to be that letter so it can
be printed out for the player to see, and for us to
check whether or not the game is over.

14

We end the original if statement by telling
the player to choose again if they did not
enter a supported input. Before we go on to the
next round of choices, we print out the hanging

man graphic as it stands, by calling the graphic
in the list that corresponds to the number of
incorrect guesses that have been made. We then
print how the clue currently looks, with a space
in between each character, and then print the
number of guesses that have been made.

15

Here we check to see if the game is
over again, first of all comparing the
letters_wrong to the number of tries. If that’s
true, we print a message that the game has
ended and reveal the mystery of the hidden word.
We increase the computer’s score and break the
loop. The next loop checks to see if the full clue
concatenated is the same as the original word – if
that’s the case, we print the win message, the full
word and add one point to the player score before
breaking the loop again. This can also be done
with ifs and elifs to avoid using breaks.

Python essentials

17

def guess_letter():
print
letter = raw_input(“Take a guess at our mystery word:”)
letter.strip()
letter.lower()
print
return letter

18

def play_again():
answer = raw_input(“Would you like to play again? y/n: “)
19 if answer in (“y”, “Y”, “yes”, “Yes”, “Of course!”):
return answer
20 else:
print “Thank you very much for playing our game. See you next time!”

21

def scores():
global player_score, computer_score
print “HIGH SCORES”
print “Player: “, player_score
print “Computer: “, computer_score
22 if __name__ == ‘__main__’:

start()

16

We end the entire game function loop by
calling upon return again, which we will
then pass all the way up to the start function once
it’s finished.

17

The human input function first of
all prints out a raw_input message.
Once the player enters the letter, the function
parses it to be used with the rest of the code.
Firstly, strip is used to remove any white space
from the input given, as we’ve not given it any
extra parameters. We then convert it into
lower-case letters, as Python will not be able
to correctly compare an upper-case character
with a lower-case alternative. We then print the
selection for the record and return it up to the
game function.

18

The last part of the game function is to
ask the player if they wish to try again.
The play_again function takes a human input
with a simple message and then analyses the
input so it knows what to send back.

19

Giving users an option of y/n like we
have should expect a response in kind.
The if statement checks to see if any of our
defined positive responses have been entered.
As Python doesn’t differentiate between upper
or lower case, we’ve made sure it accepts both
y and Y. If this is the case, it returns a positive
response to game, which will start it again.

20

If we don’t get an expected response,
we will assume the player does
not want to play again. We’ll print a goodbye
message and that will end this function. This
will also cause the start function to move onto
the next section and not restart.

21

Going all the way back to the start
function, after game finishes we move
onto the results. This section is quite simple – it
calls the scores, which are integers, and then
prints them individually after the names of the
players. This is the end of the script, as far as
the player is concerned. Currently, the code will

Homework
Now that you’ve finished with the code, why
not make your own changes? Increase the
word count; create different, selectable word
categories; or even let people guess the full
word. You have all the tools to do this in the
current code and last month’s tutorial.

not permanently save the scores, but you can
have Python write it to a file to keep if you wish.

22

The final part of the code allows for
the script to be used in two ways.
Firstly, we can execute it in the command line
and it will work fine. Secondly, we can import
this into another Python script, perhaps if
you wanted to add it as a game to a collection.
This way, it will not execute the code when
being imported.

The Python Book 37

Python essentials

Play poker dice using Python
Put on your poker face and get ready to gamble as you hone
your programming skill with a bit of poker dice

Resources
Python 2: www.python.org/download
IDLE: www.python.org/idle

So you’ve learnt how to program tic-tac-toe
and guessed your way to victory at hangman.
Now it’s time to head to Las Vegas and play our
cards right. Or in this case, virtual dice, and more
like Reno as we continue with our Python game
tutorials and introduce you to some poker dice.
We’re again using some of the lessons we’ve
already learnt, including random number
generation, list creation and modification,
human input, rule setting, scoring and more.
But we’ll also be adding some new skills in this

tutorial. Namely, we’ll be creating and appending
lists with random numbers, and using functions
multiple times in one block of code to cut down
on bloat.
Again, we recommend using IDLE, and we’re
using Python 2 to ensure compatibility with a
wider variety of distros, including the Raspberry
Pi. So, we hope luck is a lady for you and that the
odds are ever in your favour – just keep those
fingers crossed that you don’t roll a snake eyes
(we are coding in Python, after all)!

The Start
Here we’re doing some minor setups so we can
get our code to run with some extra modules not
included with the basics

#!/usr/bin/env python2

The Rules

nine = 1
ten = 2
jack = 3
queen = 4
king = 5
ace = 6

We’re setting names for each dice roll so they can
be properly identified to the player – much more
interesting than numbers

The Score
Again we’ve got some basic variables set up so we
can keep score of the games if we want to

Code listing

import random
from itertools import groupby

names = { nine: “9”, ten: “10”, jack: “J”, queen: “Q”, king: “K”, ace: “A” }
player_score = 0
computer_score = 0

The Script
The game is handled here, passing the player onto
the next function to actually play, and handling the
end of the session as well

The Game

def start():
print “Let’s play a game of Linux Poker Dice.”
while game():
pass
scores()

We access the full game loop via here, and the
function that allows us to play again if we’re
so inclined

def game():
print “The computer will help you throw your 5 dice”
throws()
return play_again()

The Throw

def throws():
roll_number = 5
dice = roll(roll_number)
dice.sort()
for i in range(len(dice)):
print “Dice”,i + 1,”:”,names[dice[i]]

The initial hand is dealt, so to speak, at the start of
the throws function. This function handles all the
decision making in the game, while passing off the
dice rolls to another function

The Hand
We’ve also got a special function so we can inform
the player exactly what style of hand they have

The Decision
There are two rounds in this version of poker
dice, and you can select how many dice you wish
to re-roll in this small while loop that makes sure
you’re also using a correct number

38 The Python Book

result = hand(dice)
print “You currently have”, result
while True:
rerolls = input(“How many dice do you want to throw again? “)
try:
if rerolls in (1,2,3,4,5):
break
except ValueError:
pass
print “Oops! I didn’t understand that. Please enter 1, 2, 3, 4 or 5.”

Python essentials

The Re-roll
We’re doing the second set of rolls and starting
the end of the game here by calling on the same
function as before, but we’re also aware that
choosing no re-rolls means the end of the game

The Dice
Here we’re finding out which dice the player wants
to re-roll, and also making sure that they enter
a valid number. Just so they know they’re doing
something, we print something after every turn

Second Hand
We change and display the new dice hand to end
the game. Again, we make sure to tell the player
what the actual hand they have is

Code listing continued

if rerolls == 0:
print “You finish with”, result
else:
roll_number = rerolls
dice_rerolls = roll(roll_number)
dice_changes = range(rerolls)
print “Enter the number of a dice to reroll: “
iterations = 0
while iterations < rerolls:
iterations = iterations + 1
while True:
selection = input(“”)
try:
if selection in (1,2,3,4,5):
break
except ValueError:
pass
print “Oops! I didn’t understand that. Please enter 1, 2, 3, 4 or 5.”
dice_changes[iterations-1] = selection-1
print “You have changed dice”, selection
iterations = 0
while iterations < rerolls:
iterations = iterations + 1
replacement = dice_rerolls[iterations-1]
dice[dice_changes[iterations-1]] = replacement
dice.sort()
for i in range(len(dice)):
print “Dice”,i + 1,”:”,names[dice[i]]

The Rolls
The function we reuse to roll our virtual six dice
using a simple while loop. This allows us to keep
the codebase smaller

The Analysis
There are eight possible types of hands in poker
dice, and we can use a bit of logic to work out all
but one of them without checking against all 7,776
outcomes – in fact, we only specifically have to
check for two

The Question
Our simple ‘play again’ function that parses player
input so we can restart or end the script

The End
Scores are displayed at the end of the script, and
the very final part allows us to import this into
other Python scripts as a module

EXTRA FUNCTIONS
Splitting up actions into functions
makes it easier to not only perform
them multiple times, but reduce
the amount of code. On larger
projects, this can aid with speed.

result = hand(dice)
print “You finish with”, result
def roll(roll_number):
numbers = range(1,7)
dice = range(roll_number)
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
dice[iterations-1] = random.choice(numbers)
return dice
def hand(dice):
dice_hand = [len(list(group)) for key, group in groupby(dice)]
dice_hand.sort(reverse=True)
straight1 = [1,2,3,4,5]
straight2 = [2,3,4,5,6]
if dice == straight1 or dice == straight2:
return “a straight!”
elif dice_hand[0] == 5:
return “five of a kind!”
elif dice_hand[0] == 4:
return “four of a kind!”
elif dice_hand[0] == 3:
if dice_hand[1] == 2:
return “a full house!”
else:
return “three of a kind.”
elif dice_hand[0] == 2:
if dice_hand[1] == 2:
return “two pair.”
else:
return “one pair.”
else:
return “a high card.”
def play_again():
answer = raw_input(“Would you like to play again? y/n: “)
if answer in (“y”, “Y”, “yes”, “Yes”, “Of course!”):
return answer
else:
print “Thank you very much for playing our game. See you next time!”
def scores():
global player_score, computer_score
print “HIGH SCORES”
print “Player: “, player_score
print “Computer: “, computer_score
if __name__ == ‘__main__’:
start()

The Python Book 39

1ZUIPOFTTFOUJBMT

01

#!/usr/bin/env python2

02

import random
from itertools import groupby

03

nine = 1
ten = 2
jack = 3
queen = 4
king = 5
ace = 6

RECYCLING
There are a few variables that
have duplicates throughout the
code – while we’ve been careful
to make sure they work where
we want them to, it’s not the best
code conduct. The names of the
variables don’t specifically matter
– it’s just best to label them in a
way you understand for bug fixing
and others to read.

names = { nine: “9”, ten: Ŏ10ŏ, jack: “J”, queen: ŎQŏ, king: “K”, ace: “A” }
04

player_score = 0
computer_score = 0

05

def start():
print ŎLetās play a game of Linux Poker Dice.ŏ
while game():
pass
scores()

06

def game():
print ŎThe computer will help you throw your 5 diceŏ
throws()
return play_again()

01

Begin

As before, we use this line to enter the
path to the Python interpreter. This allows us to
run the program inside a terminal or otherwise
outside of a Python-specific IDE like IDLE. Note
that we’re also using Python 2 for this script.

these as we go. While it’s not specifically used
in this version of the code, it’s easy enough
to expand on it and add your own simple
computer roll, or limited AI for both rolls.

05

Start

Game

02

Importing

As well as importing the random module
for our dice throws, we need to get the groupby
function so we can order the dice in a way that is
more readable and also easier for analysis when
telling the player what hand they have.

We’re starting the interactive part of the
code with the ‘start’ function. It prints a greeting
to the player, then starts a while loop that’ll allow
us to replay the game as many times as we wish.
The pass statement allows the while loop to stop
once we’ve finished. If we do stop playing the
game, the score function is then called upon.

03

Cards

06

While we’re using random numbers for
the dice rolls, unless we assign the correct cards
to each number, the player won’t know what
they’ve rolled and what constitutes a better
hand. We set each card to a number and then
equate what these should be printed out as.

04

Scores

As usual, we have the empty scores
for the player and computer so we can update

405IF1ZUIPO#PPL

Like our Rock, Paper, Scissors code,
def game pawns the rest of the game onto other
functions, with its main function allowing us to
keep repeating the game by passing the player
through to the play_again function.

07

it later with a different number that the player
chooses. We get five random numbers in a list
returned from the function, and we order it using
sort to make it a bit more readable for the player
and also later on for the hand function.

08

Dice display

09

Current hand

We print out each dice, numbering them
so the player knows which dice is which, and
also giving it the name we set at the start of the
script. We’re doing this with a loop that repeats
itself the number of times as the dice list is
long using the range(len(dice)) argument. The
i is increased each turn, and it prints out that
specific number of the dice list.

We want to find the type of hand the
player has multiple times during the game, so set
a specific function to find out. We pass the series
of dice we have on to this function, and print.

Throws

For our first throw, we want to have five
random dice. We’ve set a variable here to pass
on to our throwing function, allowing us to reuse

10

Throw again

Before we can throw the dice for the
second round, we need to know which dice the

1ZUIPOFTTFOUJBMT

07

def throws():
roll_number = 5
dice = roll(roll_number)
dice.sort()
for i in range(len(dice)):
08
print ŎDiceŏ,i + 1,ŏ:ŏ,names[dice[i]]

Watch the indentations again as
we split the else function. The
following page’s code is on the
same level as roll roll_number,
dice_rerolls and dice_changes in
the code.

09

result = hand(dice)
print ŎYou currently haveŏ, result

10

while True:
rerolls = input(ŎHow many dice do you want to throw again? Ŏ)
try:
if rerolls in (1,2,3,4,5):
break
except ValueError:
pass
print ŎOops! I didnāt understand that. Please enter 1, 2, 3, 4 or 5.ŏ
if rerolls == 0:
print ŎYou finish withŏ, result
else:
roll_number = rerolls
dice_rerolls = roll(roll_number)
WHITE SPACE
dice_changes = range(rerolls)
The big if function at the end of
print ŎEnter the number of a dice to reroll: Ŏ
throws doesn’t have many line
iterations = 0
breaks between sections – you
while iterations < rerolls:
can add these as much as you want
to break up the code into smaller
iterations = iterations + 1
chunks visually, aiding debugging.
while True:
selection = input(Ŏŏ)
try:
if selection in (1,2,3,4,5):
break
except ValueError:
pass
print ŎOops! I didnāt understand that. Please enter 1, 2, 3, 4 or 5.ŏ
13
dice_changes[iterations-1] = selection-1
print ŎYou have changed diceŏ, selection

11
12

player wants to roll again. We start this by asking
them how many re-rolls they want to do, which
allows us to create a custom while loop to ask
the user which dice to change that iterates the
correct number of times.
We also have to make sure it’s a number
within the scope of the game, which is why
we check using the try function, and print out
a message which tells the user if and how they
are wrong.

11

INDENTATIONS

Stick

One of the things we’ve been trying to do
in these tutorials is point out how logic can cut
down on a lot of coding by simply doing process

of eliminations or following flow charts. If the
user wants to re-roll zero times, then that means
they’re happy with their hand, and it must be the
end of the game. We print a message to indicate
this and display their hand again.

12

The re-rolls

Here’s where we start the second roll
and the end of the game, using a long else to the
if statement we just started. We first of all make
sure to set our variables – updating roll_number
to pass onto the roll function with the re-roll
number the user set, and creating the list that’s
the exact length of the new set of rolls we wish to
use thanks to range(rerolls).

13

Parse

We ask the player to enter the numbers
of the dice they wish to re-roll. By setting an
iterations variable, we can have the while loop
last the same number of times as we want rerolls by comparing it to the reroll variable itself.
We check each input to make sure it’s a number
that can be used, and add the valid choices to the
dice_changes list. We use iterations-1 here as
Python lists begin at 0 rather than 1. We also print
out a short message so the player knows the
selection was successful.

5IF1ZUIPO#PPL41

Python essentials

14

15

iterations = 0
while iterations < rerolls:
iterations = iterations + 1
replacement = dice_rerolls[iterations-1]
dice[dice_changes[iterations-1]] = replacement

HIGHER OR LOWER
Which hand is best? What are the
odds of getting certain hands in
the game? Some of the answers
are surprising, as the poker
hands they’re based on trump the
differing odds the dice produce.
We’ve ranked hands from highest
to lowest.

dice.sort()
for i in range(len(dice)):
print “Dice”,i + 1,”:”,names[dice[i]]

Five of a Kind ................. 6/7776
Four of a Kind ............150/7776
Full House .................300/7776
Straight ......................240/7776
Three of a Kind ........1200/7776
Two Pairs .................1800/7776
One Pair ...................3600/7776
High Card ...................480/7776

result = hand(dice)
print “You finish with”, result
16

14

def roll(roll_number):
numbers = range(1,7)
dice
= range(roll_number)
17
iterations = 0
while iterations < roll_number:
18
iterations = iterations + 1
dice[iterations-1] = random.choice(numbers)
return dice

New dice

We’re resetting and reusing the iterations
variable to perform a similar while loop to update
the rolls we’ve done to the original dice variable.
The main part of this while loop is using the
iterations-1 variable to find the number from
dice_changes list, and using that to change that
specific integer in the dice list with the number
from the replacement list. So if the first item on
the dice_changes list is two, then the second
item on the dices list is changed to the number
we want to replace it with.

15

Sorting

We’re ending the throw function in
basically the same way we ended the first throw.
First of all, we re-sort the dice list so that all the
numbers are in ascending order. Then we print
out the final cards that the dice correspond to,
before again passing it onto the hand function
so that we can fully determine the hand that the
player has. We print out this result and that ends
the function, sending the whole thing back to the
game function to ask if you want to play again.

16

Dice rolling

The roll function is used twice in the
code for both times that we roll the dice. Being
able to use the same code multiple times means

42 The Python Book

we can cut down on bloat in the rest of the
script, allowing it to run a little faster, as we’ve
explained. It also means in this case that we can
use it again if you want to change the game to
three rounds, or modify it for real poker.

17

Number of rolls

We begin the whole thing by bringing
over the roll_number variable into the function
– this is because while in the original roll it will
always be five, the second roll could between
one and the full five dice. We create a list with
the number of entries we need for each roll, and
again set an iterations variable for the upcoming
while loop.

18

Remember

Much like the while loops in the rest of the
code so far, we’re keeping it going until iterations
is the same as roll_number. Each entry in the
dice list is replaced with a random number using
the random.choice function and keeping it in the
range of the numbers variable, which is one to
six for each side of the dice. After this is done, we
return the dice variable to the throw function that
makes up the majority of the game.

19

Hand analysis

While not technically a hand of cards,
the poker terminology still applies. We start in
this function by setting up a few things. The first
part uses the groupby function we imported –

this is used in this case to count the numbers
that make up the dice variable. If there are three
twos, a four and a five, it will return [3, 1, 1]. We’re
using this to ascertain what kind of hand the
player has. As the output of this groupby won’t
be in any specific order, we use the sort function
again to sort it; however, this time we use the
reverse=TRUE argument to make the analysis
easier again.

20

Straights

Straights and high cards are odd ones
out in poker dice, as they do not rely on being
able to count any repetitions in the cards.
There are, however, only two hands that create
a straight in poker dice, so we have created
two lists here that contain them. We can then
check first to see if the dice make these hands,
and then if all other checks fail, it has to be a
high card.

21

Your hand

While seemingly lengthy, this a fairly
simple if statement. As we stated before, we
check to see if it’s one of the two straight hands.
As there are no flushes or royal straight flushes
in poker dice, we don’t have to worry about those.
We then check to see if the first item in the list
is five, which can only result in five of a kind;
similarly, if the first item is four then the hand
must be four of a kind. If the first number is three,
then it can be either a full house or three of a kind,

Python essentials

19

def hand(dice):
dice_hand = [len(list(group)) for key, group in groupby(dice)]
dice_hand.sort(reverse=True)
straight1 = [1,2,3,4,5]
20
straight2 = [2,3,4,5,6]
21

if dice == straight1 or dice == straight2:
return “a straight!”
elif dice_hand[0] == 5:
return “five of a kind!”
elif dice_hand[0] == 4:
return “four of a kind!”
elif dice_hand[0] == 3:
if dice_hand[1] == 2:
return “a full house!”
else:
return “three of a kind.”
elif dice_hand[0] == 2:
if dice_hand[1] == 2:
return “two pair.”
else:
return “one pair.”
else:
return “a high card.”

TEXT EDITORS
Instead of the IDE we’ve suggested, you
should also try coding in a text editor. Some
of them are a little more lightweight and
format code similar to the way the IDE does,
separating functions and strings by colours
etc. Some of the ones we’d recommend are
the classic gedit, a popular text editor from
GNOME desktops; Geany, which has a few
IDE-esque features written into it; TEA, a
multifunctioning text editor and project
manager; and Jedit, a text editor that lives
in the command line for minimum resource
usage. These can also be used with multiple
programming languages, so you can get used
to them with Python, then make the switch.

22

def play_again():
answer = raw_input(“Would you like to play again? y/n: “)
if answer in (“y”, “Y”, “yes”, “Yes”, “Of course!”):
return answer
else:
print “Thank you very much for playing our game. See you next time!”

23

def scores():
global player_score, computer_score
print “HIGH SCORES”
print “Player: “, player_score
print “Computer: “, computer_score

24

if __name__ == ‘__main__’:
start()

so we nest an if statement. Again, we do this for
pairs, where that could be one or two pairs. If all
else fails then, by a process of elimination, it can
only be a high card. We give each outcome a text
string to send back to the throw function so that it
can be printed.

22

HOMEWORK
There is currently no scoring in
place for this version of the game.
Try adding a computer player, or
create a rule set that requires a
certain hand or higher. You could
even make it two-player.

Play again

As before, we ask the player for raw input
with the text offering another game. Instead of
parsing it, we assume the player will choose a
specified yes response based on the text, and if
none of these versions is received, we print out

the message thanking them for playing the game.
This ends the game function.

23

Final scores

Going all the way back to the start
function, after the game finishes we move onto
the results. This section is quite simple – it
calls the scores, which are integers, and then
prints them individually after the names of the
players. This is the end of the script, as far as the
player is concerned. Currently, the code will not
permanently save the scores, but you can have
Python write it to a file to keep if you wish.

24

Modules

The final part of the code allows for
the script to be used in two ways. Firstly, we
can execute it in the command line and it will
work just fine. Secondly, we can import this into
another Python script, perhaps if you wanted to
add it as a game to a collection. This last piece of
code will prevent our script being executed when
imported by another module – it will only do so
when being run directly.

The Python Book 43

Python essentials

Create a graphical interface
for Python games
Bring everything together with a Python GUI and take the next
step in programming your own software

Resources
Python 2: www.python.org/download
IDLE: www.python.org/idle

The three basic games we have made in
Python so far have all run in the command line
or via IDLE, a Python IDE. While this allowed us
to show off different ways to use Python code,
we haven’t actually shown you how to present
it yet. In this tutorial, we will take all three
games and put them all into one neatly unified
graphical interface.
To this end, we’ll be making use of the small
line of code we added at the bottom of each
previous tutorial so we can import them as

The start
Here we’re doing some minor setup, including getting a new
module that helps us create a simple graphical interface

The imports
We’re importing the three games we created in past issues so
we can call upon or use them

The window
Create a graphical window and give it a name so we can add
some functions to it

The frame
Define the dimensions of the window and give a rough guide to
placement of the objects within

The welcome
Print a message in the window and place it in a specific
orientation. This works a little differently to print

The button
The focus of this month’s tutorial is making Rock-PaperScissors work in a graphical interface, so we’re calling a new
function we’re creating

The interface
Creating and formatting buttons to start the other two tutorial
games in the command line or shell

#!/usr/bin/env python2

modules into our main graphical script. We’ll
also modify the existing code to add some
graphical elements. To do all this we’ll be using
Tkinter, a default module available in Python
that allows you to create windows and frames
with fairly simple code.
All you need for this tutorial is an up-to-date
copy of Python, from your distro’s repository
or the website, and the IDLE development
environment. This will also work great on
Raspberry Pi distros, such as Raspbian.

Main Interface Code Listing

#Linux User & Developer presents: Mega Microgrames Collection
from Tkinter import *
import rockpaperscissors
import hangman
import pokerdice
root = Tk()
root.title (“Linux User & Developer’s Mega Microgames Collection”)
mainframe = Frame(root, height = 200, width = 500)
mainframe.pack_propagate(0)
mainframe.pack(padx = 5, pady = 5)
intro = Label(mainframe, text = “””Welcome to Linux User & Developers Mega
Microgames Collection.
Please select one of the following games to play:
“””)
intro.pack(side = TOP)
rps_button = Button(mainframe, text = “Rock, Paper, Scissors”, command =
rockpaperscissors.gui)
rps_button.pack()
hm_button = Button(mainframe, text = “Hangman”, command = hangman.start)
hm_button.pack()

The exit
Here we create a button that quits the window and ends
the script. We’ve also placed it specifically at the bottom of
the window

pd_button = Button(mainframe, text = “Poker Dice”, command = pokerdice.start)
pd_button.pack()

The loop

exit_button = Button(mainframe, text = “Quit”, command = root.destroy)
exit_button.pack(side = BOTTOM)

The mainloop allows the main window to continue to work and
be updated without exiting the program unless specified

root.mainloop()

44 The Python Book

Python essentials

New imports
Import new modules that allow us to create the GUI
part of Rock, Paper, Scissors, as well as removing
the modules we no longer need

New interface
Our new main function allows us to call the
majority of the game script when the rps_button is
pressed. This contains the game components and
the graphical components

New start
We’ve changed the start function so that it no
longer goes to the score function after it’s finished.
We’ve also removed the score function, as we track
that differently so it can be displayed properly

New game

Modified RPS Code Listing
#!/usr/bin/env python2
# Linux User & Developer presents: Rock, Paper, Scissors: The Video Game: The Module
from Tkinter import *
from ttk import *
import random
def gui():
rock = 1
paper = 2
scissors = 3
names = { rock: “Rock”, paper: “Paper”, scissors: “Scissors” }
rules = { rock: scissors, paper: rock, scissors: paper }
def start():
while game():
pass

We’ve changed the game function so that it now
takes the input from our graphical interface. We
use a new variable to do this that works with the
GUI, otherwise it works roughly the same as before

def game():
player = player_choice.get()
computer = random.randint(1, 3)
computer_choice.set(names[computer])
result(player, computer)

New results

def result(player, computer):
new_score = 0
if player == computer:
result_set.set(“Tie game.”)
else:
if rules[player] == computer:
result_set.set(“Your victory has been assured.”)
new_score = player_score.get()
new_score += 1
player_score.set(new_score)
else:
result_set.set(“The computer laughs as you realise you have been defeated.”)
new_score = computer_score.get()
new_score += 1
computer_score.set(new_score)

The result function remains largely unchanged,
only now it sends the outcome message to a
variable we use for the interface, and generally
uses the new GUI’s variables

New window
We create the game window with a slightly different
method due to already having a ‘mainloop’ root
window. We’re also giving it a name so you can
identify it properly

New variables
Our new variables are set up so they can interact with
both the game code and the interface code properly.
We’ve also made sure to have a default selection for
the player so that the code runs properly

rps_window = Toplevel()
rps_window.title (“Rock, Paper, Scissors”)

New frame

player_choice = IntVar()
computer_choice = StringVar()
result_set = StringVar()
player_choice.set(1)
player_score = IntVar()
computer_score = IntVar()

Determine the size and layout of the window for
the game using a slightly different method than
before. We’ve also allowed for elements to be
anchored in certain positions around the window

rps_frame = Frame(rps_window, padding = ‘3 3 12 12’, width = 300)
rps_frame.grid(column=0, row = 0, sticky=(N,W,E,S))
rps_frame.columnconfigure(0, weight=1)
rps_frame.rowconfigure(0,weight=1)

New choice
Here we place radio buttons in a specific
configuration in the window, giving the user the
choice of three moves. This is then passed along to
the variable and used by the game code

New move
Here we allow for the computer’s move to be
displayed under the ‘Computer’ label

New button
Pressing the Play button we’ve put here runs the
game script, prints out the scores and finally a
message based on the outcome

New ending
We’ve changed this so that the main script begins
with gui now rather than the start function

Label(rps_frame, text=’Player’).grid(column=1, row = 1, sticky = W)
Radiobutton(rps_frame, text =’Rock’, variable = player_choice, value = 1).grid(column=1,
row=2, sticky=W)
Radiobutton(rps_frame, text =’Paper’, variable = player_choice, value = 2).grid(column=1,
row=3, sticky=W)
Radiobutton(rps_frame, text =’Scissors’, variable = player_choice, value =
3).grid(column=1, row=4, sticky=W)
Label(rps_frame, text=’Computer’).grid(column=3, row = 1, sticky = W)
Label(rps_frame, textvariable = computer_choice).grid(column=3, row=3, sticky = W)
Button(rps_frame, text=”Play”, command = start).grid(column = 2, row = 2)
Label(rps_frame, text = “Score”).grid(column = 1, row = 5, sticky = W)
Label(rps_frame, textvariable = player_score).grid(column = 1, row = 6, sticky = W)
Label(rps_frame, text = “Score”).grid(column = 3, row = 5, sticky = W)
Label(rps_frame, textvariable = computer_score).grid(column = 3, row = 6, sticky = W)
Label(rps_frame, textvariable = result_set).grid(column = 2, row = 7)
if __name__ == ‘__main__’:
gui()

The Python Book 45

1ZUIPOFTTFOUJBMT

01

#!/usr/bin/env python2

MAIN WINDOW
The main interface window that
this code creates is fairly basic,
but contains the functions we
require. The window exit button
will do the same job as the Quit
button, and the Hangman and
Poker Dice buttons run the old
scripts in the Python shell.

#Linux User & Developer presents: Mega Microgrames Collection
02

from Tkinter import *

03

import rockpaperscissors
import hangman
import pokerdice

04

root = Tk()
root.title (ŎLinux User & Developerās Mega Microgames Collectionŏ)

05

mainframe = Frame(root, height = 200, width = 500)
mainframe.pack_propagate(0)
mainframe.pack(padx = 5, pady = 5)

06

intro = Label(mainframe, text = ŎŏŏWelcome to Linux User & Developers Mega Microgames Collection.
Please select one of the following games to play:
Ŏŏŏ)
intro.pack(side = TOP)

07

rps_button = Button(mainframe, text = ŎRock, Paper, Scissorsŏ, command = rockpaperscissors.gui)
rps_button.pack()

08

hm_button = Button(mainframe, text = ŎHangmanŏ, command = hangman.start)
hm_button.pack()
pd_button = Button(mainframe, text = ŎPoker Diceŏ, command = pokerdice.start)
pd_button.pack()

09

exit_button = Button(mainframe, text = ŎQuitŏ, command = root.destroy)
exit_button.pack(side = BOTTOM)
root.mainloop()

01

First line

We use this line to enter the path to the
Python interpreter. This lets us run the program
inside a terminal or otherwise outside of a
Python-specific IDE like IDLE. Note that we’re
also using Python 2 for this particular script.

02

Import graphics

03

Import games

Tkinter is the graphical interface we’re
using and while it’s a standard Python function,
you’ll need to import the module so you can use it.
We’ve used the ‘from [module] import *’ method
so that we can use the functions from it without
having to add Tkinter at the beginning.

We’re importing the modules for the
three games. We added the line at the bottom

465IF1ZUIPO#PPL

of each script so we can do this. To make sure
to differentiate the functions in each game, we
will have to specify [module].[function] so there
are no errors in the code.

04

Root window

it a minimum height and width in pixels. We
use pack_propogate to create the window, and
then make sure it’s the size that we’ve defined.
We’ve then used pack to pad the borders,
allowing the contents of the window to not
touch the sides of it.

Using the Tk() function creates the
window we’re going to be placing everything
into. We’ve decided to call it root for now;
however, you can call it anything you like, as
long as you’re consistent with it. We’ve also
named it using the title command from Tkinter
and a string of text.

06

Introductions

05

07

Rock, Paper, Scissors

Main frame

The first line has us set the variable
mainframe as a Frame in the interface. We’ve
attached it to root, the main window, and given

We create the intro variable as a label
that lives in the main frame. We give it text to
introduce the interface, using the triple quote
marks to have it go across multiple lines and
format better. We then use pack to display it, and
tell Tkinter to put it at the top of the interface.

We create a button for the Rock, Paper,
Scissors game using the Button function. We
attach to it the main frame, give it a label using

Python essentials

#!/usr/bin/env python2
# Linux User & Developer presents: Rock, Paper, Scissors: The Video Game: The Module
10
from Tkinter import *
from ttk import *
import random
def gui():

11

12

rock = 1
paper = 2
scissors = 3

PYTHON SHELL
Our other code will run in the shell
or via a command line in the same
way as before when the buttons
are pressed.

names = { rock: “Rock”, paper: “Paper”, scissors: “Scissors” }
rules = { rock: scissors, paper: rock, scissors: paper }
13

14

def start():
while game():
pass
def game():
player = player_choice.get()
computer = random.randint(1, 3)
computer_choice.set(names[computer])
result(player, computer)

text that appears on the button, and then have
it run a command. In this case, we use the
modified rockpapershotgun.py code that has a
gui function, hence rockpapershotgun.py. We
then use pack to place it in the window

08

Other games

For the other two games, the code is
mostly the same; however, we call upon the start
function in both of them. In the final interface,
this will cause the games to run in the shell or
command line as they’ve been running before.

09

Break the loop

The exit button works similarly to the
other buttons we’ve created, but instead it uses
the command root.destroy. This ends the loop
that we’ve created with root.mainloop(), which
allows the interface code to continue looping,
allowing us to continually use it. We place the
exit button at the bottom of the window with
‘side = BOTTOM’.

10

Game code

Nothing much has changed in the start of
this code, other than a few import changes. The
code for running it in the command line is still

there, and with a few modifications the code will
run independently of the main interface. We’ve
removed the time module, as we no longer need
it, and imported not only the Tkinter module,
but the ttk module. The ttk module allows us to
arrange the GUI in a grid, which will be slightly
easier to use and understand.

11

Game interface

One of the biggest changes we’re making
to this script is having it all contained in one
function, ‘def gui’. The interface code needs to
be put into a function, otherwise it will be run
during import. While we’ve chosen to put the
entirety of the code in a function, you can also
try just having the graphical interface code in
one. All our variables are kept in here so that
they still work properly.

12

Game variables

The variables are staying the same
so that we can do the same comparisons we
made in the original code. We’ve put them into
the function itself so that they don’t affect the
other imported code into the main interface –
and so that when calling just this function, we
don’t need to use global to bring them in.

13

Start function

14

Game function

We’ve removed the part that calls
the score function from the start function,
as we have the interface handle the scoring
now. It still calls upon the game function,
though, putting it into a loop so it can be
used continuously. This function is called by
the interface to begin the game by setting a
computer move and then comparing it to the
player’s choice.

The game function has had a few
modifications to make sure it works with
the interface. First of all, the player variable
is retried using get() on the special variable
we’ve created to contain the player choice.
We do a similar thing for the computer, using
‘set’ to change the variable in our interfacefriendly computer_choice value. We still use
the name variable to set the text that goes into
computer_choice. This then passes the player
and computer variables along in the same way
we did before.

The Python Book 47

Python essentials

15

def result(player, computer):
new_score = 0
if player == computer:
16
result_set.set(“Tie game.”)
else:
if rules[player] == computer:
result_set.set(“Your victory has been assured.”)
17
new_score = player_score.get()
new_score += 1
player_score.set(new_score)
else:
result_set.set(“The computer laughs as you realise you have been defeated.”)
18
new_score = computer_score.get()
new_score += 1
computer_score.set(new_score)
GAME WINDOW

19

rps_window = Toplevel()
rps_window.title (“Rock, Paper, Scissors”)

20

player_choice = IntVar()
computer_choice = StringVar()
result_set = StringVar()
player_choice.set(1)
player_score = IntVar()
computer_score = IntVar()

15

Result function

The result function still takes the same
two variables as before, which we set in the
game function. While technically we can use
the variables set up for the interface, these
are not pure integers and can cause an error if
not handled correctly. With that in mind, we’ve
created an empty new_score variable that we
can use to effectively clean the interface value
before adding it back into it.

16

Tie

The logic for determining the result is
the same as before. We first do the easy check –
whether or not the numeric value for the player
and computer variable is the same. What changes
this time is that, instead of printing the text,
we send the “Tie game” message to our result
variable using the set function from Tkinter.

17

Win

The if statement continues by seeing if
the player has won. Like before, we use the rules
we set to make the comparison for the code to

48 The Python Book

In its default state, the game
window will have rock selected
and no message will be displayed.
Once the player makes a move, the
message will be displayed at the
bottom and the computer’s move
will be printed. There’s no quit
button on this menu, but clicking
the window exit will bring you back
to the main interface.

make. We set the result_set like we did in the
tie game, with a different message to the user.
Finally, we set the new_score variable to be the
current player score, using the get function to
obtain it, plus one to the score, and then use
set again to put it back into the player_score
variable. We can’t use += with the player_score
variable, as it is not a standard variable.

18

Lose

This part of the overall if statement
works in the same way as before, by assuming
that if it isn’t a tie or a win, it’s a loss. Like the
new version of the win code, it then uses set
to change the message that will be displayed
to the player, and calls upon and changes
the computer score by putting it through the
new_score variable.

19

New window

As the original window is part of the
mainloop, we cannot have the window be
created using Tk() like in the main interface
code. As this window is coming off it, though,
we instead create it using Toplevel(). This
allows the window to run separately and on
top of the main window. We’ve also given

it a name, which will not change the main
window’s name in the process.

20

Interface variables

21

Game frame

Here is the reason we had to call and
change the variables in a different manner.
For Tkinter, we need to let the interface know
whether or not a variable is an integer or a text
value. IntVar and StringVar allow for these
respectively. We’ve also set the player_choice
variable to be one, which we have already set as
the choice for rock. This means there will at least
be a default choice when the game is started,
and it won’t cause an error.

We’ve created the frame for our
interface items slightly differently. Instead
of using the pack command in the main
interface, we’re using grid to make sure they’re
orientated in such a way that makes sense
for the user. Padding does just that, setting
up values to make sure the items in the frame
don’t touch the edge of the window. Using the
.grid command, we then create this frame.
The row and column variables allow for rows
and columns to be included in the structure of

Python essentials

21

rps_frame = Frame(rps_window, padding = ‘3 3 12 12’, width = 300)
rps_frame.grid(column=0, row = 0, sticky=(N,W,E,S))
rps_frame.columnconfigure(0, weight=1)
rps_frame.rowconfigure(0,weight=1)

22

Label(rps_frame, text=’Player’).grid(column=1, row = 1, sticky = W)
Radiobutton(rps_frame, text =’Rock’, variable = player_choice, value = 1).grid(column=1, row=2,
sticky=W)
Radiobutton(rps_frame, text =’Paper’, variable = player_choice, value = 2).grid(column=1, row=3,
sticky=W)
Radiobutton(rps_frame, text =’Scissors’, variable = player_choice, value = 3).grid(column=1,
row=4, sticky=W)

23

Label(rps_frame, text=’Computer’).grid(column=3, row = 1, sticky = W)
Label(rps_frame, textvariable = computer_choice).grid(column=3, row=3, sticky = W)

24

Button(rps_frame, text=”Play”, command = start).grid(column = 2, row = 2)
Label(rps_frame, text = “Score”).grid(column = 1, row = 5, sticky = W)
Label(rps_frame, textvariable = player_score).grid(column = 1, row = 6, sticky = W)

25

Label(rps_frame, text = “Score”).grid(column = 3, row = 5, sticky = W)
Label(rps_frame, textvariable = computer_score).grid(column = 3, row = 6, sticky = W)
Label(rps_frame, textvariable = result_set).grid(column = 2, row = 7)

23

if __name__ == ‘__main__’:
gui()

the window, and the sticky allows us to justify
items with specific directions – in this case top,
left, right and bottom justification. Finally, we
then make sure each column and row is treated
equally by giving them the same weighting, and
starting from zero.

a second label to display the actual move. We
do this by adding the textvariable option to
Label, and using the computer_choice variable
we updated earlier in the game function. This
merely prints the text from the names list and
justifies this to the left.

22

24

Player’s choice

We create a label for the player’s move
and assign it to a grid location, on the first row,
on the first column. We also justify it to the left
using ‘sticky = W’. We then add the radio buttons
for the player’s move, each on the same column
but the following row down. We give each choice
a name, then assign it to the player_choice
variable. We then make each choice have a
numerical value that corresponds to the moves
we’ve determined in the first set of rules.

23

Computer’s move

We display the computer move here.
First of all, we label what this is and then create

Press Play

The running of the code all hinges on
the Play button. It’s very simple: we put it in the
row between the Player and Computer move as
part of our three-column system; and it runs the
start function using the command option. Due to
the loop of the interface, we can keep pressing
this without needing to be asked to play again.
Simply exiting the window will go back to the
main interface window as well, meaning we do
not need a specific quit button.

25

Running score

computer. We label these the same way we’ve
done with labelling the Player and Computer
move, having them on a lower row but still in
the relevant columns. Below that, we use the
textvariable option again to get the numerical
score we assigned to the separate score
variable. Finally, we create another label to
display the message for the game’s outcome

26

End game

The final part of the code allows for
the script to be used by the main window, and
also allows for it to run on its own when used
in the command line or shell. You’ll need to
perform some modifications to make it run on
its own, such as making it the mainloop and not
a Toplevel window. However, it will run just fine
from both without the need to be launched from
the main interface.

We have two sets of scores to display
– one for the player and the other for the

The Python Book 49

Python essentials

Bring graphics to simple
Python games
Complete your trio of games with a graphical interface for the
hangman and poker dice code

Resources
Python 2: www.python.org/download
IDLE: www.python.org/idle

We have now created a simple selector for the
trio of Python games we made previously. This
interface was able to launch a GUI for our rock,
paper, scissors game, and run the other two in
the terminal. Now, we’re going to convert the
hangman and poker dice codes to work in a
similar way to rock, paper, scissors.
The trick with hangman comes in allowing
for a different type of input, text, and the ability
to have multiple rounds of the game. Tkinter
allows for text entry, and we rely a lot less on

1 Imported

Hangman Code Listing

Here we’re doing the
same minor setup,
including getting
the Tkinter module
that helps us create
a simple graphical
interface

from Tkinter import *
01 from ttk import *
from random import *
word = 0
02 word_length = 0
clue = 0

2 Words

03 def gui():

We’re keeping
our variables that
determine the word to
guess here so it can
be easily accessed
anywhere in the code

3 Function

global word, word_length, clue
dictionary = [“gnu”,”kernel”,”linux”,”magei
a”,”penguin”,”ubuntu”]
word = choice(dictionary)
04
word_length = len(word)
clue = word_length * [“_”]
tries = 6

Like last time, we’re
putting the majority of
our original code into a
new function, gui

4 Analysis
We select the word
and analyse it before
continuing on with the
rest of the code

05

5 Graphics
The hangedman
function is largely
unchanged, albeit with
new code to display
our ASCII graphics on
the interface

6 Guesses
We check the number
of mistakes made, and
call the guess_letter
function to check the
letter entered

50 The Python Book

‘while’ loops to play the game in its entirety.
Poker Dice needs to keep the dice analysis
code, and the option to change specific dice
using checkboxes.
We’ll be modifying a large amount of the
original code to fit in with the new graphical
scheme. This mainly involves cutting specific
parts and having the Tkinter-specific code
handle these itself. The code listings on these
pages include the modified code – we’ll discuss
the graphical part on the following pages.

06

def hangedman(hangman):
graphic = [
“””
+-------+
|
|
|
O
|
-||
/ \
|
===============
“””]
graphic_set = graphic[hangman]
hm_graphic.set(graphic_set)
def game():
letters_wrong = incorrect_guesses.get()
letter=guess_letter()
first_index=word.find(letter)
if first_index == -1:
letters_wrong +=1
incorrect_guesses.set(letters_
wrong)
else:
for i in range(word_length):

if letter == word[i]:
clue[i] = letter
hangedman(letters_wrong)
clue_set = “ “.join(clue)
word_output.set(clue_set)
if letters_wrong == tries:
result_text = “Game Over. The word
was “ + word
result_set.set(result_text)
new_score = computer_score.get()
new_score += 1
computer_score.set(new_score)
if “”.join(clue) == word:
result_text = “You Win! The word
was “ + word
result_set.set(result_text)
new_score = player_score.get()
new_score += 1
player_score.set(new_score)
def guess_letter():
letter = letter_guess.get()
letter.strip()
letter.lower()
return letter
def reset_game():
global word, word_length, clue
incorrect_guesses.set(0)
hangedman(0)
result_set.set(“”)
letter_guess.set(“”)
word = choice(dictionary)
word_length = len(word)
clue = word_length * [“_”]
new_clue = “ “.join(clue)
word_output.set(new_clue)
if __name__ == ‘__main__’:
gui()

Python essentials

1 More imports
We’ve added the new imported
modules we need to make Tkinter
work and keep the rest the same

Poker Dice Code Listing
01

2 Dice list
The list that holds the dice is kept
outside the main function so that it
can be accessed everywhere

02

3 Rolls
Same goes for the roll function.
It doesn’t specifically need to be
inside the gui function anyway

03

4 Decisions
The checkboxes in the graphical
code we’re going to create later will
give us numbers we can analyse for
the code. We retrieve these numbers
and check them to find out which
dice the user wishes to re-roll

05

def gui():
global dice
dice = roll(5)
dice.sort()
nine = 1
ten = 2
jack = 3
queen = 4
king = 5
ace = 6
names = { nine: “9”, ten: “10”, jack:
“J”, queen: “Q”, king: “K”, ace: “A” }
result = “You have “ + hand(dice)

If no dice have been selected to
re-roll, the hand output is changed
to show a final message

7 Re-roll
This part is almost the same as
before – a new set of dice are rolled
and then inserted into the list of dice
like before, then re-sorted to make
the hand analysis easier

8 More functions
The new gui function is the main
change to the Poker Dice code,
and as before includes the Tkinter
elements and other parts of the
original code

9 Game start

10 New hand
The new dice are named, analysed,
and everything is then set for the gui
to display the final outcome

11 Reset
Like with the hangman code, we
have a function to reset all the
variables, allowing you to start the
game again

08

04

6 No dice

A simple function that we can use to
activate the re-rolls of the dice

def roll(roll_number):
numbers = range(1,7)
dice = range(roll_number)
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
dice[iterations-1] = random.
choice(numbers)
return dice

07

def hand(dice):
dice_hand = [len(list(group)) for key,
group in groupby(dice)]
dice_hand.sort(reverse=True)
straight1 = [1,2,3,4,5]
straight2 = [2,3,4,5,6]
if dice == straight1 or dice ==
straight2:
return “a straight!”
elif dice_hand[0] == 5:
return “five of a kind!”
elif dice_hand[0] == 4:
return “four of a kind!”
elif dice_hand[0] == 3:
09
if dice_hand[1] == 2:
return “a full house!”
else:
return “three of a kind.”
elif dice_hand[0] == 2:
if dice_hand[1] == 2:
return “two pair.”
else:
return “one pair.”
else:
return “a high card.”

5 Hands
Finally, our hand analysis function
is the last part of the original code
that is kept outside the gui function.
Both this and the above function
pass the necessary details back
up the chain to then be added into
the new graphical elements of the
new interface

from Tkinter import *
from ttk import *
import random
from itertools import groupby
dice = 0

06

def game():
throws()
def throws():

10

11

global dice
dice1_check = dice1.get()
dice2_check = dice2.get()
dice3_check = dice3.get()
dice4_check = dice4.get()
dice5_check = dice5.get()
dice_rerolls = [dice1_check,
dice2_check, dice3_check, dice4_check,
dice5_check]
for i in range(len(dice_rerolls)):
if 0 in dice_rerolls:
dice_rerolls.remove(0)
if len(dice_rerolls) == 0:
result = “You finish with “ +
hand(dice)
hand_output.set(result)
else:
roll_number = len(dice_rerolls)
number_rerolls = roll(roll_number)
dice_changes = range(len(dice_
rerolls))
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
dice_changes[iterations-1]
= number_rerolls[iterations-1]
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
replacement = number_
rerolls[iterations-1]
dice[dice_
changes[iterations-1]] = replacement
dice.sort()
new_dice_list = [0,0,0,0,0]
for i in range(len(dice)):
new_dice_list[i] =
names[dice[i]]
final_dice = “ “.join(new_dice_
list)
dice_output.set(final_dice)
final_result = “You finish with
“ + hand(dice)
hand_output.set(final_result)
def reset_game():
global dice
dice = roll(5)
dice.sort()
for i in range(len(dice)):
empty_dice[i] = names[dice[i]]
first_dice = “ “.join(empty_dice)
dice_output.set(first_dice)
result = “You have “ + hand(dice)
hand_output.set(result)
if __name__ == ‘__main__’:
gui()

The Python Book 51

1ZUIPOFTTFOUJBMT

accessed at all points in the code. Python 2 does
not allow you to call upon global variables when
you’re in a nested function, whereas in Python 3
this could have gone into the gui function.

#!/usr/bin/env python2

01

from Tkinter import *
from ttk import *
from random import *
word = 0
word_length = 0
clue = 0

02
03

def gui():
global word, word_length, clue
dictionary = [Ŏgnuŏ,ŏkernelŏ,ŏlinuxŏ,ŏmageiaŏ,ŏpenguinŏ,ŏubuntuŏ]
word = choice(dictionary)
04
word_length = len(word)
YOU LOSE
clue = word_length * [Ŏ_ŏ]
tries = 6
When you’ve run out of guesses,
the game stops. From here, you
def hangedman(hangman):
can also reset the game to play
graphic = [
again if you wish.
Ŏŏŏ
+-------+
|
|
|
O
05
|
-||
/ \
|
===============
Ŏŏŏ]
graphic_set = graphic[hangman]
hm_graphic.set(graphic_set)

06

01

def game():
letters_wrong = incorrect_guesses.get()
letter=guess_letter()
first_index=word.find(letter)
if first_index == -1:
letters_wrong +=1
incorrect_guesses.set(letters_wrong)
07
else:
for i in range(word_length):
if letter == word[i]:
clue[i] = letter
hangedman(letters_wrong)
clue_set = Ŏ Ŏ.join(clue)
08
word_output.set(clue_set)
if letters_wrong == tries:
result_text = ŎGame Over. The word was Ŏ + word
result_set.set(result_text)
new_score = computer_score.get()
new_score += 1
computer_score.set(new_score)
09
if Ŏŏ.join(clue) == word:
result_text = ŎYou Win! The word was Ŏ + word
result_set.set(result_text)
new_score = player_score.get()
new_score += 1
player_score.set(new_score)

First lines

As usual, we start off each program with
the code that lets us run it in the command line,
followed by importing the necessary modules:
random, to determine the word to use; Tkinter,
for the majority of the graphical code; and

525IF1ZUIPO#PPL

ttk, for the grid code we’ll be using to align the
different elements.

02

Global variables

We have kept these three variables
outside of the gui function so they can be

03

Graphical function

04

Random word

05

The hanged man

06

Games begin

07

Check the letter

08

Update interface

09

Update scores

We’re putting all the working code into
the gui function so it can be activated from the
main interface. This means we can import the
Hangman code into the interface without the
game window popping up, and only run it when
we activate the gui function from here.

We bring in the three variables with
global so we can modify them throughout
the code, and then set the word. As before, a
random item from the list of words is selected
with choice, the length is ascertained, and the
clue to display is set.

The main difference this time for the
Hangman graphics is that instead of printing
these out, we’re going to display them in the
interface. When the function is called and the
graphic selected, it’s placed in the variable we’ve
set up in the interface code that we’re using to
display the result.

All the analysis of the letter we’ve
entered is done in this function. To that end, we
start by obtaining the incorrect guesses so far
from the variable we’ve set up so the interface
can access it if we want it to. The letter from
the entry field in the interface is then obtained
and cleaned up so it can be used with the rest of
the code.

This section of the code is again largely
unchanged – the letter is taken and compared to
the word with find to see if it matches with one
of the letters. The if statement then adds one to
the incorrect guess variable, or updates the clue
variable to add the letter in the right spot.

These three lines set the graphic for this
round, join the current clue together as a string,
and then set it on the variable for the interface
to read.

Exactly as before, we check to see if the
player has won or lost yet. In the event of either,
a message is displayed to signify this, and the
wins and losses score is updated using set.

1ZUIPOFTTFOUJBMT

10

def guess_letter():
letter = letter_guess.get()
letter.strip()
letter.lower()
return letter
def reset_game():
global word, word_length, clue
incorrect_guesses.set(0)
hangedman(0)
result_set.set(“”)
letter_guess.set(“”)
word = choice(dictionary)
word_length = len(word)
clue = word_length * [Ŏ_ŏ]
new_clue = Ŏ Ŏ.join(clue)
word_output.set(new_clue)

11

12

13

ORIGINAL INTERFACE

THE HANGMAN GUI

You’ll also need the interface
code from last issue, which
already works with the modified
Rock, Paper, Scissors code. The
way it was left off means it won’t
work with the new code, so you’ll
have to change the command in
each button from [game].start
to [game].gui.

Press the updated Hangman
button to launch a new window.
Here we have the initial graphic,
word clue and entry for the player
to interact with. The scores
are set to zero, and no result
message is displayed as no
games have been played yet.

hm_window = Toplevel()
hm_window.title (ŎHangmanŏ)
incorrect_guesses = IntVar()
incorrect_guesses.set(0)
player_score = IntVar()
computer_score = IntVar()
result_set = StringVar()
letter_guess = StringVar()
word_output = StringVar()
hm_graphic = StringVar()
hm_frame = Frame(hm_window, padding = Ă3 3 12 12ā, width = 300)
hm_frame.grid(column=0, row = 0, sticky=(N,W,E,S))
hm_frame.columnconfigure(0, weight=1)
hm_frame.rowconfigure(0,weight=1)

14

Label(hm_frame, textvariable = hm_graphic).grid(column=2, row = 1)
Label(hm_frame, text=āWordā).grid(column=2, row = 2)
Label(hm_frame, textvariable = word_output).grid(column=2, row = 3)

15

Label(hm_frame, text=āEnter a letterā).grid(column=2, row = 4)
hm_entry = Entry(hm_frame, exportselection = 0, textvariable = letter_guess).grid(column = 2, row = 5)
hm_entry_button = Button(hm_frame, text = ŎGuessŏ, command = game).grid(column = 2, row = 6)

16

Label(hm_frame,
Label(hm_frame,
Label(hm_frame,
Label(hm_frame,
Label(hm_frame,
replay_button =

text = ŎWinsŏ).grid(column = 1, row = 7, sticky = W)
textvariable = player_score).grid(column = 1, row = 8, sticky = W)
text = ŎLossesŏ).grid(column = 3, row = 7, sticky = W)
textvariable = computer_score).grid(column = 3, row = 8, sticky = W)
textvariable = result_set).grid(column = 2, row = 9)
Button(hm_frame, text = ŎResetŏ, command = reset_game).grid(column = 2, row = 10)

if __name__ == Ă__main__ā:
gui()

10

Sanitise input

The guess_letter function purely gets
the letter from the player input variable, strips it
of any formatting, makes it lower case, and then
returns it back to the game function. This is so
the letter can be used properly.

11

New window

We use the Toplevel command from
Tkinter like last month to separate the loops of
the main interface and game window. We then
use title to call it Hangman.

12

Interface variables

Tkinter only works with specific variables
– we’ve created all the ones we need or can use
here. IntVars take integers, while StringVars take
strings. We’ve used get and set throughout the
rest of the code with these to get and set values.

The frame is set
up as before

13

Framed window

The frame is set up the same way as
last time. We pad the frame from the edge of
the window, set a grid, give it sticky points at
compass points, and allow for setting objects
with specific row and column points.

14

Clue to Hangman

These labels are fairly straightforward
– we’re either giving them fixed text, or telling
them to use a specific textvariable so they can
be updated as we play the game.

15

Text entry

16

Results and reset

Entry here sets a text box we will add the
letters to. The exportselection option makes it
so selecting the letter won’t immediately copy it
to the clipboard, and the textvariable selection
is where the code stores the letter added. The
button activates the game function, analysing
the letter the player entered.
The rest of the code is similar to what
we’ve done already: labels to display fixed text
and the scores/result text that change. The
button that activates the reset function is also
put at the bottom here. The final two lines allow
us to import the module into the interface code.

5IF1ZUIPO#PPL53

Python essentials

#!/usr/bin/env python2

17

Start over

The usual array of command-line
compatibility and module importing here. The
groupby function is specifically imported here
for dice analysis.

18

17
18

19

Dice rolls

20

Hand of dice

21

GUI start

22

First roll

As we’ve mentioned last month and in
the Hangman code, we put all the GUI code into
a function so that we can call on it when we want
to. In this case, pressing the Poker Dice button
on the main interface activates pokerdice.gui,
which is this function.
As the window opens, we immediately
make the first roll. This is then sorted, each
number is attributed to a card, and then the
result is created to be displayed in the main
window. This is similar to how it worked before,
but instead it’s now entered into the StringVars
for the interface towards the end of the script

23

20

def hand(dice):
dice_hand = [len(list(group)) for key, group in groupby(dice)]
dice_hand.sort(reverse=True)
straight1 = [1,2,3,4,5]
straight2 = [2,3,4,5,6]
if dice == straight1 or dice == straight2:
return “a straight!”
elif dice_hand[0] == 5:
return “five of a kind!”
elif dice_hand[0] == 4:
THE POKER DICE GUI
return “four of a kind!”
elif dice_hand[0] == 3:
Two things are being printed out
if dice_hand[1] == 2:
on the initial window. The first
return “a full house!”
set of dice, ordered in the way
else:
we did last time, and the current
return “three of a kind.”
hand. The checkboxes activate
elif dice_hand[0] == 2:
if dice_hand[1] == 2:
a specific number that is used
return “two pair.”
when re-rolling dice with the
else:
Reroll button.
return “one pair.”
else:
return “a high card.”

24

22

23

Dice selection

The first thing we do is find out what
checkboxes have been ticked by the player. We
then put these in a list so we can change out the
correct dice numbers. We’ve also brought in dice
so we can check against that what the current
dice rolls are.

54 The Python Book

21

Start game

When we activate the button that starts
game, it immediately sends us to the rest of the
code. This would also work if you had the button
go to the throws function instead; however, you
can add other functions to this part if you wish.

We mentioned that the game function
doesn’t necessarily need to be used right
now. You can either clean up the code and
remove it, or add extra functions, such
as being able to choose a random new
selection of dice, or making it two-player.
Experiment with what you want to do!

19

The roll function has been removed from
the gui function so as not to create any code
errors with some of its variables. It can be easily
called within the nested functions. It hasn’t
changed at all from the original code.
Like roll, nothing has changed for the
hand function. It’s simply now placed outside
the gui function for the exact same reasons.
It also means that you can easily import this
function into another script if you wish.

EXTRA GAME FUNCTIONS

def roll(roll_number):
numbers = range(1,7)
dice = range(roll_number)
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
dice[iterations-1] = random.choice(numbers)
return dice

Outside dice

For Poker Dice, there’s only one variable
to show at any one time, the dice. Again, due to
the nested functions, and because we’re using
Python 2, we need to call it with global from here
to make sure the game can be reset properly.

from Tkinter import *
from ttk import *
import random
from itertools import groupby
dice = 0

24

def gui():
global dice
dice = roll(5)
dice.sort()
nine = 1
ten = 2
jack = 3
queen = 4
king = 5
ace = 6
names = { nine: “9”, ten: “10”, jack: “J”, queen: “Q”, king: “K”,
ace: “A” }
result = “You have “ + hand(dice)
def game():
throws()
def throws():
global dice
dice1_check = dice1.get()
dice2_check = dice2.get()
dice3_check = dice3.get()
dice4_check = dice4.get()
dice5_check = dice5.get()
dice_rerolls = [dice1_check, dice2_check, dice3_check, dice4_
check, dice5_check]

Python essentials

25
26

27

28

for i in range(len(dice_rerolls)):
if 0 in dice_rerolls:
dice_rerolls.remove(0)
if len(dice_rerolls) == 0:
result = “You finish with “ + hand(dice)
hand_output.set(result)
else:
roll_number = len(dice_rerolls)
number_rerolls = roll(roll_number)
dice_changes = range(len(dice_rerolls))
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
dice_changes[iterations-1] = number_rerolls[iterations-1]
iterations = 0
while iterations < roll_number:
iterations = iterations + 1
replacement = number_rerolls[iterations-1]
dice[dice_changes[iterations-1]] = replacement
dice.sort()
new_dice_list = [0,0,0,0,0]
for i in range(len(dice)):
new_dice_list[i] = names[dice[i]]
final_dice = “ “.join(new_dice_list)
dice_output.set(final_dice)
final_result = “You finish with “ + hand(dice)
hand_output.set(final_result)
def reset_game():
global dice
dice = roll(5)
dice.sort()
for i in range(len(dice)):
empty_dice[i] = names[dice[i]]
first_dice = “ “.join(empty_dice)
dice_output.set(first_dice)
result = “You have “ + hand(dice)
hand_output.set(result)

29

pd_window = Toplevel()
pd_window.title (“Poker Dice”)
dice_output = StringVar()
empty_dice = [0,0,0,0,0]
for i in range(len(dice)):
empty_dice[i] = names[dice[i]]
first_dice = “ “.join(empty_dice)
dice_output.set(first_dice)
hand_output = StringVar()
hand_output.set(result)
dice1 = IntVar()
dice2 = IntVar()
dice3 = IntVar()
dice4 = IntVar()
dice5 = IntVar()
result_set = StringVar()
player_score = IntVar()
computer_score = IntVar()

ONE WINDOW
The way we’ve made these Tkinter
interfaces is to have the games
launch in a separate window. You
can have them all running in one
window, though, by replacing the
labels and buttons of the original
interface by putting them as
different functions or classes.
Make sure to add a quit button to
the games that lets you go back
to the main page.

pd_frame = Frame(pd_window, padding = ‘3 3 12 12’, width = 300)
pd_frame.grid(column=0, row = 0, sticky=(N,W,E,S))
pd_frame.columnconfigure(0, weight=1)
pd_frame.rowconfigure(0,weight=1)
Label(pd_frame, text=’Dice’).grid(column=3, row = 1)
Label(pd_frame, textvariable = dice_output).grid(column=3, row = 2)
Label(pd_frame, textvariable = hand_output).grid(column=3, row = 3)

30

Label(pd_frame, text=’Dice to Reroll?’).grid(column=3, row = 4)
reroll1 = Checkbutton(pd_frame, text = “1”, variable = dice1, onvalue = 1, offvalue
= 0).grid(column=1, row = 5)
reroll2 = Checkbutton(pd_frame, text = “2”, variable = dice2, onvalue = 2, offvalue
= 0).grid(column=2, row = 5)
reroll3 = Checkbutton(pd_frame, text = “3”, variable = dice3, onvalue = 3, offvalue
= 0).grid(column=3, row = 5)
reroll4 = Checkbutton(pd_frame, text = “4”, variable = dice4, onvalue = 4, offvalue
= 0).grid(column=4, row = 5)
reroll5 = Checkbutton(pd_frame, text = “5”, variable = dice5, onvalue = 5, offvalue
= 0).grid(column=5, row = 5)
pd_reroll_button = Button(pd_frame, text = “Reroll”, command = game).grid(column =
3, row = 6)
replay_button = Button(pd_frame, text = “Reset”, command = reset_game).grid(column
= 3, row = 7)

The check
buttons are new

25

Dice to re-roll

26

Early finish

27

New dice

28

Game over

29

Graphical variables

30

Check buttons

If a checkbox isn’t selected, we have
it set to give a zero value. We want to remove
these from the list so that the correct dice
are changed, so we use the for loop to check
each part of the list, and then use the remove
function when the element does equal zero.

If no dice have been selected to re-roll,
the list will contain all 0s, which will then be
removed. The length of this list will then also be
zero, meaning we can use that to end the game if
the player hits Reroll without selecting any dice.
This else function works roughly
the same as before. We start by getting the
necessary information for how many dice to roll,
and a list to put the re-rolls. We then roll as many
new dice as we need with the first while loop

We use the same kind of while loop to
replace the new numbers into the original list,
much like last time. Then the dice are re-sorted,
analysed, joined as a string and then set into the
interface’s variable. The final hand message is
also create and set.

As we’re rolling the dice as soon as
we launch the game, but the interface code
doesn’t start until the end, you can see that
after creating the necessary variables, we also
then set them. Of note, the dice have to be made
into a string separately with the for loop before
adding to the variable.

The main new addition to this code is
the check buttons with Checkbutton. You can
set an on and off value, with default off being 0.
We’ve made it so that the check buttons return
the same number as the dice they’re changing,
which we explained how we used earlier in the
code. The variable option sets whatever the
outcome is to the specific Tkinter variable.

if __name__ == ‘__main__’:
gui()

The Python Book 55

Python essentials

Build an app for
Android with Python
Master Kivy, the excellent cross-platform application
framework to make your first Android app…

QHere we've drawn all the simple graphics
for our game… now we just have to make
the shapes actually do something!

The great thing about Kivy is there are loads
of directions we could take it in to do some
pretty fancy things. But, we're going to make
a beeline for one of Kivy's coolest features
- the ability it affords you to easily run your
programs on Android.
We'll approach this by first showing how to
make a new app, this time a dynamic Breakout-

style game. We'll then be able to compile this
straight to an Android APK that you can use just
like any other.
Of course, once you have mastered the
basic techniques you aren't limited to using
any particular kind of app, as even on Android
you can make use of all your favourite Python
libraries to make any sort of program you like.

Once you've mastered Kivy, your imagination
is the only limit. If you're pretty new to Kivy,
don't worry, we won't assume that you have
any pre-existing knowledge. As long as you
have mastered some of the Python tutorials
in this book so far, and so have a fairly good
understanding of the language, you shouldn’t
have any problems following along.

Before anything else, let's throw together a
basic Kivy app (Fig. 01). We've pre-imported
the widget types we'll be using, which this
time are just three: the basic Widget with
no special behaviour, the ModalView with a
pop-up behaviour as used last time, and the
FloatLayout as we will explaine later. Kivy
has many other pre-built widgets for creating
GUIs, but this time we’re going to focus on
drawing the whole GUI from scratch using
Kivy's graphics instructions. These comprise
either vertex instructions to create shapes
(including rectangles, lines, meshes, and so
on) or contextual graphics changes (such as
translation, rotation, scaling, etc), and are able

to be drawn anywhere on your screen and on
any widget type.
Before we can do any of this we'll need a class
for each kind of game object, which we’re going
to pre-populate with some of the properties
that we'll need later to control them. Remember
from last time, Kivy properties are special
attributes declared at class level, which (among
other things) can be modified via kv language
and dispatch events when they are modified
(Fig. 02).
The Game class will be one big widget
containing the entire game. We've specifically
made it a subclass of FloatLayout because
this special layout is able to position and size

its children in proportion to its own position
and size – so no matter where we run it or
how we resize the window, it will place all the
game objects appropriately.
Next we can use Kivy's graphics instructions
to draw various shapes on our widgets. We'll
just demonstrate simple rectangles to show
their locations, though there are many more
advanced options you might like to investigate.
In a Python file we can apply any instruction
by declaring it on the canvas of any widget, an
example of which is shown in Fig. 03.
This would draw a red rectangle with the
same position and size as the player at its
moment of instantiation – but this has a

56 The Python Book

1ZUIPOFTTFOUJBMT
problem, unfortunately, as the drawing is
static. When we later move the player widget,
the red rectangle will stay in the same place,
and the widget will be invisible when it is in its
real position.
We could fix this by keeping references to our
canvas instructions and repeatedly updating
their properties to track the player, but there's
actually an easier way to do all of this - we
can use the Kivy language we introduced last
time. It has a special syntax for drawing on
the widget canvas, which we can use to draw
each of our widget shapes:

:
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
:
canvas:
Color:
rgb: 1, 0.55, 0
Rectangle:
pos: self.pos
size: self.size
:
canvas:
Color:
rgb: self.colour
# A property we predefined above
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: 0.1, 0.1, 0.1
Line:
rectangle:
[self.x, self.y,
self.width, self.height]
The canvas declaration is special, underneath
it we can write any canvas instructions we
like. Don't get confused, canvas is not a
widget and nor are graphics instructions
like Line. This is just a special syntax that is
unique to the canvas. Instructions all have
different properties that can be set, like the
pos and size of the rectangle, and you can
check the Kivy documentation online for all
the possibilities. The biggest advantage is
that although we still declare simple canvas
instructions, kv language is able to detect
what Kivy properties we have referred to and
automatically track them, so when they are
updated (the widget moves or is resized) the
canvas instructions move to follow!

Once you have the basic techniques,
you aren’t limited to one app… your
imagination is the only limit
from
from
from
from

kivy.app import App
kivy.uix.widget import Widget
kivy.uix.floatlayout import FloatLayout
kivy.uix.modalview import ModalView

Fig. 01

__version__ = '0.1' # Used later during Android compilation
class BreakoutApp(App):
pass
BreakoutApp().run()

from kivy.properties import (ListProperty, NumericProperty,
ObjectProperty, StringProperty)

Fig. 02

class Game(FloatLayout): # Will contain everything
blocks = ListProperty([])
player = ObjectProperty() # The game's Player instance
ball = ObjectProperty() # The game's Ball instance
class Player(Widget): # A moving paddle
position = NumericProperty(0.5)
direction = StringProperty('none')
class Ball(Widget): # A bouncing ball
# pos_hints are for proportional positioning, see below
pos_hint_x = NumericProperty(0.5)
pos_hint_y = NumericProperty(0.3)
proper_size = NumericProperty(0.)
velocity = ListProperty([0.1, 0.5])
class Block(Widget): # Each coloured block to destroy
colour = ListProperty([1, 0, 0])

from kivy.graphics.context_instructions import Color
from kivy.graphics.vertex_instructions import Rectangle

Fig. 03

class Player(Widget):
def __init__(self, **kwargs):
super(Player, self).__init__(**kwargs)
with self.canvas:
Color(1, 0, 0, 1) # r, g, b, a -> red
Rectangle(pos=self.pos, size=self.size)
# or without the with syntax, self.canvas.add(...)

5IF1ZUIPO#PPL57

Python essentials

:
ball: the_ball
player: the_player
Ball:
id: the_ball
Player:
id: the_player

QRunning the app shows our coloured blocks on the
screen… but they all overlap! We can fix that easily

You probably noticed we had one of the
Block’s ‘Color’ instructions refer to its colour
property. This means that we can change
the property any time to update the colour
of the block, or in this case to give each block
a random colour (Fig. 04).
Now that each of our widgets has a graphical
representation, let’s now tell our Game where to
place them, so that we can start up the app and
actually see something there.

class Game(FloatLayout):
def setup_blocks(self):
for y_jump in range(5):
for x_jump in range(10):
block = Block(pos_hint={
'x': 0.05 + 0.09*x_jump,
'y': 0.05 + 0.09*y_jump})
self.blocks.append(block)
self.add_widget(block)
class BreakoutApp(App):
def build(self):
g = Game()
g.setup_blocks()
return g
Here we create the widgets we want then use
add_widget to add them to the graphics tree. Our
root widget on the screen is an instance of Game
and every block is added to that to be displayed.
The only new thing is that every Block
has been given a pos_hint. All widgets have

58 The Python Book

this special property, and it is used by
FloatLayouts like our Game to set their
position proportionate to the layout.
The dictionary is able to handle
various
parameters,
but
in
this
case ‘x’and ‘y’ give x and y Block
position as a relative fraction of the
parent width and height.
You can run the app now, and this time
it will add 50 blocks to the Game before
displaying it on the screen. Each should have
one of the three possible random colours
and be positioned in a grid, but you'll now
notice their sizes haven't been manually set
so they all overlap. We can fix this by setting
their size_hint properties – and let's also
take this opportunity to do the same for the
other widgets as well (Fig. 05).
This takes care of keeping all our game
widgets positioned and sized in proportion
to the Game containing them. Notice that
the Player and Ball use references to the
properties we set earlier, so we'll be able to
move them by just setting these properties
and letting kv language automatically update
their positions.
The Ball also uses an extra property to
remain square rather than rectangular, just
because the alternative would likely look a
little bit odd.
We've now almost finished the basic
graphics of our app! All that remains is to add
a Ball and a Player widget to the Game.

You can run the game again now, and should
be able to see all the graphics working
properly. Nothing moves yet, but thanks to
the FloatLayout everything should remain in
proportion if you resize the game/window.
Now we just have to add the game
mechanics. For a game like this you usually
want to run some update function many times
per second, updating the widget positions and
carrying out game logic – in this case collisions
with the ball (Fig. 06).
The Clock can schedule any function at
any time, either once or repeatedly. A function
scheduled at interval automatically receives the
time since its last call (dt here), which we've passed
through to the ball and player via the references
we created in kv language. It's good practice to
scale the update (eg ball distance moved) by this
dt, so things remain stable even if something
interrupts the clock and updates don't meet
the regular 1/60s you want.
At this point we have also added the first steps
toward handling keyboard input, by binding to
the kivy Window to call a method of the Player
every time a key is pressed. We can then finish
off the Player class by adding this key handler along
with touch/mouse input.

class Player(Widget):
def on_touch_down(self, touch):
self.direction = (
'right' if touch.x > self.parent.
center_x else 'left')
def on_touch_up(self, touch):
self.direction = 'none'
def on_key_down(self, keypress,
scancode, *args):
if scancode == 275:
self.direction = 'right'
elif scancode == 276:
self.direction = 'left'
else:
self.direction = 'none'
def on_key_up(self, *args):
self.direction = 'none'
def update(self, dt):
dir_dict = {'right': 1, 'left': -1,

Python essentials

'none': 0}
self.position += (0.5 * dt * dir_
dict[self.direction])
These on_touch_ functions are Kivy's general
method for interacting with touch or mouse input,
they are automatically called when the input
is detected and you can do anything you like in
response to the touches you receive. In this case
we set the Player's direction property in response
to either keyboard and touch/mouse input, and
use this direction to move the Player when its
update method is called. We can also add the right
behaviour for the ball (Fig. 07).
This makes the ball bounce off every wall by
forcing its velocity to point back into the Game,
as well as bouncing from the player paddle –
but with an extra kick just to let the ball speed
change. It doesn't yet handle any interaction
with the blocks or any win/lose conditions,
but it does try to call Game.lose() if the
ball hits the bottom of the player's screen,
so let's now add in some game end code to handle
all of this (Fig. 08). And then add the code in Fig. 09
to your 'breakout.kv 'file.
This should fully handle the loss or win,
opening a pop-up with an appropriate message
and providing a button to try again. Finally, we
have to handle destroying blocks when the
ball hits them (Fig. 10).
This fully covers these last conditions, checking
collision via Kivy's built-in collide_widget method
that compares their bounding boxes (pos and
size). The bounce direction will depend on how far
the ball has penetrated, as this will tell us how it
first collided with the Block.
So there we have it, you can run the code to
play your simple Breakout game. Obviously it's
very simple right now, but hopefully you can
see lots of different ways to add whatever extra
behaviour you like – you could add different
types of blocks and power-ups, a lives system,
more sophisticated paddle/ball interaction, or
even build a full game interface with a menu and
settings screen as well.
We’re just going to finish showing one cool thing
that you can already do – compile your game for
Android! Generally speaking you can take any Kivy
app and turn it straight into an Android APK that
will run on any of your Android devices. You can
even access the normal Android API to access
hardware or OS features such as vibration,
sensors or native notifications.
We'll build for Android using the Buildozer tool,
and a Kivy sister project wrapping other build
tools to create packages on different systems.
This takes care of downloading and running the
Android build tools (SDK, NDK, etc) and Kivy's
Python-for-Android tools that create the APK.

import random

Fig. 04

class Block(Widget):
def __init__(self, **kwargs):
super(Block, self).__init__(**kwargs)
self.colour = random.choice([
(0.78, 0.28, 0), )0.28, 0.63, 0.28), )0.25, 0.28, 0.78)])

:
size_hint: 0.09, 0.05
# ... canvas part

Fig. 05

:
size_hint: 0.1, 0.025
pos_hint: {'x': self.position, 'y': 0.1}
# ... canvas part
:
pos_hint: {'x': self.pos_hint_x, 'y': self.pos_hint_y}
size_hint: None, None
proper_size:
min(0.03*self.parent.height, 0.03*self.parent.width)
size: self.proper_size, self.proper_size
# ... canvas part

from kivy.clock import Clock
from kivy.core.window import Window
from kivy.utils import platform

Fig. 06

class Game(FloatLayout):
def update(self, dt):
self.ball.update(dt) # Not defined yet
self.player.update(dt) # Not defined yet
def start(self, *args):
Clock.schedule_interval(self.update, 1./60.)
def stop(self):
Clock.unschedule(self.update)
def reset(self):
for block in self.blocks:
self.remove_widget(block)
self.blocks = []
self.setup_blocks()
self.ball.velocity = [random.random(), 0.5]
self.player.position = 0.5
class BreakoutApp(App):
def build(self):
g = Game()
if platform() != 'android':
Window.bind(on_key_down=g.player.on_key_down)
Window.bind(on_key_up=g.player.on_key_up)
g.reset()
Clock.schedule_once(g.start, 0)
return g

The Python Book 59

Python essentials

class Ball(Widget)
def update(self, dt):
self.pos_hint_x += self.velocity[0] * dt
self.pos_hint_y += self.velocity[1] * dt
if self.right > self.parent.right: # Bounce from right
self.velocity[0] = -1 * abs(self.velocity[0])
if self.x < self.parent.x: # Bounce from left
self.velocity[0] = abs(self.velocity[0])
if self.top > self.parent.top: # Bounce from top
self.velocity[1] = -1 * abs(self.velocity[1])
if self.y < self.parent.y: # Lose at bottom
self.parent.lose() # Not implemented yet
self.bounce_from_player(self.parent.player)

Fig. 07
Here you
will be needing some basic
dependencies, which can be installed with
ease just by using your distro's normal
repositories. The main ones to use are
OpenJDK7, zlib, an up-to-date Cython,
and Git. If you are using a 64-bit distro you will also
be in need of 32-bit compatibility libraries for zlib,
libstdc++, as well as libgcc. You can then go on and
download and install Buildozer:

git clone git://github.com/kivy/buildozer
cd buildozer
sudo python2.7 setup.py install

def bounce_from_player(self, player):
if self.collide_widget(player):
self.velocity[1] = abs(self.velocity[1])
self.velocity[0] += (
0.1 * ((self.center_x - player.center_x) /
player.width))

When you’re done with that part you
can then go on and navigate to your
Kivy app, and you’ll have to name the main code file
‘main.py’, this is the access point that the Android
APK will expect. Then:

buildozer init

class GameEndPopup(ModalView):
message = StringProperty()
game = ObjectProperty()

Fig. 08

class Game(Widget):
def lose(self):
self.stop()
GameEndPopup(message='[color=#ff0000]You lose![/color]',
game=self).open()
def win(self): # Not called yet, but we'll need it later
self.stop()
GameEndPopup(message='[color=#00ff00]You win![/color]',
game=self).open()

:
size_hint: 0.8, 0.8
auto_dismiss: False # Don't close if player clicks outside
BoxLayout:
orientation: 'vertical'
Label:
text: root.message
font_size: 60
markup: True
halign: 'center'
Button:
size_hint_y: None
height: sp(80)
text: 'Play again?'
font_size: 60
on_release: root.game.start(); root.dismiss()

60 The Python Book

This creates a ‘buildozer.spec’ file, a settings file
containing all the information that Buildozer needs
to create your APK, from the name and version to
the specific Android build options. We suggest that
you check through the whole file just to see what's
available but most of the default settings will be
fine, the only thing we suggest changing is (Fig. 11).
There are various other options you will often
want to set, but none are really all that vital right
now, so you’re able to immediately tell Buildozer to
build your APK and get going!

buildozer android debug

Fig. 09

This will take some time, so be patient and it will
work out fine. When you first run it, it will download
both the Android SDK and NDK, which are large
(at least hundreds of megabytes) but vital to the
build. It will also take time to build these and to
compile the Python components of your APK. A lot
of this only needs to be done once, as future builds
will take a couple of minutes if you change the
buildozer.spec, or just a few seconds if you've only
changed your code.
The APK produced is a debug APK, and you can
install and use it but there are extra steps if you
want to fully digitally sign it so that it can be posted
on the Play store. This isn't hard, and Buildozer
can do some of the work, but you can check the
documentation online for full details.
Assuming everything goes fine (it should!),
your Android APK will be in a newly created 'bin'
directory with the name ‘KivyBreakout-0.1-debug.
apk’. You can send it to your phone any way you
like (eg email), though you may need to enable
application installation from unknown sources in
your Settings before you can install it.

Python essentials

Putting your APK
on the Play Store
Find out how to digitally sign a release
APK and upload it to an app store of
your choice

1

Build and sign a release APK
First we have to begin by creating a personal
digital key, then using it to digitally sign a
special release version of the APK. Run these
commands, and follow the instructions they then
give you.

## Create your personal digital key
## You can choose your own
## keystore name, alias, and passwords.
$ keytool -genkey -v -keystore testrelease-key.keystore \
-alias test-alias -keyalg RSA
-keysize 2048 -validity 10000
## Compile your app in release mode
$ buildozer android release
## Sign the APK with your new key
$ jarsigner -verbose -sigalg
SHA1withRSA -digestalg SHA1 \
-keystore ./test-release-key.keystore \
./bin/KivyBreakout-0.1-releaseunsigned.apk test-alias
## Align the APK zip file
$ ~/.buildozer/android/platform/androidsdk-21/tools/zipalign -v 4 \
./bin/KivyBreakout-0.1-releaseunsigned.apk \
./bin/KivyBreakout-0.1-release.apk

self.parent.do_layout()
self.parent.destroy_blocks(self)

Fig. 10

class Game(FloatLayout):
def destroy_blocks(self, ball):
for i, block in enumerate(self.blocks):
if ball.collide_widget(block):
y_overlap = (
ball.top - block.y if ball.velocity[1] > 0
else block.top - ball.y) / block.size_hint_y
x_overlap = (
ball.right - block.x if ball.velocity[0] > 0
else block.right - ball.x) / block.size_hint_x
if x_overlap < y_overlap:
ball.velocity[0] *= -1
else:
ball.velocity[1] *= -1
self.remove_widget(block)
self.blocks.pop(i)
if len(self.blocks) == 0:
self.win()
return # Only remove at most 1 block per frame
title = Kivy Breakout # Displayed in your app drawer
package.name = breakout # Just a unique identifying string,
# along with the package.domain
fullscreen = 0 # This will mean the navbar is not covered
log_level = 2 # Not vital, but this will print a lot more debug
# information and may be useful if something
# goes wrong

2

Sign up as a Google
Play Developer
Visit
https://play.google.com/
apps/publish/signup, and follow
the instructions. You'll need to pay a
one-off $25 charge, but then you can
upload as many apps as you like.

3

Upload your app to the store
Click 'Add new application'
to submit your app the store,
including uploading your APK and
adding description text. When
everything is ready, simply click
Publish, and it should take just a few
hours for your app to go live!

QYour game should run on any modern Android device… you
can even build a release version and publish to an app store!

Fig. 11

Python essentials

Making web apps with Python
Python provides quick and easy way to build
applications, including web apps. Read on to find out
how to use it to build a feature-complete web app
Python is known for its simplicity and
capabilities. At this point it is so advanced
that there is nothing you cannot do with
Python, and conquering the web is one of the
possibilities. When you are using Python for web
development you get access to a huge catalogue
of modules and community support – make the
most of them.
Web development in Python can be done
in many different ways, right from using the

plain old CGI modules to utilising fully groomed
web frameworks. Using the latter is the most
popular method of building web applications
with Python, since it allows you to build
applications without worrying about all that
low-level implementation stuff. There are many
web frameworks available for Python, such
as Django, TurboGears and Web2Py. For this
tutorial we will be using our current preferred
option, Django.

01

02

Creating the Django Project
magazine issue tracker

The django-admin.py file is used to create new
Django projects. Let’s create one for our issue
tracker project…
In Django, a project represents the site and
its settings. An application, on the other hand,
represents a specific feature of the site, like
blogging or tagging. The benefit of this approach
is that your Django application becomes
portable and can be integrated with other
Django sites with very little effort.

$ django-admin.py startproject
ludIssueTracker

Resources
Python 2.7:
https://www.python.org/download/releases/2.7/

Django version 1.4:
https://www.djangoproject.com/

62 The Python Book

A project directory will be created. This will also
act as the root of your development web server
that comes with Django. Under the project
directory you will find the following items…
manage.py: Python script to work with your
project.
ludIssueTracker: A python package (a directory
with __init__.py file) for your project. This
package contains your project’s settings and
configuration data.
ludIssueTracker/settings.py: This file contains
all the configuration options for the project.
ludIssueTracker/urls.py: This file contains
various URL mappings.
wsgi.py: An entry-point for WSGI-compatible
web servers to serve your project. Only useful
when you are deploying your project. For this
tutorial we won’t be needing it.

Configuring the Django project
settings

Before we start working on the application,
let’s configure the Django project as per our
requirements.
Edit ludIssueTracker/settings.py as follows
(only parts requiring modification are shown):
Database Settings: We will be using SQLite3
as our database system.
NOTE: Red text indicates new code or
updated code.

‘default’: {
‘ENGINE’: ‘django.
db.backends.sqlite3’,
‘NAME’: ‘ludsite.db3,

Path settings
Django requires an absolute path for directory
settings. But we want to be able to pass in the
relative directory references. In order to do that
we will add a helper Python function. Insert the
following code at the top of the settings.py file:

import os
def getabspath(*x):
return os.path.join(os.path.
abspath(os.path.dirname(__file__)),
*x)
Now you can update the path options:

@code
TEMPLATE_DIRS = (
getabspath(‘templates’)
)
MEDIA_ROOT = getabspath(‘media’)

Python essentials

MEDIA_URL = ‘/media/’
Now we will need to enable the admin interface
for our Django site. This is a neat feature of Django
which allows the automatic creation of an admin
interface of the site based on the data model. The
admin interface can be used to add and manage
content for a Django site.
Uncomment the following line:

INSTALLED_APPS = (
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.sites’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘django.contrib.admin’,
# ‘django.contrib.admindocs’,
)

03

Creating ludissues app

In this step we will create the primary
app for our site, called ludissues. To do that, we
will use the manage.py script:

$ python manage.py startapp
ludissues
We will need to enable this app in the config file
as well:

INSTALLED_APPS = (
.............
'django.contrib.admin',
‘ludissues’,
)

04

Creating the data model

This is the part where we define the
data model for our app. Please see the inline
comments to understand what is happening.
From django.db import models:

# We are importing the user
authentication module so that we use
the built
# in authentication model in this
app
from django.contrib.auth.models
import User
# We would also create an admin
interface for our app
from django.contrib import admin
# A Tuple to hold the multi choice
char fields.
# First represents the field name
the second one repersents the
display name
ISSUE_STATUS_CHOICES = (

('new', 'New'),
('accepted','Accepted'),
('reviewed','Reviewed'),
('started','Started'),
('closed','Closed'),

You just installed Django's auth
system, which means you don't have
any superusers defined.
Would you like to create one now?
(yes/no): yes

)
class Issue(models.Model):
# owner will be a foreign key
to the User model which is already
built-in Django
owner = models.ForeignKey(User,n
ull=True,blank=True)
# multichoice with defaulting to
"new"
status = models.CharField(max_
length=25,choices=ISSUE_STATUS_
CHOICES,default='new')
summary = models.TextField()
# date time field which will be
set to the date time when the record
is created
opened_on = models.
DateTimeField('date opened', auto_
now_add=True)
modified_on = models.
DateTimeField('date modified', auto_
now=True)
def name(self):
return self.summary.
split('\n',1)[0]
# Admin front end for the app. We
are also configuring some of the
# built in attributes for the admin
interface on
# how to display the list, how it
will be sorted
# what are the search fields etc.
class IssueAdmin(admin.ModelAdmin):
date_hierarchy = 'opened_on'
list_filter = ('status','owner')
list_display = ('id','name','sta
tus','owner','modified_on')
search_fields =
['description','status']
# register our site with the Django
admin interface
admin.site.
register(Issue,IssueAdmin)
To have the created data model reflected in the
database, run the following command:

05

Enabling the admin site

The admin site is already enabled,
but we need to enable it in the urls.py file – this
contains the regex-based URL mapping from
model to view. Update the urls.py file as follows:

from django.conf.urls import
patterns, include, url
from django.contrib import admin
admin.autodiscover()
urlpatterns = patterns(‘’,
url(r’^admin/’, include(admin.
site.urls)),
)

06

Starting the Django web server

Django includes a built-in web server
which is very handy to debug and test Django
applications. Let’s start it to see how our admin
interface works…
To start the web server:

$ python manage.py runserver
If you do not have any errors in your code, the
server should be available on port 8000. To
launch the admin interface, navigate your
browser to http://localhost:8000/admin.
You will be asked to log in here. Enter the
username and password that you created while
syncing the database.

Q Admin login screen

After logging in, you will notice that all the apps
installed in your project are available here. We are
only interested in the Auth and LudIssues app.
You can click the +Add to add a record. Click
the Add button next to Users and add a few
users to the site.
Once you have the users inside the system,
you can now add a few issues to the system.

$ python manage.py syncdb
You’ll be also asked to create a superuser for it:

The Python Book 63

Python essentials

07

Creating the public user interface
for ludissues

At this point, the admin interface is working. But
we need a way to display the data that we have
added using the admin interface. But there is no
public interface. Let’s create it now.
We will have to begin by editing the main
urls.py (ludIssueTracker/urls.py).

Q Admin homepage

Click the Add button next to Issues. Here you
will notice that you can enter Owner, Status
and Summary for the issue. But what about
the opened_on and modified_on field that
we defined while modelling the app? They
are not here because they are not supposed
to be entered by the user. opened_on will
automatically set to the date time it is created
and modified_on will automatically set to the
date time on which an issue is modified.
Another cool thing is that the owner field is
automatically populated with all the users inside
the site.
We have defined our list view to show ID,
name, status, owner and ‘modified on’ in the
model. You can get to this view by navigating to
http://localhost:8000/admin/ludissues/issue/.

urlpatterns = patterns(‘’,
(r’^’,include(‘ludissues.
urls’)),
(r’^admin/’, include(admin.site.
urls)),
)
This ensures that all the requests will be
processed by ludissues.urls first.

08

Creating ludissues.url

Create a urls.py file in the app directory
(ludissues/urls.py) with the following content:

)
To display an issue list and details, we are using
a Django feature called generic views. In this
case we are using views called list and details.
This allow us to create an issue list view and
issue detail view. These views are then applied
using the issue_list.html and issue_detail.html
template. In the following steps we will create
the template files.

from django.conf.urls import
patterns, include, url
# use ludissues model
from models import ludissues

09

# dictionary with all the objects in
ludissues
info = {
‘queryset’:ludissues.objects.
all(),
}

TEMPLATE_DIRS = (
getabspath(‘templates’)
)

# To save us writing lots of python
code
# we are using the list_detail
generic view

Q The ‘Add issue’ menu

template names
#which will be looked in the default
template
#directories
url(r’^$’,’object_
list’,info,name=’issue-list’),
url(r’^(?P\d+)/$’,’object_
detail’,info,name=’issue-detail’),

#list detail is the name of view we
are using
urlpatterns = patterns(‘django.
views.generic.list_detail’,
#issue-list and issue-detail are the

Setting up template and media
directories

In this step we will create the template and
media directories. We have already mentioned
the template directory as

Which
translates
to
ludIssueTracker/
ludIssueTracker/templates/. Since we will be
accessing the templates from the ludissues
app, the complete directory path would be
ludIssueTracker/ludIssueTracker/templates/
ludissues. Create these folders in your
project folder.
Also, create the directory ludIssueTracker/
ludIssueTracker/media/ for holding the CSS
file. Copy the style.css file from the resources
directory of the code folder.
To serve files from this folder we need to make
it available publicly. To do that, open settings.py
and add the following lines in ludIssueTracker/
ludIssueTracker/urls.py:

from django.conf.urls import
patterns, include, url
from django.conf import settings
# Uncomment the next two lines to
enable the admin:
from django.contrib import admin
admin.autodiscover()

Q The list view for issues

64 The Python Book

urlpatterns = patterns(‘’,
(r’^’,include(‘ludissues.
urls’)),
(r’^admin/’, include(admin.site.

Python essentials

urls)),
(r’^media/
(?P.*)$’,’django.views.static.
serve’,
{‘document_root’:settings.
MEDIA_ROOT})
)

10

Creating the template files

Templates will be loaded from the
ludIssueTracker/ludIssueTracker/templates
directory. In Django, we start with the
ludIssueTracker/ludIssueTracker/templates/
base.html template. Think of it as the master
template which can be inherited by slave ones.
ludIssueTracker/ludIssueTracker/templates/
base.html




{% block title %}{%
endblock %}LUD Issues



LUD Issue Tracker

{% block content %} {% endblock %}
{{ variablename }} represents a Django variable. (% block title %} represents blocks. Contents of a block are evaluated by Django and are displayed. These blocks can be replaced by the child templates. Q The magazine Issue Tracker in action – list of issues Now we need to create the issue_list.html template. This template is responsible for displaying all the issues available in the system. ludIssueTracker/ludIssueTracker/templates/ ludissues/issue_list.html {% extends ‘base.html’ %} {% block title %}View Issues - {% endblock %} {% block content %} {% for issue in object_list %} {% endfor %}
Issue Description Status Owner
{{ issue.id }} {{ issue.name }} {{ issue.status }} {{ issue.owner}}
{% endblock %} Here we are inheriting the base.html file that we created earlier. {% for issue in object_list %} runs on the object sent by the urls.py. Then we are iterating on the object_list for issue.id and issue.name. Now we will create issue_detail.html. This template is responsible for displaying the detail view of a case. ludIssueTracker/ludIssueTracker/templates/ ludissues/issue_detail.html {% extends ‘base.html’ %} {% block title %}Issue #{{ object.id }} - {% endblock %} {% block content %}

Issue #{{ object.id }} {{ object.status }}

Information

Opened {{ object.opened_on }} ago

Last modified {{ object.modified_on }} ago

 

Owner

{{ object. owner }}

 

Summary

{{ object. summary }}

{% endblock %} And that’s everything! The issue tracker app is now complete and ready to use. You can now point your browser at localhost:8000 to start using the app. The Python Book 65 Python essentials 0 5 n o h s t y it p P Python is a programming language that lets you work more quickly and integrate your systems more effectively. Today, Python is one of the most popular programming languages in the open source space. Look around and you will find it running everywhere, from various configuration tools to XML parsing. Here is the collection of 50 gems to make your Python experience worthwhile… Basics 1. Running Python scripts command at the command prompt (>>>), one by one, and the answer is immediate. Python interpreter can be started by issuing the command: 2. Running Python programs from Python interpreter $ python kunal@ubuntu:~$ python Python 2.6.2 (release26-maint, Apr 19 2009, 01:56:41) [GCC 4.3.3] on linux2 Type “help”, “copyright”, “credits” or “license” for more information. >>> The Python interactive interpreter makes it easy to try your first steps in programming and using all Python commands. You just issue each In this article, all the code starting at the >>> symbol is meant to be given at the Python prompt. On most of the UNIX systems, you can run Python scripts from the command line. $ python mypyprog.py 66 The Python Book It is also important to remember that Python takes tabs very seriously – so if you are receiving any error that mentions tabs, correct the tab spacing. 3. Dynamic typing In Java, C++, and other statically typed languages, you must specify the data type of the function return value and each function argument. On the other hand, Python is a dynamically typed language. In Python you never have to explicitly specify the data type of anything. Based on what value you assign, Python will keep track of the data type internally. Python essentials 4. Python statements x,y = my_function.minmax(25, 6.3) Python uses carriage returns to separate statements, and a colon and indentation to separate code blocks. Most of the compiled programming languages, such as C and C++, use semicolons to separate statements and curly brackets to separate code blocks. Example: The built-in function ‘dir()’ can be used to find out which names a module defines. It returns a sorted list of strings. 5. == and = operators Python uses ‘==’ for comparison and ‘=’ for assignment. Python does not support inline assignment, so there’s no chance of accidentally assigning the value when you actually want to compare it. 6. Concatenating strings You can use ‘+’ to concatenate strings. >>> print ‘kun’+’al’ kunal 7. The __init__ method The __init__ method is run as soon as an object of a class is instantiated. The method is useful to do any initialization you want to do with your object. The __init__ method is analogous to a constructor in C++, C# or Java. Example: class Person: def __init__(self, name): self.name = name def sayHi(self): print ‘Hello, my name is’, self.name p = Person(‘Kunal’) p.sayHi() 9. Module defined names >>> import time >>> dir(time) [‘__doc__’, ‘__file__’, ‘__name__’, ‘__package__’, ‘accept2dyear’, ‘altzone’, ‘asctime’, ‘clock’, ‘ctime’, ‘daylight’, ‘gmtime’, ‘localtime’, ‘mktime’, ‘sleep’, ‘strftime’, ‘strptime’, ‘struct_ time’, ‘time’, ‘timezone’, ‘tzname’, ‘tzset’] 10. Module internal documentation You can see the internal documentation (if available) of a module name by looking at .__doc__. Example: >>> import time >>> print time.clock.__doc__ clock() -> floating point number You can convert a list to string in either of the following ways. 1st method: >>> mylist = [‘spam’, ‘ham’, ‘eggs’] >>> print ‘, ‘.join(mylist) spam, ham, eggs 2nd method: >>> print ‘\n’.join(mylist) spam ham eggs 15. Tab completion in Python interpreter You can achieve auto completion inside Python interpreter by adding these lines to your .pythonrc file (or your file for Python to read on startup): import rlcompleter, readline readline.parse_and_bind(‘tab: complete’) This will make Python complete partially typed function, method and variable names when you press the Tab key. 16. Python documentation tool 11. Passing arguments to a Python script $ pydoc -g Output: [~/src/python $:] python initmethod.py Hello, my name is Kunal import sys print sys.argv 8. Modules 12. Loading modules or commands at startup # file my_function.py def minmax(a,b): if a <= b: min, max = a, b else: min, max = b, a return min, max Module Usage import my_function 14. Converting a list to a string for display This example returns the CPU time or real time since the start of the process or since the first call to clock(). This has as much precision as the system records. Python lets you access whatever you have passed to a script while calling it. The ‘command line’ content is stored in the sys.argv list. To keep your programs manageable as they grow in size, you may want to break them up into several files. Python allows you to put multiple function definitions into a file and use them as a module that can be imported into other scripts and programs. These files must have a .py extension. Example: dateobj = DateTime(string) You can load predefined modules or commands at the startup of any Python script by using the environment variable $PYTHONSTARTUP. You can set environment variable $PYTHONSTARTUP to a file which contains the instructions load necessary modules or commands . 13. Converting a string to date object You can use the function ‘DateTime’ to convert a string to a date object. Example: from DateTime import DateTime You can pop up a graphical interface for searching the Python documentation using the command: You will need python-tk package for this to work. 17. Python documentation server You can start an HTTP server on the given port on the local machine. This will give you a nice-looking access to all Python documentation, including third-party module documentation. $ pydoc -p 18. Python development software There are plenty of tools to help with Python development. Here are a few important ones: IDLE: The Python built-in IDE, with autocompletion, function signature popup help, and file editing. IPython: Another enhanced Python shell with tab-completion and other features. Eric3: A GUI Python IDE with autocompletion, class browser, built-in shell and debugger. WingIDE: Commercial Python IDE with free licence available to open-source developers everywhere. The Python Book 67 1ZUIPOFTTFOUJBMT Built-in modules 19. Executing functions at the time of Python interpreter termination You can use ‘atexit’ module to execute functions at the time of Python interpreter termination. Example: def sum(): print(4+5) def message(): print(ŎExecuting Nowŏ) import atexit atexit.register(sum) atexit.register(message) Output: Executing Now 9 20. Converting from integer to binary, hexadecimal and octal Python provides easy-to-use functions – bin(), hex() and oct() – to convert from integer to binary, decimal and octal format respectively. Example: >>> bin(24) Ă0b11000ā >>> hex(24) Ă0x18ā >>> oct(24) Ă030ā 21. Converting any charset to UTF-8 You can use the following function to convert any charset to UTF-8. data.decode(Ŏinput_charset_hereŏ). encode(Ăutf-8ā) 22. Removing duplicates from lists If you want to remove duplicates from a list, just put every element into a dict as a key (for example with ‘none’ as value) and then check dict.keys(). from operator import setitem def distinct(l): d = {} map(setitem, (d,)*len(l), l, []) return d.keys() 685IF1ZUIPO#PPL 23. Do-while loops Since Python has no do-while or do-until loop constructs (yet), you can use the following method to achieve similar results: sum: This function returns the sum of all elements in the list. It accepts an optional second argument: the value to start with when summing (defaults to 0). while True: do_something() if condition(): break 28. Representing fractional numbers 24. Detecting system platform Fraction([numerator [,denominator]]) To execute platform-specific functions, it is very useful to detect the platform on which the Python interpreter is running. You can use ‘sys.platform’ to find out the current platform. Example: On Ubuntu Linux >>> import sys >>> sys.platform Ălinux2ā On Mac OS X Snow Leopard >>> import sys >>> sys.platform Ădarwinā 25. Disabling and enabling garbage collection Sometimes you may want to enable or disable the garbage collector at runtime. You can use the ‘gc’ module to enable or disable the garbage collection. Example: >>> import gc >>> gc.enable >>> gc.disable 26. Using C-based modules for better performance Many Python modules ship with counterpart C modules. Using these C modules will give a significant performance boost in complex applications. Example: cPickle instead of Pickle, cStringIO instead of StringIO . 27. Calculating maximum, minimum and sum out of any list or iterable You can use the following built-in functions. max: Returns the largest element in the list. min: Returns the smallest element in the list. Fraction instance can be created using the following constructor: 29. Performing math operations The ‘math’ module provides a plethora of mathematical functions. These work on integer and float numbers, except complex numbers. For complex numbers, a separate module is used, called ‘cmath’. For example: math.acos(x): Return arc cosine of x. math.cos(x): Returns cosine of x. math.factorial(x) : Returns x factorial. 30. Working with arrays The ‘array’ module provides an efficient way to use arrays in your programs. The ‘array’ module defines the following type: array(typecode [, initializer]) Once you have created an array object, say myarray, you can apply a bunch of methods to it. Here are a few important ones: myarray.count(x): Returns the number of occurrences of x in a. myarray.extend(x): Appends x at the end of the array. myarray.reverse(): Reverse the order of the array. 31. Sorting items The ‘bisect’ module makes it very easy to keep lists in any possible order. You can use the following functions to order lists. bisect.insort(list, item [, low [, high]]) Inserts item into list in sorted order. If item is already in the list, the new entry is inserted to the right of any existing entries. bisect.insort_left(list, item [, low [, high]]) Inserts item into list in sorted order. If item is already in the list, the new entry is inserted to the left of any existing entries. Python essentials 32. Using regular expression-based search The ‘re’ module makes it very easy to use regxpbased searches. You can use the function ‘re.search()’ with a regexp-based expression. Check out the example below. Example: >>> import re >>> s = “Kunal is a bad boy” >>> if re.search(“K”, s): print “Match!” # char literal ... Match! >>> if re.search(“[@A-Z]”, s): print “Match!” # char class ... # match either at-sign or capital letter Match! >>> if re.search(“\d”, s): print “Match!” # digits class ... 33. Working with bzip2 (.bz2) compression format You can use the module ‘bz2’ to read and write data using the bzip2 compression algorithm. bz2.compress() : For bz2 compression bz2.decompress() : For bz2 decompression Example: # File: bz2-example.py import bz2 MESSAGE = “Kunal is a bad boy” compressed_message = bz2. compress(MESSAGE) decompressed_message = bz2. decompress(compressed_message) print “original:”, repr(MESSAGE) print “compressed message:”, repr(compressed_message) print “decompressed message:”, repr(decompressed_message) Output: [~/src/python $:] python bz2example.py original: ‘Kunal is a bad boy’ compressed message: ‘BZh91AY&SY\xc4\ x0fG\x98\x00\x00\x02\x15\x80@\x00\ x00\x084%\x8a \x00”\x00\x0c\x84\r\ x03C\xa2\xb0\xd6s\xa5\xb3\x19\x00\ xf8\xbb\x92)\xc2\x84\x86 z<\xc0’ decompressed message: ‘Kunal is a bad boy’ 34. Using SQLite database with Python SQLite is fast becoming a very popular embedded database because of its zero configuration needed, and superior levels of performance. You can use the module ‘sqlite3’ in order to work with SQLite databases. Example: >>> import sqlite3 >>> connection = sqlite.connect(‘test. db’) >>> curs = connection.cursor() >>> curs.execute(‘’’create table item ... (id integer primary key, itemno text unique, ... scancode text, descr text, price real)’’’) 35. Working with zip files You can use the module ‘zipfile’ to work with zip files. zipfile.ZipFile(filename [, mode [, compression [,allowZip64]]]) Open a zip file, where the file can be either a path to a file (a string) or a file-like object. zipfile.close()¶ Close the archive file. You must call ‘close()’ before exiting your program or essential records will not be written. zipfile.extract(member[, path[, pwd]]) Extract a member from the archive to the current working directory; ‘member’ must be its full name (or a zipinfo object). Its file information is extracted as accurately as possible. ‘path’ specifies a different directory to extract to. ‘member’ can be a filename or a zipinfo object. ‘pwd’ is the password used for encrypted files. 36. Using UNIX-style wildcards to search for filenames You can use the module ‘glob’ to find all the pathnames matching a pattern according to the rules used by the UNIX shell. *, ?, and character ranges expressed with [ ] will be matched. Example: >>> import glob >>> glob.glob(‘./[0-9].*’) [‘./1.gif’, ‘./2.txt’] >>> glob.glob(‘*.gif’) [‘1.gif’, ‘card.gif’] >>> glob.glob(‘?.gif’) [‘1.gif’] 37. Performing basic file operations (copy, delete and rename) You can use the module ‘shutil’ to perform basic file operation at a high level. This module works with your regular files and so will not work with special files like named pipes, block devices, and so on. shutil.copy(src,dst) Copies the file src to the file or directory dst. shutil.copymode(src,dst) Copies the file permissions from src to dst. shutil.move(src,dst) Moves a file or directory to dst. shutil.copytree(src, dst, symlinks [,ignore]]) Recursively copy an entire directory at src. shutil.rmtree(path [, ignore_errors [, onerror]]) Deletes an entire directory. 38. Executing UNIX commands from Python You can use module commands to execute UNIX commands. This is not available in Python 3 – instead you need to use the module ‘subprocess’. Example: >>> import commands >>> commands.getoutput(‘ls’) ‘bz2-example.py\ntest.py’ 39. Reading environment variables You can use the module ‘os’ to gather operatingsystem-specific information: Example: >>> import os >>> os.path >>> os.environ {‘LANG’: ‘en_ IN’, ‘TERM’: ‘xterm-color’, ‘SHELL’: ‘/bin/bash’, ‘LESSCLOSE’: ‘/usr/bin/lesspipe %s %s’, ‘XDG_SESSION_COOKIE’: ‘925c4644597c791c704656354adf56d61257673132.347986-1177792325’, ‘SHLVL’: ‘1’, ‘SSH_TTY’: ‘/dev/ pts/2’, ‘PWD’: ‘/home/kunal’, ‘LESSOPEN’: ‘| /usr/bin lesspipe ......} >>> os.name ‘posix’ >>> os.linesep ‘\n’ The Python Book 69 Python essentials 40. Sending email You can use the module ‘smtplib’ to send email using an SMTP (Simple Mail Transfer Protocol) client interface. smtplib.SMTP([host [, port]]) Example (send an email using Google Mail SMTP server): import smtplib # Use your own to and from email address fromaddr = ‘kunaldeo@gmail.com’ toaddrs = ‘toemail@gmail.com’ msg = ‘I am a Python geek. Here is the proof.!’ # Credentials # Use your own Google Mail credentials while running the program username = ‘kunaldeo@gmail.com’ password = ‘xxxxxxxx’ # The actual mail send server = smtplib.SMTP(‘smtp.gmail. com:587’) # Google Mail uses secure connection for SMTP connections server.starttls() server.login(username,password) server.sendmail(fromaddr, toaddrs, msg) server.quit() 41. Accessing FTP server ‘ftplib’ is a fully fledged client FTP module for Python. To establish an FTP connection, you can use the following function: ftplib.FTP([host [, user [, passwd [, acct [, timeout]]]]]) Example: host = “ftp.redhat.com” username = “anonymous” password = “kunaldeo@gmail.com” import ftplib import urllib2 ftp_serv = ftplib. FTP(host,username,password) # Download the file u = urllib2.urlopen (“ftp:// ftp.redhat.com/pub/redhat/linux/ README”) # Print the file contents print (u.read()) Output: [~/src/python $:] python ftpclient.py 70 The Python Book Older versions of Red Hat Linux have been moved to the following location: ftp://archive.download. redhat.com/pub/redhat/linux/ 42. Launching a webpage with the default web browser The ‘webbrowser’ module provides a convenient way to launch webpages using the default web browser. Example (launch google.co.uk with system’s default web browser): >>> import webbrowser >>> webbrowser.open(‘http://google. co.uk’) True 43. Creating secure hashes The ‘hashlib’ module supports a plethora of secure hash algorithms including SHA1, SHA224, SHA256, SHA384, SHA512 and MD5. Example (create hex digest of the given text): >>> import hashlib # sha1 Digest >>> hashlib.sha1(“MI6 Classified Information 007”).hexdigest() ‘e224b1543f229cc0cb935a1eb9593 18ba1b20c85’ # sha224 Digest >>> hashlib.sha224(“MI6 Classified Information 007”).hexdigest() ‘3d01e2f741000b0224084482f905e9b7b97 7a59b480990ea8355e2c0’ # sha256 Digest >>> hashlib.sha256(“MI6 Classified Information 007”).hexdigest() ‘2fdde5733f5d47b672fcb39725991c89 b2550707cbf4c6403e fdb33b1c19825e’ # sha384 Digest >>> hashlib.sha384(“MI6 Classified Information 007”).hexdigest() ‘5c4914160f03dfbd19e14d3ec1e74bd8b99 dc192edc138aaf7682800982488daaf540be 9e0e50fc3d3a65c8b6353572d’ # sha512 Digest >>> hashlib.sha512(“MI6 Classified Information 007”).hexdigest() ‘a704ac3dbef6e8234578482a31d5ad29d25 2c822d1f4973f49b850222edcc0a29bb89077 8aea807a0a48ee4ff8bb18566140667fbaf7 3a1dc1ff192febc713d2’ # MD5 Digest >>> hashlib.md5(“MI6 Classified Information 007”).hexdigest() ‘8e2f1c52ac146f1a999a670c826f7126’ 44. Seeding random numbers You can use the module ‘random’ to generate a wide variety of random numbers. The most used one is ‘random.seed([x])’. It initialises the basic random number generator. If x is omitted or None, current system time is used; current system time is also used to initialise the generator when the module is first imported. 45. Working with CSV (comma-separated values) files CSV files are very popular for data exchange over the web. Using the module ‘csv’, you can read and write CSV files. Example: import csv # write stocks data as commaseparated values writer = csv.writer(open(‘stocks. csv’, ‘wb’, buffering=0)) writer.writerows([ (‘GOOG’, ‘Google, Inc.’, 505.24, 0.47, 0.09), (‘YHOO’, ‘Yahoo! Inc.’, 27.38, 0.33, 1.22), (‘CNET’, ‘CNET Networks, Inc.’, 8.62, -0.13, -1.49) ]) # read stocks data, print status messages stocks = csv.reader(open(‘stocks. csv’, ‘rb’)) status_labels = {-1: ‘down’, 0: ‘unchanged’, 1: ‘up’} for ticker, name, price, change, pct in stocks: status = status_ labels[cmp(float(change), 0.0)] print ‘%s is %s (%s%%)’ % (name, status, pct) 47. Installing thirdparty modules using setuptools ‘setuptools’ is a Python package which lets you download, build, install, upgrade and uninstall packages very easily. To use ‘setuptools’ you will need to install from your distribution’s package manager. After installation you can use the command ‘easy_install’ to perform Python package management tasks. Python essentials Third-party modules Example (installing simplejson using setuptools): kunal@ubuntu:~$ sudo easy_install simplejson Searching for simplejson Reading http://pypi.python.org/simple/ simplejson/ Reading http://undefined.org/ python/#simplejson Best match: simplejson 2.0.9 Downloading http://pypi.python. org/packages/source/s/simplejson/ simplejson-2.0.9.tar.gz#md5=af5e67a39c a3408563411d357e6d5e47 Processing simplejson-2.0.9.tar.gz Running simplejson-2.0.9/setup.py -q bdist_egg --dist-dir /tmp/easy_ install-FiyfNL/simplejson-2.0.9/eggdist-tmp-3YwsGV Adding simplejson 2.0.9 to easyinstall.pth file Installed /usr/local/lib/python2.6/ dist-packages/simplejson-2.0.9-py2.6linux-i686.egg Processing dependencies for simplejson Finished processing dependencies for simplejson 46. Logging to system log You can use the module ‘syslog’ to write to system log. ‘syslog’ acts as an interface to UNIX syslog library routines. Example: import syslog syslog.syslog(‘mygeekapp: started logging’) for a in [‘a’, ‘b’, ‘c’]: b = ‘mygeekapp: I found letter ‘+a syslog.syslog(b) syslog.syslog(‘mygeekapp: the script goes to sleep now, bye,bye!’) Output: $ python mylog.py $ tail -f /var/log/messages Nov 8 17:14:34 ubuntu -- MARK -Nov 8 17:22:34 ubuntu python: mygeekapp: started logging Nov 8 17:22:34 ubuntu python: mygeekapp: I found letter a Nov 8 17:22:34 ubuntu python: mygeekapp: I found letter b Nov 8 17:22:34 ubuntu python: mygeekapp: I found letter c Nov 8 17:22:34 ubuntu python: mygeekapp: the script goes to sleep now, bye,bye! 48. Generating PDF documents ‘ReportLab’ is a very popular module for PDF generation from Python. Perform the following steps to install ReportLab $ wget http://www.reportlab.org/ftp/ ReportLab_2_3.tar.gz $ tar xvfz ReportLab_2_3.tar.gz $ cd ReportLab_2_3 $ sudo python setup.py install For a successful installation, you should see a similar message: ############SUMMARY INFO########### ################################### #Attempting install of _rl_accel, sgmlop & pyHnj #extensions from ‘/home/kunal/python/ ReportLab_2_3/src/rl_addons/rl_accel’ ################################### #Attempting install of _renderPM #extensions from ‘/home/kunal/python/ ReportLab_2_3/src/rl_addons/renderPM’ # installing with freetype version 21 ################################### Example: >>> from reportlab.pdfgen.canvas import Canvas # Select the canvas of letter page size >>> from reportlab.lib.pagesizes import letter >>> pdf = Canvas(“bond.pdf”, pagesize = letter) # import units >>> from reportlab.lib.units import cm, mm, inch, pica >>> pdf.setFont(“Courier”, 60) >>> pdf.setFillColorRGB(1, 0, 0) >>> pdf.drawCentredString(letter[0] / 2, inch * 6, “MI6 CLASSIFIED”) >>> pdf.setFont(“Courier”, 40) >>> pdf.drawCentredString(letter[0] / 2, inch * 5, “For 007’s Eyes Only”) # Close the drawing for current page >>> pdf.showPage() # Save the pdf page >>> pdf.save() Output: @image:pdf.png @title: PDF Output Perform the following steps to install Python-Twitter: $ wget http://python-twitter. googlecode.com/files/python-twitter0.6.tar.gz $ tar xvfz python-twitter* $ cd python-twitter* $ sudo python setup.py install Example (fetching followers list): >>> import twitter # Use you own twitter account here >>> mytwi = twitter.Api(username=’kunald eo’,password=’xxxxxx’) >>> friends = mytwi.GetFriends() >>> print [u.name for u in friends] [u’Matt Legend Gemmell’, u’jono wells’, u’The MDN Big Blog’, u’Manish Mandal’, u’iH8sn0w’, u’IndianVideoGamer.com’, u’FakeAaron Hillegass’, u’ChaosCode’, u’nileshp’, u’Frank Jennings’,..’] 50. Doing Yahoo! news search You can use the Yahoo! search SDK to access Yahoo! search APIs from Python. Perform the following steps to install it: $wget http://developer.yahoo.com/ download/files/yws-2.12.zip $ unzip yws* $ cd yws*/Python/pYsearch*/ $ sudo python setup.py install Example: # Importing news search API >>> from yahoo.search.news import NewsSearch >>> srch = NewsSearch(‘YahooDemo’, query=’London’) # Fetch Results >>> info = srch.parse_results() >>> info.total_results_available 41640 >>> info.total_results_returned 10 >>> for result in info.results: ... print “’%s’, from %s” % (result[‘Title’], result[‘NewsSource’]) ... ‘Afghan Handover to Be Planned at London Conference, Brown Says’, from Bloomberg ................. 49. Using Twitter API You can connect to Twitter using the ‘PythonTwitter’ module. The Python Book 71 8PSLXJUI Python 74$SFBUEZOBNJDUFNQMBUFT 6TF+JOKB 'MBTLBOENPSF 78&YUFOTJPOTGPS9#.$ &OIBODF9#.$XJUIUIJTUVUPSJBM 844DJFOUJöDDPNQVUJOH (FUUPHSJQTXJUI/VN1Z 88*OTUBOUNFTTBHJOH (FUDIBUUJOHVTJOH1ZUIPO 943FQMBDFZPVSTIFMM 6TF1ZUIPOGPSZPVSQSJNBSZTIFMM 981ZUIPOGPSTZTUFNBENJOT )PX1ZUIPOIFMQTTZTUFNBENJOJTUSBUJPO 1024DSBQF8JLJQFEJB 6TF#FBVUJGVM4PVQUPSFBEPõ JOF 88 i&OIBODFZPVSTZTUFNTXJUI 1ZUIPOTQPXFSGVMDBQBCJMJUJFTw 725IF1ZUIPO#PPL 75 78 84 5IF1ZUIPO#PPL73 8PSLXJUI1ZUIPO Creating dynamic templates with Flask, Jinja2 and Twitter Create a dynamic webpage with Twitter and Flask’s rendering engine, Jinja2 Resources Python 2.7+ Flask 0.10.0: flask.pocoo.org Flask GitHub: github.com/mitsuhiko/flask A Twitter account Your favourite text editor Code downloaded from FileSilo QThe template uses a loop to generate a list of Twitter tweets Python and Flask are a great combination when you’re looking to handle the Twitter OAuth process and build requests to obtain tokens. We’ve used Twitter here because of the large amount of easily digestible data available on it. However, since Twitter adheres to the standards set out by OAuth 1.0, the code we’ve used to sign and build requests can be modified to work with any third-party API using the same standard without a great deal of work. For years PHP has been a mainstay of template generation, but now with welldocumented frameworks such as Flask, Sinatra and Handlebars, the ability to use powerful scripting languages greatly improves our ability to make great web services. Here, we’re going to use Python, Flask and its templating engine to display tweets. Flask comes with the super-nifty Jinja2 templating engine, If you’re familiar with Node.js or frontend JavaScript, the syntax will look very similar to the Handlebars rendering engine. But, before we dive into that, we need to organise some of the example code that we’re using for this. 745IF1ZUIPO#PPL 01 Rearranging our code Server code can get messy and unmaintainable quickly, so the first thing we’re going to do is move our helper functions to another file and import them into our project, much like you would a module. This way, it will be clear which functions are our server logic and endpoints and which are generic Python functions. Open the TwitterAuthentication file downloaded from FileSilo (stored under Twitter OAuth files) and locate the getParameters, sign_request and create_oauth_headers functions. Cut and paste them into a new file called helpers.py in the root of your project folder. At the top of this file we want to import some libraries. import urllib, collections, hmac, binascii, time, random, string helpers. Because Python is smart, It will look in the current directory for a helpers.py file before it looks for a system module. Now every function included in helpers.py is accessible to our project. All we need to do to call them is prepend our the methods we called before with helper.function_name and it will execute. For sign_request, we’ll need to pass our oauth_secret and consumer_secret for each request rather than accessing it from the session. Adjust the function declaration like so: def sign_request(parameters, method, baseURL, consumer_secret, oauth_secret): 02 server.py modules With a lot of the modules needed in this project having been moved to helpers.py, we can now remove most of them from server.py. If we amend our first import statement to be… from hashlib import sha1 import urllib2, time, random, json Now we can head back over to server.py and import the helper functions back into our project. We do this by simply calling import …our project will continue to function as it did before. Note the addition of the json module: Work with Python we’ll be using that later as we start handling Twitter data. Having Flask use a rendering engine is super-simple. Flask comes packaged with the Jinja2 template rendering engine, so we’ve nothing to install – we just need to import the package into the project. We can do this by adding render_template to the end of our from flask import […] statement. 03 Our first template Now that we have a rendering engine, we need to create some templates for it to use. In the root of our project’s folder, create a new folder called templates. Whenever we try to render a template, Flask will look in this folder for the template specified. To get to grips with templating, we’ll rewrite some of our authentication logic to use a template, rather than manually requesting endpoints. In templates, create an index.html file. You can treat this HTML file like any other – included in the resources for this tutorial is an index.html that includes all of the necessary head tags and declarations for this file. 04 Fig 01 {% if session[‘oauth_token’] != “” %}

Already Authorised

Hello, You’ve authenticated!
Let’s get some tweets

{% else %}

Authorisation required

We need to authenticate

{% endif %} QThe BSD-licensed Flask is easy to set up and use – check out the website for more info Code on FileSilo Rendering our template In server.py, let’s create a route for ‘/’ to handle the authorisation process. @app.route(‘/’) def home(): if not ‘oauth_token’ in session: session.clear() session[‘oauth_secret’] = ‘’ session[‘oauth_token’] = ‘’ return render_template(‘index.html’) It’s a simple function: all we want to do is check whether or not we have an oauth_token already and create those properties in the Flask session so we don’t throw an error if we try to access it erroneously. In order to send our generated template in response to the request, we return render_template(‘index.html’). 05 Template variables We can choose to send variables to our template with render_template(‘index.htm’, variableOne=value, variableTwo=Value) but in this instance we don’t need to as each template has access to the request and session variables. The Python Book 75 Work with Python Open index.html. All code executed in a Flask template is contained within {% %}. As this is our homepage, we want to direct users accordingly, So let’s check if we’ve got an access token (Fig 01). Between the ifs and else of the template is standard HTML. If we want to include some data – for example, the access token – we can just add {{ session[‘oauth_token’] }} in the HTML and it will be rendered in the page. Previously, in our / authorised endpoint, we would display the OAuth token that we received from Twitter; however, now that we have a template, we can redirect our users back our root URL and have a page rendered for us that explains the progress we’ve made. 06 Getting lost (and then found again) With every server, some things get misplaced or people get lost. So how do we handle this? Rather than defining a route, we can define a handler that deals with getting lost. @app.errorhandler(404) def fourOhFour(error): return render_template(‘fourohfour.html’) If a page or endpoint is requested and triggers a 404, then the fourOhFour function will be fired. In this case, we’ll generate a template that tells the user, but we could also redirect to another page or dump the error message. 07 intercept and handle the path get-tweets. The second lets us define a parameter that we can use as a value in our getTweets function. By including count=0 in our function declaration, we ensure that there will always be a default value when the function is executed; this way we don’t have to check the value is present before we access it. If a value is included in the URL, it will override the value in the function. The string inside the determines the name of the variable. If you want the variable passed to the function to have a specific type, you can include a converter with the variable name. For example, if we wanted to make sure that was always an integer instead of a float or string, we’d define our route like so: Let’s get some tweets So now we know how to build templates, let’s grab some tweets to display. In server.py define a new route, get-tweets,like so: @app.route(‘/get-tweets’) @app.route(‘/get-tweets/’) def getTweets(count=0): You’ll notice that unlike our other authentication endpoints, we’ve made two declarations. The first is a standard route definition: it will 76 The Python Book 10 Signing and sending our request We’ve built our parameters, So let’s sign our request and then add the signature to the parameters (Fig 03). Before we create the authorisation headers, we need to remove the count and user_id values from the tweetRequestParams dictionary, otherwise the signature we just created won’t be valid for the request. We can achieve this with the del keyword. Unlike our token requests, this request is a GET request, so instead of including the parameters in the request body, we define them as query parameters. ?count=tweetRequestParams[‘count’] &user_id=tweetRequestParams[‘user_id’] @app.route(‘/get-tweets/’) 09 Checking our session and building our request Before we start grabbing tweets, we want to run a quick check to make sure we have the necessary credentials and if not, redirect the user back the authorisation flow. We can do this by having Flask respond to the request with a redirection header, like so: Static files Pretty much every webpage uses JavaScript, CSS and images, but where do we keep them? With Flask we can define a folder for use with static content. For Flask, we create a static folder in the root of our project and access files by calling /static/css/styles.css or /static/js/core.js. The tutorial resources include a CSS file for styling this project. 08 Now we know how to build templates, let’s grab some tweets to display if session[‘oauth_token’] == “” or session[‘oauth_secret’] == “”: return redirect(rootURL) Assuming we have all we need, we can start to build the parameters for our request (Fig 02). You’ll notice that the nonce value is different from that in our previous requests. Where the nonce value in our authenticate and authorise requests can be any random arrangement of characters that uniquely identify the request, for all subsequent requests the nonce needs to be a 32-character hexadecimal string using only the characters a-f. If we add the following function to our helpers.py file, we can quickly build one for each request. def nonce(size=32, chars=”abcdef” + string.digits): return ‘’.join(random.choice (chars) for x in range(size)) 11 Handling Twitter’s response Now we’re ready to fire off the request and we should get a JSON response back from Twitter. This is where we’ll use the json module we imported earlier. By using the json.loads function, we can parse the JSON into a dictionary that we can access and we’ll pass through to our tweets.html template. tweetResponse = json. loads(httpResponse.read()) return render_template(‘tweets.html’, data=tweetResponse) Whereas before, we accessed the session to get data into our template, this time we’re explicitly passing a value through to our template. 12 Displaying our tweets Let’s create that template now, exactly the same as index.html but this time, instead of using a conditional, we’re going to create a loop to generate a list of tweets we’ve received. First, we check that we actually received some data from our request to Twitter. If we’ve got something to render, we’re ready to work through it, otherwise we’ll just print that we didn’t get anything. Once again, any template logic that we want to use to generate our page is included between Work with Python {% %}. This time we’re creating a loop; inside the loop we’ll be able to access any property we have of that object and print it out. In this template we’re going to create an
  • element for each tweet we received and display the user’s profile picture and text of the tweet (Fig 04). In our template we can access properties using either dot notation (.) or with square brackets ([]). They behave largely the same; the [] notation will check for an attribute on the dictionary or object defined whereas the . notation will look for an item with the same name. If either cannot find the parameter specified, it will return undefined. If this occurs, the template will not throw an error, it will simply print an empty string. Keep this in mind if your template does not render the expected data: you’ve probably just mis-defined the property you’re trying to access. Unlike traditional Python, we need to tell the template where the for loop and if/ else statements end, so we do that with {% endfor %} and {% endif %}. 13 Flask filters Sometimes, when parsing from JSON, Python can generate erroneous characters that don’t render particularly well in HTML. You may notice that after tweet[‘text’] there is |forceescape, This is an example of a Flask filter; it allows us to effect the input before we render – in this case it’s escaping our values for us. There are many, many different builtin filters that come included with Flask. Your advisor recommends a full reading of all the potential options. 14 Wrapping up That’s pretty much it for templating with Flask. As we’ve seen, it’s insanely quick and easy to build and deploy dynamic sites. Flask is great tool for any Python developer looking to run a web service. Although we’ve used Twitter to demonstrate Flask’s power, all of the techniques described can be used with any third-party service or database resource. Flask can work with other rendering engines, such as Handlebars (which is superb), but Jinja2 still needs to be present to run Flask and conflicts can occur between the two engines. With such great integration between Flask and Jinja2, it makes little sense to use another engine outside of very specific circumstances. tweetRequestParams = { “oauth_consumer_key” : consumer_key, “oauth_nonce” : helpers.nonce(32), “oauth_signature_method” : “HMAC-SHA1”, “oauth_timestamp” : int(time.time()), “oauth_version” : “1.0”, “oauth_token” : session[‚Äòoauth_token’], “user_id” : session[‘user_id’], “count” : str(count) } Fig 02 tweetRequest = helpers.sign_request(tweetRequestParams, “GET”, “https://api.twitter.com/1.1/statuses/user_timeline.json”, consumer_secret, session[‘oauth_secret’]) Fig 03 tweetRequestParams[“oauth_signature”] = tweetRequest makeRequest=urllib2.Request(“https://api.twitter.com/1.1/statuses/ user_timeline.json?count=” + tweetRequestParams[‘count’] + “&user_id=” + tweetRequestParams[‘user_id’]) del tweetRequestParams[‘user_id’], tweetRequestParams[‘count’] makeRequest.add_header(“Authorization”, helpers.create_oauth_ headers(tweetRequestParams)) try: httpResponse = urllib2.urlopen(makeRequest) except urllib2.HTTPError, e: return e.read() {% if data %} Fig 04 {% else %}

    We didn’t get any tweets :(

    {% endif %} The Python Book 77 Work with Python Rating (only available for hosted plug-ins) Current media selection List of installed plug-ins Configure launcher Localised description string Make extensions for XBMC with Python Opens changelog for the plug-in Python is the world’s most popular easy-to-use open source language. Learn how to use it to build your own features for XBMC, the world’s favourite FOSS media centre Resources XBMC: www.xbmc.org/download Python 2.7x Python IDE (optional) Code on FileSilo XBMC is perhaps the most important thing that has ever happened in the open source media centre space. It started its life on the original Xbox videogames console and since then it has become the de facto software for multimedia aficionados. It also has been forked into many other successful media centre applications such as Boxee and Plex. XBMC has ultimately grown into a very powerful open source application with a solid community behind it. It supports almost 78 The Python Book all major platforms, including different hardware architectures. It is available for Linux, Windows, Mac OS X, Android, iOS and Raspberry Pi. In these pages we will learn to build extensions for XBMC. Extensions are a way of adding features to XBMC without having to learn the core of XBMC or alter that core in any way. One additional advantage is that XBMC uses Python as its scripting language, and this can be also used to build the extensions. This really helps new developers get involved in the project since Python is easy to learn compared to languages like C/C++ (from which the core of XBMC is made). XBMC supports various types of extensions (or Add-ons): Plugins, Programs and Skins. Plugins add features to XBMC. Depending on the type of feature, a plug-in will appear in the relevant media section of XBMC. For example, a YouTube plug-in would appear in the Videos section. Scripts/Programs are like mini-applications for XBMC. They appear in the Programs section. Skins are important since XBMC is a completely customisable application – you can change the look and feel of just about every facet of the package. Depending upon which category your extension fits, you will have to create the extension directory accordingly. For example… Plug-ins: plugin.audio.ludaudi: An audio plug-in plugin.video.ludvidi: A video plug-in script.xxx.xxx: A program In this tutorial we will build an XBMC plug-in called LUD Entertainer. This plug-in will provide a nice way to watch videos from Reddit from within XBMC. Our plug-in will show various content such as trailers and documentaries from Reddit. We’ll also allow our users to add their own Subreddit. Each video can then be categorised as Hot, New, Top, Controversial etc. With this plug-in we will demonstrate how easy it is hook into XBMC’s built-in method to achieve a very high-quality user experience. Due to space limitations, we aren’t able to print the full code here. We recommend downloading the complete code from FileSilo. Work with Python 01 Preparing the directory structure As we have mentioned previously, each XBMC extension type follows a certain directory naming convention. In this case we are building a video plug-in, so the plug-in directory name would be plugin.video.ludlent. But that’s just the root directory name – we will need several other folders and files as well. The following describes the directory structure of LUD Linux Entertainer: plugin.video.ludent – Root Plugin directory |-- addon.xml |-- changelog.txt |-- default.py |-- icon.png |-- LICENSE.txt |-- README `-- resources |-- lib `-- settings.xml 02 Creating addon.xml An addon.xml file needs to be created in the root of the extension directory. The addon.xml file contains the primary metadata from a XBMC extension. It contains overview, credits, version information and dependencies information about the extension. The root element of addon.xml is the element. It is defined as: rest of the content is placed here Here, id is the identifier for the plug-in, so it should be unique among all the XBMC extensions, and id is also used for the directory name; version tells XBMC the extension version number, which helps in its ability to deliver automatic updates – XBMC follows the Major.Minor.Patch versioning convention; name is the English title of the plug-in. Note: Steps 3 to 5 cover entries that need to be added within the addon.xml file. 03 Adding dependency information Dependency inside an extension is managed using the element. In the above code we have added a dependency to a library called xbmc.python version 2.1. Currently it is added as a mandatory dependency. To make the dependency optional you will need to add optional="true"; eg In the above example we have added core dependency xbmc.python to 2.1.0 because it’s the version shipped with XBMC version Frodo 12.0 and 12.1 . If you were to add xbmc.python to 2.0 then it would only work in XBMC Eden 11.0 and not in the latest version. For the current version of XBMC 12.1, the following versions of core XBMC components are shipped: xbmc.python 2.1.0 xbmc.gui 4.0.0 xbmc.json 6.0.0 xbmc.metadata 2.1.0 xbmc.addon 12.0.0 In addition to xbmc.python we are also adding some third-party plug-ins as dependencies, such as plugin.video.youtube. These plug-ins will be installed automatically when we install plugin.video.ludent. 04 Setting up the provider and entry point Our extension is supposed to provide the video content for XBMC. In order to convey that, we have to set up the following element: video Here, the library attribute sets up the plug-in entry point. In this example default.py will be executed when the user activates the plug-in. The elements sets up the media type it provides. This also gets reflected in the placement of the plug-in. Since ours is a video plug-in, it will show up in the Videos section of XBMC. 05 Setting up plug-in metadata Metadata about the plug-in is provided in . The following are the important elements… : Most of the time, XBMC extensions are cross-platform compatible. However, if you depend on the native platform library that is only available on certain platforms then you will need to set the supported platforms here. Accepted values for the platform are: all, linux, osx, osx32, osx64, ios (Apple iOS) , windx (Windows DirectX), wingl (Windows OpenGL) and android. : This gives a brief description of the plug-in. Our example sets the language attribute as English, but you can use other languages too. : A detailed description of the plug-in. : Webpage where the plug-in is hosted. : Source code repository URL. If you are hosting your plug-in on GitHub, you can mention the repository URL here. : Discussion forum URL for your plug-in. : Author email. You can directly type email or use a bot-friendly email address like max at domain dot com. 06 Setting changelog, icon, fanart and licence We need a few additional files in the plug-in directory… changelog.txt: You should list the changes made to your plug-in between releases. The changelog is visible from the XBMC UI. An example changelog: 0.0.1 - Initial Release 0.0.2 - Fixed Video Buffering Issue icon.png: This will represent the plug-in in the XBMC UI. It needs to be a non-transparent PNG file of size 256x256. fanart.jpg (optional): The fanart.jpg is rendered in the background if a user selects the plug-in in XBMC. The art needs to be rendered in HDTV formats, so its size can range from 1280x720 (720p) up to the maximum 1920x1080 (1080p). The Python Book 79 Work with Python License.txt: This file contains the licence of the distributed plug-in. The XBMC project recommends the use of the Creative Commons Attribution-ShareAlike 3.0 licence for skins, and GPL 2.0 for add-ons. However, most of the copyleft licences can be used. Note: For the purpose of packaging, extensions/ add-ons/themes/plug-ins are the same. 07 Providing settings for the plug-in Settings can be provided by the file resources/settings.xml. These are great for userconfigurable options. Partial: resources/settings.xml Here, label defines the language id string which will then be used to display the label. id defines the name which will be used for programmatic access. type defines the data type you want to collect; it also affects the UI which will be displayed for the element. default defines the default value for the setting. You should always use a default value wherever possible to provide a better user experience. 80 The Python Book The following are a few important settings types that you can use… text: Used for basic string inputs. ipaddress: Used to collect internet addresses. number: Allows you enter a number. XBMC will also provide an on-screen numeric keyboard for the input. slider: This provides an elegant way to collect integer, float and percentage values. You can get the slider setting in the following format: In the above example we are creating a slider with min range 1, max range 10 and step as 1. In the option field we are stating the data type we are interested in – we can also set option to "float" or "percent". bool: Provides bool selection in the form of on or off. file: Provides a way to input file paths. XBMC will provide a file browser to make the selection of file. If you are looking to make selection for a specific type of file you can use audio, video, image or executable instead of file. folder: Provides a way to browse for a folder… Example: Here, source sets the start location for the folder, while option sets the write parameter for the application. sep & lsep: sep is used to draw a horizontal line in the setting dialog; lsep is used for drawing a horizontal line with text. They do not collect any input but are there for building better user interface elements… 08 Language support Language support is provided in the form of the strings.xml file located in resources/languages/[language name]. This approach is very similar to many large software projects, including Android, where static strings are never used. resource/language/english/string.xml example: Add subreddit Hot New Top Controversial Hour Day Week Month Year As you may have seen in the settings.xml example, all the labels are referring to string ids. You can have many other languages as well. Depending upon the language XBMC is running in, the correct language file will be loaded automatically. Post XBMC Frodo (12.1), strings.xml will be deprecated. Post Frodo, XBMC will be moved to a GNU gettext-based translation system; gettext uses PO files. You can use a tool called xbmc-xml2po to convert strings.xml into equivalent PO files. 09 Building default.py Since our plug-in is small, it will all be contained inside default.py. If you are developing a more complex add-on then you can create supporting files in the same directory. If your library depends upon third-party libraries, you have two ways to go about it. You can either place the third-party libraries into the resources/lib folder; or bundle the library itself into a plug-in, then add that plug-in as the dependency in the addon.xml file. Our plug-in works with reddit.tv. This is the website from Reddit which contains trending videos shared by its readers. Videos posted on Reddit are actually sourced from YouTube, Vimeo and Dailymotion. We will be starting off default.py using the following imports: import urllib import urllib2 … import xbmcplugin Work with Python import xbmcgui import xbmcaddon Apart from xbmcplugin, xbmcgui and xbmcaddon, the rest are all standard Python libraries which are available on PyPI (Python Package Index) via pip. You will not need to install any library yourself since the Python runtime for XBMC has all the components built in. urllib and urllib2 help in HTTP communication. socket is used for network I/O; re is used for regular expression matching; sqlite3 is the Python module for accessing an SQLite embedded database; xbmcplugin, xbmcgui and xbmcaddon contain the XBMC-specific routine. 10 Initialising During the initialisation process, we will be reading various settings from settings.xml. Settings can be read in the following way: addon = xbmcaddon.Addon() filterRating = int(addon. getSetting("filterRating")) filterVoteThreshold = int(addon.getS etting("filterVoteThreshold")) In order to read settings of type bool you will need to do something like: filter = addon.getSetting("filter") == "true" We are also setting the main URL, plug-in handle and the user agent for it: pluginhandle = int(sys.argv[1]) urlMain = "http://www.reddit.com" userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:22.0) Gecko/20100101 Firefox/22.0" opener = urllib2.build_opener() opener.addheaders = [(‘User-Agent’, userAgent)] 11 Reading localised strings As mentioned, XBMC uses strings.xml to serve up the text. In order to read those strings, you will need to use getLocalizedString. translation = addon. getLocalizedString translation(30002) In this example, translation(30002) will return the string "Hot" when it is running in an English environment. idFile idPath strFilename 1 1 plugin://plugin. 2 2 plugin://plugin. 1 2013-08-07 22:42 3 2 plugin://plugin. 1 2013-08-08 00:09 4 2 plugin://plugin. 1 2013-08-08 00:55 5 2 plugin://plugin. 1 2013-08-08 00:58 12 playCount lastPlayed dateAdded 2013-08-06 23:47 Building helper functions In this step we will look at some of the important helper functions. getDbPath(): This returns the location of the SQLite database file for videos. XBMC stores library and playback information in SQLite DB files. There are separate databases for videos and music, located inside the .xbmc/userdata/ Database folder. We are concerned with the videos DB. It is prefixed with ‘MyVideos’… def getDbPath(): path = xbmc. translatePath("special://userdata/ Database") files = os.listdir(path) latest = "" for file in files: if file[:8] == ‘MyVideos’ and file[-3:] == ‘.db’: if file > latest: latest = file return os.path.join(path, latest) getPlayCount(url): Once we have the database location, we can get the play count using a simple SQL query. The MyVideo database contains a table called files, which keeps a record of all the video files played in XBMC by filename. In this case it will be URL. dbPath = getDbPath() conn = sqlite3.connect(dbPath) c = conn.cursor() def getPlayCount(url): c.execute(‘SELECT playCount FROM files WHERE strFilename=?’, [url]) result = c.fetchone() if result: result = result[0] if result: return int(result) return 0 return -1 The above table is an example of a files table. addSubreddit(): Our plug-in allows users to add their own Subreddit. This function takes the Subreddit input from the user, then saves it in the subreddits file inside the addon data folder. The following sets the subreddits file location: subredditsFile = xbmc. translatePath("special://profile/ addon_data/"+addonID+"/subreddits") this translates into .xbmc/userdata/ addon_data/plugin.video.ludent/ subreddits def addSubreddit(): keyboard = xbmc.Keyboard(‘’, translation(30001)) keyboard.doModal() if keyboard.isConfirmed() and keyboard.getText(): subreddit = keyboard. getText() fh = open(subredditsFile, ‘a’) fh.write(subreddit+’\n’) fh.close() This function also demonstrates how to take a text input from the user. Here we are calling the Keyboard function with a text title. Once it detects the keyboard, it writes the input in the subreddits file with a newline character. getYoutubeUrl(id): When we locate a YouTube URL to play, we pass it on to the YouTube plug-in (plugin.video.youtube) to handle the playback. To do so, we need to call it in a certain format… def getYoutubeUrl(id): url = "plugin://plugin. video.youtube/?path=/root/ video&action=play_video&videoid=" + id return url The Python Book 81 Work with Python On the same lines, we can build a function to place links as well… Similarly for Vimeo: def getVimeoUrl(id): url = "plugin://plugin.video. vimeo/?path=/root/video&action=play_ video&videoid=" + id return url And for Dailymotion: def getDailyMotionUrl(id): url = "plugin://plugin.video. dailymotion_com/?url=" + id + "&mode=playVideo" return url Once we have the video URL resolved into the respective plug-in, playing it is very simple: def playVideo(url): listitem = xbmcgui. ListItem(path=url) xbmcplugin. setResolvedUrl(pluginhandle, True, listitem) 13 Populating plug-in content listing xbmcplugin contains various routines for handling the content listing inside the plug-ins UI. The first step is to create directory entries which can be selected from the XBMC UI. For this we will use a function called xbmcplugin.addDirectoryItem. For our convenience we will be abstracting addDirectoryItem to suit it to our purpose, so that we can set name, URL, mode, icon image and type easily. def addDir(name, url, mode, iconimage, type=""): u = sys.argv[0]+"?url="+urllib. quote_plus(url)+"&mode="+str(mode)+" &type="+str(type) ok = True liz = xbmcgui.ListItem(name, iconImage="DefaultFolder.png", thumbnailImage=iconimage) liz.setInfo(type="Video", infoLabels={"Title": name}) ok = xbmcplugin. addDirectoryItem(handle=int(sys. argv[1]), url=u, listitem=liz, isFolder=True) return ok 82 The Python Book def addLink(name, url, mode, iconimage, description, date): u = sys.argv[0]+"?url="+urllib. quote_plus(url)+"&mode="+str(mode) ok = True liz = xbmcgui.ListItem(name, iconImage="DefaultVideo.png", thumbnailImage=iconimage) liz.setInfo(type="Video", infoLabels={"Title": name, "Plot": description, "Aired": date}) liz.setProperty(‘IsPlayable’, ‘true’) ok = xbmcplugin. addDirectoryItem(handle=int(sys. argv[1]), url=u, listitem=liz) return ok Based on the abstractions we have just created, we can create the base functions which will populate the content. But before we do that, let’s first understand how Reddit works. Most of the Reddit content filters are provided through something called Subreddits. This allows you to view discussions related to a particular topic. In our plug-in we are interested in showing videos; we also want to show trailers, documentaries etc. We access these using Subreddits. For example, for trailers it would be reddit.com/r/ trailers. For domains we can use /domain; for example, to get all the YouTube videos posted on Reddit, we will call reddit.com/domain/ youtube.com. Now you may ask what is the guarantee that this Subreddit will only list videos? The answer is that it may not. For that reason we scrape the site ourselves to find videos. More on this in the next step. The first base function we’ll define is index(). This is called when the user starts the plug-in. def index(): defaultEntries = ["videos", "trailers", "documentaries", "music"] entries = defaultEntries[:] if os.path. exists(subredditsFile): fh = open(subredditsFile, ‘r’) content = fh.read() fh.close() spl = content.split(‘\n’) for i in range(0, len(spl), 1): if spl[i]: subreddit = spl[i] entries. append(subreddit) entries.sort() for entry in entries: if entry in defaultEntries: addDir(entry.title(), "r/"+entry, ‘listSorting’, "") else: addDirR(entry.title(), "r/"+entry, ‘listSorting’, "") addDir("[ Vimeo.com ]", "domain/vimeo.com", ‘listSorting’, "") addDir("[ Youtu.be ]", "domain/ youtu.be", ‘listSorting’, "") addDir("[ Youtube.com ]", "domain/youtube.com", ‘listSorting’, "") addDir("[ Dailymotion.com ]", "domain/dailymotion.com", ‘listSorting’, "") addDir("[B]"+translation(30001)+" -[/B]", "", ‘addSubreddit’, "") xbmcplugin. endOfDirectory(pluginhandle) Here, the penultimate entry makes a call to addSubreddit. listSorting takes care of sorting out the data based on criteria such as Hot, New etc. It also calls in Reddit’s JSON function, which returns nice easy-to-parse JSON data. We have created a settings entry for all the sorting criteria. Based on what is set, we go ahead and build out the sorted list. def listSorting(subreddit): if cat_hot: addDir(translation(30002), urlMain+"/"+subreddit+"/hot/. json?limit=100", ‘listVideos’, "") if cat_new: addDir(translation(30003), urlMain+"/"+subreddit+"/new/. json?limit=100", ‘listVideos’, "") if cat_top_d: addDir(translation(30004)+": "+translation(30007), urlMain+"/"+subreddit+"/ top/.json?limit=100&t=day", ‘listVideos’, "") xbmcplugin. endOfDirectory(pluginhandle) Work with Python def listVideos(url): currentUrl = url xbmcplugin.setContent(pluginhandle, "episodes") content = opener.open(url).read() spl = content.split(‘"content"’) for i in range(1, len(spl), 1): entry = spl[i] try: match = re.compile(‘"title": "(.+?)"’, re.DOTALL).findall(entry) title = match[0].replace("&", "&") match = re.compile(‘"description": "(.+?)"’, re.DOTALL). findall(entry) description = match[0] match = re.compile(‘"created_utc": (.+?),’, re.DOTALL).findall(entry) downs = int(match[0].replace("}", "")) rating = int(ups*100/(ups+downs)) if filter and (ups+downs) > filterVoteThreshold and rating < filterRating: continue title = title+" ("+str(rating)+"%)" match = re.compile(‘"num_comments": (.+?),’, re.DOTALL). findall(entry) comments = match[0] description = dateTime+" | "+str(ups+downs)+" votes: "+str(rating)+"% Up | "+comments+" comments\n"+description match = re.compile(‘"thumbnail_url": "(.+?)"’, re.DOTALL). findall(entry) thumb = match[0] matchYoutube = re.compile(‘"url": "http://www.youtube.com/ watch\\?v=(.+?)"’, re.DOTALL).findall(entry) matchVimeo = re.compile(‘"url": "http://vimeo.com/(.+?)"’, re.DOTALL).findall(entry) url = "" if matchYoutube: url = getYoutubeUrl(matchYoutube[0]) elif matchVimeo: url = getVimeoUrl(matchVimeo[0].replace("#", "")) if url: addLink(title, url, ‘playVideo’, thumb, description, date) except: pass match = re.compile(‘"after": "(.+?)"’, re.DOTALL).findall(entry) xbmcplugin.endOfDirectory(pluginhandle) if forceViewMode: xbmc.executebuiltin(‘Container.SetViewMode(‘+viewMode+’)’) 14 Populating the episode view (listing videos) At this point we have the URL in hand, which returns JSON data; now we need to extract the data out of it which will make sense to us. By looking at the JSON data, you can see there’s a lot of interesting information present here. For example, url is set to youtube.com/watch?v=n4rTztvVx8E; title is set to ‘The Counselor – Official Trailer’. There also many other bits of data that we will use, such as ups, downs, num_comments, thumbnail_url and so on. In order to filter out the data that we need, we will use regular expressions. There is one more thing to note: since we are not presenting directories any more but are ready to place content, we have to set the xbmcplugin.setContent to episodes mode. In the code listed to the left here, we are opening the URL, then – based on regular expression matches – we are discovering the location title, description, date, ups, downs and rating. We are also locating video thumbnails and then passing them on to XBMC. Later in the code, we also try to match the URL to a video provider. With our plug-in we are supporting YouTube, Vimeo and Dailymotion. If this is detected successfully, we call the helper functions to locate the XBMC plugin based playback URL. During this whole parsing process, if any exception is raised, the whole loop is ignored and the next JSON item is parsed. 15 Installing & running the add-on You can install the add-on using one of the following two methods: • You can copy the plug-in directory to .xbmc/addons. • You can install the plug-in from the zip file. To do so, compress the add-on folder into a zip file using the command: $ zip -r plugin.video.ludent.zip plugin.video.ludent To install the plug-in from the zip file, open XBMC, go to System then Add-ons, then click ‘Install from zip file’. The benefit of installing from a zip file is that XBMC will automatically try to install all the dependent plug-ins as well. Once you have the plug-in installed, you can run it by going to the Videos Add-ons section of XBMC, selecting Get More… and then clicking on LUD Reddit Viewer. You can access the settings dialog of the plug-in by right-clicking the LUD Reddit Viewer, then selecting ‘Add-on settings’. So, you have seen how robust and powerful XBMC’s extension system is. In this example, we were able to leverage the full power of Python (including those magical regular expression matches) from within XBMC. XBMC itself also offers a robust UI framework, which provides a very professional look for our add-on. As powerful as it may seem, we have only built a video plug-in. XBMC’s extension system also provides a framework for building fully fledged programs (called Programs). We will cover this in a later issue. The Python Book 83 Work with Python Matplotlib generated output A simple Python program for Polynomial Fitting! Finding help is easy A Python script that uses SciPy to process an image Scientific computing with NumPy Powerful calculations with NumPy, SciPy and Matplotlib Resources NumPy: www.numpy.org SciPy: www.scipy.org Matplotlib: www.matplotlib.org 84 The Python Book NumPy is the primary Python package for performing scientific computing. It has a powerful N-dimensional array object, tools for integrating C/C++ and Fortran code, linear algebra, Fourier transform, and random number capabilities, among other things. NumPy also supports broadcasting, which is a clever way for universal functions to deal in a meaningful way with inputs that do not have exactly the same form. Apart from its capabilities, the other advantage of NumPy is that it can be integrated into Python programs. In other words, you may get your data from a database, the output of another program, an external file or an HTML page and then process it using NumPy. This article will show you how to install NumPy, make calculations, plot data, read and write external files, and it will introduce you to some Matplotlib and SciPy packages that work well with NumPy. NumPy also works with Pygame, a Python package for creating games, though explaining its use is beyond of the scope of this article. It is considered good practice to try the various NumPy commands inside the Python shell before putting them into Python programs. The examples in this article are using either Python shell or iPython. 01 Installing NumPy Most Linux distributions have a ready-to-install package you can use. After installation, you can find out the NumPy version you are using by executing the following: $ python Python 2.7.3 (default, Mar 13 2014, 11:03:55) [GCC 4.7.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> numpy.version.version Work with Python Traceback (most recent call last): File "", line 1, in NameError: name 'numpy' is not defined >>> import numpy >>> numpy.version.version '1.6.2' >>> 03 Making simple calculations Not only have you found the NumPy version but you also know that NumPy is properly installed. 02 About NumPy Despite its simplistic name, NumPy is a powerful Python package that is mainly for working with arrays and matrices. There are many ways to create an array but the simplest is by using the array() function: >>> oneD = array([1,2,3,4]) The aforementioned command creates a one-dimensional array. If you want to create a two-dimensional array, you can use the array() function as follows: >>> twoD = array([ [1,2,3], ... [3,3,3], ... [-1,-0.5,4], ... [0,1,0]] ) You can also create arrays with more dimensions. 03 Making simple calculations using NumPy Given an array named myArray, you can find the minimum and maximum values in it by executing the following commands: >>> myArray.min() >>> myArray.max() Should you wish to find the mean value of all array elements, run the next command: >>> myArray.mean() Similarly, you can find the median of the array by running the following command: >>> median(myArray) The median value of a set is an element that divides the data set into two subsets (left and right subsets) with the same number of elements. If the data set has an odd number of elements, then the median is part of the data set. On the other side, if the data set has an even number of elements, then the median is the mean value of the two centre elements of the sorted data set. 04 Using arrays with NumPy NumPy not only embraces the indexing methods used in typical Python for strings and lists but also extends them. If you want to select a given element from an array, you can use the following notation: 06 Writing to files Writing variables to a file is largely similar to reading a file. If you have an array variable named aa1, you can easily save its contents into a file called aa1.txt by using the following command: >>> twoD[1,2] In [17]: np.savetxt("aa1.txt", aa1) You can also select a part of an array (a slice) using the following notation: As you can easily imagine, you can read the contents of aa1.txt later by using the loadtxt() function. >>> twoD[:1,1:3] Finally, you can convert an array into a Python list using the tolist() function. 05 Reading files Imagine that you have just extracted information from an Apache log file using AWK and you want to process the text file using NumPy. The following AWK code finds out the total number of requests per hour: $ cat access.log | cut -d[ -f2 | cut -d] -f1 | awk -F: '{print $2}' | sort -n | uniq -c | awk '{print $2, $1}' > timeN.txt The format of the text file (timeN.txt) with the data is the following: 00 01 02 03 191 225 121 104 Reading the timeN.txt file and assigning it to a new array variable can be done as follows: 07 Common functions 08 Working with matrices NumPy supports many numerical and statistical functions. When you apply a function to an array, the function is automatically applied to all array elements. When working with matrices, you can find the inverse of a matrix AA by typing “AA.I”. You can also find its eigenvalues by typing “np.linalg. eigvals(AA)” and its eigenvector by typing “np. linalg.eig(BB)”. A special subtype of a two-dimensional NumPy array is a matrix. A matrix is like an array except that matrix multiplication replaces element-by-element multiplication. Matrices are generated using the matrix (or mat) function as follows: In [2]: AA = np.mat('0 1 1; 1 1 1; 1 1 1') You can add two matrices named AA and BB by typing AA + BB. Similarly, you can multiply them by typing AA * BB. aa = np.loadtxt("timeN.txt") The Python Book 85 Work with Python 09 Plotting with Matplotlib 09 Plotting with Matplotlib The first move you should make is to install Matplotlib. As you can see, Matplotlib has many dependencies that you should also install. The first thing you will learn is how to plot a polynomial function. The necessary commands for plotting the 3x^2-x+1 polynomial are the following: import numpy as np import matplotlib.pyplot as plt myPoly = np.poly1d(np.array([3, -1, 1]). astype(float)) x = np.linspace(-5, 5, 100) y = myPoly(x) plt.xlabel('x values') plt.ylabel('f(x) values') xticks = np.arange(-5, 5, 10) yticks = np.arange(0, 100, 10) plt.xticks(xticks) plt.yticks(yticks) plt.grid(True) plt.plot(x,y) The variable that holds the polynomial is myPoly. The range of values that will be plotted for x is defined using “x = np.linspace(-5, 5, 100)”. The other important variable is y, which calculates and holds the values of f(x) for each x value. It is important that you start ipython using the “ipython --pylab=qt” parameters in order to see the output on your screen. If you are interested in plotting polynomial functions, you should experiment more, as NumPy can also calculate the derivatives of a function and plot multiple functions in the same output. SciPy is built on top of NumPy and is more advanced 10 In [36]: In [37]: In [38]: In [39]: In [40]: In [41]: Out[41]: array([ In [42]: Out[42]: In [43]: Out[43]: 86 The Python Book from scipy.stats import poisson, lognorm mySh = 10; myMu = 10; ln = lognorm(mySh) p = poisson(myMu) ln.rvs((10,)) 9.29393114e-02, 1.15957068e+01, 8.26370734e-07, 5.64451441e-03, 4.98471222e-06, 1.45947948e+02, 5.87353720e-02]) p.rvs((10,)) array([12, 11, 9, 9, 9, 10, 9, ln.pdf(3) 0.013218067177522842 9.78411983e+01, 4.61744055e-09, 9.25502852e-06, 4, 13, 8]) Fig 01 About SciPy SciPy is built on top of NumPy and is more advanced than NumPy. It supports numerical integration, optimisations, signal processing, image and audio processing, and statistics. The example in Fig. 01 (to the left) uses a small part of the scipy.stats package that is about statistics. The example uses two statistics distributions and may be difficult to understand even if you know mathematics, but it is presented in order to give you a better taste of SciPy commands. 11 Using SciPy for image processing Now we will show you how to process and transform a PNG image using SciPy. The most important part of the code is the following line: Work with Python image = np.array(Image.open('SA.png'). convert('L')) This line allows you to read a usual PNG file and convert it into a NumPy array for additional processing. The program will also separate the output into four parts and displays a different image for each of these four parts. 12 Other useful functions It is very useful to be able to find out the data type of the elements in an array; it can be done using the dtype() function. Similarly, the ndim() function returns the number of dimensions of an array. When reading data from external files, you can save their data columns into separate variables using the following way: Process and transform a PNG image using SciPy 11 Using SciPy for image processing In [10]: aa1,aa2 = np.loadtxt("timeN.txt", usecols=(0,1), unpack=True) The aforementioned command saves column 1 into variable aa1 and column 2 into variable aa2. The “unpack=True” allows the data to be assigned to two different variables. Please note that the numbering of columns starts with 0. 13 Fitting to polynomials The NumPy polyfit() function tries to fit a set of data points to a polynomial. The data was found from the timeN.txt file, created earlier in this article. The Python script uses a fifth degree polynomial, but if you want to use a different degree instead then you only have to change the following line: 13 Fitting to Polynomials coefficients = np.polyfit(aa1, aa2, 5) 14 Array broadcasting in NumPy To close, we will talk more about array broadcasting because it is a very useful characteristic. First, you should know that array broadcasting has a rule: in order for two arrays to be considered for array broadcasting, “the size of the trailing axes for both arrays in an operation must either be the same size or one of them must be one.” Put simply, array broadcasting allows NumPy to “change” the dimensions of an array by filling it with data in order to be able to do calculations with another array. Nevertheless, you cannot stretch both dimensions of an array to do your job. The Python Book 87 Work with Python The server notifies all clients when a new client joins Each message has a time stamp prefixed to it Similarly, the server notifies all clients when a client leaves A client can detect when the server exits without crashing or hanging Instant messaging with Python How to program both the client, complete with a GUI, and server of a simple instant messenger in Python Resources A computer – running your favourite Linux distribution Internet connection – to access documentation Python 2.x, PyGTK and GObject – packages installed 88 The Python Book He’re we’ll be implementing an instant messenger in Python with a client-server architecture. This means each client connects to the server, which relays any message that one client sends to all other clients. The server will also notify the other clients when someone joins or leaves the server. The instant messenger can work anywhere a TCP socket can: on the same computer with the loopback interface, across various computers on a LAN, or even over the internet if you were to configure your router correctly. However, our messages aren’t encrypted, so we wouldn’t recommend that. Writing an instant messenger is an interesting technical problem that covers a bunch of areas that you may not have come across while programming before: • We’ll be employing sockets, which are used to transmit data across networks. • We’ll also be using threading, which allows a program to do multiple things at once. • We’ll cover the basics of writing a simple graphical user interface with GTK, as well as how to interact with that from a different thread. • Finally, we’ll be touching on the use of regular expressions to easily analyse and extract data from strings. Before getting started, you’ll need to have a Python2.x interpreter installed, as well as the PyGTK bindings and the Python2 GObject bindings. The chances are that if you have a system with a fair amount of software on it, you will already have these packages, so it may be easier to wait and see if you’re missing any libraries when you attempt to import them. All of the above packages are commonly used, so you should be able to install them using your distro’s package manager. Work with Python 01 The server The server will do the following jobs: • Listen for new clients • Notify all clients when a new client joins • Notify all clients when a client leaves • Receive and deliver messages to all clients We’re going to write the server side of the instant messenger first, as the client requires it. There will be two code files, so it’s a good idea to make a folder to keep them inside. You can create an empty file with the command touch [filename], and mark that file as executable using chmod +x [filename]. This file is now ready to edit in your favourite editor. [liam@liam-laptop Python-IM [liam@liam-laptop Python-IM/ [liam@liam-laptop IM-Server.py [liam@liam-laptop +x IM-Server.py 02 Python]$ mkdir Python]$ cd Python-IM]$ touch Python-IM]$ chmod Starting off As usual, we need to start off with the line that tells the program loader what it needs to interpret the rest of the file with. In your advisor’s case, that line is: #!/usr/bin/env python2. On your system, it may need to be changed to #!/usr/bin/env/ python2.6 or #!/usr/ bin/env python2.7 After that, we’ve written a short comment about what the application does, and imported the required libraries. We’ve already mentioned what the threading and socket libraries are for. The re library is used for searching strings with regular expressions. The signal library is used for dealing with signals that will kill the program, such as SIGINT. SIGINT is sent when Ctrl+C is pressed. We handle these signals so that the program can tell the clients that it’s exiting rather than dying unexpectedly. The sys library is used to exit the program. Finally, the time library is used to put a sensible limit on how frequently the body of while loops execute. #!/usr/bin/env python2 # The server side of an instant messaging application. Written as part of a Linux User & Developer tutorial by Liam Fraser in 2013. import threading import import import import import 03 socket re signal sys time The Server class The Server class is the main class of our instant messenger server. The initialiser of this class accepts a port number to start listening for clients on. It then creates a socket, binds the socket to the specified port on all interfaces, and then starts to listen on that port. You can optionally include an IP address in the tuple that contains the port. Passing in a blank string like we have done causes it to listen on all interfaces. The value of 1 passed to the listen function specifies the maximum number of queued connections we can accept. This shouldn’t be a problem as we’re not expecting a bunch of clients to connect at exactly the same time. Now that we have a socket, we’ll create an empty array that will be later used to store a collection of client sockets that we can echo messages to. The final part is to tell the signal library to run the self.signal_handler function, which we have yet to write, when a SIGINT or SIGTERM is sent to the application so that we can tidy up nicely. class Server(): def __init__(self, port): # Create a socket and bind it to a port self.listener = socket. socket(socket.AF_INET, socket.SOCK_ STREAM) self.listener.bind((‘’, port)) self.listener.listen(1) print “Listening on port {0}”.format(port) # Used to store all of the client sockets we have, for echoing to them self.client_sockets = [] # Run the function self.signal_ handler when Ctrl+C is pressed signal.signal(signal.SIGINT, self.signal_handler) signal.signal(signal. SIGTERM, self.signal_handler) 04 The server’s main loop Useful documentation Threading: docs.python.org/2/library/ threading.html Sockets: docs.python.org/2/library/ socket.html Regular expressions: docs.python. org/2/library/re.html The signal handler: docs.python.org/ 2/library/signal.html PyGTK: www.pygtk.org/ pygtk2reference GObject: www.pygtk.org/ pygtk2reference/gobject-functions.html sockets and then starts an instance of the ClientListener class, which we have yet to write, in a new thread. Sometimes, defining interfaces you are going to call before you’ve written them is good, because it can give an overview of how the program will work without worrying about the details. Note that we’re printing information as we go along, to make debugging easier should we need to do it. Sleeping at the end of the loop is useful to make sure the while loop can’t run quickly enough to hang the machine. However, this is unlikely to happen as the line that accepts new connections is blocking, which means that the program waits for a connection before moving on from that line. For this reason, we need to enclose the line in a try block, so that we can catch the socket error and exit when we can no longer accept connections. This will usually be when we’ve closed the socket during the process of quitting the program. def run(self): while True: # Listen for clients, and create a ClientThread for each new client print “Listening for more clients” try: (client_socket, client_address) = self.listener. accept() except socket.error: sys.exit(“Could not The server’s main loop essentially accepts new connections from clients, adds that client’s socket to the collection of The Python Book 89 Work with Python accept any more connections”) self.client_sockets. append(client_socket) print “Starting client thread for {0}”.format(client_ address) client_thread = ClientListener(self, client_socket, client_address) client_thread.start() time.sleep(0.1) 05 The echo function We need a function that can be called from a client’s thread to echo a message to each client. This function is pretty simple. The most important part is that sending data to sockets is in a try block, which means that we can handle the exception if the operation fails, rather than having the program crash. def echo(self, data): # Send a message to each socket in self.client_socket print "echoing: {0}". format(data) for socket in self.client_ sockets: # Try and echo to all clients try: socket.sendall(data) except socket.error: print "Unable to send message" 06 Finishing the Server class The remainder of the Server class is taken up with a couple of simple functions; one to remove a socket from the collection of sockets, which doesn’t need an explanation, and the signal_handler function that we talked about in the initialiser of the class. This function stops listening for new connections, and unbinds the socket from the port it was listening on. Finally, we send a message to each client to let them know that we are exiting. The signal will continue to close the program as expected once the signal_handler function has ended. def remove_socket(self, socket): 90 The Python Book # Remove the specified socket from the client_sockets list self.client_sockets. remove(socket) def signal_handler(self, signal, frame): # Run when Ctrl+C is pressed print "Tidying up" # Stop listening for new connections self.listener.close() # Let each client know we are quitting self.echo("QUIT") 07 The client thread The class that is used to deal with each client inherits the Thread class. This means that the class can be created, then started with client_thread.start(). At this point, the code in the run function of the class will be run in the background and the main loop of the Server class will continue to accept new connections. We have to start by initialising the Thread base class, using the super keyword. You may have noticed that when we created a new instance of the ClientListener class in the server’s main loop, we passed through the server’s self variable. We do this because it’s better for each instance of the ClientListener class to have its own reference to the server, rather than using the global one that we’ll create later to actually start the application. class ClientListener(threading. Thread): def __init__(self, server, socket, address): # Initialise the Thread base class super(ClientListener, self).__init__() # Store the values that have been passed to the constructor self.server = server self.address = address self.socket = socket self.listening = True self.username = "No Username" 08 The client thread’s loop The loop that runs in the client thread is pretty similar to the one in the server. It keeps listening for data while self.listening is true, and passes any data it gets to a handle_msg function that we will write shortly. The value passed to the socket.recv function is the size of the buffer to use while receiving data. def run(self): # The thread's loop to receive and process messages while self.listening: data = "" try: data = self.socket. recv(1024) except socket.error: "Unable to recieve data" self.handle_msg(data) time.sleep(0.1) # The while loop has ended print "Ending client thread for {0}".format(self.address) 09 Tidying up We need to have a function to tidy up the thread. We’ll call this either when the client sends us a blank string (indicating that it’s stopped listening on the socket) or sends us the string “QUIT”. When this happens, we’ll echo to every client that the user has quit. def quit(self): # Tidy up and end the thread self.listening = False self.socket.close() self.server.remove_ socket(self.socket) self.server.echo("{0} has quit.\n".format(self.username)) 10 Handling messages There are three possible messages our clients can send: • QUIT • USERNAME user • Arbitrary string to be echoed to all clients The client will also send a bunch of empty messages if the socket has been closed, so we will end their thread if that happens. The code should be pretty self-explanatory apart from the regular expression part. If someone sends the USERNAME message, then the server tells every client that a new user has joined. This is tested with a regular expression. ^ indicates the start of the string, $ indicates the end, and the brackets containing .* extract whatever comes after “USERNAME ”. Work with Python We need to tell GObject that we’ll be using threading def handle_msg(self, data): # Print and then process the message we’ve just recieved print "{0} sent: {1}". format(self.address, data) # Use regular expressions to test for a message like "USERNAME liam" username_result = re.search('^USERNAME (.*)$', data) if username_result: self.username = username_result.group(1) self.server.echo("{0} has joined.\n".format(self. username)) elif data == "QUIT": # If the client has sent quit then close this thread self.quit() elif data == "": # The socket at the other end is probably closed self.quit() else: # It's a normal message so echo it to everyone self.server.echo(data) 11 Starting the server The code that actually starts the Server class is as follows. Note that you are probably best picking a high-numbered port as you need to be root to open ports <1024. if __name__ == "__main__": # Start a server on port 59091 server = Server(59091) server.run() 12 The client Create a new file for the client as we did for the server and open it in your favourite editor. The client requires the same imports as the server, as well as the gtk, gobject and datetime libraries. One important thing we need to do is to tell GObject that we’ll be using threading, so we can call functions from other threads and have the main window, which is running in the main GTK thread, update. #!/usr/bin/env python2 # The client side of an instant messaging application. Written as part of a Linux User & Developer tutorial by Liam Fraser in 2013. import import import import import import import threading gtk gobject socket re time datetime # Tell gobject to expect calls from multiple threads gobject.threads_init() 13 The client graphical user interface The user interface of the client isn’t the main focus of the tutorial, and won’t be explained in as much detail as the rest of the code. However, the code should be fairly straightforward to read and we have provided links to documentation that will help. Our MainWindow class inherits the gtk Window class, so we need to start by initialising that using the super keyword. Then we create the controls that will go on the window, connect any events they have to functions, and finally lay out the controls how we want. The destroy event is raised when the program is closed, and the other events should be obvious. GTK uses a packing layout, in which you use Vboxes and Hboxes to lay out the controls. V and H stand for vertical and horizontal. These controls essentially let you split a window up almost like a table, and will automatically decide the size of the controls depending on the size of the application. GTK doesn’t come with a control to enter basic information, such as the server’s IP address, port and your chosen username, so we’ve made a function called ask_for_info, which creates a message box, adds a text box to it and then retrieves the results. We’ve done this because it’s simpler and uses less code than creating a new window to accept the information. class MainWindow(gtk.Window): def __init__(self): # Initialise base gtk window class super(MainWindow, self).__ init__() # Create controls self.set_title("IM Client") vbox = gtk.VBox() hbox = gtk.HBox() self.username_label = gtk. Label() self.text_entry = gtk. Entry() send_button = gtk. Button("Send") self.text_buffer = gtk. TextBuffer() text_view = gtk. TextView(self.text_buffer) # Connect events self.connect("destroy", self.graceful_quit) send_button. connect("clicked", self.send_ message) # Activate event when user presses Enter self.text_entry. connect("activate", self.send_ message) # Do layout vbox.pack_start(text_view) hbox.pack_start(self. username_label, expand = False) 8PSLXJUI1ZUIPO hbox.pack_start(self.text_ entry) hbox.pack_end(send_button, expand = False) vbox.pack_end(hbox, expand = False) # Show ourselves self.add(vbox) self.show_all() # Go through the configuration process self.configure() def ask_for_info(self, question): # Shows a message box with a text entry and returns the response dialog = gtk. MessageDialog(parent = self, type = gtk.MESSAGE_QUESTION, flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, buttons = gtk.BUTTONS_OK_CANCEL, message_format = question) entry = gtk.Entry() entry.show() dialog.vbox.pack_end(entry) response = dialog.run() response_text = entry. get_text() dialog.destroy() if response == gtk.RESPONSE_ OK: return response_text else: return None 14 Configuring the client This code is run after we’ve added the controls to the main window, and asks the user for input. Currently, the application will exit if the user enters an incorrect server address or port; but this isn’t a production system, so that’s fine. def configure(self): # Performs the steps to connect to the server # Show a dialog box asking for server address followed by a port server = self.ask_for_ info("server_address:port") # Regex that crudely matches an IP address and a port number regex = re.search('^(\d+\.\ d+\.\d+\.\d+):(\d+)$', server) address = regex.group(1). strip() port = regex.group(2). strip() # Ask for a username self.username = self.ask_ for_info("username") self.username_label.set_ text(self.username) # Attempt to connect to the server and then start listening self.network = Networking(self, self.username, address, int(port)) self.network.listen() 15 The remainder of MainWindow The rest of the MainWindow class has plenty of comments to explain itself, as follows. One thing to note is that when a client sends a message, it doesn’t display it in the text view straight away. The server is going to echo the message to each client, so the client simply displays its own message when the server echoes it back. This means that you can tell if the server is not receiving your messages when you don’t see a message that you send. def add_text(self, new_text): # Add text to the text view text_with_timestamp = "{0} {1}".format(datetime.datetime.now(), new_text) # Get the position of the end of the text buffer, so we know where to insert new text end_itr = self.text_buffer. get_end_iter() # Add new text at the end of the buffer self.text_buffer.insert(end_ itr, text_with_timestamp) def send_message(self, widget): # Clear the text entry and send the message to the server # We don't need to display it as it will be echoed back to each client, including us. new_text = self.text_entry. get_text() self.text_entry.set_text("") message = "{0} says: {1}\n". format(self.username, new_text) self.network.send(message) def graceful_quit(self, widget): # When the application is closed, tell GTK to quit, then tell the server we are quitting and tidy up the network gtk.main_quit() self.network.send("QUIT") self.network.tidy_up() The server is going to echo the message to each client Work with Python 16 The client’s Networking class Much of the client’s Networking class is similar to that of the server’s. One difference is that the class doesn’t inherit the Thread class – we just start one of its functions as a thread. class Networking(): def __init__(self, window, username, server, port): # Set up the networking class self.window = window self.socket = socket. socket(socket.AF_INET, socket.SOCK_ STREAM) self.socket.connect((server, port)) self.listening = True # Tell the server that a new user has joined self.send("USERNAME {0}". format(username)) def listener(self): # A function run as a thread that listens for new messages while self.listening: data = "" try: data = self.socket. recv(1024) except socket.error: "Unable to recieve data" self.handle_msg(data) # Don't need the while loop to be ridiculously fast time.sleep(0.1) 17 Running a function as a thread The listener function above will be run as a thread. This is trivial to do. Enabling the daemon option on the thread means that it will die if the main thread unexpectedly ends. def listen(self): # Start the listening thread self.listen_thread = threading.Thread(target=self. listener) # Stop the child thread from keeping the application open self.listen_thread.daemon = True self.listen_thread.start() 18 Finishing the Networking class Again, most of this code is similar to the code in the server’s Networking class. One difference is that we want to add some things to the text view of our window. We do this by using the idle_add function of GObject. This allows us to call a function that will update the window running in the main thread when it is not busy. def send(self, message): # Send a message to the server print "Sending: {0}". format(message) try: self.socket. sendall(message) except socket.error: print "Unable to send message" def tidy_up(self): # We'll be tidying up if either we are quitting or the server is quitting self.listening = False self.socket.close() # We won't see this if it's us that's quitting as the window will be gone shortly gobject.idle_add(self. window.add_text, "Server has quit.\n") def handle_msg(self, data): if data == "QUIT": # Server is quitting self.tidy_up() elif data == "": # Server has probably closed unexpectedly self.tidy_up() else: # Tell the GTK thread to add some text when it's ready gobject.idle_add(self. window.add_text, data) 19 Starting the client The main window is started by initialising an instance of the class. Notice that we don’t need to store anything that is returned. We then start the GTK thread by calling gtk.main(). if __name__ == "__main__": # Create an instance of the main window and start the gtk main loop MainWindow() gtk.main() 20 you’ve started the server, open an instance of the client and enter 127.0.0.1:port, where ‘port’ is the port you decided to use. The server will print the port it’s listening on to make this easy. Then enter a username and click OK. Here is an example output from the server with two clients. You can use the client over a network by replacing 127.0.0.1 with the IP address of the server. You may have to let the port through your computer’s firewall if it’s not working. [liam@liam-laptop Python]$ ./IMServer.py Listening on port 59091 Listening for more clients Starting client thread for ('127.0.0.1', 38726) ('127.0.0.1', 38726) sent: USERNAME client1 echoing: client1 has joined. Listening for more clients Starting client thread for ('127.0.0.1', 38739) ('127.0.0.1', 38739) sent: USERNAME client2 echoing: client2 has joined. Listening for more clients ('127.0.0.1', 38739) sent: client2 says: Hi echoing: client2 says: Hi ('127.0.0.1', 38726) sent: client1 says: Hi echoing: client1 says: Hi ('127.0.0.1', 38726) sent: QUIT echoing: client1 has quit. Ending client thread for ('127.0.0.1', 38726) ^CTidying up echoing: QUIT Could not accept any more connections ('127.0.0.1', 38739) sent: echoing: client2 has quit. Ending client thread for ('127.0.0.1', 38739) 21 That’s it! So, it’s not perfect and could be a little more robust in terms of error handling, but we have a working instant messenger server that can accept multiple clients and relay messages between them. More importantly, we have learned a bunch of new concepts and methods of working. Trying it out You’ll want a few terminals: one to start the server, and some to run clients. Once The Python Book 93 Work with Python Replace your shell with Python Python is a great programming language, but did you know that it is even capable of replacing your primary shell (command-line interface)? Here, we explain all… Resources You will require a version of Python installed on your system. The good news is you don’t have to do anything to get it installed. Most of the Linux distributions already ship with either Python 2.6 or Python 2.7 94 The Python Book We all use shell on a daily basis. For most of us, shell is the gateway into our Linux system. For years and even today, Bash has been the default shell for Linux. But it is getting a bit long in the tooth. No need to be offended: we still believe Bash is the best shell out there when compared to some other UNIX shells such as Korn Shell (KSH), C Shell (CSH) or even TCSH. This tutorial is not about Bash being incapable, but it is about how to breathe completely new life into the shell to do old things conveniently and new things which were previously not possible, even by a long shot. So, without further delay, let’s jump in. While the Python programming language may require you to write longer commands to accomplish a task (due to the way Python’s modules are organised), this is not something to be particularly concerned about. You can easily write aliases to the equivalent of the Bash command that you intend to replace. Most of the time there will be more than one way to do a thing, but you will need to decide which way works best for you. Python provides support for executing system commands directly (via the os or subprocess module), but where possible we will focus on Python-native implementations, as this allows us to develop portable code. Work with Python SECTION 1: Completing basic shell tasks in Python 1. File management The Python module shutil provides support for file and directory operations. It provides support for file attributes, directory copying, archiving etc. Let’s look at some of its important functions. shutil module copy (src,dst): Copy the src file to the destination directory. In this mode permissions bits are copied but metadata is not copied. copy2 (src,dst): Same as copy() but also copies the metadata. copytree(src, dst[, symlinks=False[, ignore=None]]): This is similar to ‘cp -r’, it allows you to copy an entire directory. ignore_patterns (*patterns): ignore_ patterns is an interesting function that can be used as a callable for copytree(), it allows you to ignore files and directories specified by the glob-style patterns. rmtree(path[, ignore_errors[, onerror]]): rmtree() is used to delete an entire directory. move(src,dst): Similar to mv command it allows you to recessively move a file or directory to a new location. Example: >>>from shutil import copytree, ignore_ patterns >>>copytree(source, destination, ignore=ignore_patterns(‘*.pyc’, ‘tmp*’)) make_archive(base_name, format[, root_ dir[, base_dir[, verbose[, dry_run[, owner[, group[, logger]]]]]]] : Think of this as a replacement for tar, zip, bzip etc. make_archive() creates an archive file in the given format such as zip, bztar, tar , gztar. Archive support can be extended via Python modules. Example >>> from shutil import make_archive >>> import os >>> archive_name = os.path. expanduser(os.path.join(‘~’, ‘ludarchive’)) >>> root_dir = os.path.expanduser(os. You can easily write aliases to the equivalent of the Bash command that you intend to replace path.join(‘~’, ‘.ssh’)) >>> make_archive(archive_name, ‘gztar’, root_dir) ‘/Users/kunal/ludarchive.tar.gz’ 2. Interfacing operating system & subprocesses Python provides two modules to interface with the OS and to manage processes, called os and subprocess. These modules allow you to interact with the core operating system shell and let you work with the environment, processes, users and file descriptors. The subprocess module was introduced to support better management of subprocesses (part of which already exists in the os module) in Python and is aimed to replace os.system, os.spawn*, os.popen, popen2.* and commands.* modules. os module environ: environment represents the environment variables in a string object. OS example: >>> import os >>> os.environ {‘VERSIONER_PYTHON_PREFER_32_BIT’: ‘no’, ‘LC_CTYPE’: ‘UTF-8’, ‘TERM_ PROGRAM_VERSION’: ‘297’, ‘LOGNAME’: ‘kunaldeo’, ‘USER’: ‘kunaldeo’, ‘PATH’: ‘/System/Library/Frameworks/Python. framework/Versions/2.7/bin:/Users/ kunaldeo/narwhal/bin:/opt/local/sbin:/ usr/local/bin:/usr/bin:/bin:/usr/sbin:/ sbin:/usr/local/bin:/usr/X11/bin:/opt/ local/bin:/Applications/MOTODEV_Studio_ For_Android_2.0.0_x86/android_sdk/ tools:/Applications/MOTODEV_Studio_For_ Android_2.0.0_x86/android_sdk/platformtools:/Volumes/CyanogenModWorkspace/ bin’, ‘HOME’: ‘/Users/kunaldeo’, ‘PS1’: ‘\\[\\e[0;32m\\]\\u\\[\\e[m\\] \\[\\e[1;34m\\]\\w\\[\\e[m\\] \\ [\\e[1;32m\\]\\$\\[\\e[m\\] \\ [\\e[1;37m\\]’, ‘NARWHAL_ENGINE’: ‘jsc’, ‘DISPLAY’: ‘/tmp/launch-s2LUfa/ org.x:0’, ‘TERM_PROGRAM’: ‘Apple_ Terminal’, ‘TERM’: ‘xterm-color’, ‘Apple_PubSub_Socket_Render’: ‘/tmp/ launch-kDul5P/Render’, ‘VERSIONER_ PYTHON_VERSION’: ‘2.7’, ‘SHLVL’: ‘1’, ‘SECURITYSESSIONID’: ‘186a5’, ‘ANDROID_SDK’: ‘/Applications/MOTODEV_ Studio_For_Android_2.0.0_x86/android_ sdk’,’_’: ‘/System/Library/Frameworks/ Python.framework/Versions/2.7/bin/ python’, ‘TERM_SESSION_ID’: ‘ACFE2492BB5C-418E-8D4F-84E9CF63B506’, ‘SSH_ AUTH_SOCK’: ‘/tmp/launch-dj6Mk4/ Listeners’, ‘SHELL’: ‘/bin/bash’, ‘TMPDIR’: ‘/var/folders/6s/pgknm8b118 737mb8psz8x4z80000gn/T/’, ‘LSCOLORS’: ‘ExFxCxDxBxegedabagacad’, ‘CLICOLOR’: ‘1’, ‘__CF_USER_TEXT_ENCODING’: ‘0x1F5:0:0’, ‘PWD’: ‘/Users/kunaldeo’, ‘COMMAND_MODE’: ‘unix2003’} You can also find out the value for an environment value: >>> os.environ[‘HOME’] ‘/Users/kunaldeo’ putenv(varname,value) : Adds or sets an environment variable with the given variable name and value. getuid() : Return the current process’s user id. getlogin() : Returns the username of currently logged in user getpid(pid) : Returns the process group id of given pid. When used without any parameters it simply returns the current process id. getcwd() : Return the path of the current working directory. chdir(path) : Change the current working directory to the given path. The Python Book 95 Work with Python listdir(path) : Similar to ls, returns a list with the content of directories and file available on the given path. command with arguments. On process completion it returns the returncode attribute. Example: Example: >>> os.listdir(“/home/homer”) [‘.gnome2’, ‘.pulse’, ‘.gconf’, ‘.gconfd’, ‘.beagle’, ‘.gnome2_ private’, ‘.gksu.lock’, ‘Public’, ‘.ICEauthority’, ‘.bash_history’, ‘.compiz’, ‘.gvfs’, ‘.updatenotifier’, ‘.cache’, ‘Desktop’, ‘Videos’, ‘.profile’, ‘.config’, ‘.esd_auth’, ‘.viminfo’, ‘.sudo_ as_admin_successful’, ‘mbox’, ‘.xsession-errors’, ‘.bashrc’, ‘Music’, ‘.dbus’, ‘.local’, ‘.gstreamer-0.10’, ‘Documents’, ‘.gtk-bookmarks’, ‘Downloads’, ‘Pictures’, ‘.pulsecookie’, ‘.nautilus’, ‘examples. desktop’, ‘Templates’, ‘.bash_logout’] >>> import subprocess >>> print subprocess.call([“ls”,”-l”]) total 3684688 drwx------+ 5 kunaldeo staff 170 Aug 19 01:37 Desktop drwx------+ 10 kunaldeo staff 340 Jul 26 08:30 Documents drwx------+ 50 kunaldeo staff 1700 Aug 19 12:50 Downloads drwx------@ 127 kunaldeo staff 4318 Aug 19 01:43 Dropbox drwx------@ 42 kunaldeo staff 1428 Aug 12 15:17 Library drwx------@ 3 kunaldeo staff 102 Jul 3 23:23 Movies drwx------+ 4 kunaldeo staff 136 Jul 6 08:32 Music drwx------+ 5 kunaldeo staff 170 Aug 12 11:26 Pictures drwxr-xr-x+ 5 kunaldeo staff 170 Jul 3 23:23 Public -rwxr-xr-x 1 kunaldeo staff 1886555648 Aug 16 21:02 androidsdk.tar drwxr-xr-x 5 kunaldeo staff 170 Aug 16 21:05 sdk drwxr-xr-x 19 kunaldeo staff 646 Aug 19 01:47 src -rw-r--r-1 root staff 367 Aug 16 20:36 umbrella0.log mkdir(path[, mode]) : Creates a directory with the given path with the numeric code mode. The default mode is 0777. makedirs(path[, mode]) : Creates given path (inclusive of all its directories) recursively. The default mode is 0777. : Example: >>> import os >>> path = “/home/kunal/greatdir” >>> os.makedirs( path, 0755 ); rename (old,new) : The file or directory “old” is renamed to “new” If “new” is a directory, an error will be raised. On Unix and Linux, if “new” exists and is a file, it will be replaced silently if the user has permission to do so. renames (old,new) : Similar to rename but also creates any directories recessively if necessary. rmdir(path) : Remove directory from the path mentioned. If the path already has files you will need to use shutil. rmdtree() subprocess: call(*popenargs, **kwargs) : Runs the 96 The Python Book STD_INPUT_HANDLE: The standard input device. Initially, this is the console input buffer. STD_OUTPUT_HANDLE: The standard output device. Initially, this is the active console screen buffer. STD_ERROR_HANDLE: The standard error device. Initially, this is the active console screen buffer. SECTION 2: IPython: a ready-made Python system shell replacement In section 1 we have introduced you to the Python modules which allow you to do system shell-related tasks very easily using vanilla Python. Using the same features, you can build a fully featured shell and remove a lot of Python boilerplate code along the way. However, if you are kind of person who wants everything ready-made, you are in luck. IPython provides a powerful and interactive Python shell which you can use as your primary shell. IPython supports Python 2.6 to 2.7 and 3.1 to 3.2 . It supports two type of Python shells: Terminal based and Qt based. Just to reiterate, IPython is purely implemented in Python and provides a 100% Pythoncompliant shell interface, so everything you have learnt in section 1 can be run inside IPython without any problems. IPython is already available in most Linux distributions. Search your distro’s repositories to look for it. In case you are not able to find it, you can also install it using easy_install or PyPI. IPython provides a lot of interesting features which makes it a great shell replacement… Tab completion: Tab completion provides an excellent way to explore any Python object that you are working with. It also helps you to avoid making typos. Example : In [3]: import o {hit tab} objc opcode operator optparse os os2emxpath In [3]: import os In [4]: os.p os.pardir os.popen os.path os.popen2 os.pathconf os.popen3 {hit tab} os.pathconf_names os.popen4 os.pathsep os.putenv os.pipe Built In Object Explorer: You can add ‘?’ after any Python object to view its details such as Type, Base Class, String Form, Namespace, File and Docstring. Example: In [28]: os.path? Type: module Base Class: String Form: Namespace: Interactive File: /System/Library/Frameworks/ Work with Python You can start the Qt console with: $ ipython qtconsole IPython also comes with its own Qt-based console Python.framework/Versions/2.7/lib/ python2.7/posixpath.py Docstring: Common operations on POSIX pathnames. Instead of importing this module directly, import os and refer to this module as os.path. The ‘os.path’ name is an alias for this module on POSIX systems; on other systems (eg Mac, Windows), os.path provides the same operations in a manner specific to that platform, and is an alias to another module (eg macpath, ntpath). Some of this can actually be useful on nonPOSIX systems too, eg for manipulation of the pathname component of URLs. You can also use double question marks (??) to view the source code for the relevant object. Magic functions: IPython comes with a set of predefined ‘magic functions’ that you can call with a command-line-style syntax. IPython ‘magic’ commands are conventionally prefaced by %, but if the flag %automagic is set to on, then you can call magic commands without the preceding %. To view a list of available magic functions, you can use ‘magic function %lsmagic’. Magic functions include functions that work with code such as %run, %edit, %macro, %recall etc; functions that affect shell such as %colors, %xmode, %autoindent etc; and other functions such as %reset, %timeit, %paste etc. Most of the cool features of IPython are powered using magic functions. Example: In [45]: %lsmagic Available magic functions: %alias %autocall %autoindent %automagic %bookmark %cd %colors %cpaste %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %install_default_ config %install_profiles %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %lsmagic %macro %magic %page %paste %pastebin %pdb If you get errors related to missing modules, make sure that you have installed the dependent packages, such as PyQt, pygments, pyexpect and ZeroMQ. %pdef %pdoc %pfile %pinfo %pinfo2 %popd %pprint %precision %profile %prun %psearch %psource %pushd %pwd %pycat %pylab %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %run %save %sc %sx %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode Automagic is OFF, % prefix IS needed for magic functions To view help on any Magic Function, call ‘%somemagic?’ to read its docstring. Python script execution and runtime code editing: You can use %run to run any Python script. You can also control-run the Python script with pdb debugger using -d, or pdn profiler using -p. You can also edit a Python script using the %edit command. %edit will open the given Python script in the editor defined by the $EDITOR environment variable. Shell command support: If you are in the mood to just run a shell command, you can do it very easily by prefixing the command with ! . Q IPython Qt console with GUI capabilities Example : In [5]: !ps PID TTY 4508 ttys000 84275 ttys001 17958 ttys002 TIME 0:00.07 0:00.03 0:00.18 CMD -bash -bash -bash In [8]: !clang prog.c -o prog prog.c:2:1: warning: type specifier missing, defaults to ‘int’ [-Wimplicitint] main() ^~~~ 1 warning generated. Qt console : IPython also comes with its own Qt-based console. This provides a number of features that are only available in a GUI, such as inline figures, multiline editing with syntax highlighting, and graphical calltips . As you can see, it’s easy to tailor Python for all your shell environment needs. Python modules like os, subprocess and shutil are available at your disposal to do just about everything you need using Python. IPython turns this whole experience into an even more complete package. You get to do everything a standard Python shell does and with much more convenient features. IPython’s magic functions really do provide a magical Python shell experience. So next time you open a Bash session, think again: why settle for gold when platinum is a step away? The Python Book 97 Work with Python Python for system administrators Learn how Python can help in system administration as it dares to replace the usual shell scripting… Resources Python-devel Python development libraries, required for compiling third-party Python module setuptools setuptools allows you to download, build, install, upgrade, and uninstall Python packages with ease System administration is an important part of our computing environment. It does not matter whether you are managing systems at your work our home. Linux, being a UNIX-based operating system, already has everything a system administrator needs, such as the world-class shells (not just one but many, including Bash, csh, zsh etc), handy tools, and many other features which make the Linux system an administrator’s dream. So why do we need Python when Linux already has everything built-in? Being a dynamic scripting language, Python is very easy to read and learn. That’s just not us saying that, but many Linux distributions actually use Python in core administrative parts. For example, Red Hat (and Fedora) system setup tool Anaconda is written in Python (read this line again, got the snake connection?). Also, tools like GNU Mailman, CompizConfig Settings Manager (CCSM) and hundreds of tiny GUI and non-GUI configuration tools are written using Python. Python does not limit you on the choice of user interface to follow – you can build command-line, GUI and web apps using Python. This way, it has got covered almost all the possible interfaces. Here we will look into executing sysadminrelated tasks using Python. Parsing configuration files Configuration files provide a way for applications to store various settings. In order to write a script that allows you to modify settings of a particular application, you should be able to parse the configuration file of the application. In this section we learn how to parse INI-style configuration files. Although old, the INI file format is very popular with much modern open source software, such as PHP and MySQL. Excerpt for php.ini configuration file: [PHP] engine = On zend.ze1_compatibility_mode = Off short_open_tag = On asp_tags = Off precision = 14 y2k_compliance = On output_buffering = 4096 ;output_handler = zlib.output_compression = Off [MySQL] ; Allow or prevent persistent links. mysql.allow_persistent = On mysql.max_persistent = 20 mysql.max_links = -1 mysql.default_port = 3306 mysql.default_socket = mysql.default_host = localhost mysql.connect_timeout = 60 mysql.trace_mode = Off Python provides a built-in module called ConfigParser (known as configparser in Python 3.0). You can use this module to parse and create configuration files. @code: writeconfig.py @description: The following demonstrates adding MySQL section to the php.ini file. @warning: Do not use this script with the actual php.ini file, as it’s not designed to handle all aspects of a complete php.ini file. import ConfigParser config = ConfigParser. 98 The Python Book RawConfigParser() config.add_section(‘MySQL’) config.set(‘MySQL’,’mysql.trace_ mode’,’Off’) config.set(‘MySQL’,’mysql.connect_ timeout’,’60’) config.set(‘MySQL’,’mysql.default_ host’,’localhost’) config.set(‘MySQL’,’mysql.default_ port’,’3306’) config.set(‘MySQL’,’mysql.allow_ persistent’, ‘On’ ) config.set(‘MySQL’,’mysql.max_ persistent’,’20’) with open(‘php.ini’, ‘ap’) as configfile: config.write(configfile) Output:php.ini [MySQL] mysql.max_persistent = 20 mysql.allow_persistent = On mysql.default_port = 3306 mysql.default_host = localhost mysql.trace_mode = Off mysql.connect_timeout = 60 @code: parseconfig.py @description: Parsing and updating the config file import ConfigParser config = ConfigParser.ConfigParser() config.read(‘php.ini’) # Print config values print config.get(‘MySQL’,’mysql. Note This is written for the Python 2.X series, as it is still the most popular and default Python distribution across all the platforms (including all Linux distros, BSDs and Mac OS X). Work with Python default_host’) print config.get(‘MySQL’,’mysql. default_port’) config.remove_option(‘MySQL’,’mysql. trace_mode’) with open(‘php.ini’, ‘wb’) as configfile: config.write(configfile) Parsing JSON data JSON (also known as JavaScript Object Notation) is a lightweight modern datainterchange format. JSON is an open standard under ECMA-262. It is a text format and is completely language-independent. JSON is also used as the configuration file format for modern applications such as Mozilla Firefox and Google Chrome. JSON is also very popular with modern web services such as Facebook, Twitter, Amazon EC2 etc. In this section we will use the Python module ‘simplejson’ to access Yahoo Search (using the Yahoo Web Services API), which outputs JSON data. To use this section, you should have the following: 1. Python module: simplejson. Note: You can install Python modules using the command ‘easy_install ’. This command assumes that you have a working internet connection. 2. Yahoo App ID: The Yahoo App ID can be created from https://developer.apps.yahoo. com/dashboard/createKey.html. The Yahoo App ID will be generated on the next page. See the screenshot below for details. QGenerating the Yahoo App ID simplejson is very easy to use. In the following example we will use the capability of mapping JSON data structures directly to Python data types. This gives us direct access to the JSON data without developing any XML parsing code. JSON PYTHON DATA MAPPING JSON Python object dict array list string unicode number (int) int, long number (real) float TRUE TRUE FALSE FALSE null None For this section we will use the simplejson. load function, which allows us to deserialise a JSON object into a Python object. @code: LUDSearch.py import simplejson, urllib APP_ID = ‘xxxxxxxx’ # Change this to your APP ID SEARCH_BASE = ‘http://search. yahooapis.com/WebSearchService/V1/ webSearch’ class YahooSearchError(Exception): pass def search(query, results=20, start=1, **kwargs): kwargs.update({ ‘appid’: APP_ID, ‘query’: query, ‘results’: results, ‘start’: start, ‘output’: ‘json’ }) url = SEARCH_BASE + ‘?’ + urllib.urlencode(kwargs) result = simplejson.load(urllib. urlopen(url)) if ‘Error’ in result: # An error occurred; raise an exception raise YahooSearchError, result[‘Error’] return result[‘ResultSet’] Let’s use the above code from the Python shell to see how it works. Change to the directory where you have saved the LUDYSearch.py and open a Python shell. @code: Python Shell Output. Lines starting with ‘>>>’ indicate input >>> execfile(“LUDYSearch.py”) >>> results = search(‘Linux User and Developer’) >>> results[‘totalResultsAvailable’] 123000000 >>> results[‘totalResultsReturned’] 20 >>> items = results[‘Result’] >>> for Result in items: ... print Result[‘Title’],Result[‘Url’] ... Linux User http://www.linuxuser. co.uk/ Linux User and Developer Wikipedia, the free encyclopedia http://en.wikipedia.org/wiki/Linux_ User_and_Developer Linux User &amp; Developer | Linux User http://www.linuxuser. co.uk/tag/linux-user-developer/ Gathering system information One of the important jobs of a system administrator is gathering system information. In this section we will use the SIGAR (System Information Gatherer And Reporter) API to demonstrate how we can gather system information using Python. SIGAR is a very complete API and it can provide lot of information, including the following: 1. System memory, swap, CPU, load average, uptime, logins. 2. Per-process memory, CPU, credential info, state, arguments, environment, open files. 3. File system detection and metrics. 4. Network interface detection, configuration info and metrics. 5. TCP and UDP connection tables. 6. Network route table. Installing SIGAR The first step is to build and install SIGAR. SIGAR is hosted at GitHub, so make sure that you have Git installed in your system. Then perform the following steps to install SIGAR and its Python bindings: $ git clone git://github.com/ hyperic/sigar.git sigar.git $ cd sigar.git/bindings/python $ sudo python setup.py install Python doesn’t limit your choice of interface The Python Book 99 Work with Python At the end you should see a output similar to the following : Writing /usr/local/lib/python2.6/ dist-packages/pysigar-0.1.egg-info SIGAR is a very easy-to-use library and can be used to get information on almost every aspect of a system. The next example shows you how. The following code shows the memory and the file system information @code: PySysInfo.py import os import sigar sg = sigar.open() mem = sg.mem() swap = sg.swap() fslist = sg.file_system_list() print “==========Memory Information==============” print “\tTotal\tUsed\tFree” print “Mem:\t”,\ (mem.total() / 1024), \ (mem.used() / 1024), \ (mem.free() / 1024) print “Swap:\t”, \ (swap.total() / 1024), \ (swap.used() / 1024), \ (swap.free() / 1024) print “RAM:\t”, mem.ram(), “MB” print “==========File System Information===============” def format_size(size): return sigar.format_size(size * 1024) print ‘Filesystem\tSize\tUsed\ tAvail\tUse%\tMounted on\tType\n’ for fs in fslist: dir_name = fs.dir_name() usage = sg.file_system_ usage(dir_name) total = usage.total() used = total - usage.free() avail = usage.avail() pct = usage.use_percent() * 100 if pct == 0.0: pct = ‘-’ print fs.dev_name(), format_ size(total), format_size(used), format_size(avail),\ pct, dir_name, fs.sys_type_ name(), ‘/’, fs.type_name() @Output ==========Memory Information============== Total Used Free Mem: 8388608 6061884 2326724 100 The Python Book Swap: 131072 16048 115024 RAM: 8192 MB ==========File System Information=============== Filesystem Size Used Avail Use% Mounted on Type /dev/disk0s2 300G 175G 124G 59.0 / hfs / local devfs 191K 191K 0 - /dev devfs / none Accessing Secure Shell (SSH) services SSH (Secure Shell) is a modern replacement for an old remote shell system called Telnet. It allows data to be exchanged using a secure channel between two networked devices. System administrators frequently use SSH to administrate networked systems. In addition to providing remote shell, SSH is also used for secure file transfer (using SSH File Transfer Protocol, or SFTP) and remote X server forwarding (allows you to use SSH clients as X server). In this section we will learn how to use the SSH protocol from Python using a Python module called paramiko, which implements the SSH2 protocol for Python. paramiko can be installed using the following steps: $ git clone https://github.com/robey/ paramiko.git $ cd paramiko $ sudo python setup.py install To the core of paramiko is the SSHClient class. This class wraps L{Transport}, L{Channel}, and L{SFTPClient} to handle most of the aspects of SSH. You can use SSHClient as: client = SSHClient() client.load_system_host_keys() client.connect(‘some.host.com’) stdin, stdout, stderr = client.exec_ command(‘dir’) The following example demonstrates a full SSH client written using the paramiko module. @code: PySSHClient.py import base64, getpass, os, socket, sys, socket, traceback import paramiko import interactive # setup logging paramiko.util.log_to_file(‘demo_simple. log’) # get hostname username = ‘’ if len(sys.argv) > 1: hostname = sys.argv[1] if hostname.find(‘@’) >= 0: username, hostname = hostname. split(‘@’) else: hostname = raw_input(‘Hostname: ‘) if len(hostname) == 0: print ‘*** Hostname required.’ sys.exit(1) port = 22 if hostname.find(‘:’) >= 0: hostname, portstr = hostname. split(‘:’) port = int(portstr) # get username if username == ‘’: default_username = getpass. getuser() username = raw_input(‘Username [%s]: ‘ % default_username) if len(username) == 0: username = default_username password = getpass.getpass(‘Password for %s@%s: ‘ % (username, hostname)) # now, connect and use paramiko Client to negotiate SSH2 across the connection try: client = paramiko.SSHClient() client.load_system_host_keys() client.set_missing_host_key_ policy(paramiko.WarningPolicy) print ‘*** Connecting...’ client.connect(hostname, port, username, password) chan = client.invoke_shell() print repr(client.get_transport()) print ‘*** SSH Server Connected! ***’ print interactive.interactive_ shell(chan) chan.close() client.close() except Exception, e: print ‘*** Caught exception: %s: %s’ % (e.__class__, e) traceback.print_exc() try: client.close() except: pass sys.exit(1) To run this code you will also need a custom Python class interactive.py which implements Note If you are confused with the tab spacing of the code, look for the code files on FileSilo. Work with Python the interactive shell for the SSH session. Look for this file on FileSilo and copy it into the same folder where you have created PySSHClient.py . @code_Output kunal@ubuntu-vm-kdeo:~/src/paramiko/ demos$ python demo_simple.py Hostname: 192.168.1.2 Username [kunal]: luduser Password for luduser@192.168.1.2: *** Connecting... *** SSH Server Connected! *** Last login: Thu Jan 13 02:01:06 2011 from 192.168.1.9 [~ $:] If the host key for the SSH server is not added to your $HOME/.ssh/known_hosts file, the client will throw the following error: *** Caught exception: : unbound method missing_host_key() must be called with WarningPolicy instance as first argument (got SSHClient instance instead) This means that the client cannot verify the authenticity of the server you are connected to. To add the host key to known_hosts, you can use the ssh command. It is important to remember that this is not the ideal way to add the host key; instead you should use sshkeygen. But for simplicity’s sake we are using the ssh client. kunal@ubuntu-vm-kdeo:~/.ssh$ ssh luduser@192.168.1.2 The authenticity of host ‘192.168.1.2 (192.168.1.2)’ can’t be established. RSA key fingerprint is be:01:76:6a:b 9:bb:69:64:e3:dc:37:00:a4:36:33:d1. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added ‘192.168.1.2’ (RSA) to the list of known hosts. So now you’ve seen how easy it can be to carry out the complex sysadmin tasks using Python’s versatile language. As is the case with all Python coding, the code that is presented here can fairly easily be adopted into your GUI application (using software such as PyGTK or PyQt) or a web application (using a framework such as Django or Grok). Writing a user interface using Python Learn how to create a user-friendly interface using Python Administrators are comfortable with running raw scripts by hand, but end-users are not. So if you are writing a script that is supposed to be used by common users, it is a good idea to create a userfriendly interface on top of the script. This way end-users can run the scripts just like any other application. To demonstrate this, we will create a simple GRUB configuration tool which allows users to select default boot entry and the timeout. We will be creating a TUI (text user interface) application and will use the Python module ‘snack’ to facilitate this (not to be confused with the Python audio library, tksnack). This app consists of two files… grub.py: GRUB Config File (grub.conf) Parser (available on FileSilo). It implements two main functions, readBootDB() and writeBootFile(), which are responsible for reading and writing the GRUB configuration file. grub_tui.py: Text user interface file for manipulating the GRUB configuration file using the functions available in grub.py. @code:grub_tui.py import sys from snack import * from grub import (readBootDB, writeBootFile) def main(entry_ value=’1’,kernels=[]): try: (default_value, entry_ value, kernels)=readBootDB() except: print >> sys.stderr, (“Error reading /boot/grub/grub. conf.”) sys.exit(10) screen=SnackScreen() while True: g=GridForm(screen, (“Boot configuration”),1,5) if len(kernels)>0 : li=Listbox(height=len(kernels), width=20, returnExit=1) for i, x in enumerate(kernels): li.append(x,i) g.add(li, 0, 0) li.setCurrent(default_value) bb = ButtonBar(screen, (((“Ok”), “ok”), ((“Cancel”), “cancel”))) e=Entry(3, str(entry_ value)) l=Label((“Timeout (in seconds):”)) gg=Grid(2,1) gg.setField(l,0,0) gg.setField(e,1,0) g.add(Label(‘’),0,1) g.add(gg,0,2) g.add(Label(‘’),0,3) g.add(bb,0,4,growx=1) result = g.runOnce() if bb.buttonPressed(result) == ‘cancel’: screen.finish() sys.exit(0) else: entry_value = e.value() try : c = int(entry_ value) break except ValueError: continue writeBootFile(c, li.current()) screen.finish() if __name__== ‘__main__’: main() Start the tool using the sudo command (as it reads the grub. conf file) $ sudo grub_tui.py The Python Book 101 Work with Python 01 Full code listing import os, sys, urllib2, argparse, datetime, atexit from bs4 import BeautifulSoup addresses = [] deepestAddresses = [] maxLevel = 1 storeFolder = "Wikistore " + str(datetime.datetime.now().strftime("%Y-%m-%d %H:%M")) 1 Import libraries These are the libraries we are going to be using for this program 02 2 Set up variables These are some variables we’ll use to keep track of the script’s progress undesirables = [ {"element" : "table", "attr" : {'class' : 'infobox'} }, {"element" : "table", "attr" : {'class' : 'vertical-navbox'}}, {"element" : "span", "attr" : {'class' : 'mw-editsection'}}, {"element" : "div", "attr" : {'class' : 'thumb'}}, {"element" : "sup", "attr" : {'class' : 'reference'}}, {"element" : "div", "attr" : {'class' : 'reflist'}}, {"element" : "table", "attr" : {'class' : 'nowraplinks'}}, {"element" : "table", "attr" : {'class' : 'ambox-Refimprove'}}, {"element" : "img", "attr" : None}, {"element" : "script", "attr" : None}, {"element" : "table", "attr" : {'class' : 'mbox-small'}} , {"element" : "span", "attr" : {"id" : "coordinates"}}, {"element" : "table", "attr" : {"class" : "ambox-Orphan"}}, {"element" : "div", "attr" : {"class" : "mainarticle"}}, {"element" : None, "attr" : {"id" : "References"}} ] def init(): parser = argparse.ArgumentParser(description='Handle the starting page and number of levels we\'re going to scrape') parser.add_argument('-URL', dest='link', action='store', help='The Wikipedia page from which we will start scraping') parser.add_argument('-levels', dest="levels", action='store', help='How many levels deep should the scraping go') args = parser.parse_args() 3 Initialisation This is the initialising function that we will use to handle the input from the user 03 if(args.levels != None): global maxLevel8 maxLevel = int(args.levels) if(args.link == None): print("You need to pass a link with the -URL flag") sys.exit(0) else: if not os.path.exists(storeFolder): os.makedirs(storeFolder) grabPage(args.link, 0, args.link.split("/wiki/")[1].strip().replace("_", " ")) atexit.register(cleanUp) def isValidLink(link): Scrape Wikipedia with Beautiful Soup Use the Beautiful Soup Python library to parse Wikipedia’s HTML and store it for offline reading Resources Beautiful Soup: www.crummy.com/software/BeautifulSoup/ HTML5Lib: https://github.com/html5lib/html5lib-python Python 2.6+ & WikiParser.zip Six: https://pypi.python.org/pypi/six/ 102 The Python Book In this tutorial we’ll use the popular Python library Beautiful Soup to scrape Wikipedia for links to articles and then save those pages for offline reading. This is ideal for when travelling or in a location with a poor internet connection. The plan is simple: using Beautiful Soup with the HTML5Lib Parser, we’re going to load a Wikipedia page, remove all of the GUI and unrelated content, search the content for links to other Wikipedia articles and then, after a tiny bit of modification, write them to a file. Even though it’s now the de facto knowledge base of the world, Wikipedia isn’t great when it comes to DOM consistency – that is, IDs and classes are sometimes quite loose in their usage. Because of this, we will also cover how to handle all of the excess bits and bobs of the Wikipedia GUI that we don’t need, as well as the various erroneous links that won’t be of much use to us. You can find the CSS stylings sheet and a Python script pertaining to this tutorial at http://bit.ly/19MibBv. Work with Python Full code listing continued 4 Get the page if "/wiki/" in link and ":" not in link and "http://" not in link and "wikibooks" not in link and "#" not in link and "wikiquote" not in link and "wiktionary" not in link and "wikiversity" not in link and "wikivoyage" not in link and "wikisource" not in link and "wikinews" not in link and "wikiversity" not in link and "wikidata" not in link: return True else: return False Here we grab the page we want to store and remove the bits of the document we don’t need fileName = str(name) if level == maxLevel: deepestAddresses.append(fileName. replace('/', '_') + ".html") doctype = "" 06 head = "" + fileName + "" def grabPage(URL, level, name): 5 Check links page = req.read() f = open(storeFolder + "/" + fileName.replace('/', '_') + ".html", 'w') f.write(doctype + "" + head + "

    " + fileName + "

    " + str(content) + "") f.close() req.close() def cleanUp(): soup = BeautifulSoup(page, "html5lib", from_encoding="UTF-8") print("\nRemoving links to pages that have not been saved\n") opener = urllib2.build_opener() opener.addheaders = [('User-agent', 'Mozilla/5.0')] req = opener.open(URL) Then we iterate through all of the tags and check if there’s a valid link to another page we can grab, and tweak them for our own use content = soup.find(id="mw-content-text") for deepPage in deepestAddresses: if hasattr(content, 'find_all'): rF = open(storeFolder + "/" + deepPage, 'r') 04 global undesirables 6 Copy to file deepSoup = BeautifulSoup(rF.read(), "html5lib", from_encoding="UTF-8") for notWanted in undesirables: After that, We take the content we’ve parsed and put it into a brand new HTML file for deepLinks in deepSoup.find_all('a'): link = deepLinks.get("href") removal = content.find_ all(notWanted['element'], notWanted['attr']) if len(removal) > 0: for el in removal: el.extract() also = content.find(id="See_also") pageStored = False for addr in addresses: if addr == link: pageStored = True 07 if(also != None): also.extract() tail = also.find_all_next() if(len(tail) > 0): for element in tail: element.extract() 7 Clean up Once every page has been parsed and stored, we’ll go on through and try to remove any dead links if pageStored == False: if link is not None: if '#' not in link: del for link in content.find_all('a'): deepLinks['href'] elif '#' in link href = link["href"] and len(link.split('#')) > 1 or ':' in link: del if isValidLink(href): deepLinks['href'] if level < maxLevel: 8 Initialise wF = open(storeFolder + "/" + deepPage, 'w') wF.write(str(deepSoup)) wF.close() stored = False; for addr in This is how we will initialise our script addresses: print("Complete") if addr == link.get("href"): 05 08 stored = True if __name__ == "__main__": init() if(stored == False): title = link.get('href').replace("/wiki/", "") addresses.append(str(title + ".html")) grabPage("http://en.wikipedia.org" + link.get('href'), level + 1, title) print title link["href"] = link["href"].replace("/ wiki/", "") + ".html" Wikipedia isn’t great when it comes to DOM consistency The Python Book 103 Work with Python 02 WIKI-EVERYTHING Wikipedia has so many different services that interlink with each other; however, we don’t want to grab those pages, so we’ve got quite a lengthy conditional statement to stop that. It’s pretty good at making sure we only get links from Wikipedia. 03 INFINITE LINKS Wikipedia has a lot of links and when you start following links to links to links, the number of pages you have to parse can grow exponentially, depending on the subject matter. By passing through the levels value, we put a cap on the amount of pages we can grab–- although the number of files stored can still vary greatly. Use it wisely. 01 Install Beautiful Soup & HTML5Lib Before we can start writing code, we need to install the libraries we’ll be using for the program (Beautiful Soup, HTML5Lib, Six). The installation process is fairly standard: grab the libraries from their respective links, then unzip them. In the terminal, enter the unzipped directory and run python setup.py install for each library. They will now be ready for use. 02 Creating some useful variables These variables will keep track of the links we’ve accessed while the script has been running: addresses is a list containing every link we’ve accessed; deepestAddresses are the links of the pages that were the furthest down the link tree from our starting point; storeFolder is where we will save the HTML files we create and maxLevel is the maximum depth that we can follow the links to from our starting page. 104 The Python Book 03 Handling the user’s input In the first few lines of this function, we’re just creating a helper statement. Afterwards, we’re parsing any arguments passed into the program on its execution and looking for a -URL flag and a -levels flag. The -levels flag is optional as we already have a preset depth that we’ll follow the links to, but we need a link to start from so if the -URL flag is missing, we’ll prompt the user and exit. If we have a link, then we quickly check whether or not we have a directory to store files in – which we’ll create if we don’t – and then we’ll fire off the function to get that page. Finally, we register a handler for when the script tries to exit. We’ll get to that bit later. 04 Retrieving the page from the URL Here we’re using URLLib2 to request the page the the user has asked for and then, once we’ve received that page, we’re going to pass the content through to Beautiful Soup with the soup variable. This gives us access to the methods we’re going to call as we parse the document. 05 Trimming the fat Wikipedia has a lot of nodes that we don’t want to parse. The content variable allows us to straight away ignore most of Wikipedia’s GUI, but there are still lots of elements that we don’t want to parse. We remedy this by iterating through the list ‘undesirables’ that we created Wikipedia has a lot of nodes Work with Python STYLING 06 Currently, the HTML page will use the built-in browser styles when rendering the page. If you like, you can include the style sheet included in the tutorial resources to make it look a little nicer. To use it, you can minify the script and include it inside a