Skip to content
Theory · Exceptions · lesson 2 of 11

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:

Python
texts = ["12", "ten", "7"]
total = 0
for text in texts:
    try:
        total += int(text)
    except ValueError:
        print("skip", text)  # skip ten
print(total)  # 19

Let's go step by step:

  1. For "12", the call to int goes through, and total becomes 12.
  2. For "ten", the call to int raises a ValueError, and except ValueError prints skip ten.
  3. For "7", the loop goes on as usual, and total becomes 19.
  4. 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:

  1. The lines of the try block run in order.
  2. If no exception happened, the except block is skipped.
  3. If an exception happens on a line, the rest of the try block does not run.
  4. 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:

Python
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.

LiveAn exception climbs the callsstep 1 of 9 · frames: 1

The module code enters the try block and calls report([]).

Watch which lines after the error never ran

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:

Python
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 cake

Let's take each item:

  1. For tea, both operations in the try go through without an error, and the program prints 40.
  2. For milk, the error happens already at prices[name]: there is no such key, and except KeyError runs. int is never reached.
  3. For cake, the key exists, but int("abc") raises a ValueError. 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:

Python
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/except catches an exception, and the program goes on after the except block.
  • After the failing line, the rest of the try block does not run; except catches the named class and its descendants.
  • An exception climbs the calls, abandoning each function mid-line, until a fitting except catches it.
  • except branches 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.

Sign in another way