Installing Python
Introduction
If you haven't seen them
before, you're not trying hard
enough. What are they? Errors.
Exceptions. Problems. Know what
I'm talking about? I got it with
this program:
|
Code Example 1 - buggy
program |
|
def menu(list, question):
for entry in list:
print 1 + list.index(entry),
print ") " + entry
return input(question) - 1
# running the function
# remember what the backslash does
answer = menu(['A','B','C','D','E','F','H','I'],\
'Which letter is your favourite? ')
print 'You picked answer ' + (answer + 1)
|
This is just an example of the
menu program we made earlier.
Appears perfectly fine to me. At
least until when I first tried it.
Run the program, and what happens?
Bugs - Human Errors
The most common problems with
your code are of your own doing.
Sad, but true. What do we see when
we try to run our crippled
program?
|
Code Example 2 - error
message |
Traceback (most recent call last):
File "/home/steven/errortest.py", line 8, in -toplevel-
answer = menu(< I'll snip it here >)
File "/home/steven/errortest.py", line 6, in menu
return raw_input(question) - 1
TypeError: unsupported operand type(s) for -: 'str' and 'int'
|
Say what? What python is trying
to tell you (but struggling to
find a good word for it) is that
you can't join a string of letters
and a number into one string of
text. Let's go through the error
message and have a look at how it
tells us that:
- File "/home/steven/errortest.py",
line 8, in -toplevel- tells us a
couple of things. File "/home/steven/errortest.py"
tells us which file the error
occured in. This is useful if
you use lots of modules that
refer to each other. line 8, in
-toplevel- tells us that it is
in line # 8 of the file, and in
the top level (that is, no
indentation).
- answer =
menu(['A','B','C','D','E','F','H','I'],'Which
letter is your favourite? ')
duplicates the code where the
error is.
- Since this line calls a
function, the next two lines
describe where in the function
the error occured.
- TypeError: unsupported
operand type(s) for -: 'str' and
'int' tells you the error. In
this case, it is a 'TypeError',
where you tried to subtract
incompatible variables.
There are muliple file and code
listings for a single error,
because the error occured with the
interaction of two lines of code
(e.g. when using a function, the
error occured on the line where
the function was called, AND the
line in the function where things
went wrong).
Now that we know what the
problem is, how do we fix it.
Well, the error message has
isolated where the problem is, so
we'll only concentrate on that bit
of code.
|
Code Example 3 - calling
the menu function |
|
answer = menu(['A','B','C','D','E','F','H','I'],\
'Which letter is your favourite? ')
|
This is a call to a function.
The error occured in the function
in the following line
|
Code Example 4 - Where it
went wrong |
|
return raw_input(question) - 1
|
raw_input always returns a
string, hence our problem. Let's
change it to input(), which, when
you type in a number, it returns a
number:
|
Code Example 5 - Fixing it |
return input(question) - 1
|
Bug fixed!
Exceptions - Limitations of the
Code
OK, the program works when you
do something normal. But what if
you try something weird? Type in a
letter (lets say, 'm') instead of
a number? Whoops!
|
Code Example 6 - Another
error message |
Traceback (most recent call last):
File "/home/steven/errortest.py", line 8, in -toplevel-
answer = menu(< I'll snip it here >)
File "/home/steven/errortest.py", line 6, in menu
return input(question) - 1
File "", line 0, in -toplevel-
NameError: name 'g' is not defined
|
What is this telling us? There
are two code listings - one in
line 8, and the other in line 6.
What this is telling us is that
when we called the menu function
in line 8, an error occured in
line 6 (where we take away 1).
This makes sense if you know what
the input() function does - I did
a bit of reading and testing, and
realised that if you type in a
letter or word, it will assume
that you are mentioning a
variable! so in line 6, we are
trying to take 1 away from the
variable 'm', which doesn't exist.
Have no clue on how to fix
this? One of the best and easiest
ways is to use the try and except
operators.
Here is an example of try being
used in a program:
|
Code Example 7 - The try
operator |
|
try:
function(world,parameters)
except:
print world.errormsg
|
This is an example of a really
messy bit of code that I was
trying to fix. First, the code
under try: is run. If there is an
error, the compiler jumps to the
except section and prints
world.errormsg. The program
doesn't stop right there and
crash, it runs the code under
except: then continues on.
Lets try that where the error
occured in our code (line 6). The
menu function now is:
|
Code Example 8 - testing
our fix |
|
def menu(list, question):
for entry in list:
print 1 + list.index(entry),
print ") " + entry
try:
return input(question) - 1
except NameError:
print "Enter a correct number"
|
Try entering a letter when
you're asked for a number and see
what happens. Dang. We fixed one
problem, but now it has caused
another problem furthur down the
track. This happens all
the time. (Sometimes you end
up going around in circles,
because your code is an absolute
mess). Let's have a look at the
error:
|
Code Example 9 - Yet
another error message |
Traceback (most recent call last):
File "/home/steven/errortest.py", line 12, in -toplevel-
print 'You picked answer', (answer + 1)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
|
What has happened this time is
that the menu function has
returned no value - it only
printed an error message. When, at
the end of the program, we try to
print the returned value plus 1,
what is the returned value? There
is no returned value? So what is 1
+ ... well, we have no clue what
we are adding 1 to!
We could just return any old
number, but that would be lying.
What we really should to is
rewrite the program to cope with
this exception. With what? try and
except!
|
Code Example 10 - yet
another solution |
# from when we finish defining the function
answer = menu(['A','B','C','D','E','F','H','I'],\
'Which letter is your favourite? ')
try:
print 'You picked answer', (answer + 1)
# you can put stuff after a comma in the 'print' statement,
# and it will continue as if you had typed in 'print' again
except:
print '\nincorrect answer.'
# the '\n' is for formatting reasons. Try without it and see.
|
Problem solved again.
Endless Errors
The approach that we used above
is not recomended.
Why? Because apart from the error
that we know can happen, except:
catches every other error too.
What if this means we never see an
error that could cause problems
down the track? If except: catches
every error under the sun, we have
no hope of controlling what errors
we deal with, and the other ones
that we want to see, because so
far we haven't dealt with them. We
also have little hope of dealing
with more than one type of error
in the same block of code. What
should one do, when all is
hopeless? Here is an example of
code with such a situation:
|
Code Example 11 - The
Problem We Face |
print 'Subtraction program, v0.0.1 (beta)'
a = input('Enter a number to subtract from > ')
b = input('Enter the number to subtract > ')
print a - b
|
Ok, you enter your two numbers
and it works. Enter a letter, and
it gives you a NameError. Lets
rewrite the code to deal with a
NameError only. We'll put the
program in a loop, so it restarts
if an error occurs (using
continue, which starts the loop
from the top again, and break,
which leaves the loop):
|
Code Example 12 - Dealing
With NameError |
print 'Subtraction program, v0.0.2 (beta)'
loop = 1
while loop == 1:
try:
a = input('Enter a number to subtract from > ')
b = input('Enter the number to subtract > ')
except NameError:
print "\nYou cannot subtract a letter"
continue
print a - b
try:
loop = input('Press 1 to try again > ')
except NameError:
loop = 0
|
Here, we restarted the loop if
you typed in something wrong. In
line 12 we assumed you wanted to
quit the program if you didn't
press 1, so we quit the program.
But there are still problems.
If we leave something blank, or
type in an unusual character like
! or ;, the program gives us a
SyntaxError. Lets deal with this.
When we are asking for the numbers
to subtract, we will give a
different error message. When we
ask to press 1, we will again
assume the user wants to quit.
|
Code Example 13 - Now,
Dealing With SyntaxError |
print 'Subtraction program, v0.0.3 (beta)'
loop = 1
while loop == 1:
try:
a = input('Enter a number to subtract from > ')
b = input('Enter the number to subtract > ')
except NameError:
print "\nYou cannot subtract a letter"
continue
except SyntaxError:
print "\nPlease enter a number only."
continue
print a - b
try:
loop = input('Press 1 to try again > ')
except (NameError,SyntaxError):
loop = 0
|
As you can see, you can have
multiple except uses, each dealing
with a different problem. You can
also have one except to deal with
multiple exceptions, by putting
them inside parentheses and
seperating them with commas.
Now we have a program that is
very difficult, to crash by an end
user. As a final challenge, see if
you can crash it. There is one way
I have thought of - if you read
the chapter on Human Error
carefully, you might know what it
is.
|