try / except
Learn how to catch errors before they crash your program, handle different exception types gracefully, and always clean up after yourself.
Every program eventually runs into trouble. Maybe a user types letters when you expected a number. Maybe a file you need has been deleted. Maybe you divided by zero by accident.
When something goes wrong, Python raises an exception — a signal that says "I don't know how to continue." If you don't handle it, your program crashes.
The good news: Python gives you a way to catch those signals and decide what to do instead of crashing.
See it in action
— step through the idea, then dive into the details below.Errors Happen — Don't Crash
When Python hits a problem it can't solve, it raises an exception and your program stops cold. Learning to catch exceptions means your program can recover instead of crashing.
#What Does a Crash Look Like?
number = int("hello") # can't convert "hello" to a numberThat red wall of text is called a traceback. It tells you what went wrong and where. The last line is the most important — it names the exception type (ValueError) and gives a short description.
Instead of letting Python crash, we can catch the exception ourselves.
#The try / except Block
Think of it like a safety net
Imagine a trapeze artist. The try block is the daring move. The except block is the safety net below. If the move goes perfectly, the net is never used. If something goes wrong, the net catches them — and the show goes on.
try:
number = int("hello")
except ValueError:
print("That wasn't a valid number!")Here is the basic structure:
try:— put the risky code hereexcept SomeError:— put the recovery code here, which runs only if that specific error happens
If no error occurs, the except block is completely skipped.
#Common Exception Types
Python has many built-in exception types. Here are the ones beginners encounter most often:
- `ValueError` — right type, wrong value (e.g.
int("hello")) - `TypeError` — wrong type entirely (e.g.
"2" + 2) - `ZeroDivisionError` — dividing by zero
- `KeyError` — looking up a dictionary key that doesn't exist
- `IndexError` — accessing a list index that doesn't exist
- `FileNotFoundError` — trying to open a file that isn't there
scores = {"Alice": 95, "Bob": 87}
try:
print(scores["Charlie"])
except KeyError:
print("No score found for that name.")numbers = [10, 20, 30]
try:
print(numbers[99])
except IndexError:
print("That index is out of range!")#Catch Specific Exceptions — Not Everything
Avoid bare except — it hides real bugs
It is tempting to write except: with no error type to catch absolutely everything. Don't. A bare except will silence bugs you didn't intend to handle — like a typo in a variable name — making them nearly impossible to track down.
Always name the specific exception you expect, like except ValueError:.
# BAD: catches everything, even bugs you didn't mean to handle
try:
result = 10 / 0
except:
print("Something went wrong")
# GOOD: only catches the specific error you expect
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")You can also catch multiple exception types in one except clause by grouping them in parentheses:
def safe_divide(a, b):
try:
return a / b
except (ZeroDivisionError, TypeError):
print("Invalid input for division.")
return None
print(safe_divide(10, 2))
print(safe_divide(10, 0))
print(safe_divide(10, "x"))#Capturing the Error Message with "as e"
Sometimes you want to see the error message Python would have shown, but handle it gracefully. Use as e to capture the exception object — then you can print it or log it.
try:
value = int("abc")
except ValueError as e:
print("Caught an error:", e)Log the error, don't silence it
In real programs, it is good practice to at least print or log the error message when you catch an exception. That way, if something unexpected happens, you have a clue about what went wrong instead of a mystery.
#else and finally
A try block can have two optional extra clauses:
- `else:` runs only if the
tryblock succeeded (no exception was raised) - `finally:` runs no matter what — whether an exception happened or not. It is perfect for cleanup like closing files.
try:
number = int(input("Enter a number: "))
except ValueError:
print("That was not a number.")
else:
print("Great! You entered:", number)
finally:
print("Thanks for using the program!")# Simulating both paths
# --- Path 1: valid input ---
try:
number = int("42")
except ValueError:
print("Not a number.")
else:
print("Success! Got:", number)
finally:
print("Always runs.")
print("---")
# --- Path 2: invalid input ---
try:
number = int("oops")
except ValueError:
print("Not a number.")
else:
print("Success! Got:", number)
finally:
print("Always runs.")#A Real-World Example
def read_config(filename):
try:
file = open(filename)
except FileNotFoundError:
print(f"Config file '{filename}' not found. Using defaults.")
return {}
else:
content = file.read()
file.close()
print("Config loaded successfully.")
return content
finally:
print("read_config() finished.")
read_config("settings.txt")What is the purpose of the `finally` block in a try/except statement?
Key takeaways
- Unhandled exceptions crash your program — use try/except to catch them gracefully.
- Always catch specific exception types (like ValueError or KeyError), never use a bare except.
- Use `as e` to capture and inspect the error message.
- The `else` block runs only when no exception occurred; `finally` always runs — great for cleanup.
- Knowing common exception names (ValueError, TypeError, KeyError, IndexError, ZeroDivisionError, FileNotFoundError) helps you write targeted handlers.
What does this code print?
try:
result = 10 / 0
except ZeroDivisionError:
print("Oops, divided by zero!")
else:
print("Division worked fine.")
finally:
print("All done.")This code is meant to safely convert user input to an integer and print it, but it has a bug. What is wrong?
try:
number = int("hello")
except:
print("Please enter a valid number.")
print("You entered:", number)Complete the code so it catches a KeyError when the name is not in the dictionary and prints 'Name not found.'
scores = {"Alice": 95, "Bob": 87} try: print(scores["Charlie"]) except : print("Name not found.")
Put these lines in the right order to define a function that converts a string to an integer and returns 0 if it fails.
return 0
try:
return int(value)
def safe_int(value):
except ValueError:
Write a function called safe_int that takes a single argument and tries to convert it to an integer. If it succeeds, return the integer. If a ValueError occurs, print a friendly message and return 0. Test it with both a valid string like "42" and an invalid one like "banana".
Try it live — edit the code and hit Run to execute real Python: