Learning Python - Mark Lutz [454]
If you really want a general “catch-all” clause, an empty except does the trick:
try:
action()
except NameError:
... # Handle NameError
except IndexError:
... # Handle IndexError
except:
... # Handle all other exceptions
else:
... # Handle the no-exception case
The empty except clause is a sort of wildcard feature—because it catches everything, it allows your handlers to be as general or specific as you like. In some scenarios, this form may be more convenient than listing all possible exceptions in a try. For example, the following catches everything without listing anything:
try:
action()
except:
... # Catch all possible exceptions
Empty excepts also raise some design issues, though. Although convenient, they may catch unexpected system exceptions unrelated to your code, and they may inadvertently intercept exceptions meant for another handler. For example, even system exit calls in Python trigger exceptions, and you usually want these to pass. That said, this structure may also catch genuine programming mistakes for you which you probably want to see an error message. We’ll revisit this as a gotcha at the end of this part of the book. For now, I’ll just say “use with care.”
Python 3.0 introduced an alternative that solves one of these problems—catching an exception named Exception has almost the same effect as an empty except, but ignores exceptions related to system exits:
try:
action()
except Exception:
... # Catch all possible exceptions, except exits
This has most of the same convenience of the empty except, but also most of the same dangers. We’ll explore how this form works its voodoo in the next chapter, when we study exception classes.
* * *
Note
Version skew note: Python 3.0 requires the except E as V: handler clause form listed in Table 33-1 and used in this book, rather than the older except E, V: form. The latter form is still available (but not recommended) in Python 2.6: if used, it’s converted to the former. The change was made to eliminate errors that occur when confusing the older form with two alternate exceptions, properly coded in 2.6 as except (E1, E2):. Because 3.0 supports the as form only, commas in a handler clause are always taken to mean a tuple, regardless of whether parentheses are used or not, and the values are interpreted as alternative exceptions to be caught. This change also modifies the scoping rules: with the new as syntax, the variable V is deleted at the end of the except block.
* * *
The try else Clause
The purpose of the else clause is not always immediately obvious to Python newcomers. Without it, though, there is no way to tell (without setting and checking Boolean flags) whether the flow of control has proceeded past a try statement because no exception was raised, or because an exception occurred and was handled:
try:
...run code...
except IndexError:
...handle exception...
# Did we get here because the try failed or not?
Much like the way else clauses in loops make the exit cause more apparent, the else clause provides syntax in a try that makes what has happened obvious and unambiguous:
try:
...run code...
except IndexError:
...handle exception...
else:
...no exception occurred...
You can almost emulate an else clause by moving its code into the try block:
try:
...run code...
...no exception occurred...
except IndexError:
...handle exception...
This can lead to incorrect exception classifications, though. If the “no exception occurred” action triggers an IndexError, it will register as a failure of the try block and erroneously trigger the exception handler below the try (subtle, but true!). By using an explicit else clause instead, you make the logic more obvious and guarantee that except handlers will run only for real failures in the code you’re wrapping in a try, not for failures in