try and except
In the previous lesson, the news of the crack traveled along the dotted trail past every box and stopped the program. Now let's stretch a net across its path. The box with the net catches the news of the break, and the column keeps working.
In Python, that net is the try/except construct. The program below adds up numbers from strings. Without try, it would stop at the first string that does not look like a number:
texts = ["12", "ten", "7"]
total = 0
for text in texts:
try:
total += int(text)
except ValueError:
print("skip", text) # skip ten
print(total) # 19Let's go step by step:
- For
"12", the call tointgoes through, andtotalbecomes12. - For
"ten", the call tointraises aValueError, andexcept ValueErrorprintsskip ten. - For
"7", the loop goes on as usual, andtotalbecomes19. - The last line prints
19: an error in one string did not stop the program.
How try works
Python runs a try block like this:
- The lines of the
tryblock run in order. - If no exception happened, the
exceptblock is skipped. - If an exception happens on a line, the rest of the
tryblock does not run. - Python checks whether the exception fits the
except, and if it does, runs its block.
The named class and any of its descendants fit: except ValueError catches a ValueError but not a KeyError; except Exception catches any program error. Catching an exception this way is called exception handling.
If the except does not fit, the exception goes on as if there were no try, stopping the program with a traceback. That is why int("ten") under except KeyError still stops the program. Here the net picture holds exactly: a net catches only news of its own kind, and the rest fly through it.
After as in the except line, you can give the exception a name. That name holds the exception object itself, and print shows its message:
try:
print(int("ten"))
except ValueError as e:
print("error:", e) # error: invalid literal for int() with base 10: 'ten'An exception climbs the calls
The net does not have to be in the same function where the error happened. An exception goes up from a function to the code that called it, and further up. The first try with a fitting except on that path catches it.
Every function on the path is abandoned mid-line. The code after the failing line does not run in it, and it returns no value. Let's go back to average and report from the previous lesson, but wrap the call in a try.
Press "Next step" and watch the column of frames on the right. When the error happens, the frames come off one by one, and the print calls after the failing lines never run.
1def average(nums):2 return sum(nums) / len(nums)3 4 5def report(nums):6 print("report starts")7 avg = average(nums)8 print("average:", avg)9 10 11try:12 report([])13 print("all done")14except ZeroDivisionError as e:15 print("caught:", e)16print("program goes on")
The module code enters the try block and calls report([]).
So the program printed only three lines. The lines average: … and all done never appeared: both came after lines where the exception flew. If there were no try in <module> either, the program would stop with the traceback from the previous lesson.
Several excepts
One try can have several except branches. Python checks them from top to bottom and runs only the first one that fits, skipping the rest:
prices = {"tea": "40", "cake": "abc"}
for name in ["tea", "milk", "cake"]:
try:
print(int(prices[name])) # 40
except KeyError:
print("no", name) # no milk
except ValueError:
print("bad price", name) # bad price cakeLet's take each item:
- For
tea, both operations in thetrygo through without an error, and the program prints40. - For
milk, the error happens already atprices[name]: there is no such key, andexcept KeyErrorruns.intis never reached. - For
cake, the key exists, butint("abc")raises aValueError. The first branch does not fit, and the second one runs.
In Python, the usual practice is to try the action first and catch the failure. This approach is called EAFP, short for "easier to ask forgiveness than permission". A string that int will read is hard to check in advance: "-5" and " 7" are numbers, while "5.0" is not. An attempt with except ValueError solves this in one line.
Interviewers often ask about EAFP. The opposite approach is to check first whether the action is possible, and only then act. In Python, EAFP is the usual choice for parsing strings and looking up keys.
Common mistake
The general class is placed above the specific one:
stock = {"tea": 3}
try:
print(stock["milk"])
except Exception:
print("something went wrong") # something went wrong
except KeyError: # ✗
print("no such item")Python reports no error, but the except KeyError branch never runs. KeyError is a descendant of Exception, and the upper branch catches it first. Specific classes go above general ones: swap the branches, and the program prints no such item.
Key points
try/exceptcatches an exception, and the program goes on after theexceptblock.- After the failing line, the rest of the
tryblock does not run;exceptcatches the named class and its descendants. - An exception climbs the calls, abandoning each function mid-line, until a fitting
exceptcatches it. exceptbranches are checked from top to bottom, so specific classes go above general ones.
Subscribe to take the course
The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.