I l@ve RuBoard |
In a nutshell, exceptions let us jump around arbitrarily large chunks of a program. Remember that pizza-making robot we talked about in the last chapter? Suppose we took the idea seriously and actually built such a machine (there are worse hobbies, after all). To make a pizza, our culinary automaton would need to execute a plan, which we implement as a Python program. It would take an order, prepare the dough, add toppings, bake the pie, and so on.
Now, suppose that something goes very wrong during the "bake the pie" step. Perhaps the oven is broken. Or perhaps our robot miscalculates its reach and spontaneously bursts into flames. Clearly, we want to be able to jump to code that handles such states quickly (especially if our robot is melting all over the kitchen floor!). Since we have no hope of finishing the pizza task in such unusual cases, we might as well abandon the entire plan.
That's exactly what exceptions let you do; you can jump to an exception handler in a single step, past all suspended function calls. They're a sort of "super-goto."[1] An exception handler (try statement) leaves a marker and executes some code. Somewhere further ahead in the program, an exception is raised that makes Python jump back to the marker immediately, without resuming any active functions that were called since the marker was left. Code in the exception handler can respond to the raised exception as appropriate (calling the fire department, for instance). Moreover, because Python jumps to the handler statement immediately, there is usually no need to check status codes after every call to a function that could possibly fail.
[1] In fact, if you've used C, you may be interested to know that Python exceptions are roughly equivalent to C's setjmp/longjmp standard function pair. The try statement acts much like a setjmp, and raise works like a longjmp. But in Python, exceptions are based on objects and are a standard part of the execution model.
In typical Python programs, exceptions may be used for a variety of things:
Python raises exceptions when it detects errors in programs at runtime; you can either catch and respond to the errors internally in your programs or ignore the exception. If ignored, Python's default exception-handling behavior kicks in; it kills the program and prints an error message showing where the error occurred.
Exceptions can also signal a valid condition, without having to pass result flags around a program or test them explicitly. For instance, a search routine might raise an exception on success, rather than return an integer 1.
Sometimes a condition may happen so rarely that it's hard to justify convoluting code to handle it. You can often eliminate special-case code by handling unusual cases in exception handlers instead.
And finally, because exceptions are a type of high-level goto, you can use them as the basis for implementing exotic control flows. For instance, although backtracking is not part of the language itself, it can be implemented in Python with exceptions and a bit of support logic to unwind assignments.[2]
[2] Backtracking isn't part of the Python language, so we won't say more about it here. See a book on artificial intelligence or the Prolog or icon programming languages if you're curious.
We'll see some of these typical uses in action later in this chapter. First, let's get started with a closer look at Python's exception-processing tools.
I l@ve RuBoard |