An exception in Python: the error that stops the program

An exception is the signal a program sends when it can no longer carry on. It stops execution and travels up until something knows how to handle it.
5 min read
Believemy logo

Definition

A program constantly meets situations it cannot resolve: the expected file is not there, a calculation asks for a division by zero, a requested key is missing from the dictionary. Carrying on regardless produces wrong results, discovered hours later; stopping and saying what went wrong leaves a chance of understanding.

Python picked the second, and that choice has a name: the exception. It is the signal a program sends when it refuses to carry on. It stops the current statement, then travels back up the call stack looking for a place set up to handle it. With nobody to take it, it exits the program and prints a traceback.

That upward journey is valuable: the place where the problem happens and the place where it is caught need not be neighbours. A function buried deep down reports the incident, and the calling code handles it, being the only one that knows what to do.

Catching it, on the other hand, means marking out the area to watch and then stating what to do if it fails.

PYTHON
try:
    # if share_count is 0, this line raises ZeroDivisionError
    total = amount / share_count
except ZeroDivisionError:
    # we only get here if the announced exception was actually raised
    total = 0

The word is misleading: an exception is not exceptional at all. It is the normal way of reporting a problem, and a solid program raises plenty of them, deliberately.


A family, not a list

Python defines several dozen exception types. Listing them one by one in every except block would be endless, and forgetting a single one would let the program stop anyway.

Hence the choice to arrange them as a tree, through inheritance: each type descends from a more general one, and catching a parent catches all its children along with it. That is how you set the width of the net.

The exception tree and what an except block catches Exception at the top; below it ValueError, TypeError and LookupError; under LookupError, IndexError and KeyError. The orange frame shows that except LookupError catches three types, while except KeyError catches only one. Exception ValueError TypeError LookupError IndexError KeyError except LookupError catches these 3 types except KeyError catches just 1 type

A handful of types keeps coming back. Here is what each one reports, the question to ask when an unfamiliar name shows up in a traceback.

ExceptionWhat it reports
TypeErrorAn operation on a type that does not support it
ValueErrorThe right type, but an unacceptable value
KeyErrorA key missing from a dictionary
IndexErrorA position past the end of a sequence
AttributeErrorAn attribute the object does not have
LookupErrorThe parent of KeyError and IndexError

At the top of the tree sits Exception, the common ancestor of nearly everything: except Exception therefore catches just about anything.

Warning

An except Exception thrown too wide also swallows your own typos: a misspelled variable name becomes indistinguishable from a network outage, and the message printed names the wrong cause.


Raising your own

Exceptions are not reserved for the language. A function you write also receives requests it cannot honour, withdrawing 500 euros from an account holding 30, and the way it reports that decides what follows.

raise raises an exception from your own code, exactly as Python does from its own.

PYTHON
def withdraw(balance, amount):
    if amount > balance:
        # refuse before computing: no wrong amount leaves this function
        raise ValueError("Amount exceeds balance")
    return balance - amount

Returning a fallback value, None or -1, feels gentler, and that is the problem: the checking falls to the caller, who will forget it on a tired day. The wrong value then flows through the program and only blows up much later, with no visible link to its cause.

An exception cannot be ignored by accident: either the caller deals with it, or the program stops on the offending line, where the problem was born.


Asking forgiveness rather than permission

One question of method remains: is it better to check that everything is in order before acting, or to act and then catch the failure? Python commits to the second road.

Checking that a file exists before opening it looks tidier, but it leaves a window during which the file can be deleted or locked. Opening it straight inside a try closes that window: the attempt and its failure are handled in a single move.

The normal path then reads in one go, and a finally block guarantees the clean-up, whether an exception was raised or not.

Good to know

This preference has a name in the Python community: EAFP, for "easier to ask forgiveness than permission". The opposite approach is called LBYL, "look before you leap".


Frequently asked questions

Question

What is the difference between an exception and a syntax error?

The moment of detection separates them. A SyntaxError is spotted while Python reads the file: nothing starts at all, and no catching block can rescue it. An exception happens during execution, in valid code that meets a situation it cannot handle.

Question

Should every exception be caught?

No, only the ones you know how to handle. An exception reaching the top at least reports a real problem. Swallowed by an empty except, it gives you a program carrying on with inconsistent data, which costs far more than a clean stop.

Question

Does an exception slow the program down?

Its cost only shows when it is actually raised, never on the normal path: a try block that triggers nothing costs almost nothing, which makes this style well suited to loops. Knowing what to catch and what to let through is a matter of judgement, and our Python course works the question through on concrete cases.

Related terms

Discover our python glossary

Browse the terms and definitions most commonly used in development with Python.

Share this article

Want to help us? Share this article on your networks or even better: on your site, in an article or in your newsletter.