try / except — Handling Failure Gracefully
Errors aren't the enemy — unhandled errors are. A program that crashes with a wall of red text loses the user; a program that says "That wasn't a number — try again" keeps them. try/except is how you take control of failure.
The crash you already know
age = int(input("Age: ")) # user types "abc"Output:
ValueError: invalid literal for int() with base 10: 'abc'The whole program dies. In a real app, that's a user lost. Here's the same moment, handled:
The try/except structure
try:
age = int(input("Age: "))
print(f"Next year: {age + 1}")
except ValueError:
print("That's not a number!")Python tries the indented block. If any line raises an error, it jumps immediately to the matching except block instead of crashing. The program continues afterward — failure handled, dignity intact.
Catching specific errors matters
# ❌ lazy — catches EVERYTHING, hides real bugs
try:
...
except:
print("Something went wrong")
# ✅ precise — catches exactly what you expect
try:
...
except ValueError:
print("Not a number")Bare except swallows typos, logic bugs, everything — making bugs *invisible* instead of handled. Always name the exception. The ones you'll meet most:
| Error | Raised when |
|---|---|
ValueError | right type, bad value (int("abc")) |
TypeError | wrong type entirely ("5" + 5) |
NameError | undefined variable |
ZeroDivisionError | dividing by zero |
KeyError | missing dict key |
FileNotFoundError | missing file |
Multiple excepts — different problems, different plans
try:
a = int(input("Numerator: "))
b = int(input("Denominator: "))
print(f"Result: {a / b}")
except ValueError:
print("Please enter numbers only")
except ZeroDivisionError:
print("Cannot divide by zero!")Python checks except blocks in order and runs the first match. A non-number hits ValueError; a zero denominator hits ZeroDivisionError; success skips them all.
else and finally — the complete picture
try:
file_data = open("data.txt").read()
except FileNotFoundError:
print("File missing — starting fresh")
file_data = ""
else:
print("File loaded successfully") # runs only if NO error
finally:
print("(attempt finished)") # runs ALWAYS — error or notYou'll see else occasionally; finally becomes essential the day you work with databases and network connections.
The error object — reading the details
try:
age = int(input("Age: "))
except ValueError as err:
print(f"Could not convert: {err}")as err captures the exception object — its text often names the exact offending value, which is gold for debugging.
The retry loop (putting it all together)
The pattern behind every "please enter a valid number" prompt ever written:
while True:
try:
age = int(input("Age: "))
break # success — leave the loop
except ValueError:
print("Numbers only, try again")
print(f"Got it: {age}")Try → fail politely → loop → try again. Users forgive anything except being crashed on.
Common Errors & Fixes
as keyword.✅ Checkpoint
except:? *(Hides real bugs — always name the exception)*else run in try/except/else? *(Only when the try block had no error)*Next: raising exceptions — making YOUR code fail loudly when its rules are broken.