Beginning Python: Exceptions, Errors, and Warnings

01
of 08

What is an Exception?

More often than not, a program is written to address a certain problem. It may be as simple as converting certain kinds of British spelling to American spelling, or vice versa. Or it may be working with hundreds of internet spiders throughout the Web or tracking and processing millions of financial transactions. Of the latter two, Google uses Python for the first and the New York Stock Exchange (NYSE) does the second every day.

Any publisher who has authors in Australia, New Zealand, Canada or elsewhere in the former British Commonwealth must do the first task whenever they bring a book to the US markets. If their conversion program expects only plain English (ASCII) it will be in trouble. The program will inevitably encounter an foreign phrase or other unexpected piece of text. It will then throw an error [read: crash].

Whenever Python throws an error on a program that is programmed with proper Python syntax, it has hit upon an exception. While your data may vary, you can program Python to expect variability in the data. Using the information presented in this tutorial, your Python programs will cope quite nicely and deal with failures in the way that you decide.

Other tutorials in this series: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8

02
of 08

Exception Exemplified

If reading the previous page has caused you to wonder: "Gee, what does Python do with unexpected variations in data?", try this in your Python shell:

 Python 2.5 (r25:51908, Dec 8 2006, 15:53:50) 
 [GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2 
 Type "help", "copyright", "credits" or "license" for more information. 
 >>> print a 
You will immediately receive Python's response: a NameError.
 Traceback (most recent call last): 
 File "<stdin>", line 1, in <module> 
 NameError: name 'a' is not defined 

If you would like another example, try this one from "Beginning Python":

 >>> 1/0 

If you have come far enough in life to be reading this, there is a good chance that you know that division by zero is a no-no in the world of non-imaginary numbers. Python may not have been around as long as you have, but it knows that, too, and it has a special error just for it:

 Traceback (most recent call last): 
 File "<stdin>", line 1, in <module> 
 ZeroDivisionError: integer division or modulo by zero 

You will notice that this error is called a ZeroDivisionError. Python has many kinds of exceptions. Descriptions of each can be found on the last page of this tutorial. Alternatively, if you just want to get a feel for what kinds of exceptions can be thrown, type the following in your Python shell:

 >>> import exceptions 
 >>> dir(exceptions) 
03
of 08

If at First You Don't Succeed

As mentioned earlier, Python throws an error or exception whenever things do not go to plan. Fortunately, when this happens, a well-coded program knows how to handle these errors and can "catch" the error. This is sometimes called "trapping". To catch the error, one must be a bit less forceful with one's commands and use the try...except program structure.

To use the first exception from the previous page, we know that we get a NameError if we try

 print a 

If we want to ensure that the whole house of code does not fall down on us, we can couch the print statement in a try clause and handle the exception with except:

 try: 
 print a 
 except: 
 print "Doh, you need to define 'a' before you can print it!" 

If you plug this into your Python shell, being sure to indent the arguments of try and except, you will get the following output:

Doh, you need to define 'a' before you can print it!

Of course, this except clause handles every exception. What if you only want to process the NameError with that statement? Then tell Python to take exception at the NameError to the implicit exclusion of other types:

 try: 
 print a 
 except NameError: 
 print "Doh, you need to define 'a' before you can print it!" 

The output will be the same.

You can except any error in the module exceptions. In the section on the Python Library, there are lists of all exceptions and warnings.

04
of 08

Try, Try Again

Now that you can catch errors and turn them into simple exceptions. The question begs asking: "How do you catch more than one kind of error?" Simple: Use multiple except statements.

If, for example, we take Hetland's example of dividing by 0 and turn the division equation into variables instead of values, we should check for both attribution of value and zero division. In which case, we want a program like that below.

 a = input("Please enter the dividend (the number to be divided):") 
 b = input("Please enter the divisor (the number by which to divide):") 
 
 try: 
 print a/b 
 except NameError: 
 print "Both values must be integers!" 
 except ZeroDivisionError: 
 print "The divisor must not be zero. Division by null is not allowed." 

Similarly, if you need to do more calculations with the two values (e.g., monetary conversion for multiple currencies), you can lob all of the calculations into the single try statement. If anything goes wrong, the same except statements for one calculation will pick up the mathematical debris of the others.

If you would like to perform the same action on multiple errors, you can combine the errors into a single argument for except:

 
 a = input("Please enter the dividend (the number to be divided):") 
 b = input("Please enter the divisor (the number by which to divide):") 
 
 try: 
 print a/b 
 except (NameError, ZeroDivisionError): 
 print "The divisor must not be zero. Null division is not allowed." 
05
of 08

Taking Exception

While it is all well and good to handle an exception and do something predictable when it happens, what if you want to process the error as data, perhaps printing it in a bold HTML typeface? Simply pass to except the variable by which you want to reference the error data. Using the last example from the previous page, it would look like this:

 a = input("Please enter the dividend (the number to be divided):") 
 b = input("Please enter the divisor (the number by which to divide):") 
 
 try: 
 print a/b 
 except (NameError, ZeroDivisionError), error: 
 print "The divisor must not be zero. When the divisor is zero, Python hiccups like every good calculator should. The error passed was:" 
 print "<div><b>%s</b><div>" %(error) 
06
of 08

If All Else Fails...

Sometimes you may want Python to behave one way if there is an exception and another way if no error occurred. In this case, you will want to use a structure of try...except...else. To nuance the same previous example, we can add a third clause to affirm the user in not dividing by zero.

 a = input("Please enter the dividend (the number to be divided):") 
 b = input("Please enter the divisor (the number by which to divide):") 
 
 try: 
 print a/b 
 except (NameError, ZeroDivisionError), error: 
 print "The divisor must not be zero. When the divisor is zero, Python hiccups like every good calculator should. The error passed was:" 
 print "<div><b>%s</b><div>" %(error) 
 else: 
 print "Not dividing by zero is a good thing." 
When run, this program can produce the following output:
Please enter the dividend (the number to be divided): 6
Please enter the divisor (the number by which to divide): 3
2
Not dividing by zero is a good thing.
07
of 08

Raising Your Own Exceptions With raise - Part 1

The standard way by which Python "handles" exceptions is by throwing an error of some sort. If the program is not coded to "catch" the error and do something with it, the program usually crashes, as we saw earlier. However, even if the program works just as you intended, you can program in your own exceptions using the raise statement.

At a Python shell, type the following:

 raise NameError 
You will get feedback from the Python interpreter that looks like this:
 >>> raise NameError 
 Traceback (most recent call last): 
 File "<stdin>", line 1, in <module> 
 NameError 

You can use any kind of error that is included in the module exceptions (for a full list of exceptions, see the page of exceptions). You can also raise your own exceptions (see below). However, the exception raised must be a class or an instance of a class. Anything else will result in a TypeError. If you want to see what would happen, type the following at a Python shell prompt:

 >>> raise 

Whenever an exception is raised in the code, Python will raise that error -- even if it sees nothing wrong. In this way, your programs can be stricter than the Python interpreter. Say, for example, you have a set of options and would like a NameError error to be thrown if the user chooses an option not listed. Python will do that as part of the exception handling process, instead of throwing a KeyError or something similar.

08
of 08

Raising Your Own Exceptions With raise - Part 2

But what if you do not want to give the user something obtuse like NameError or IOError. Python also provides a way to present customised error messages by using the built-in class Exception. To use it, simply plug "Exception" as the argument of raise.

 >>> raise Exception 
 Traceback (most recent call last): 
 File "<stdin>", line 1, in <module> 
 Exception 
"Where is the error message?" Well, I wanted you to see that you could raise a simple error by not giving any further arguments than "Exception". If you want to print something beyond this, enclose your message in quotes and separate it from "Exception" by a comma:
 >>> raise Exception, "This is my customised error message." 
 Traceback (most recent call last): 
 File "<stdin>", line 1, in <module> 
 Exception: This is my customised error message. 

That summarises Python's exceptions, if you would like a list of them, you will find a page each of Python's exceptions and warnings in the section on the Python Library.

Other tutorials in this series: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8