Python Programming for the Absolute Beginner, 3rd Edition

When Python runs into an error, it stops the current program and displays an error message. More precisely, it raises an exception, indicating that, well, something exceptional has occurred. If nothing is done with the exception, Python halts what it's doing and prints an error message detailing the exception.

Here's a simple example of Python raising an exception:

>>> num = float(raw_input("Enter a number: ")) Enter a number: Hi! Traceback (most recent call last): File "<pyshell#0>", line 1, in ? num = float(raw_input("Enter a number: ")) ValueError: invalid literal for float(): Hi!

In this interactive session, Python tries to convert the string "Hi!" to a floating-point number. Since it can't, Python raises an exception and prints the details.

Using Python's exception handling functionality, you can intercept and handle exceptions so that your program doesn't end abruptly (even if a user enters "Hi!" when you ask for a number). At the very least, you can have your program exit gracefully instead of crashing awkwardly.

Introducing the Handle It Program

The Handle It program opens itself up to errors from user input and then purposely generates a few errors of its own. But instead of halting, the program runs to completion. That's because the program handles the exceptions that are raised. Figure 7.5 shows the program in action.

Figure 7.5: Although the program can't convert "Hi!" to a number, it doesn't halt when exceptions are raised.

Using a try Statement with an except Clause

The most basic way to handle (or trap) exceptions is to use the try statement with an except clause. By using a try statement, you section off some code that could potentially raise an exception. Then, you write an except clause with a block of statements that are executed only if an exception is raised.

The first thing I do in the Handle It program is ask the user for a number. I get a string from the user and then attempt to convert the string to a floating-point number. I use try and except to handle any exceptions that might be raised in the process.

# Handle It # Demonstrates handling exceptions # Michael Dawson 5/3/03 # try/except try: num = float(raw_input("Enter a number: ")) except: print "Something went wrong!"

If the call to float() raises an exception (as a result of the user entering an unconvertible string, like "Hi!", for example), the exception is caught and the user is informed that Something went wrong! If no exception is raised, num gets the number the user entered and the program skips the except clause, continuing with the rest of the code.

Specifying an Exception Type

Different kinds of errors result in different types of exceptions. For example, trying to convert the string "Hi!" with float() results in a ValueError exception because the characters in the string are of the wrong value (they're not digits). There are over two dozen exception types, but Table 7.4 lists a few of the most common ones.

Table 7.4: SELECTED EXCEPTION TYPES

Exception Type

Description

IOError

Raised when an I/O operation fails, such as when an attempt is made to open a nonexistent file in read mode.

IndexError

Raised when a sequence is indexed with a number of a nonexistent element.

KeyError

Raised when a dictionary key is not found.

NameError

Raised when a name (of a variable or function, for example) is not found.

SyntaxError

Raised when a syntax error is encountered.

TypeError

Raised when a built-in operation or function is applied to an object of inappropriate type.

ValueError

Raised when a built-in operation or function receives an argument that has the right type but an inappropriate value.

ZeroDivisionError

Raised when the second argument of a division or modulo operation is zero.

The except clause lets you specify exactly which type of exceptions it will handle. You just list the specific type of exceptions in parentheses after except.

I again ask the user for a number, but this time I specifically trap for a ValueError:

# specifying exception type try: num = float(raw_input("\nEnter a number: ")) except(ValueError): print "That was not a number!"

Now, the print statement will only execute if a ValueError is raised. As a result, I can be even more specific and display the message That was not a number! However, if any other exception is raised inside the try statement, the except clause will not catch it and the program will come to a halt.

It's good programming practice to specify exception types so that you handle each individual case. In fact, it's dangerous to catch all exceptions the way I did in the first except clause of the program. Generally, you should avoid that type of catchall.

HINT

When should you trap for exceptions? Any point of external interaction with your program is a good place to think about exceptions. It's a good idea to trap for exceptions when opening a file for reading, even if you believe the file already exists. You can also trap for exceptions when you attempt to convert data from an outside source, like the user.

TRICK

So, let's say you know you want to trap for an exception, but you're not exactly sure what the exception type is called. Well, here's a shortcut for finding out: just create the exception. For example, if you know you want to trap for a division-by-zero exception, but can't remember exactly what the exception type is called, jump into the interpreter and divide a number by zero:

>>> 1/0 Traceback (most recent call last): File "<pyshell#0>", line 1, in ? 1/0 ZeroDivisionError: integer division or modulo by zero

From this interactive session, I can see that the exception is called ZeroDivisionError. Fortunately, the interpreter isn't shy about telling you exactly which type of exception you raise.

Handling Multiple Exception Types

A single piece of code can result in different types of exceptions. Fortunately, you can trap for multiple exception types. One way to trap for multiple exception types is to list them in a single except clause:

# handle multiple exceptions print for value in (None, "Hi!"): try: print "Attempting to convert", value, "—>", print float(value) except(TypeError, ValueError): print "Something went wrong!"

This code tries to convert two different values to a floating-point number. Both fail, but each raises a different exception type. float(None) raises a TypeError because the function can only convert strings and numbers. float("Hi!") raises a ValueError because, while "Hi!" is a string, the characters in the string are of the wrong value (they're not digits). As a result of the except clause, each type of exception is handled.

Another way to catch multiple exceptions is with multiple except clauses. You can list as many as you'd like, following a single try statement:

print for value in (None, "Hi!"): try: print "Attempting to convert", value, "—>", print float(value) except(TypeError): print "I can only convert a string or a number!" except(ValueError): print "I can only convert a string of digits!"

Now, each exception type has its own block. So when value is None, a TypeError is raised and the string "I can only convert a string or a number!" is printed. When value is "Hi!", a ValueError is raised and the string "I can only convert a string of digits!" is printed.

Using multiple except clauses allows you to define unique reactions to different types of exceptions from the same try block. In this case, I offer a more specific error message by trapping each exception type individually.

Getting an Exception's Argument

When an exception occurs, it may have an associated value, the exception's argument. The argument is usually an official message from Python describing the exception. You can receive the argument if you list a variable before the colon in the except statement.

Here, I receive the exception's argument in variable e and print it out along with my regular error message:

# get an exception's argument try: num = float(raw_input("\nEnter a number: ")) except(ValueError), e: print "That was not a number! Or as Python would say:\n", e

Adding an else Clause

You can add a single else clause after all the except clauses in a try statement. The else block executes only if no exception is raised in the try block.

# try/except/else try: num = float(raw_input("\nEnter a number: ")) except(ValueError): print "That was not a number!" else: print "You entered the number", num raw_input("\n\nPress the enter key to exit.")

In this code, num is printed in the else block only if the assignment statement in the try block doesn't raise an exception. This is perfect because that means num will be printed only if the assignment statement was successful and the variable exists.

Категории