Introduction to Python Programming. Section 12. Exceptions
12 Exceptions
12.1 Objectives
In this section you will learn:
- Why one should write resilient software which won’t fail with wrong input data.
- To be especially careful when working with user input data.
- About catching exceptions with the try-except statement.
- About ZeroDivisionError, TypeError and other types of exceptions.
- About the built-in function assert and the AssertionError exception.
- How to raise exceptions with the raise statement.
- The full form of the try-except-else-finally statement.
12.2 Why learn about exceptions?
Imagine that you are responsible for a software module which processes user data. The data
is coming from another software module or from the user directly. Part of the data is a
list of ages of a group of people, and you need to calculate their average. This is
easy:
A quick test to confirm that the function works correctly:
It is a mistake of novices to think that the story ends here. On the contrary, merely it begins
here. You won’t get commended for writing a simple function like this. But you will get a lot
of complaints when your function fails. Let’s show some examples. First, what if the list
ages happens to arrive empty?
Oops, not good. Of course this is not your fault but life is not fair. Next, what if some of the
ages arrive as text strings (although they shouldn’t)?
Sometimes, unbelievable things can happen in computer programming – more precisely, they
sound unbelievable until you get used to them. Such as, a colleague or a user who is
supposed to provide a list can send you something which is not a list at all. Let’s see what
happens if your function receives a dictionary. After all, these should be the ages of people,
right?
Or, somebody will provide an integer instead of a list by mistake:
Guess who will be blamed if a customer decides against buying the software because of a few
crashes which occurred in a function you wrote. Nobody will ask what caused
them. There is a famous saying in computer science which has a lot of truth to
it:
"A good programmer is someone who looks both ways before crossing a one-way street."
(Doug Linder)
On the other hand, the good news is that Python makes it easy to fortify your software (and protect yourself) by catching and handling exceptions without letting the program crash. That’s what we want to show you in this section.
12.3 Catching exceptions – statement try-except
Let’s stay with the previous example for a while. One could try to anticipate all things that
might go wrong, but the users are always one step ahead in their creativity. Therefore,
Python provides exceptions whose philosophy is the opposite – instead of worrying in
advance, let the code run and only take a corrective action if something goes wrong. We have
seen in Subsection 12.2 that ZeroDivisionError and TypeError can be expected.
Therefore, let’s fortify the function average against them:
~~~
Calculate average of the numbers in the list L.
Return False if the calculation fails.
~~~
try:
a = 0
for x in L:
a+=x
return a / len(L)
except ZeroDivisionError:
print(’Warning: ZeroDivisionError in average().’)
print(’Returning False.’)
return False
except TypeError:
print(’Warning: TypeError in average().’)
print(’Returning False.’)
return False
In the above program, the original code is in the try branch. This branch can be followed by
as many except branches as you wish, that will handle different sorts of problems. Of
course none of them will be executed if the try branch passes without generating an
exception. We will give a list of the most frequently used exceptions in the following
subsection.
It is needless to say that the function has improved. It works as before when the input data is
correct:
But with missing input data it does not crash anymore! Instead, it issues a warning and
returns False:
The same if the data contain items of a wrong type:
Next let’s look at various other types of exceptions that one can catch.
12.4 List of common exceptions
Here is a list of the most frequently used exceptions for reference:
- Exception: Base class for all exceptions. It can be used to catch a general exception.This will be discussed in Subsection 12.5.
- StopIteration: Raised when the next method of an iterator does not point to any object. For iterators see Subsection 9.13.
- StandardError Base class for all built-in exceptions except StopIteration and SystemExit.
- ArithmeticError Base class for all errors that occur for numeric calculation.
- OverflowError Raised when a calculation exceeds maximum limit for a numeric type.
- FloatingPointError Raised when a floating point calculation fails.
- ZeroDivisionError Raised when division or modulo by zero takes place for all numeric types.
- AssertionError Raised in case of failure of the assert statement. This will be discussed in Subsection 12.6.
- AttributeError Raised in case of failure of attribute reference or assignment.
- EOFError Raised when there is no input from either the raw_input or input function and the end of file is reached.
- ImportError Raised when an import statement fails.
- KeyboardInterrupt Raised when the user interrupts program execution, usually by pressing CTRL+C.
- LookupError Base class for all lookup errors.
- IndexError Raised when an index is not found in a sequence.
- KeyError Raised when the specified key is not found in the dictionary.
- NameError Raised when an identifier is not found in the local or global namespace.
- UnboundLocalError Raised when trying to access a local variable in a function or method but no value has been assigned to it.
- EnvironmentError Base class for all exceptions that occur outside the Python environment.
- IOError Raised when an input/ output operation fails, such as the print statement or the open function when trying to open a file that does not exist.
- OSError Raised for operating system-related errors.
- SyntaxError Raised when there is an error in Python syntax.
- IndentationError Raised when indentation is not specified properly.
- SystemError Raised when the interpreter finds an internal problem, but when this error is encountered the Python interpreter does not exit.
- SystemExit Raised when Python interpreter is quit by using the sys.exit function. If not handled in the code, causes the interpreter to exit.
- TypeError Raised when an operation or function is attempted that is invalid for the specified data type.
- ValueError Raised when the built-in function for a data type has the valid type of arguments, but the arguments have invalid values specified.
- RuntimeError Raised when a generated error does not fall into any category.
- NotImplementedError Raised when an abstract method that needs to be implemented in an inherited class is not actually implemented.
12.5 Catching a general exception
If one does not need to perform different corrective actions based on different types of
exceptions, it is often enough to only catch the general exception:
When called with missing input data, the function now responds as follows:
And when the data is wrong:
12.6 Function assert
The built-in function assert raises an exception when the Boolean statement used as its
argument is False. This is a quick way to make sure that the program does not continue
with incorrect data:
Alternatively, the AssertionError exception can be caught using the try command as
usual:
Returning nan.
nan
12.7 Throwing exceptions – statement raise
Python does not have a command to stop program execution. If you need to terminate your program prematurely, for example because of wrong input data, the best thing is to raise an exception using the raise statement.
Let’s illustrate this on a function which is undefined for x = 3 and x = -3:
When the function f(x) is called with 3 or -3, the output will be
12.8 The full statement try-except-else-finally
You already know from Subsection 12.3 that the try-except statement can contain multiple except branches. Moreover, it can contain optional branches else and/or finally. Your understanding of the else branch in for loops (Subsection 9.12) and in while loops (Subsection 11.8) will make this very simple.
The else branch: The code is executed only if no exceptions were raised in the try branch. This is analogous to for-else and while-else where the else branch is executed only if no break was used. Code executed in this branch is just like normal code: if there is an exception, it will not be automatically caught (and probably stop the program).
The finally branch: The code always executes after the other blocks, even if there was an uncaught exception (that didnt cause a crash) or a return statement in one of the other branches. Code executed in this branch is just like normal code: if there is an exception, it will not be automatically caught.
Table of Contents
- Preface
- 1. Introduction
- 2. Using Python as a Scientific Calculator
- 3. Drawing, Plotting, and Data Visualization with Matplotlib
- 4. Working with Text Strings
- 5. Variables and Types
- 6. Boolean Values, Functions, Expressions, and Variables
- 7. Lists, Tuples, Dictionaries, and Sets
- 8. Functions
- 9. The ’For’ Loop
- 10. Conditions
- 11. The ’While’ Loop
- 12. Exceptions
- 13. File Operations
- 14. Object-Oriented Programming I – Introduction
- 15. Object-Oriented Programming II – Class Inheritance
- 16. Object-Oriented Programming III – Advanced Aspects
- 17. Recursion
- 18. Decorators
- 19. Selected Advanced Topics