Previous Page
Next Page

6.1. The try Statement

The try statement provides Python's exception-handling mechanism. It is a compound statement that can take one of two different forms:

  • A try clause followed by one or more except clauses (and optionally an else clause)

  • A try clause followed by exactly one finally clause

In Python 2.5, a TRy statement can have except clauses (and optionally an else clause) followed by a finally clause; however, in all previous versions of Python, the two forms cannot be merged, so I present them separately in the following. See "The try/except/finally statement" on page 124 for this small 2.5 enhancement to try statement syntax.

6.1.1. try/except

Here's the syntax for the try/except form of the try statement:

try:
    statement(s)
except [expression [, target]]:
    statement(s)
[else:
    statement(s)]

This form of the TRy statement has one or more except clauses, as well as an optional else clause.

The body of each except clause is known as an exception handler. The code executes if the expression in the except clause matches an exception object propagating from the try clause. expression is a class or tuple of classes, and matches any instance of one of those classes or any of their subclasses. The optional target is an identifier that names a variable that Python binds to the exception object just before the exception handler executes. A handler can also obtain the current exception object by calling the exc_info function of module sys (covered in exc_info on page 168).

Here is an example of the try/except form of the try statement:

try: 1/0
except ZeroDivisionError: print "caught divide-by-0 attempt"

If a TRy statement has several except clauses, the exception-propagation mechanism tests the except clauses in order; the first except clause whose expression matches the exception object is used as the handler. Thus, you must always list handlers for specific cases before you list handlers for more general cases. If you list a general case first, the more specific except clauses that follow will never enter the picture.

The last except clause may lack an expression. This clause handles any exception that reaches it during propagation. Such unconditional handling is a rare need, but it does occur, generally in wrapper functions that must perform some extra task before re-raising an exception, as we'll discuss in "The raise Statement" on page 128. Beware of using a "bare except" (an except clause without an expression) unless you're re-raising the exception in it: such sloppy style can make bugs very hard to find, since the bare except is generally over-broad and can easily mask coding errors and other kinds of bugs.

Exception propagation terminates when it finds a handler whose expression matches the exception object. Thus, if a try statement is nested in the try clause of another try statement, a handler established by the inner try is reached first during propagation and, therefore, is the one that handles the exception, if it matches the expression. For example:

try:
    try: 1/0
    except: print "caught an exception"
except ZeroDivisionError:
    print "caught divide-by-0 attempt"
# prints: caught an exception

In this case, it does not matter that the handler established by clause except ZeroDivisionError: in the outer try clause is more specific and appropriate than the catch-all except: in the inner try clause. The outer try does not even enter into the picture because the exception doesn't propagate out of the inner try. For more on propagation, see "Exception Propagation" on page 126.

The optional else clause of try/except executes only when the TRy clause terminates normally. In other words, the else clause does not execute when an exception propagates from the try clause, or when the try clause exits with a break, continue, or return statement. The handlers established by try/except cover only the TRy clause, not the else clause. The else clause is useful to avoid accidentally handling unexpected exceptions. For example:

print repr(value), "is ",
try:
    value + 0
except TypeError:
    # not a number, maybe a string, Unicode, UserString...?
    try:
        value + ''
    except TypeError:
        print "neither a number nor a string"
    else:
        print "a string or string-like value"
else:
    print "some kind of number"

6.1.2. try/finally

Here's the syntax for the TRy/finally form of the try statement:

try:
    statement(s)
finally:
    statement(s)

This form has exactly one finally clause and cannot have an else clause.

The finally clause establishes what is known as a clean-up handler. The code always executes after the try clause terminates in any way. When an exception propagates from the TRy clause, the TRy clause terminates, the clean-up handler executes, and the exception keeps propagating. When no exception occurs, the clean-up handler executes anyway, whether the try clause reaches its end or exits by executing a break, continue, or return statement.

Clean-up handlers established with try/finally offer a robust and explicit way to specify finalization code that must always execute, no matter what, to ensure consistency of program state and/or external entities (e.g., files, databases, network connections). Here is an example of the try/finally form of the TRy statement:

f = open(someFile, "w")
try:
    do_something_with_file(f)
finally:
    f.close( )

Note that the TRy/finally form is distinct from the try/except form: a try statement cannot have both except and finally clauses, unless you're using Python 2.5. If you need both exception handlers and a clean-up handler, and your code must run under Python 2.3 or 2.4, nest a try statement in the TRy clause of another TRy statement to define execution order explicitly and unambiguously.

A finally clause cannot directly contain a continue statement, but it may contain a break or return statement. Such usage, however, makes your program less clear, as exception propagation stops when such a break or return executes. Most programmers would not normally expect propagation to be stopped in a finally clause, so this usage may confuse people who are reading your code. In Python 2.3 and 2.4, a try/finally statement cannot contain a yield statement (in 2.5, it can).

