Skip to content

Knowing Why Python Doesn’t Understand You

Knowing Why Python Doesn’t Understand You

Developers often get frustrated with programming languages and computers because they seemingly go out of their way to cause communication problems. Of course, programming languages and computers are both inanimate — there is no desire for anything on the part of either. Programming languages and computers also don’t think; they accept whatever the developer has to say quite literally. Therein lies the problem.

 

Neither Python nor the computer will “know what you mean” when you type instructions as code. Both follow whatever instructions you provide to      the letter and literally as you provide them. You may not have meant to tell

Python to delete a data file unless some absurd condition occurred. However,  if you don’t make the conditions clear, Python will delete the file whether the condition exists or not. When an error of this sort happens, people commonly say that the application has a bug in it. Bugs are simply coding errors that you can remove using a debugger. (A debugger is a special kind of tool that lets you stop or pause application execution, examine the content of variables, and generally dissect the application to see what makes it tick.)

 

 

Errors occur in many cases when the developer makes assumptions that  simply aren’t true. Of course, this includes assumptions about the application user, who probably doesn’t care about the extreme level of care you took when crafting your application. The user will enter bad data. Again, Python won’t know or care that the data is bad and will process it even when your intent was to disallow the bad input. Python doesn’t understand the concepts of good or bad data; it simply processes incoming data according to any rules you set, which means that you must set rules to protect users from themselves.

 

Python isn’t proactive or creative — those qualities exist only in the developer. When a network error occurs or the user does something unexpected, Python doesn’t create a solution to fix the problem. It only processes code. If you don’t provide code to handle the error, the application is likely to fail and crash ungracefully — possibly taking all of the user’s data with it. Of course, the devel- oper can’t anticipate every potential error situation, either, which is why most complex applications have errors in them — errors of omission, in this case.

 

Some developers out there think they can create bulletproof code, despite the absurdity of thinking that such code is even possible. Smart developers assume that some number of bugs will get through the code-screening pro- cess, that nature and users will continue to perform unexpected actions, and that even the smartest developer can’t anticipate every possible error condi- tion. Always assume that your application is subject to errors that will cause exceptions; that way, you’ll have the mindset required to actually make your application more reliable.

 

 

Considering the Sources of Errors

You might be able to divine the potential sources of error in your applica-  tion by reading tea leaves, but that’s hardly an efficient way to do things. Errors actually fall into well-defined categories that help you predict (to some degree) when and where they’ll occur. By thinking about these categories as you work through your application, you’re far more likely to discover poten- tial errors sources before they occur and cause potential damage. The two principle categories are

 

  • Errors that occur at a specific time
  • Errors that are of a specific type

 

The following sections discuss these two categories in greater detail. The overall concept is that you need to think about error classifications in order to start finding and fixing potential errors in your application before they become a problem.

 

 

Classifying when errors occur

Errors occur at specific times. The two major time frames are

 

  • Compile time
  • Runtime

 

No matter when an error occurs, it causes your application to misbehave. The following sections describe each time frame.

 

Compile time

A compile time error occurs when you ask Python to run the application. Before Python can run the application, it must interpret the code and put it into a form that the computer can understand. A computer relies on machine code that is specific to that processor and architecture. If the instructions you write are malformed or lack needed information, Python can’t perform the required conversion. It presents an error that you must fix before the application can run.

 

Fortunately, compile-time errors are the easiest to spot and fix. Because the application won’t run with a compile-time error in place, user never sees this error category. You fix this sort of error as you write your code.

 

The appearance of a compile-time error should tell you that other typos or omissions could exist in the code. It always pays to check the surrounding code to ensure that no other potential problems exist that might not show up as part of the compile cycle.

 

Runtime

A runtime error occurs after Python compiles the code you write and the com- puter begins to execute it. Runtime errors come in several different types, and some are harder to find than others. You know you have a runtime error when the application suddenly stops running and displays an exception dialog box or when the user complains about erroneous output (or at least instability).

 

Not all runtime errors produce an exception. Some runtime errors cause instabil- ity (the application freezes), errant output, or data damage. Runtime errors can affect other applications or create unforeseen damage to the platform on which the application is running. In short, runtime errors can cause you quite a bit of grief, depending on precisely the kind of error you’re dealing with at the time.

 

