Python Programming · Foundations

Exceptions

Want it in plain words first? Jump to Eli explains — the same idea, no jargon.
On this page 9 sections
  1. In 30 seconds
  2. Why this matters
  3. The college version
  4. Eli explains
  5. Worked example
  6. Key takeaway
  7. Quick check
  8. Study tools
  9. Sources & references

In 30 seconds

An is a runtime event that interrupts normal Python execution, such as converting invalid text with int() or dividing by zero. A try statement lets a program handle an expected kind of exception deliberately. Put only the operation that may fail in try, catch its specific exception in except, use else for the success path, and use finally for work that must happen before the statement finishes.

Why this matters

Exceptions let a program distinguish an expected problem from a successful result instead of pretending every operation succeeds. In coursework, they make input-validation and code tracing more precise. In production code, a targeted handler can give a useful response to a known condition while allowing unexpected defects to remain visible. That distinction prevents both crashes from routine bad input and silent failures caused by catching too much.

The college version

Exceptions describe execution-time problems

Python can reject code before it runs when its syntax is invalid, but syntactically valid code can also fail while executing. Python calls these execution-time errors exceptions. For example, int("four") is valid code, yet the conversion cannot produce an integer and raises ValueError. Similarly, 1 / 0 raises ZeroDivisionError. If no code handles an exception, Python reports a that identifies the route through source code to the point where it occurred. An exception is therefore not merely a printed message; it is an object-based control-flow event that can be handled, allowed to to a caller, or left unhandled.

The exception type carries important meaning. ValueError says an operation received a value of an appropriate general type but an inappropriate value; TypeError commonly signals an operation applied to an unsuitable type. Choosing a handler based on that meaning is safer than treating every failure alike. This lesson is about handling expected, local conditions. Finding an unexpected defect through tracing and inspection belongs to debugging, and safe acquisition and closing of files belongs to the file lessons.

A try statement separates protected work from outcomes

A try statement begins by executing its try suite. If that suite completes normally, its except suites are skipped. If an exception occurs in the try suite, the rest of that suite is skipped and Python looks for a matching except clause. A matching handler runs, after which execution continues after the whole statement. If no handler matches, the exception propagates to an enclosing caller or becomes unhandled. A handler does not automatically catch a problem raised inside a different except suite.

Keep a try suite narrow. If a program intends to handle a conversion failure, the conversion—not unrelated printing, calculation, or state changes—belongs in the protected suite. A narrow suite makes the intended recovery clear and avoids mislabeling an unrelated bug as bad input. An else suite is useful for code that should run only when the try suite did not an exception. Keeping success-only work there avoids accidentally catching an exception from that work. A finally suite executes as the last task before the try statement completes, whether the protected work succeeded, was handled, or an exception is continuing outward. Do not use a return, break, or continue in finally to hide an exception; that makes control flow needlessly surprising.

Target the exception type and respect the hierarchy

Built-in exceptions are classes. BaseException is their common base; Exception is the usual base for ordinary application-level errors. An except SomeClass handler matches an instance of SomeClass or a subclass of it. It does not match one of its base classes. This is why order matters when two handlers overlap: Python executes the first matching handler. A handler for a subclass such as FileNotFoundError must appear before a handler for its superclass OSError if the program needs different responses.

For introductory code, prefer a handler for the specific problem you expect, such as except ValueError: around int(text). A bare except: is especially risky because it catches every exception derived from BaseException, including KeyboardInterrupt and SystemExit, which programs normally should not swallow. except Exception: is less broad but still inappropriate when the program only knows how to recover from one expected condition. If a handler cannot make a correct decision, allow the exception to propagate or, after adding needed context, re-raise it.

raise lets code state a violated contract explicitly. A function that requires a nonnegative value can raise ValueError when it receives a negative one. That is different from using exceptions as ordinary branching: test predictable conditions directly when a simple conditional expresses the rule. Raise an exception when the function cannot sensibly continue under its documented input contract.

Trace success and failure paths independently

To trace a try statement, first identify the operation inside try that can raise. Then follow two paths: the no-exception path runs else if present, then finally; the matching-exception path runs the matching handler, then finally. An unmatched-exception path still runs finally before carrying the exception outward. This procedure explains output without guessing and makes it easier to decide whether a handler’s response is appropriate.

Exception handling should preserve useful information. A helpful handler can report what input was invalid or return a clearly documented fallback. A harmful handler silently substitutes a value that makes later results misleading. The goal is neither to prevent all exceptions nor to make a program continue at any cost. The goal is to handle the specific failures the program understands, while leaving unexpected failures available for diagnosis.

