I l@ve RuBoard Previous Section Next Section

7.6 Exception Gotchas

There isn't much to trip over here, but here are a few general pointers on exception use.

7.6.1 Exceptions Match by Identity, Not Equality

As we've seen, when an exception is raised (by you or by Python itself), Python searches for the most recently entered try statement with a matching except clause, where matching means the same string object, the same class object, or a superclass of the raised class object. It's important to notice that matching is performed by identity, not equality. For instance, suppose we define two string objects we want to raise as exceptions:

>>> ex1 = "spam"
>>> ex2 = "spam"
>>> ex1 == ex2, ex1 is ex2
(1, 0)

Applying the == test returns true (1) because they have equal values, but is returns false (0) since they are two distinct string objects in memory. Now, an except clause that names the same string object will always match:

>>> try:
...    raise ex1
... except ex1:
...    print 'got it'
got it

But one that lists an equal but not identical object will fail:

>>> try:
...    raise ex1
... except ex2:
...    print 'Got it'
Traceback (innermost last):
  File "<stdin>", line 2, in ?

Here, the exception isn't caught, so Python climbs to the top level of the process and prints a stack trace and the exception automatically (the string "spam"). For class exceptions, the behavior is similar, but Python generalizes the notion of exception matching to include superclass relationships.

7.6.2 Catching Too Much?

Because Python lets you pick and choose which exceptions to catch, you sometimes have to be careful to not be too inclusive. For example, you've seen that an empty except clause catches every exception that might be raised while the code in the try block runs. Sometimes that's wanted, but you may also wind up intercepting an error that's expected by a try handler higher up in a system. An exception handler such as the following catches and stops every exception that reaches it, whether or not another handler is waiting for it:

 ...                          # everything comes here!

The problem here is that you might not expect all the kinds of exceptions that could occur during an operation:

    x = myditctionary[spam]     # oops: misspelled 
    x = None                    # assume we got KeyError or IndexError Solution

In this case, you're assuming the only sort of error that can happen when indexing a dictionary is an indexing error. But because the name myditctionary is misspelled (you meant to say mydictionary), Python raises a NameError instead (since it's an undefined name reference), which will be silently caught and ignored by your handler. You should say: except (KeyError, IndexError): to make your intentions explicit.

7.6.3 Catching Too Little?

Conversely, you sometimes need to not be so exclusive. When listing specific exceptions in a try, you catch only what you actually list. This isn't necessarily a bad thing either, but if a system evolves to raise other exceptions in the future, you may need to go back and add them to exception lists elsewhere in the code. For instance, the following handler is written to treat myerror1 and myerror2 as normal cases and treat everything else as an error. If a myerror3 is added in the future, it is processed as an error unless you update the exception list:

except (myerror1, myerror2):    # what if I add a myerror3?
    ...                         # nonerrors
    ...                         # assumed to be an error Solution

Careful use of class exceptions can make this gotcha go away completely. As we saw earlier in this chapter, if you catch a general superclass, you can add and raise more specific subclasses in the future without having to extend except clause lists manually.

Whether you use classes here or not, a little design goes a long way. The moral of the story is that you have to be careful not to be too general or too specific in exception handlers. Especially in larger systems, exception policies should be a part of the overall design.

I l@ve RuBoard Previous Section Next Section