Many runtime errors are caused by errant code. For example, you can mis- spell the name of a variable, preventing Python from placing information in the correct variable during execution. Leaving out an optional but necessary

 

 

argument when calling a method can also cause problems. These are exam- ples of errors of commission, which are specific errors associated with your code. In general, you can find these kinds of errors using a debugger or by simply reading your code line by line to check for errors.

 

Runtime errors can also be caused by external sources not associated with your code. For example, the user can input incorrect information that the application isn’t expecting, causing an exception. A network error can make a required resource inaccessible. Sometimes even the computer hardware has a glitch that causes a nonrepeatable application error. These are all examples of errors of omission, from which the application might recover if your appli- cation has error-trapping code in place. It’s important that you consider both kinds of runtime errors — errors of commission and omission — when build- ing your application.

 

 

Distinguishing error types

You can distinguish errors by type, that is, by how they’re made. Knowing the error types helps you understand where to look in an application for poten- tial problems. Exceptions work like many other things in life. For example, you know that electronic devices don’t work without power. So, when you

try to turn your television on and it doesn’t do anything, you might look to ensure that the power cord is firmly seated in the socket.

 

Understanding the error types helps you locate errors faster, earlier, and more consistently, resulting in fewer misdiagnoses. The best developers know that fixing errors while an application is in development is always easier than fixing it when the application is in production because users are inherently impa- tient and want errors fixed immediately and correctly. In addition, fixing an error earlier in the development cycle is always easier than fixing it when the application nears completion because less code exists to review.

 

The trick is to know where to look. With this in mind, Python (and most other programming languages) breaks errors into the following types:

 

  • Syntactical
  • Semantic
  • Logical

 

The following sections examine each of these error types in more detail. I’ve arranged the sections in order of difficulty, starting with the easiest to find. A syntactical error is generally the easiest; a logical error is generally the hardest.

 

 

Syntactical

Whenever you make a typo of some sort, you create a syntactical error. Some Python syntactical errors are quite easy to find because the application simply doesn’t run. The interpreter may even point out the error for you by highlighting the errant code and displaying an error message. However, some syntactical errors are quite hard to find. Python is case sensitive, so you may use the wrong case for a variable in one place and find that the variable isn’t quite working as you thought it would. Finding the one place where you used the wrong capitalization can be quite challenging.

 

Most syntactical errors occur at compile time and the interpreter points them out for you. Fixing the error is made easy because the interpreter generally tells you what to fix, and with considerable accuracy. Even when the inter- preter doesn’t find the problem, syntactical errors prevent the application from running correctly, so any errors the interpreter doesn’t find show up during the testing phase. Few syntactical errors should make it into produc- tion as long as you perform adequate application testing.

 

Semantic

When you create a loop that executes one too many times, you don’t gener- ally receive any sort of error information from the application. The applica- tion will happily run because it thinks that it’s doing everything correctly, but that one additional loop can cause all sorts of data errors. When you create an error of this sort in your code, it’s called a semantic error.

 

Semantic errors occur because the meaning behind a series of steps used to perform a task is wrong — the result is incorrect even though the code appar- ently runs precisely as it should. Semantic errors are tough to find, and you sometimes need some sort of debugger to find them. (Chapter 19 provides

a discussion of tools that you can use with Python to perform tasks such as debugging applications. You can also find blog posts about debugging on my blog at http://blog.johnmuellerbooks.com.)

 

Logical

Some developers don’t create a division between semantic and logical errors, but they are different. A semantic error occurs when the code is essentially correct but the implementation is wrong (such as having a loop execute once too often). Logical errors occur when the developer’s thinking is faulty. In many cases, this sort of error happens when the developer uses a relational or logical operator incorrectly. However, logical errors can happen in all sorts of other ways, too. For example, a developer might think that data is always stored on the local hard drive, which means that the application may behave in an unusual manner when it attempts to load data from a network drive instead.

 

 

Logical errors are quite hard to fix because the problem isn’t with the actual code, yet the code itself is incorrectly defined. The thought process that went into creating the code is faulty; therefore, the developer who created the error  is less likely to find it. Smart developers use a second pair of eyes to help spot logical errors. Having a formal application specification also helps because the logic behind the tasks the application performs is usually given a formal review.

 

Catching Exceptions

Generally speaking, a user should never see an exception dialog box. Your application should always catch the exception and handle it before the user sees it. Of course, the real world is different — users do see unexpected exceptions from time to time. However, catching every potential exception is still the goal when developing an application. The following sections describe how to catch exceptions and handle them.

 

 

Understanding the built-in exceptions

 

Python comes with a host of built­in exceptions — far more than you might think possible. You can see a list of these exceptions at https://docs.python.org/3.3/ library/exceptions.html. The docu­ mentation breaks the exception list down into categories. Here is a brief overview of the Python exception categories that you work with regularly:

  • Base classes: The base classes provide the essential building blocks (such as the Exception exception) for other excep­ However, you might actually see some of these exceptions, such as the ArithmeticError exception, when working with an application.
  • Concrete exceptions: Applications can experience hard errors — errors that are hard to overcome because there really isn’t a good way to handle them or they signal an event that the application must handl For example, when a system runs out of memory, Python generates a MemoryError exception. Recovering

from this error is hard because it isn’t always possible to release memory from other uses. When the user presses an interrupt key (such as Ctrl+C or Delete), Python gener­ ates a KeyboardInterrupt exception. The application must handle this exception before proceeding with any other tasks.

  • OS exceptions: The operating system can generate errors that Python then passes them along to your For exam­ ple, if your application tries to open a file that doesn’t exist, the operating system generates a FileNotFoundError exception.
  • Warnings: Python tries to warn you about unexpected events or actions that could result in errors For example, if you try to inappropriately use a resource, such as an icon, Python generates a ResourceWarning exception. It’s important to remember that this particular category is a warning and not an actual error: Ignoring it can cause you woe later, but you can ignore it.

 

 

Basic exception handling

To handle exceptions, you must tell Python that you want to do so and then provide code to perform the handling tasks. You have a number of ways in which you can perform this task. The following sections start with the sim- plest method first and then move on to more complex methods that offer added flexibility.

 

Handling a single exception

In Chapter 7, the IfElse.py and other examples have a terrible habit of spitting out exceptions when the user inputs unexpected values. Part of the solution is to provide range checking. However, range checking doesn’t over- come the problem of a user typing text such as Hello in place of an expected numeric value. Exception handling provides a more complex solution to the problem, as described in the following steps. This example also appears with the downloadable source code as BasicException1.py.

 

  1. Open a Python File window.

You see an editor in which you can type the example code.

2y.peT the following code into the window — pressing Enter after each line:

 

 

The code within the try block has its exceptions handled. In this case, handling the exception means getting input from the user using the int(input()) calls. If an exception occurs outside this block, the code doesn’t handle it. With reliability in mind, the temptation might be to enclose all the executable code in a try block so that every exception would be handled. However, you want to make your exception handling small and specific to make locating the problem easier.

 

 

The except block looks for a specific exception in this case: ValueError.

When the user creates a ValueError exception by typing Hello instead of a numeric value, this particular exception block is executed. If the  user were to generate some other exception, this except block wouldn’t handle it.

The else block contains all the code that is executed when the try block code is successful (doesn’t generate an exception). The remain- der of the code is in this block because you don’t want to execute it unless the user does provide valid input. When the user provides a whole number as input, the code can then range check it to ensure that it’s correct.

  1. Choose RunRun

You see a Python Shell window open. The application asks you to type a number between 1 and 10.

  1. Type Hello and press Enter.

The application displays an error message, as shown in Figure 9-1.

 

 

 

Figure 9-1:

Typing the wrong input type generates an error instead

of an exception.

 

 

5fo.rPmerSteps 3 and 4 again, but type               5.5 instead of Hello.

The application generates the same error message, as shown in Figure 9-1.

6fo.rPmerSteps 3 and 4 again, but type               22 instead of Hello.

The application outputs the expected range error message, as shown in Figure 9-2. Exception handling doesn’t weed out range errors. You must still check for them separately.

 

 

 

 

 

 

 

 

 

 

 

Figure 9-2: Exception handling doesn’t ensure that the value is in the cor­ rect range.

 

 

7fo.rPmerSteps 3 and 4 again, but type              7 instead of Hello.

This time, the application finally reports that you’ve provided a correct value of 7. Even though it seems like a lot of work to perform this level of checking, you can’t really be certain that your application is working correctly without it.

8fo.rPmerSteps 3 and 4 again, but press Ctrl+C, Cmd+C, or the alterna              – tive for your platform instead of typing anything.

The application generates a KeyboardInterrupt exception, as shown in Figure 9-3. Because this exception isn’t handled, it’s still a problem for the user. You see several techniques for fixing this problem later in the chapter.

 

Using the except clause without an exception

You can create an exception handling block in Python that’s generic because it doesn’t look for a specific exception. In most cases, you want to provide a specific exception when performing exception handling for these reasons:

 

  • To avoid hiding an exception you didn’t consider when designing the application
  • To ensure that others know precisely which exceptions your application will handle
  • To handle the exceptions correctly using specific code for that exception

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 9-3: The excep­ tion han­ dling in this example

deals only with Value Error exceptions.

 

 

However, sometimes you may need a generic exception-handling capability, such as when you’re working with third-party libraries or interacting with  an external service. The following steps demonstrate how to use an except

clause without a specific exception attached to it. This example also appears with the downloadable source code as BasicException2.py.

 

  1. Open a Python File

You see an editor in which you can type the example code.

 

 

2y.peT the following code into the window — pressing Enter after each line:

 

 

The only difference between this example and the previous example is that the except clause doesn’t have the ValueError exception specifi- cally associated with it. The result is that this except clause will also catch any other exception that occurs.

  1. Choose RunRun

You see a Python Shell window open. The application asks you to type a number between 1 and 10.

  1. Type Hello and press Enter.

The application displays an error message (refer to Figure 9-1).

5fo.rPmerSteps 3 and 4 again, but type              5.5 instead of Hello.

The application generates the same error message (again, refer to Figure 9-1).

6fo.rPmerSteps 3 and 4 again, but type              22 instead of Hello.

The application outputs the expected range error message (refer to Figure 9-2). Exception handling doesn’t weed out range errors. You must still check for them separately.

7fo.rPmerSteps 3 and 4 again, but type              7 instead of Hello.

This time, the application finally reports that you’ve provided a correct value of 7. Even though it seems like a lot of work to perform this level of checking, you can’t really be certain that your application is working correctly without it.

8fo.rPmerSteps 3 and 4 again, but press Ctrl+C, Cmd+C, or the alterna              – tive for your platform instead of typing anything.

You see the error message that’s usually associated with input error, as shown in Figure 9-4. The error message is incorrect, which might con- fuse users. However, the plus side is that the application didn’t crash,

 

 

which means that you won’t lose any data and the application can recover. Using generic exception handling does have some advantages, but you must use it carefully.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 9-4: Generic exception handling traps the Keyboard Inter-

rupt

exception.

 

 

Working with exception arguments

Most exceptions don’t provide arguments (a list of values that you can check for additional information). The exception either occurs or it doesn’t. However, a few exceptions do provide arguments, and you see them used later in the book. The arguments tell you more about the exception and pro- vide details that you need to correct it.

 

For the sake of completeness, this chapter includes a simple example that generates an exception with an argument. You can safely skip the remainder of this section if desired because the information is covered in more detail later  in the book. This example also appears with the downloadable source code as ExceptionWithArguments.py.

 

 

  1. Open a Python File

You see an editor in which you can type the example code.

2y.peT the following code into the window — pressing Enter after each line:

 

 

This example uses some advanced features. The import statement obtains code from another file. Chapter 10 tells you how to use this Python feature.

The open() function opens a file and provides access to the file through the File variable. Chapter 15 tells you how file access works. Given that myfile.txt doesn’t exist in the application directory, the operating system can’t open it and will tell Python that the file doesn’t exist.

Trying to open a nonexistent file generates an IOError exception. This particular exception provides access to two arguments:

  • errno: Provides the operating system error number as an integer
  • strerror: Contains the error information as a human-readable string

The as clause places the exception information into a variable, e, that you can access as needed for additional information. The except block contains a print() call that formats the error information into an easily read error message.

If you should decide to create the myfile.txt file, the else clause executes. In this case, you see a message stating that the file opened normally. The code then closes the file without doing anything with it.

  1. Choose RunRun Module.

You see a Python Shell window open. The application displays the Error opening file information, as shown in Figure 9-5.

 

 

 

 

 

 

Figure 9-5: Attempting to open a nonexistent file never works.

 

 

 

 

 

Obtaining a list of exception arguments

The list of arguments supplied with exceptions varies by exception and by what the sender pro­ vides. It isn’t always easy to figure out what you can hope to obtain in the way of additional informa­ tion. One way to handle the problem is to simply print everything using code like this (this example also appears with the downloadable source code as GetExceptionArguments1.py):

import sys

 

try:

File = open(‘myfile.txt’) except IOError as e:

for Arg in e.args: print(Arg)

else:

print(“File opened as expected.”) File.close();

The args property always contains a list of the exception arguments in string format. You can use a simple for loop to print each of the arguments. The only problem with this approach is that you’re missing the argument names, so you know the output information (which is obvious in this case), but you don’t know what to call it.

A more complex method of dealing with the issue is to print both the names and the contents of the arguments. The following code displays both the names and the values of each of the arguments (this example also appears with the downloadable source as GetExceptionArguments2.py):

import sys

 

try:

File = open(‘myfile.txt’)

 

(continued)

 

 

(continued)

 

except IOError as e: for Entry in dir(e):

if (not Entry.startswith(“_”)): try:

print(Entry, ” = “, e. getattribute (Entry)) except AttributeError:

print(“Attribute “, Entry, ” not accessible.”)

else:

print(“File opened as expected.”) File.close();

In this case, you begin by getting a listing of the attributes associated with the error argument object using the dir() function. The output of the dir() function is a list of strings containing the names of the attributes that you can print. Only those arguments that don’t start with an under­ score (_) contain useful information about the exception. However, even some of those entries are inaccessible, so you must encase the output code in a second try…except block (see the “Nested exception handling” section, later in the chapter, for details).

The attribute name is easy because it’s contained in Entry. To obtain the value associated with that attribute, you must use the getattribute () function and supply the name of the attribute you want. When you run this code, you see both the name and the value of each of the attri­ butes supplied with a particular error argument object. In this case, the actual output is as follows:

args  =  (2, ‘No such file or directory’) Attribute      characters_written        not accessible. errno    =      2

 

filename

=

myfile.txt

strerror

=

No such file or directory

winerror

=

None

with_traceback   =  <built-in method with_traceback of FileNotFoundError object at 0x0000000003416DC8>

 

 

 

Handling multiple exceptions with a single except clause

Most applications can generate multiple exceptions for a single line of code. This fact demonstrated earlier in the chapter with the BasicException1. py example. How you handle the multiple exceptions depends on your goals for the application, the types of exceptions, and the relative skill of your users. Sometimes when working with a less skilled user, it’s simply easier to say that the application experienced a nonrecoverable error and then log the details into a log file in the application directory or a central location.

 

Using a single except clause to handle multiple exceptions works only  when a common source of action fulfills the needs of all the exception types. Otherwise, you need to handle each exception individually. The follow-

ing steps show how to handle multiple exceptions using a single except clause. This example also appears with the downloadable source code as MultipleException1.py.

 

 

  1. Open a Python File window.

You see an editor in which you can type the example code.

2y.peT the following code into the window — pressing Enter after each line:

 

This code is very much like the BasicException1.py. However, notice that the except clause now sports both a ValueError and a KeyboardInterrupt exception.  In  addition,  these  exceptions  appear within  parentheses  and  are  separated  by  commas.

  1. Choose RunRun

You see a Python Shell window open. The application asks you to type a number between 1 and 10.

  1. Type Hello and press Enter.

The application displays an error message (refer to Figure 9-1).

5fo.rPmerSteps 3 and 4 again, but type               22 instead of Hello.

The application outputs the expected range error message (refer to Figure 9-2).

6fo.rPmerSteps 3 and 4 again, but press Ctrl+C, Cmd+C, or the alterna              – tive for your platform instead of typing anything.

You see the error message that’s usually associated with error input (refer to Figure 9-1).

7fo.rPmerSteps 3 and 4 again, but type               7 instead of Hello.

This time, the application finally reports that you’ve provided a correct value of 7.

 

Handling multiple exceptions with multiple except clauses

When working with multiple exceptions, it’s usually a good idea to place each exception in its own except clause. This approach allows you to provide custom handling for each exception and makes it easier for the user to know precisely what went wrong. Of course, this approach is also a lot more work.

 

 

The following steps demonstrate how to perform exception handling using multiple except clauses. This example also appears with the downloadable source code as MultipleException2.py.

 

  1. Open a Python File

You see an editor in which you can type the example code.

2y.peT the following code into the window — pressing Enter after each line:

 

 

Notice the use of multiple except clauses in this case. Each except clause handles a different exception. You can use a combination of techniques, with some except clauses handling just one exception and other except clauses handling multiple exceptions. Python lets you use the approach that works best for the error-handling situation.

  1. Choose RunRun

You see a Python Shell window open. The application asks you to type a number between 1 and 10.

  1. Type Hello and press Enter.

The application displays an error message (refer to Figure 9-1).

5fo.rPmerSteps 3 and 4 again, but type              22 instead of Hello.

The application outputs the expected range error message (refer to Figure 9-2).

6fo.rPmerSteps 3 and 4 again, but press Ctrl+C, Cmd+C, or the alterna              – tive for your platform instead of typing anything.

The application outputs a specific message that tells the user what went wrong, as shown in Figure 9-6.

7fo.rPmerSteps 3 and 4 again, but type              7 instead of Hello.

This time, the application finally reports that you’ve provided a correct value of 7.

 

 

 

 

 

 

 

 

 

 

Figure 9-6:

Using multiple except clauses makes spe­ cific error messages possible.

 

 

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. This example also appears with the downloadable source code as MultipleException3.py.

 

 

  1. Open a Python File window.

You see an editor in which you can type the example code.

2y.peT the following code into the window — pressing Enter after each line:

 

 

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.

  1. Choose RunRun

You see a Python Shell window open. The application asks you to type the first number.

  1. Type Hello and press Enter.

As expected, Python displays the ValueError exception message. However, it always pays to check for potential problems.

  1. Choose RunRun Module

You see a Python Shell window open. The application asks you to type the first number.

  1. Type 8 and press Enter.

The application asks you to enter the second number.

 

 

  1. Type 0 and press Enter.

You see the error message for the ArithmeticError exception, as shown in Figure 9-7. What you should actually see is the ZeroDivisionError exception because it’s more specific than the ArithmeticError exception.

 

 

 

 

 

 

 

 

Figure 9-7: The order in which Python processes exceptions

is important.

 

 

  1. Reverse the order of the two exceptions so that they look like this:

 

9fo.rPmerSteps 5 through 7 again.

This time, you see the ZeroDivisionError exception message because the exceptions appear in the correct order.

1fo0r.mPeSrteps 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, as shown in Figure 9-8.

Notice that the output shown in Figure 9-8 is a floating-point value. Division results in a floating-point value unless you specify that you want an integer output by using the floor division operator (//).

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Figure 9-8: Providing usable input results in

a usable output.

 

 

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 fol- lowing steps demonstrate how this sort of code might work. This example also appears with the downloadable source code as MultipleException4.py.

 

  1. Open a Python File

You see an editor in which you can type the example code.

 

 

2y.peT the following code into the window — pressing Enter after each line:

 

 

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.

  1. Choose RunRun

You see a Python Shell window open. The application asks the user to input a whole number.

  1. Type Hello and press Enter.

The application displays an error message and asks whether you want to try again.

  1. Type Y and press Enter.

The application asks you to input a whole number again, as shown in Figure 9-9.

 

 

 

 

Figure 9-9: Using a loop means

that the application can recover

from the

error.

 

 

  1. Type 5 and press Enter.

The application again displays the error message and asks whether you want to try again.

7es. sPCrtrl+C, Cmd+C, or another key combination to interrupt the application.

The application ends, as shown in Figure 9-10. 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.

  1. Choose RunRun Module.

You see a Python Shell window open. The application asks the user to input a whole number.

 

 

 

 

 

 

 

 

Figure 9-10: The inner exception handler pro­ vides sec­ ondary input

support.

 

 

9es. sPCrtrl+C, Cmd+C, or another key combination to interrupt the application.

The application ends, as shown in Figure 9-11. 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.

 

 

 

 

 

 

 

 

 

 

 

 

Figure 9-11: The outer exception handler provides pri­ mary input support.