Handling more specific to less specific exceptions
One strategy for handling exceptions is to provide specific except
clauses for all known exceptions and generic except clauses to handle unknown
exceptions. You can see the exception hierarchy that Python uses at
https://docs.python.org/3.3/library/exceptions. html#exception-hierarchy. When
viewing this chart, BaseException is the uppermost exception. Most exceptions
are derived from Exception. When working through math errors, you can use the
generic
ArithmeticError or a more specific ZeroDivisionError exception.
Python evaluates except clauses in the order in which they appear
in the source code file. The first clause is examined first, the second clause
is exam-ined second, and so on. The following steps help you examine an example
that demonstrates the importance of using the correct exception order. In this
case, you perform tasks that result in math errors.
Open a Python File window.
You see an editor in which you can type the example code.
Type the following code
into the window — pressing Enter after each line:
try:
Value1 = int(input("Type the first number: ")) Value2 =
int(input("Type the second number: ")) Output = Value1 / Value2
except ValueError:
print("You must type a whole number!") except
KeyboardInterrupt:
print("You pressed Ctrl+C!") except ArithmeticError:
print("An undefined math error occurred.") except
ZeroDivisionError:
print("Attempted to divide by zero!") else:
print(Output)
The code begins by obtaining two inputs: Value1 and Value2. The
first two except clauses handle unexpected input. The second two except clauses
handle math exceptions, such as dividing by zero. If everything goes well with
the application, the else clause executes, which prints the result of the
operation.
Choose Run➪Run Module.
You see a Python Shell window open. The application asks you to
type the first number.
Type Hello and press Enter.
As expected, Python displays the ValueError exception message.
However, it always pays to check for potential problems.
Choose Run➪Run Module again.
You see a Python Shell window open. The application asks you to
type the first number.
Type 8 and press Enter.
The application asks you to enter the second number.
Type 0 and press Enter.
You see the error message for the ArithmeticError exception. What
you should actually see is the ZeroDivisionError exception because it’s more
specific than the ArithmeticError exception.
8. Reverse the order of the two exceptions so that they look like
this:
except ZeroDivisionError: print("Attempted to divide by
zero!")
except ArithmeticError:
print("An undefined math error occurred.")
Perform Steps 5 through 7
again.
This time, you see the ZeroDivisionError exception message because
the exceptions appear in the correct order.
Perform Steps 5 through 7
again, but type 2 for the second number instead of 0.
This time, the application finally reports an output value of 4.0.
Division results in a floating-point value unless you specify that you want an
integer output by using the floor division operator (//).
Nested exception handling
Sometimes you need to place one exception-handling routine within
another in a process called nesting. When you nest exception-handling routines,
Python tries to find an exception handler in the nested level first and then
moves to the outer layers. You can nest exception-handling routines as deeply
as needed to make your code safe.
One of the more common reasons to use a dual layer of
exception-handling code is when you want to obtain input from a user and need
to place the input code in a loop to ensure that you actually get the required
information. The following steps demonstrate how this sort of code might work.
Open a Python File window.
You see an editor in which you can type the example code.
Type the following code
into the window — pressing Enter after each line:
TryAgain = True
while TryAgain:
try:
Value = int(input("Type a whole number. ")) except
ValueError:
print("You must type a whole number!")
try:
DoOver = input("Try again (y/n)? ") except:
print("OK, see you next time!") TryAgain = False
else:
if (str.upper(DoOver) == "N"): TryAgain = False
except KeyboardInterrupt: print("You pressed Ctrl+C!")
print("See you next time!") TryAgain = False
else:
print(Value) TryAgain = False
The code begins by creating an input loop. Using loops for this
type of purpose is actually quite common in applications because you don’t want
the application to end every time an input error is made. This is a simpli-fied
loop, and normally you create a separate function to hold the code.
When the loop starts, the application asks the user to type a
whole number. It can be any integer value. If the user types any non-integer
value or presses Ctrl+C, Cmd+C, or another interrupt key combination, the
exception-handling code takes over. Otherwise, the application prints the value
that the user supplied and sets TryAgain to False, which causes the loop to
end.
A ValueError exception can occur when the user makes a mistake.
Because you don’t know why the user input the wrong value, you have to ask if
the user wants to try again. Of course, getting more input from the user could
generate another exception. The inner try . . . except code block handles this
secondary input.
Notice the use of the str.upper() function when getting character
input from the user. This function makes it possible to receive y or Y as input
and accept them both. Whenever you ask the user for character input, it’s a
good idea to convert lowercase characters to uppercase so that you can perform
a single comparison (reducing the potential for error).
The KeyboardInterrupt exception displays two messages and then
exits automatically by setting TryAgain to False. The KeyboardInterrupt occurs
only when the user presses a specific key combination designed to end the
application. The user is unlikely to want to continue using the application at
this point.
Choose Run➪Run Module.
You see a Python Shell window open. The application asks the user
to input a whole number.
Type Hello and press Enter.
The application displays an error message and asks whether you
want to try again.
Type Y and press Enter.
The application asks you to input a whole number again.
Type 5.5 and press Enter.
The application again displays the error message and asks whether
you want to try again.
Press Ctrl+C, Cmd+C, or
another key combination to interrupt the application.
The application ends. Notice that the message is the one from the
inner exception. The application never gets to the outer exception because the
inner exception handler provides generic exception handling.
Choose Run➪Run Module.
You see a Python Shell window open. The application asks the user
to input a whole number.
Press Ctrl+C, Cmd+C, or
another key combination to interrupt the application.
The application ends. Notice that the message is the one from the
outer exception. In Steps 7 and 9, the user ends the application by pressing an
interrupt key. However, the application uses two different exception handlers
to address the problem.
Raising Exceptions
So far, the examples in this Post have reacted to exceptions.
Something happens and the application provides error-handling support for that
event. However, situations arise for which you may not know how to handle an
error event during the application design process. Perhaps you can’t even
handle the error at a particular level and need to pass it up to some other
level to handle. In short, in some situations, your application must generate
an excep-tion. This act is called raising (or sometimes throwing) the
exception. The fol-lowing sections describe common scenarios in which you raise
exceptions in specific ways.
Raising exceptions during exceptional conditions
The example in this section demonstrates how you raise a simple
exception — that it doesn’t require anything special. The following steps simply
create the exception and then handle it immediately.
Open a Python File window.
You see an editor in which you can type the example code.
Type the following code
into the window — pressing Enter after each line:
try:
raise ValueError except ValueError:
print("ValueError Exception!")
You wouldn’t ever actually create code that looks like this, but
it shows you how raising an exception works at its most basic level. In this
case, the raise call appears within a try . . . except block. A basic raise call
simply provides the name of the exception to raise (or throw). You can also
provide arguments as part of the output to provide additional information.
Notice that this try . . . except block lacks an else clause
because there is nothing to do after the call. Although you rarely use a try .
. . except block in this manner, you can. You may encounter situations like
this one sometimes and need to remember that adding the else clause is purely
optional. On the other hand, you must add at least one except clause.
Choose Run➪Run Module.
You see a Python Shell window open. The application displays the
expected exception text.
0 comments:
Post a Comment