Exception Handling
Lesson 5 of 8
5Exception Handling
The big pictureCatching only the error you expect instead of swallowing everything, how except, else and finally differ, and why silent failure is worse than a crash.
What the picture shows: The error is born in parse, nobody catches it in load so it climbs, until it reaches main where an except is waiting and it stops there.
Map of this part
The concepts in order, click any one to jump to it:
Two ways into the same idea
An exception is like a fire alarm. Switch off every alarm in the building because they are noisy, and you will miss the real fire. The right move is to handle the alarm you expect ("the user typed letters instead of a number") and let the rest ring until someone sees it.
try wraps code that may fail, except ValueError catches one specific type, else runs if nothing failed, and finally always runs for clean-up. Avoid a bare except: that swallows everything including bugs; raise re-raises or throws your own error.
Before You Start
🧩Functions
A function calls a function, and each returns a value.
🔢Converting types
int("5") turns text into a number, and it can fail.
The Core Idea
An error while running is not the end of the program if you expected it. Here you learn to catch an error and decide what happens next, in three small examples.
1Catch the error instead of stopping
int("12") turns text into a number. But int("twelve") cannot, so it raises an error named ValueError. Put the risky line inside try, and what you want to happen on error inside except.
text = "12"
print(int(text) + 1)
broken = "twelve"
try:
print(int(broken) + 1)
except ValueError:
print("that text is not a number")
print("the program is still running")
The last line printed, so the program carried on after the error instead of stopping. That is the whole point of exceptions.
2Return a fallback value
Dividing by zero raises ZeroDivisionError. Inside a function you can catch it and return None, meaning "no result", and leave the decision to the caller.
def divide(a, b):
try:
return a / b
except ZeroDivisionError:
return None
print(divide(10, 2))
print(divide(1, 0))
Note that we named the exact error type. A bare except catches everything and hides errors you did not expect, so avoid it.
3Clean dirty data
The most common practical pattern: a list where some values are valid and some are not. Try to convert each value, keep what worked, and log what failed.
values = ["3", "x", "7"]
clean = []
for value in values:
try:
clean.append(int(value))
except ValueError:
print("skipped:", value)
print(clean)
The try sits inside the loop, not around it. Around the whole loop, it would stop at the first bad value and lose the rest.
except: "so the program never stops". It will indeed not stop, but it will swallow every error including your own typos in variable names, and you will spend an hour hunting a bug Python would have told you about in a second.How It Works, Step by Step: The journey of an error to whoever catches it
A line fails, like int("abc"), and an error object is made.
Python stops the function at once and looks for a matching except.
If there is none it climbs to the caller, and so on.
The first matching except catches it; otherwise the program stops and prints a traceback.
Going deeper
A professional program doesn't "crash" at the first unexpected error (bad input, missing file). Exception handling lets you detect an error and handle it safely.
Diagram 5, else runs only when try succeeds with no exception at all, while finally runs in every case (success or failure), ideal for cleaning up resources.
| Type | Typically occurs when |
|---|---|
ValueError | Converting text that doesn't represent a valid number, like int("abc") |
TypeError | An operation between incompatible types, like "5" + 5 |
IndexError | Accessing an element outside a List's bounds |
KeyError | Accessing a key that doesn't exist in a Dict |
ZeroDivisionError | Dividing by zero |
## Example: safely converting text input to a number
def convert_to_integer(text):
try:
value = int(text)
except ValueError:
print(f"'{text}' is not a valid integer")
return None
else:
print("Conversion succeeded") # runs only if no exception occurred
return value
finally:
print("Conversion attempt finished") # always runs no matter what
convert_to_integer("42") # succeeds -> prints "Conversion succeeded" then "...finished"
convert_to_integer("abc") # fails -> prints the error message then "...finished"
## Explicitly raising an exception for an illogical state in your own logic
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
return age
except: without specifying the exception type. This hides real programming bugs (like a typo in a variable name) instead of fixing them, because it silently "swallows" everything.
Check your understanding: what's the practical difference between putting cleanup code inside finally versus right after the whole block?
finally guarantees execution even if an unhandled exception occurs and the program later stops because of it (like closing a file before the error propagates), while code placed right after the block won't execute at all if there's an unhandled exception that propagates upward.
Worked example
try: age = int(text), then except ValueError: print("Type a number"). Catch ValueError specifically, not every error, so you do not hide another bug you did not expect.Myth vs Reality
| Myth | Reality |
|---|---|
| A bare except is safer because it catches everything. | It catches your own bugs and even Ctrl+C, hiding the problem instead of solving it. Catch the type you expect. |
| An exception means the program is bad. | An exception is Python saying "I could not", like a missing file. A good program expects it and deals with it. |
| finally only runs when there was an error. | It always runs, success or failure, which is why it is the place for clean-up such as closing a connection. |
Try it yourself
You write try: x = int("5") then except ValueError: x = 0. What is x?
The conversion succeeded because "5" is valid text for a number, so no error was raised and the except block was never entered. An except block runs only when the named error happens; otherwise it is skipped entirely.
Quick Review Flashcards
Check Your Understanding
When does the else branch of a try run?
When the try part succeeds with no error.
Why catch ValueError rather than Exception?
Because you know what to do with it, and other errors should surface so you can fix them.
A function does not catch an error: where does it go?
It climbs to the function that called it, until someone catches it or the program stops.
Resources for this part
Sorted by kind: start with the official docs when you want the precise reference, or with an article or video when you want the explanation first.
Resources for this lesson
Grouped by type. Start with the official docs for precision, or an article or video for the explanation.
Official docs3
Done with this lesson?
Sign in to save your progress.