Python Programming/Exceptions
Python 2 handles all errors with exceptions.
An exception is a signal that an error or other unusual condition has occurred. There are a number of built-in exceptions, indicating conditions such as reading past the end of a file or dividing by zero. You can also define your own exceptions.
Overview
editExceptions in Python at a glance:
import random
try:
ri = random.randint(0, 2)
if ri == 0:
infinity = 1/0
elif ri == 1:
raise ValueError("Message")
#raise ValueError, "Message" # Deprecated
elif ri == 2:
raise ValueError # Without message
except ZeroDivisionError:
pass
except ValueError as valerr:
# except ValueError, valerr: # Deprecated?
print(valerr)
raise # Raises the exception just caught
except: # Any other exception
pass
finally: # Optional
pass # Clean up
class CustomValueError(ValueError): pass # Custom exception
try:
raise CustomValueError
raise TypeError
except (ValueError, TypeError): # Value error catches custom, a derived class, as well
pass # A tuple catches multiple exception classes
Raising exceptions
editWhenever your program attempts to do something erroneous or meaningless, Python raises exception to such conduct:
>>> 1 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
This traceback indicates that the ZeroDivisionError
exception is being raised. This is a built-in exception -- see below for a list of all the other ones.
Catching exceptions
editTo handle errors, you can set up exception handling blocks in your code. The keywords try
and except
are used to catch exceptions. When an error occurs within the try
block, Python looks for a matching except
block to handle it. If there is one, execution jumps there.
If you execute this code:
try:
print(1/0)
except ZeroDivisionError:
print("You can't divide by zero!")
Then Python will print this:
You can't divide by zero!
If you don't specify an exception type on the except
line, it will cheerfully catch all exceptions. This is generally a bad idea in production code, since it means your program will blissfully ignore unexpected errors as well as ones that the except
block is actually prepared to handle.
Exceptions can propagate up the call stack:
def f(x):
return g(x) + 1
def g(x):
if x < 0: raise ValueError, "I can't cope with a negative number here."
else: return 5
try:
print(f(-6))
except ValueError:
print("That value was invalid.")
In this code, the print
statement calls the function f
. That function calls the function g
, raising an exception of type ValueError. Neither f
nor g
has a try
/except
block to handle ValueError. So the exception raised propagates out to the main code, where there is an exception-handling block waiting for it. This code prints:
That value was invalid.
Sometimes it is useful to find out exactly what went wrong, or to print the python error text yourself. For example:
try:
the_file = open("the_parrot")
except IOError, (ErrorNumber, ErrorMessage):
if ErrorNumber == 2: # file not found
print("Sorry, 'the_parrot' has apparently joined the choir invisible.")
else:
print("Congratulation! you have managed to trip a #%d error" % ErrorNumber)
print(ErrorMessage)
Printing:
Sorry, 'the_parrot' has apparently joined the choir invisible.
Custom Exceptions
editCode similar to that seen above can be used to create custom exceptions and pass information along with them. This can be useful when trying to debug complicated projects. Here is how that code would look; first creating the custom exception class:
class CustomException(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return repr(self.parameter)
And then using that exception:
try:
raise CustomException("My Useful Error Message")
except CustomException, (instance):
print("Caught: " + instance.parameter)
Trying over and over again
editRecovering and continuing with finally
edit
Exceptions could lead to a situation where, after raising an exception, the code block where the exception occurred might not be revisited. In some cases this might leave external resources used by the program in an unknown state.
finally
clause allows programmers to close such resources in case of an exception. Between 2.4 and 2.5 version of python there is change of syntax for finally
clause.
- Python 2.4
try:
result = None
try:
result = x/y
except ZeroDivisionError:
print("division by zero!")
print("result is ", result)
finally:
print("executing finally clause")
- Python 2.5
try:
result = x / y
except ZeroDivisionError:
print("division by zero!")
else:
print("result is", result)
finally:
print("executing finally clause")
Built-in exception classes
editExotic uses of exceptions
editExceptions are good for more than just error handling. If you have a complicated piece of code to choose which of several courses of action to take, it can be useful to use exceptions to jump out of the code as soon as the decision can be made. The Python-based mailing list software Mailman does this in deciding how a message should be handled. Using exceptions like this may seem like it's a sort of GOTO -- and indeed it is, but a limited one called an escape continuation. Continuations are a powerful functional-programming tool and it can be useful to learn them.
Just as a simple example of how exceptions make programming easier, say you want to add items to a list but you don't want to use "if" statements to initialize the list we could replace this:
if hasattr(self, 'items'):
self.items.extend(new_items)
else:
self.items = list(new_items)
Using exceptions, we can emphasize the normal program flow—that usually we just extend the list—rather than emphasizing the unusual case:
try:
self.items.extend(new_items)
except AttributeError:
self.items = list(new_items)
External links
edit- 8. Errors and Exceptions in The Python Tutorial, docs.python.org
- 8. Errors and Exceptions in The Python Tutorial for Python 2.4, docs.python.org
- 6. Built-in Exceptions, docs.python.org