Exception Handling
What is Exception?
An exception is an event, which occurs during the
execution of a program that disrupts the normal flow of the program's
instructions. In general, when a Python script encounters a situation that it
can't cope with, it raises an exception. An exception is a Python object that
represents an error. When a Python script raises an exception, it must either
handle the exception immediately otherwise it would terminate and come out.
Handling an
exception:
If
you have some suspicious code that may raise an exception, you
can defend your program by placing the suspicious code in a try: block. After the try: block, include
an except: statement, followed by a block of code
which handles the problem as elegantly as possible.
SYNTAX:
Here is
simple syntax of try....except...else blocks:
try:
You do your operations here;
......................
except
ExceptionI:
If there is ExceptionI, then execute this
block.
except
ExceptionII:
If there is ExceptionII, then execute this
block.
......................
else:
If there is no exception then execute this
block.
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 >)
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'
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 multiple 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
Okay,
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
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.
Let's 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
# 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
Okay,
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 section on human error
carefully, you might know what it is.
No comments:
Post a Comment