Python course: Home - Worksheets - Package - Developers - Licence - Credits
Python course: Home - Worksheets - Package - Developers - Licence - Credits
Gareth McCaughan, 1999
A note about web browsers: This sheet uses a few newish features of HTML. If you're reading it online with an old browser, you may find that a few unimportant things come out wrongly: for instance, some quotation marks may disappear. I think nothing vital is lost even with the nastiest oldest browsers.if statement
Python is an elegant modern programming language, intended to make easy things easy without making hard things impossible. This brief introduction is intended to do the following:
You'll probably find that this stuff sticks in your memory best if you try all the examples. But if you don't have a copy of Python handy, don't worry.
Python is byte-compiled, object-oriented, lexically scoped and has exceptions. If you know what any of that means, you probably shouldn't be reading this introduction.
I need to find out about how this works on systems other than mine. I'm sorry there's no useful text here yet. Anyway, this is basically rather easy. If you have an installation of Python at all, you probably already know what to do.
So, you have a window in which Python is running. It should
be displaying a prompt
that looks like this:
>>>
Whenever Python displays that prompt, you can type in any
expression and it will evaluate
it for you:
>>> 1+2*3
7
Expressions are not limited to arithmetic. You can work with strings:
>>> 'foo' + 2*'bar'
foobarbar
or with lists:
>>> [1,2,3] + 2*[4,5]
[1,2,3,4,5,4,5]
or with all sorts of other things that we'll meet later.
One brief word of warning about arithmetic.
>>> 7/3
2
Notice that it doesn't say 2 1/3 or
2.33333333; it just throws away the fractional
part of the answer: that's just what Python does when working
with integers. If you force it to realise that it might not
be working only with integers, all is well:
>>> 7.0/3
2.33333333333
This is one of the few Really Annoying Things in Python.
Like pretty much every other programming language, Python has variables. You use them in much the same way as in other languages:
>>> my_salary = 12000
>>> print 'Your salary is $', 2*my_salary
Your salary is $ 24000
(It would be nicer not to have the space after the dollar sign.
More on output later.)
A variable can hold any kind of value.
>>> name = 'Frederick'
>>> print name + ' has two cats.'
Frederick has two cats.
for loop
Here's something a bit different.
>>> for n in 2,3,5,7,11:
...
Python is suddenly presenting you with a different prompt.
The ... means: You've started to say something but you might not have finished. Do go on.In this case, the
for introduces a loop: whatever follows will
be done five times, once with n=2, once with
n=3, ..., once with n=11.
But you need to tell it what exactly you want to do five times. For instance:
>>> for n in 2,3,5,7,11:
... print n, 'squared is', n*n
...
2 squared is 4
3 squared is 9
5 squared is 25
7 squared is 49
11 squared is 121
The extra spaces in the second line are important; they are
how Python knows exactly what material is within the loop.
BASIC manages this by ending a FOR loop with
NEXT; C manages it by surrounding the contents
with { ... }. With both these
languages (and all others) it's usual to indicate the structure
of your program with indentation; with Python it's
necessary. The meaning of the program depends
on how it is indented!
(On the third line, just press enter. The machine will understand that this means you've finished entering your command.)
As you can see, Python's loops are a bit different from
BASIC's and C's. (And from those in most other languages,
too. Lisp has something similar.) Instead of giving a range
of values (as in BASIC), or a recipe for getting from each
value to the next one (as in C), you give a list of
values. Obviously this is more flexible; but what if you
want to get the same effect as BASIC's
FOR loops?
>>> range(1,5)
[1, 2, 3, 4]
Aha!
>>> for n in range(1,5):
... print n, 'squared is', n*n
...
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
You may be wondering why range(1,5) doesn't
go all the way up to 5. There isn't really a simple answer,
other than that lots of programmers are used to working
that way. It does mean, for instance, that
range(1,5) + range(5,8) = range(1,8).
If you want the effect of BASIC's STEP keyword
(to go up in different units), you can have that:
>>> range(1,20,3)
[1, 4, 7, 10, 13, 16, 19]
(If you'd said range(1,19,3) then 19 wouldn't have been
included.)
while loop
Most languages have a way to say: Do this over and over
until some condition is met
. Python is no exception.
Here's how it works.
>>> n=3
>>> while n<1000:
... print n,
... n = n*2
...
3 6 12 24 48 96 192 384 768
This is our first encounter with Boolean expressions
:
things like n<3 that can be either true or
false. Python actually represents Boolean values with integers:
>>> 1000<3
0
>>> 1000>3
1
Indeed, every value Python can work with is considered
either trueor
false. The number 0 is
false; so are the empty string
'', the empty list []
and a few other special values. (Numbers other than 0 and non-empty
strings and lists are all considered true.)
if statement
Python has an if statement much like any other
language's.
>>> if 100<3:
... print 'I am the walrus'
... else:
... print 'They are the eggmen'
...
They are the eggmen
Like almost every other language (but unlike some versions of BASIC), Python allows you to do this:
>>> n=3
>>> if n<0:
... print 'n is negative'
... elif n>1000:
... print 'n is huge'
... elif n%2 == 0:
... print 'n is even'
... elif n%3 == 0:
... print 'n is a multiple of 3'
... else:
... print 'n is boring'
...
n is a multiple of 3
(You use ==, not =, to test
whether two things are equal or not.
And the % sign means modulo, or
remainder on division by. Most versions of BASIC have this, under the name
MOD.
So 10%3==1 is true.)
Sometimes you may want to get out of a loop before it has
finished, or skip to the end of one iteration. Python has
statements called break and continue
to do these things. They work in for loops and
in while loops.
>>> for n in range(1,6):
... print 'Trying', n
... if n<3:
... continue
... if n==2 or n==4:
... print n, 'is magic'
... break
...
Trying 1
Trying 2
Trying 3
Trying 4
4 is magic
Sometimes you care whether a loop ended normally or with
a break. If you attach some code to the end
of the loop with else, Python will execute it
if and only if the loop ended naturally.
>>> n=11
>>> for p in range(2,n):
... if n % p == 0:
... print n, 'is not prime'
... break
... else:
... print n, 'is prime'
...
11 is prime
Lists in Python can do everything arrays can in BASIC, and more. Here are a few illustrations.
>>> a=[1,2,3,4]
>>> a
[1, 2, 3, 4]
>>> a[1]
2
>>> a[2]=99
>>> a
[1, 2, 99, 4]
>>> a[1:3]
[2, 99]
>>> a[1:3] = [9,8,7]
>>> a
[1, 9, 8, 7, 4]
>>> len(a)
Maybe it's time for a few explanations. The elements of a
list a are a[0], a[1],
and so on up to a[len(a)-1]. You can refer to
a slice of the list a with the notation
a[m:n], which means the list consisting of
elements m (inclusive) to n
(exclusive). Notice that this funny inclusive/exclusive thing
is just the same as for the range function.
A couple of other handy things... You can count elements of a list from the right-hand end ...
>>> a=[1,2,3,4]
>>> a[-1]
4
>>> a[-3:-1]
[2, 3]
... and when doing slices you can miss out either of the
two numbers; Python will use the ends of the list by default.
>>> a=[1,2,3,4]
>>> a[:2]
[1, 2]
>>> a[2:]
[3, 4]
>>> a[:]
[1, 2, 3, 4]
(That last one looks a bit silly, but it can be useful if you
want to make a copy of a list that you can change without changing
the original.)
Strings behave very much like lists.
>>> name='walrus'
>>> len(name)
6
>>> name[2:]
'lrus'
>>> name[2]
'l'
>>> name[-3:]
'rus'
However, you can't modify a string:
>>> name='eggman'
>>> name[5]='e'
Traceback (innermost last):
File "", line 1, in ?
AttributeError: __setitem__
(Ouch! Never mind exactly what that means...)
But of course you can build up a new string instead.
>>> name='eggman'
>>> name[:4]+'e'+name[5:]
'eggmen'
A function is a piece of program with a name. BASIC has
functions (and also things called procedures
, which
are just another kind of function really), but you may not
have used them much.
Functions are a very important way to organise a program; if possible, you should usually split up what your program does into sensible and meaningful chunks, and put those into functions. This is good for two reasons:
Here's a rather pointless function.
>>> def print_underlined(text):
... length = len(text)
... print text
... print '-' * length
...
>>> print_underlined('Ouch!!')
Ouch!!
------
The variable text exists only while the function
is in operation; if there was another variable of that name
before it's temporarily forgotten about. The variable
length also exists only while the function is
in operation. These variables are called local variables.
Which brings me to another advantage of using functions:
Unlike the function print_underlined above,
a lot of functions return a value. What that means
is ... well, the easiest thing is to give an example.
>>> def thrice(x):
... return x*3
...
>>> thrice(100)
300
>>> thrice(100)+5
305
In this example, the function thrice eats up
a number (actually, it needn't be a number. Try asking for
thrice('xyz')!) and returns thrice that
number. The value of a function can be used anywhere where
any other value can be used, as you can see in the last two
lines of the example.
The two functions we've seen so far each take a single
argument; that is, a single value inside their
parentheses. In print_underlined, the argument
was called text and was expected to be a string
(incidentally, it might amuse you to consider what would happen
if you said print_underlined([1,2,3])...); in
thrice, the argument was called x
and was expected to be a number.
You can write functions that take no arguments, or functions that take several. This is pretty easy:
>>> def print_greeting():
... print 'A big hello from Python!'
... print '2+2 is', 2+2
... print 'Are you impressed?'
...
>>> def sum_of_four(a,b,c,d):
... return a+b+c+d
...
You use these by doing, say, print_greeting()
or print sum_of_four(100,-3,my_salary,10*100).
But there's more! Function arguments can have default values:
>>> def f(x, y=7):
... return x+y
...
>>> f(1,2)
3
>>> f(1)
8
Even weirder, when you're using a function you can refer to its arguments by name to save yourself the trouble of remembering what order they come in:
>>> def silly(a, b, c, d=6):
... print 'a =',a, 'b =',b,'c =',c,'d =',d
...
>>> silly(1,2,3,4)
a = 1 b = 2 c = 3 d = 4
>>> silly(1,2,3)
a = 1 b = 2 c = 3 d = 6
>>> silly(c=9,b=4,d=8,a=2)
a = 2 b = 4 c = 9 d = 8
You now know plenty enough to get started writing Python programs, but there's plenty more to learn if you want to. This section is just a collection of excessively brief mentions of interesting things about Python. You can ignore it if you like.
# (unless it's in a string)
begins a comment, which extends to the end of the line.
for i in 2,3,5,7,9:
# This line is a comment and has no effect on anything.
print i*i
try:
z = x/y
except ZeroDivisionError:
z = 100000000
object-oriented, and everyone will be very impressed. I won't give an example of how you use classes, because it would be a little too long.
Finally, here is a complete short program written in Python,
illustrating most of the things I described above and more.
It plays a game a little like Twenty Questions
, in which
you think of something and the computer tries to work out what
it is with yes/no questions. When it fails (as it usually will)
you give it a question that distinguishes between the best guess
it had and the thing you were actually thinking of. For
reasons of tradition, this program actually assumes it's always
animals you're thinking of.
Here's a sample run of the program, to give you a feeling for what it's like.
>>> play_animals('lion')
Think of an animal...
Is it a lion? no
Rats. What was your animal? a mouse
Tell me a question that will distinguish a lion from a mouse.
--> is it a carnivore
What's the answer for a mouse? no
So far I've played 1 games and won 0.
Would you like another game? yes
Think of an animal...
Is it a carnivore? yes
Is it a lion? no
Rats. What was your animal? rat
Tell me a question that will distinguish a lion from a rat.
--> Is it a rodent?
What's the answer for a rat? y
So far I've played 2 games and won 0.
Would you like another game? yes
Think of an animal...
Is it a carnivore? yes
Is it a rodent? yes
Is it a rat? yes
I win!
So far I've played 3 games and won 1.
Would you like another game? no
Thank you for playing.
>>>
Here is the whole program, interspersed with what I hope are helpful words of explanation. Don't worry if a lot of it doesn't make sense; the idea is just to give you an idea of what a real Python program looks like. (For this reason, I haven't been too careful to define every word I use, and I've skirted over many details.)
import string
This means: The program might want to do some interesting
things with strings, so load in the module that
contains some string operations. You'll recognise those in
what follows because they have names like
.
string.lower()
beginning with string.
class Animal_BadSplit(Exception): pass
class Animal_BadBoolean(Exception): pass
These lines define new kinds of exception
, which
we use when something bad happens that we might want the
program to be able to cope with. Ignore them for the moment.
def prompting_input(str):
if str[-1:] != ' ': str=str+' '
if len(str) > 40:
print str
return raw_input('--> ')
else:
return raw_input(str)
This function is used to get input from the user. Its argument
str is the prompt to use. The function adds a space
onto the end if there isn't one there already. If the prompt
is too long, the function prints it on a line by itself and then
prompts with -->
so that there's enough room
on the line for the user to type something longish.
The raw_input function it uses is provided by
Python itself.
def is_yes(x):
xl = string.lower(x)
if xl in ('y','yes','true'):
return 1
if xl in ('n','no','false'):
return 0
raise Animal_BadBoolean
This looks at a string (which will of course come from the user)
and tries to work out whether it means
yes
or no
. It returns either 1 or 0 (these values
are conventionally used by Python to mean true and
false).
If the string doesn't seem to say yes
or no
,
is_yes doesn't return a value at all. Instead,
it raises an exception (of a type we defined earlier).
You'll see what gets done with this in just a moment.
def get_yesno(question):
prompted_again=0
while 1:
answer = prompting_input(question)
try:
return is_yes(answer)
except Animal_BadBoolean:
if not prompted_again:
question = "Please answer yes or no. "+question
prompted_again=1
This is basically just a combination of the last two functions,
except that it has to deal with the possibility that is_yes
raised an exception. That's what the try...except
is for. If is_yes complains, we modify the question
to start with Please answer yes or no.
, unless
we've already done that, and then we try again.
def articled(str):
if str[0:2]=='a ' \
or str[0:3]=='an ' \
or str[0:4]=='the ' \
or str[0] in string.uppercase:
return str
if str[0] in 'aeiou': return 'an '+str
else: return 'a '+str
This turns yeti
into a yeti
,
aardvark
into an aardvark
, and
leaves John Prescott
and a lion
alone.
class Node:
Almost all of what follows defines a new class
called Node. The idea is that a Node
describes a possible state of the program's knowledge about
the animal you're thinking of. There are two kinds of node:
animal nodes (meaning that there is only one animal
the program knows about that's consistent with the answers
you've given, so it's about to ask you whether that's the animal
you're thinking of), and question nodes (meaning that
there's more than one possibility, and indicating the question
the program needs to ask next).
def make_animal(self, name):
self.animal = name
self.question = None
self.yes = None
self.no = None
return self
def make_question(self, q, yes, no):
self.animal = None
self.question = q
self.yes = yes
self.no = no
return self
It may not be obvious, but these definitions are indented further
than the line that says class Node:. That means that
these are part of the class definition. Functions defined inside
a class are called methods. The idea is that a method
defined in the Node class describes something you can
do to a Node. To apply make_animal
to a node x, you write something like
x.make_animal('tiger'); this will do the above stuff
with self=x and name='tiger'.
Anyway, these two functions are for making a Node
into either an animal node or a question node. An animal node
has an animal name for its animal attribute and
the special value None (defined by Python itself)
for its others. A question node is more interesting. Its
question attribute is the question itself; the
yes and no attributes are other nodes.
If you answer the question with yes, the next node the
program looks at will be the one stored in the question node's
yes attribute.
Thus, each time you play the game the program moves through
its question nodes, going from each to either its yes
child
or its no child
. When it reaches
an animal node, it makes its guess and (one way or another) the
game is over.
def get_question(self):
if self.question:
q = self.question
if q[-1:] != '?':
q = q+'?'
else:
q = 'Is it '+articled(self.animal)+'?'
return q
For every node (both animal nodes and question nodes), there
is a question to be asked. The get_question method,
when applied to a node, returns the question needed. If the node
is a question node (the program checks this by seeing whether
its question attribute is set) then that attribute
itself will always contain the question; if not, we need to
manufacture a question out of the animal name.
def split(self, question, new_is_yes, new_name):
if self.animal is None:
raise Animal_BadSplit(self)
child1 = Node()
child2 = Node()
child1.make_animal(new_name)
child2.make_animal(self.animal)
if new_is_yes:
self.make_question(question, child1, child2)
else:
self.make_question(question, child2, child1)
This method is the heart of the program. When the program
has asked you Is it an aardvark? and you have
answered no, the animal node representing aardvarks gets
replaced by a question node whose two
So, what we do is to make two new nodes (here called
The
The
When we reach an animal node, we stop applying
If you've followed everything so far (in which case, I congratulate
you) you'll see that playing a game is now very easy. We just
apply
Playing a single game is very boring. The
And, finally, the function (not a method: we're out of the class
definition now, as you can tell from the indentation if you look
carefully) that we saw at the very start of the sample run.
It makes a new animal node, and applies children
are
an animal node for aardvarks and an animal node for whatever
sort of animal you were really thinking of. So, when the
program would have asked child1
and child2, which we make into animal nodes using
the make_animal method; and to modify the existing
node using the make_question method. The
new_is_yes argument to split is
supposed to be true if the new animal being added is to be
the result of answering yes
to the new question, and
false if not.
def child(self, bool):
if bool: return self.yes
else: return self.no
def choose_child(self):
question = self.get_question()
bool = get_yesno(question)
return self.child(bool)child method is straightforward enough; it
selects one or other child of a node depending on whether you
pass it a true or a false value.
choose_child method is a little more involved.
It decides what question to ask by applying the get_question
method to the node it's being applied to; it asks the question
using the get_yesno function; and it selects the
appropriate next node using the child method.
def check_terminal(self):
solved = get_yesno(self.get_question())
if solved:
print "I win!"
return 1
else:
new_name = prompting_input("Rats. What was your animal? ")
question = prompting_input("Tell me a question that will distinguish "
+articled(self.animal)+" from "
+articled(new_name)+". ")
question = string.upper(question[0]) + question[1:]
new_is_yes = get_yesno("What's the answer for "+articled(new_name)+"?")
self.split(question, new_is_yes, new_name)
return 0choose_child and apply check_terminal
instead. This asks the Is it ...? question;
if the answer is yes
then it prints I win! and
returns something true (namely, 1); if not, then it asks the user
for the information needed to apply split does that,
and returns something false (namely, 0).
def play_game(self):
print "\nThink of an animal...\n"
while self.question:
self = self.choose_child()
return self.check_terminal()choose_child until we're no longer at a question
node, and then apply check_terminal. We return whatever
that returned; remember that this indicates whether the program won
or lost.
def play_series(self):
played=0
won=0
while 1:
played = played+1
won = won+self.play_game()
print "\nSo far I've played %d games and won %d." % (played,won)
if not get_yesno("Would you like another game? "):
break
print "\nThank you for playing.\n"play_series
method keeps playing until you've had enough. It should be pretty
self-explanatory by now, except for the funny business in that first
print statement, which I shan't explain.
def play_animals(name):
initial_node = Node()
initial_node.make_animal(name)
initial_node.play_series()play_series
to it.