26.2 Exception Idioms
We've seen the mechanics behind exceptions. Now, let's take a look at some of the other ways they are typically used.
26.2.1 Exceptions Aren't Always Errors
In Python, all errors are exceptions, but not all exceptions are errors. For instance, we saw in Chapter 7 that file object read
while 1: try: line = raw_input( ) # Read line from stdin. except EOFError: break # Exit loop at end of file else: ...process next line here...
Other built-in exceptions are similarly signals, not errors. Python also has a set of built-in exceptions that represent warnings , rather than errors. Some of these are used to signal use of deprecated (phased out) language features. See the standard library manual's description of built-in exceptions and the warnings module for more on warnings.
26.2.2 Functions Signal Conditions with raise
User-defined exceptions can also signal nonerror conditions. For instance, a search routine can be coded to raise an exception when a match is found, instead of returning a status flag that must be interpreted by the caller. In the following, the try / except / else exception handler does the work of an if / else return value tester:
Found = "Item found" def searcher( ): if ... success ...: raise Found else: return try: searcher( ) except Found: # Exception if item was found ...success... else: # else returned: not found ...failure...
failure = "not found" def searcher( ): if ... success ...: return ... founditem ... else: raise failure try: item = searcher( ) except failure: ... report ... else: ...use item here...
Because Python is dynamically typed and polymorphic to the
26.2.3 Debugging with Outer try Statements
You can also make use of exception handlers to replace Python's default top-level exception-handling behavior. By wrapping an entire program (or a call to it) in an outer try in your top-level code, you can catch any exception that may occur while your program runs, thereby subverting the default program termination.
In the following, the empty except clause catches any uncaught exception raised while the program runs. To get hold of the actual exception that occurred, fetch the exc_type and exc_value attributes from the built-in sys module; they're automatically set to the current exception's name and extra data: 
try: ...run program... except: # All uncaught exceptions come here. import sys print 'uncaught!', sys.exc_type, sys.exc_value
This structure is commonly used during development, to keep your program active even after errors occur—you can run additional tests without having to restart. It's also used when testing code, as described in the next section.
26.2.4 Running in-Process Tests
You might combine some of these coding patterns in a test-driver application, which tests other code within the same process:
import sys log = open('testlog', 'a') from testapi import moreTests, runNextTest, testName def testdriver( ): while moreTests( ): try: runNextTest( ) except: print >> log, 'FAILED', testName( ), sys.exc_type else: print >> log, 'PASSED', testName( ) testdriver( )
The testdriver function here cycles through a series of test calls (module testapi is left abstract in this example). Because an uncaught exception in a test case would normally kill this test driver, we need to wrap test case calls in a try if we want to continue the testing process after a test fails. As usual, the empty except catches any uncaught exception generated by a test case, and uses sys.exc_type to log the exception to a file; the else clause is run when no exception occurs—the test success case.