Exceptions Are Messages
Every error you have met so far, the ValueError from int, the KeyError from a dictionary, the FileNotFoundError from open, is an exception. It is Python's way of saying: I cannot carry on with this instruction, and here is exactly why. Once you see exceptions as messages rather than crashes, you can decide what your program should say in reply.
Think of an employee who cannot finish a task. They write a note saying what went wrong and pass it to their manager. If the manager cannot deal with it, the note goes up again, until it reaches someone who can decide, or the top of the company, where work stops. An exception travels the same way through a program.
What an Exception Is
When an instruction fails, Python creates an exception: an object with a type, such as ValueError, and a message, the sentence after the colon. Python then stops the current line and hands the exception to the code that called it, and then to the code that called that, looking for something that will deal with it. If nothing does, the program stops and prints the traceback. The next topic shows how to be the something that deals with it.
The Family
You have already met most of the everyday exceptions. Each name tells you the kind of problem before you read the message.
| Exception | What it means | Example that raises it |
|---|---|---|
| ValueError | right type, unusable value | int("forty") |
| TypeError | wrong type for the operation | "5" + 5 |
| NameError | a name with no value | print(totl) |
| KeyError | a missing dictionary key | phones["Zoe"] |
| IndexError | a position that does not exist | items[10] |
| FileNotFoundError | no file at that path | open("todo.txt") |
| ZeroDivisionError | dividing by zero | 10 / 0 |
A Traceback Through Several Functions
With functions calling functions, a traceback lists the whole chain of calls, oldest at the top and the failing line at the bottom. The program below has main, which calls average, which divides by the number of values. Given an empty list, the division fails. Read it from the bottom, as Chapter 3 taught: a ZeroDivisionError, division by zero, on the line in average that divides. Then read upward to see how the program got there: main called average, and the file called main.
def average(values): return sum(values) / len(values) def main(): readings = [] print(average(readings)) main()
Traceback (most recent call last):
File "/Users/you/python-course/chain.py", line 10, in <module>
main()
~~~~^^
File "/Users/you/python-course/chain.py", line 7, in main
print(average(readings))
~~~~~~~^^^^^^^^^^
File "/Users/you/python-course/chain.py", line 2, in average
return sum(values) / len(values)
~~~~~~~~~~~~^~~~~~~~~~~~~
ZeroDivisionError: division by zero
The chain is valuable. It tells you not only where the program failed but how it got there, and the fix often belongs higher up than the line that failed. Here, the real question is why main passed an empty list.
Crashing Is Sometimes Right
It is tempting to think a good program never shows a traceback. It is better to think a good program never carries on with wrong data. A program that stops loudly on a real problem is doing its job; one that quietly continues and prints a wrong total is not. The rest of this chapter is about telling those cases apart.
- "Exceptions are bugs." Many are expected events: a missing file, a word typed where a number was wanted. A program can and should handle those.
- "The top of a long traceback is where it failed." The failing line is at the bottom. The lines above show how the program got there.
- "A good program never raises exceptions." A good program raises them clearly when it cannot continue, and handles the ones it can do something about.
- Knowing the family by name makes every later error faster to understand, often before you read the message.
- The chain of calls tells you where to look for the real cause, which is frequently one function above the one that failed.
Knowledge Check
When an exception is raised and nothing handles it, what happens?
- It passes up through the callers, then the program stops
- Python skips the failing line and carries on
- The program restarts itself from its very first line
- Python asks the person at the keyboard what it should do next
In a traceback through several functions, where is the line that actually failed?
- At the top, just below the word Traceback itself
- In the middle, between the functions
- At the bottom, just above the error's name
- It is not shown; only the function names are
Which exception does int("forty") raise?
- TypeError, because forty is text and not a number at all
- NameError, because the word forty is not defined
- KeyError, because forty is not a number Python knows about
- ValueError, because the text is not a whole number
Why can a program that stops on an error be better than one that keeps going?
- Because stopping makes the program run faster overall
- Carrying on with wrong data gives results that look right and are not
- Because Python requires every program to stop the moment any error happens
- Because a stopped program saves its data automatically
You got correct