Saturday, December 24, 2011

computational economics lecture 28


Handling Exceptions

Runtime errors cause execution of the relevant program to stop
  • Frustrating if you're in the middle of a large computation
  • Sometimes the debugging information is not very informative
  • Disappointing for users of your code
A better way is to add code to your program that deals with errors as they occur

Errors

If you've got this far then you've already seen lots of errors
Here's an example:
>>> def f:
  File "<stdin>", line 1
    def f:
         ^
SyntaxError: invalid syntax
This is a syntax error
  • Illegal syntax cannot be executed
  • Always terminates execution of the program
Here's a different kind of error, unrelated to syntax:
>>> 1 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
Here's another:
>>> x = y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'y' is not defined
And another:
>>> 'foo' + 6
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
And another:
>>> X = []
>>> x = X[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range
On each occaision, the interpreter informs us of the error type
  • IndexErrorZeroDivisionError, etc.
In Python, these errors are called exceptions
We can catch and deal with exceptions using try-except blocks
Here's a simple example
def f(x):
    try:
        return 1.0 / x 
    except ZeroDivisionError:
        print 'Error: division by zero.  Returned None'
    return None
When we call f we get the following output
>>> f(2)
0.5
>>> f(0)
Error: division by zero.  Returned None
>>> f(0.0)
Error: division by zero.  Returned None
>>> 
The error is caught and execution of the program is not terminated
Note that other error types are not caught
If we are worried the user might pass in a string, we can catch that error too
def f(x):
    try:
        return 1.0 / x 
    except ZeroDivisionError:
        print 'Error: Division by zero.  Returned None'
    except TypeError:
        print 'Error: Unsupported operation.  Returned None'
    return None
Here's what happens
>>> f(2)
0.5
>>> f(0)
Error: Division by zero.  Returned None
>>> f('foo')
Error: Unsupported operation.  Returned None
>>> 
If we feel lazy we can catch these errors together
def f(x):
    try:
        return 1.0 / x 
    except (TypeError, ZeroDivisionError):
        print 'Error: Unsupported operation.  Returned None'
    return None
Here's what happens
>>> f(2)
0.5
>>> f(0)
Error: Unsupported operation.  Returned None
>>> f('foo')
Error: Unsupported operation.  Returned None
If we feel extra lazy we can catch all error types as follows
def f(x):
    try:
        return 1.0 / x 
    except:
        print 'Error.  Returned None'
    return None
In general it's better to be specific
Problem:
Suppose we have a text file numbers.txt containing
prices
3
8

7
21
Using try-except, write a program to read in the contents of the file and sum the numbers, ignoring lines without numbers
Solution:
f = open('numbers.txt')

total = 0.0 
for line in f:
    try:
        total += float(line)
    except ValueError:
        pass

f.close()

print total