try and except let your program deal with something going wrong instead of stopping dead.
try:
age = int(input("Your age: "))
except ValueError:
print("That was not a whole number.")Python runs the try block. If the specific error you named happens, it runs the except block instead of crashing. If nothing goes wrong, the except block is skipped entirely.
Catch the specific error, not everything#
This is the whole discipline in one rule. Name the exception you are prepared for:
try:
with open("scores.txt") as f:
data = f.read()
except FileNotFoundError:
data = "" # first run, no file yetCompare that with catching everything:
try:
with open("scores.txt") as f:
data = f.read()
except: # catches literally anything
data = ""The second version also swallows your typo in the filename variable, a permissions problem, and a NameError from a mistake three lines up. The program keeps running and quietly does the wrong thing, and you get no message telling you why.
The errors worth catching#
| Exception | Happens when |
|---|---|
ValueError |
int("hello") — right type, impossible value |
TypeError |
"2" + 2 — wrong type for the operation |
FileNotFoundError |
Opening a file that is not there |
KeyError |
Asking a dictionary for a key it lacks |
IndexError |
Asking a list for a position that does not exist |
ZeroDivisionError |
Dividing by zero |
PermissionError |
Writing where you are not allowed |
Each of these is explained with examples in common Python errors and how to fix them.
Catching more than one#
try:
value = int(data["count"])
except (KeyError, ValueError):
value = 0Or handle them differently:
try:
value = int(data["count"])
except KeyError:
print("No count in the data.")
value = 0
except ValueError:
print("Count was not a number.")
value = 0Reading the error itself#
try:
number = int("abc")
except ValueError as err:
print("Could not convert:", err)
# Could not convert: invalid literal for int() with base 10: 'abc'as err gives you the exception object, and printing it gives you Python’s own description — usually more precise than anything you would write yourself.
else and finally#
try:
f = open("data.txt")
except FileNotFoundError:
print("No file.")
else:
print("Opened fine:", len(f.read()), "characters")
f.close()
finally:
print("This runs either way.")elseruns only if nothing went wrong. Use it to keep thetryblock down to the single line that might fail — the smaller thetry, the more precisely you know what you caught.finallyruns whatever happens, including when an exception is on its way up. It is for cleanup: closing files, releasing a connection.
For files specifically, with already does the cleanup for you, so you rarely need finally:
with open("data.txt") as f: # closes itself, even on an error
print(f.read())Raising your own#
Sometimes the right move is to stop, loudly, with a message that explains what was wrong.
def set_age(value):
if not isinstance(value, int):
raise TypeError("Age must be a whole number")
if value < 0:
raise ValueError("Age cannot be negative")
return valueThis is better than returning None and hoping the caller checks. An exception cannot be ignored by accident.
When not to use try/except#
If you can simply check first, checking is clearer:
try:
print(person["email"]) # heavy-handed
except KeyError:
print("no email")
print(person.get("email", "no email")) # bettertry:
average = total / len(items)
except ZeroDivisionError:
average = 0
average = total / len(items) if items else 0 # betterRough rule: use try/except for things outside your control — files, networks, other people’s input. Use a plain if for things you can check yourself.
A worked example#
Reading a number from someone, safely, without crashing and without giving up:
def ask_number(prompt, low, high):
while True:
raw = input(prompt)
try:
value = int(raw)
except ValueError:
print("Please type a whole number.")
continue
if value < low or value > high:
print(f"Please stay between {low} and {high}.")
continue
return value
age = ask_number("Your age: ", 1, 120)
print("Thanks:", age)The try covers exactly one line — the conversion — and the range check is a plain if, because that is something we can check ourselves. The while loop keeps asking until both pass.
Questions people ask#
Does try/except slow my program down?
Setting up a try block costs effectively nothing. Actually raising and handling an exception is more expensive, which is why exceptions are for unusual situations rather than ordinary control flow.
What is the difference between an error and an exception?
In everyday Python they mean the same thing. Strictly, SyntaxError stops your file being parsed at all — you cannot catch that with try/except, because the program never starts.
Should I use try/except to hide errors from users?
Handle them, do not hide them. A user should see “That file could not be found — check the name”, not a traceback and not silence. Log the detail for yourself, show a plain sentence to them.
What does “EAFP” mean?
“Easier to ask forgiveness than permission” — the Python habit of attempting an operation and catching the failure, rather than checking every precondition first. It suits things that are usually fine and occasionally not, such as opening a file.
Can I catch an exception and then re-raise it?
Yes. A bare raise inside an except block re-raises the original with its trace intact — useful when you want to log something and still let the error travel upward.
Where to go next#
- Common Python errors and how to fix them
- How to read a stack trace
- Build a to-do list that saves to a file — try/except in a real program
- Reading and writing files in Python — where FileNotFoundError comes from