Eli, the EliExplains learning guide

Eli explains

The same idea, in plain words

Explain it like I’m 10

Imagine a recipe machine that sometimes receives an ingredient it cannot use. An exception is its clear signal: it cannot finish this step normally. A try block is the small area where you expect that particular problem might happen. An except ValueError block is the prepared instruction for that exact signal, such as asking for a number again. If nothing goes wrong, else handles the normal success work. finally is the last checklist item that happens on either path.

The important idea is to listen for the right signal. A plan for a bad number should not also silence every possible alarm in the machine. If an unfamiliar alarm rings, let it be heard so someone can investigate it.

Picture it like this

A try statement is like a small station with a trained response for one known alarm, a normal-work lane, and a final shutdown checklist.

Where the picture stops working

Programs do not literally have alarms or lanes. The analogy does not explain exception objects, inheritance, or all effects of returning from a finally block.

Worked example

This executed function accepts text that represents a nonnegative whole number. The conversion may raise ValueError, so only int(text) is in the try suite. On success, else prints the converted value. A negative result violates the function’s documented rule, so raise ValueError creates a deliberate exception; the same targeted handler reports it. In both cases, finally prints its message. The calls produce the shown two outcomes.

def show_count(text):
    try:
        count = int(text)
        if count < 0:
            raise ValueError("count must be nonnegative")
    except ValueError as error:
        print(f"invalid count: {error}")
    else:
        print(f"accepted: {count}")
    finally:
        print("checked")

show_count("12")
show_count("-3")
# accepted: 12
# checked
# invalid count: count must be nonnegative
# checked

Key takeaway

Handle only failures your code understands: keep try narrow, catch a specific exception type, use else for the normal path, and let finally perform its final task without hiding an exception.

Quick check

3 questions here, of 5 in this lesson’s practice set. Answers stay hidden until you check.

Question 1 of 3foundational

Which event is a Python exception rather than a syntax error?

Choose an answer, then check it.
Question 2 of 3intermediate

A function expects an integer typed as text. Which handler is most appropriate directly around int(text)?

Choose an answer, then check it.
Question 3 of 3intermediate

When a try suite completes without raising an exception, what happens to an attached else suite?

Choose an answer, then check it.
Practice all 5

Keep learning

Ready to build on this? Continue to the next lesson.

Practice this lesson
Study tools & related lessonsYou’ll learn to · Common mistakes · Easily confused · Key vocabulary · Related

You’ll learn to

  • Define a Python runtime exception and distinguish it from a syntax error.
  • Trace the control flow of try, except, else, and finally.
  • Select a targeted exception handler for a known operation.
  • Explain how exception inheritance and handler order affect matching.
  • Use raise ValueError to enforce a simple function contract.

Common mistakes

  • Using a bare except: for ordinary input errors.

    Catch the expected type, such as ValueError, so interrupts and unrelated failures are not silently swallowed.

  • Putting a large amount of unrelated code in try.

    Protect the smallest operation whose expected exception you can handle correctly.

  • Putting a superclass handler before a subclass handler.

    Place the more specific exception first because Python uses the first matching handler.

  • Assuming else runs after a handled exception.

    else runs only when the try suite completed without an exception.

  • Returning from finally to guarantee a result.

    Avoid control-transfer statements in finally; they can suppress an exception that should continue outward.

Easily confused

Syntax error vs. Exception

A syntax error is detected while parsing code; an exception is raised while syntactically valid code executes.

`except ValueError` vs. bare `except`

The targeted handler catches the known conversion/value condition; a bare handler catches nearly every exception, including signals usually allowed to terminate.

`else` vs. `finally`

else runs after a successful try suite; finally runs as the try statement completes on both success and exception paths.

Key vocabulary

exception
An event raised during execution that interrupts normal control flow until code handles it or it propagates.
traceback
Python’s report of the call path and source locations associated with an unhandled exception.
try suite
The block of statements Python executes first in a try statement.
exception handler
An except clause that responds to matching exception instances.
propagate
To pass an exception outward when the current code does not handle it.
exception hierarchy
The subclass relationships among exception classes that determine which handlers match.
raise
The statement used to cause a specified exception to occur.
finally suite
The optional block that runs as the last task before a try statement completes.

Sources & references

  1. Errors and Exceptions — Python Documentation
  2. Built-in Exceptions — Python Software Foundation
  3. The Python Language Reference — The try statement — Python Software Foundation

EliExplains lessons are original prose written from the open, credible references above. See Copyright & Licensing.

Researched 2026-08-19

Educational content only. It is not medical, legal or professional advice. Found an error? Tell us.