Exceptions
Let's consider the following code. I know it doesn't work as written. But, what I'd like to do is to consider how it breaks:
def addNumbers(): sum = 0 while (True): number = raw_input("number> ") sum = sum+int(number) return sum print addNumbers()
It adds numbers, so long as it is fed integer numbers -- but then it dies when it is fed anything else:
Traceback (most recent call last): File "./example.py", line 13, inprint addNumbers() File "./example.py", line 9, in addNumbers sum = sum+int(number) ValueError: invalid literal for int() with base 10: 'q'
Now, let's considered the revised version below. Any idea what it is doing?
def addNumbers(): sum = 0 while (True): number = raw_input("number> ") try: sum = sum+int(number) except: break return sum print addNumbers()
What do you think the try and except do? In effect, try tries to execute the associated block of code as normal, but if there is an error, looks to one or more associated except blocks for how to handle the error. In this case, we handle the error by breaking out of the loop.
So, now our function adds numbers provided by the usr, and lets the user stop by entering a non-number. Pretty cool, huh?
The Exception, as an Object
Exceptions are actually special types of complex entities called, "Objects". They contain data and associated functions, known as "methods".When the user enters a non-number, and we try to use it as a number, Python generates an exception object to describe this situation. In effect, this object is realized as part of the "except:" block. In the code above, we used a short-hand "except:" syntax that let us know about the existence of the exception, but didn't actually allow us to get our hands on the exception object, itself.
Notice that, in the "except block" below, we use "as" to associate this object with the variable "e", and then print it. This is obviously not helpful to our user -- but it is a good example for us.
def addNumbers(): sum = 0 while (True): number = raw_input("number> ") try: sum = sum+int(number) except: break return sum print addNumbers()
The output of the "print e" above, is shown below:
invalid literal for int() with base 10: 'a'
Multiple Exception Types
The code below illustates the syntax for handling multiple exceptions within one "except:" block. Note that we are able to look for more than one exception in an except clause by listing them within a tuple. We'll learn more about tuples soon, but, in short, they are unchangable, ordered, ,-comma separated lists defiend within parentheses, e.g. "(4, 5, 6)", or, in the case below, "(ZeroDivisionError,TypeError)".
#!/usr/bin/python def divideNumbersAndPrint(fmtString, x,y): try: result = x / y newString = fmtString % (result) except (ZeroDivisionError,TypeError): print "Invalid format string or divide by zero" divideNumbersAndPrint("Result is %d", 5, 3) divideNumbersAndPrint("Result is %f", 5.0, 3.0) divideNumbersAndPrint("Result is %f %f", 5.0, 1.0) divideNumbersAndPrint("Result is %f", 5.0, 0.0)
The example below is somewhat similar, except that we use multiple except blocks, which enables us to handle each exception differently:
#!/usr/bin/python def divideNumbersAndPrint(fmtString, x,y): try: result = x / y newString = fmtString % (result) except ZeroDivisionError: print "Undefined" # As we called the result fo dividing by zero in high school except TypeError: print result # Without broken formatting divideNumbersAndPrint("Result is %d", 5, 3) divideNumbersAndPrint("Result is %f", 5.0, 3.0) divideNumbersAndPrint("Result is %f %f", 5.0, 1.0) divideNumbersAndPrint("Result is %f", 5.0, 0.0)