try and except
try and except let a program say: attempt this, and if this particular thing goes wrong, do that instead. Used precisely, they turn a crash into a helpful message and let the program carry on. Used carelessly, they hide exactly the bugs you most need to see, so this page is as much about what not to catch as about what to catch.
Think of a safety net under one trapeze. It catches that performer's fall, and the show goes on. A net stretched under the whole circus would catch the audience too, and hide every other accident in the building.
The Shape
Put the risky code in a try block, and after it an except block that names the exception you expect. If that exception happens anywhere in the try block, Python jumps straight to the except block, runs it, and carries on after it. If nothing goes wrong, the except block is skipped. In the program below, the text forty cannot be converted, so the except block prints a message instead of the program crashing.
answer = "forty" try: number = int(answer) print(f"Got {number}") except ValueError: print(f"'{answer}' is not a whole number.") print("The program carries on.")
'forty' is not a whole number. The program carries on.
Notice that the line printing "Got" never ran. When the conversion failed, Python left the try block at once.
Catch the Error You Expect
Name the specific exception you know how to handle, and only that one. Here it is ValueError, the error int raises for text it cannot read. Any other kind of problem, such as a typo in a name, still stops the program with its own traceback, which is exactly what you want: it is a different problem that needs a different fix.
else and finally
Two optional blocks complete the shape. else runs only if the try block finished without an exception, which keeps the "it worked" code apart from the risky line. finally runs whatever happened, success or failure; it is for tidying up. In this book finally is rarely needed, because with already closes files for you.
for answer in ["15", "forty"]: try: percent = int(answer) except ValueError: print(f"'{answer}': not a number") else: print(f"'{answer}': tip of {percent} percent")
'15': tip of 15 percent 'forty': not a number
Never a Bare except
An except with no exception named catches everything, and that is the trap. The program below has a typo: answr, with the e missing, instead of answer. That is a NameError, a real bug. But the bare except catches it too and prints the friendly message about numbers, so the program looks as if it is handling bad input correctly while it is actually broken. Catching Exception, which covers nearly all errors, has the same problem on a smaller scale.
answer = "15" try: percent = int(answr) except: print("Please type a whole number.")
Please type a whole number.
The input was a perfectly good 15. With except ValueError, the typo would have shown itself at once as a NameError with a "Did you mean" suggestion.
The Ask-Until-Valid Loop, Finished
Chapter 4's loop used isdigit, which rejects minus signs and decimal points. The honest test of "can this be a number?" is to try converting it. The loop below asks for a temperature, tries float, and asks again only when the conversion raises a ValueError. It accepts minus eleven and rejects the word cold.
while True: answer = input("Temperature: ") try: temp = float(answer) break except ValueError: print("Please type a number, like 21.5 or -3.") print(f"Recorded {temp} degrees")
Temperature: cold Please type a number, like 21.5 or -3. Temperature: -11 Recorded -11.0 degrees
- "Wrapping everything in try makes code safe." It makes errors invisible, which makes code unsafe. Put only the risky line inside, and catch only what you expect.
- "except Exception is the same as naming the error." It still catches almost everything, including your own bugs.
- "The lines after the failing one inside try still run." Python jumps straight to except from the line that failed.
- "A bare except is fine for small scripts." It is how small scripts end up printing the wrong message for the wrong reason.
- Programs that meet people and files must handle expected failures gracefully, and try with a named exception is how.
- Catching narrowly is the difference between a program that copes with bad input and one that is silently wrong.
Knowledge Check
A ValueError happens on the first line of a try block. What runs next?
- The rest of the try block, then the except block
- The matching except block, straight away
- The else block, because an error occurred
- Nothing: the program stops with a traceback
Why is a bare except: dangerous?
- It makes the program noticeably slower to run
- Python refuses to run a file that contains one
- It also catches real bugs, such as typos, and hides them
- It catches nothing at all unless you name a specific error after it
When does an else block after try and except run?
- Only when the try block raised no exception
- Only when the except block has finished running
- Every time, whatever happened in the try block
- Only when an error was raised but not caught
Why does the finished input loop use float(answer) inside try instead of isdigit?
- Because isdigit has been removed from newer versions of Python
- Because try blocks cannot contain an if statement
- Because float can turn any word into a number
- Trying the conversion accepts minus signs and decimal points
You got correct