[ Team LiB ] Previous Section Next Section

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

  • A try clause followed by exactly one finally clause

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 that propagates from the try clause. expression is an optional class or tuple of classes that matches any exception object of one of the listed 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 Chapter 8).

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 reraising an exception, as we'll discuss later in the chapter.

Note that 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.

The optional else clause of try/except executes only if the try clause terminates normally. In other words, it does not execute if an exception propagates from the try clause or if 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 "a number of some kind"

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 it 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, as execution order might be ambiguous. If you need both exception handlers and a clean-up handler, 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.

    [ Team LiB ] Previous Section Next Section