6.1.3. Python 2.5 Exception-Related Enhancements

Besides allowing a try statement to have both except clauses and a finally clause, Python 2.5 introduces a new with statement, which nicely wraps many cases of try/except into one concise and handy syntax. Python 2.5 also includes enhancements to generators that make them more useful with the new with statement and with exceptions in general.

6.1.3.1. The try/except/finally statement

A Python 2.5-only try/except/finally statement, such as:

try:
    ...guarded clause...
except...expression...:
    ...exception handler code...
finally:
    ...clean-up code...

is equivalent to the statement (which you can write in 2.5 or any previous version):

try:
    try:
        ...guarded clause...
    except...expression...:
        ...exception handler code...
finally:
    ...clean-up code...

You can also have multiple except clauses, and optionally an else clause, before the terminating finally clause. In all variations, the effect is always like the abovei.e., just like nesting a TRy/except statement, with all the except clauses and the else clause if any, into a containing TRy/finally statement.

6.1.3.2. The with statement

The with statement is new in Python 2.5. To use this statement in a given module in Python 2.5, you must turn with into a keyword by placing the following instruction at the start of the module:

from _ _future_ _ import with_statement

In Python 2.6 and later, with will always be a keyword, and the above statement will be unnecessary (although accepted and innocuous).

with has the following syntax:

with expression [as varname]
    statement(s)

The semantics of with are defined as being equivalent to:

_normal_exit = True
_temporary = expression varname = _temporary._ _enter_ _( )
try:
    statement(s)
except:
    _normal_exit = False
    if not _temporary._ _exit_ _(*sys.exc_info( )):
        raise
    # exception does not propagate if _ _exit_ _ returns a true value finally:
    if _normal_exit:
        _temporary._ _exit_ _(None, None, None)

where _temporary and _normal_exit are arbitrary internal names that are not used elsewhere in the current scope. If you omit the optional as varname part of the with clause, Python still calls _temporary._ _enter_ _( ), but doesn't bind the result to any name, and still calls _temporary._ _exit_ _( ) at block termination.

The new with statement embodies the well-known C++ idiom "resource acquisition is initialization": you need only write classes with the two new special methods _ _enter_ _ (callable without arguments) and _ _exit_ _ (callable with three arguments; all None if the body completes without propagating exceptions, otherwise the type, value, and traceback of the exception) to have the same guaranteed finalization behavior as typical ctor/dtor pairs have for auto variables in C++ (with the added ability to finalize differently depending on what exception, if any, propagates, as well as optionally blocking a propagating exception by returning a true value from _ _exit_ _).

For example, here is one way, with Python 2.5, to wrap the opening of a file in order to ensure the file is closed when you're done:

class opened(object):
    def _ _init_ _(self, filename, mode='r'):
        self.f = open(filename, mode)
    def _ _enter_ _(self):
        return self.f
    def _ _exit_ _(self, etyp, einst, etb):
        self.f.close( )
# to be used as:
with opened('foo.txt') as f:
   ...statements using open file object f...

This example code is not particularly useful, since in Python 2.5 built-in file objects already supply the needed methods _ _enter_ _ and _ _exit_ _; the example's purpose is a purely illustrative one.

An even simpler way to build such wrappers is most likely going to be supplied by the new contextlib module of the standard Python library: the module is scheduled to contain a decorator (probably to be called contextmanager) that turns a generator function into a factory of such wrappers, as well as wrapper functions closing (to call some object's close method upon _ _exit_ _) and nested (to nest multiple such wrappers for use in a single with statement).

Many more examples and detailed discussion can be found in PEP 343 at http://www.python.org/peps/pep-0343.html.

6.1.3.3. Generator enhancements

In Python 2.5, yield statements are allowed inside try/finally statements (in previous versions, this combination was not allowed). Moreover, generator objects now have two other new methods, throw and close (in addition to the other new method send mentioned in "Generators in Python 2.5" on page 80). Given a generator object g, built by calling a generator function, the throw method's syntax is:

g.throw(exc_type, exc_value=None,
exc_traceback=None]

When the generator's caller calls g.tHRow, the effect is just as if a raise statement with the same arguments was executed at the spot of the yield at which generator g is suspended. Method close has no arguments; when the generator's caller calls g.close( ), the effect is just like calling g.throw(GeneratorExit). GeneratorExit is a built-in exception class, new in 2.5, which inherits directly from Exception. A generator's close method should re-raise (or propagate) the GeneratorExit exception, or, equivalently, raise StopIteration, after doing whatever clean-up operations the generator may need. Generators now also have a destructor (special method _ _del_ _) that is exactly equivalent to method close.

For many more details on Python 2.5's generator enhancements, and examples of how they can be used (for example, to use generators for implementing co-routines), see PEP 342 at http://www.python.org/peps/pep-0342.html.


Previous Page
Next Page