Python try, except, else and finally
Updated 8 min read Aimerscrew
In the previous lesson, every exception stopped the program with a traceback. Real programs can't just crash when a user types "ten" instead of "10" or a network call fails. Python try except is how you catch those problems and decide what to do next. In this lesson, you'll learn try, except, else and finally, and how to use them the right way.
🌍 Real-life example
Think about paying at a store. You tap your card (the try). If the payment is declined, the cashier doesn't shut the store down; they ask for another card (the except). If it goes through, you get your receipt (the else). Either way, the cashier hands back your card (the finally). That's exactly the structure of error handling in Python.
What is try except in Python?
A try/except statement has two blocks:
- The try block holds code that might raise an exception.
- The except block holds code that runs only if that exception happens. This is called handling or catching the exception.
try:
result = 10 / 0
print(result)
except ZeroDivisionError:
print("You can't split a bill between zero people.")
print("The program keeps going.")
You can't split a bill between zero people.
The program keeps going.
When 10 / 0 raises ZeroDivisionError, Python skips the rest of the try block (so print(result) never runs), jumps to the matching except block, and then carries on after the whole statement. No traceback, no crash.
How do you catch a specific exception?
Always name the exception you expect after except. Converting text to a number is the classic case, because users type all sorts of things:
try:
age = int(input("Your age: "))
print(f"Next year you'll be {age + 1}.")
except ValueError:
print("That doesn't look like a number.")
Your age: twenty
That doesn't look like a number.
Here the user typed twenty. If they had typed 34, the program would print Next year you'll be 35. instead.
An except block only catches the exception type it names. Any other exception still crashes the program:
try:
print(10 / 0)
except ValueError:
print("Not a number")
ZeroDivisionError: division by zero
That's a good thing. It means you only hide the problems you planned for, and unexpected bugs still show up loudly.
Handling multiple exceptions
One try block can have several except blocks. Python checks them from top to bottom and runs the first one that matches:
prices = {"latte": 4.50, "mocha": 5.25}
def price_per_person(drink, people):
try:
return prices[drink] / people
except KeyError:
return f"Sorry, we don't sell {drink}."
except ZeroDivisionError:
return "Need at least one person."
print(price_per_person("latte", 2))
print(price_per_person("chai", 2))
print(price_per_person("mocha", 0))
2.25
Sorry, we don't sell chai.
Need at least one person.
If two exceptions need the same handling, group them in a tuple (round brackets):
def to_number(value):
try:
return float(value)
except (ValueError, TypeError):
return 0.0
print(to_number("3.5"))
print(to_number("abc"))
print(to_number(None))
3.5
0.0
0.0
Getting the error message with as e
Add as and a name after the exception type to get the exception object itself. Printing it shows the same message you'd see on the last line of a traceback:
inventory = {"apples": 12, "pears": 0}
try:
print(inventory["bananas"])
except KeyError as e:
print("Missing key:", e)
try:
int("12 boxes")
except ValueError as e:
print("Problem:", e)
print("Type:", type(e).__name__)
Missing key: 'bananas'
Problem: invalid literal for int() with base 10: '12 boxes'
Type: ValueError
The name e is just a convention; err or error work too. It's handy for logging what went wrong without crashing.
What does else do in try except?
The else block runs only if the try block finished without an exception. It goes after all the except blocks:
def divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Cannot divide by zero.")
else:
print(f"{a} / {b} = {result}")
divide(10, 4)
divide(10, 0)
10 / 4 = 2.5
Cannot divide by zero.
Why not just put the print inside the try block? Because then any error in the print line would also be caught by your except, hiding a different bug. The else block keeps the try block small: only the risky line goes in try, and the "it worked" code goes in else.
What does finally do?
The finally block always runs: after a success, after a handled error, and even when an error is not handled. It's used for clean-up, like closing a connection or saying goodbye.
def process_payment(amount, balance):
print(f"Processing ${amount}...")
try:
if amount > balance:
print("Declined: not enough funds.")
else:
balance = balance - amount
print(f"Approved. New balance: ${balance}")
finally:
print("Card returned to customer.")
process_payment(30, 100)
process_payment(250, 100)
Processing $30...
Approved. New balance: $70
Card returned to customer.
Processing $250...
Declined: not enough funds.
Card returned to customer.
Here's what happens when the exception is not handled. The finally block still runs first, and then the program crashes:
try:
print("Opening the shop")
print(10 / 0)
finally:
print("Locking the door")
Opening the shop
Locking the door
ZeroDivisionError: division by zero
The full try, except, else, finally structure
You can use all four blocks together. The order is always try, then except (one or more), then else, then finally:
def safe_divide(a, b):
try:
result = a / b
except ZeroDivisionError:
print("Error: division by zero")
else:
print("Result:", result)
finally:
print("Done.")
safe_divide(9, 3)
print("---")
safe_divide(9, 0)
Result: 3.0
Done.
---
Error: division by zero
Done.
else, an error goes through except. Both always end in finally.| Block | When it runs | Required? |
|---|---|---|
try | Always, first | Yes |
except | Only if a matching exception was raised in try | Need at least one except or a finally |
else | Only if try raised no exception | No (needs an except) |
finally | Always, last | No |
Real-world example: asking for a number until it's valid
Combine try/except with a while loop and break to keep asking until the user types something usable:
while True:
try:
guests = int(input("How many guests? "))
break
except ValueError:
print("Please type a whole number, like 4.")
print(f"Table for {guests} booked!")
How many guests? four
Please type a whole number, like 4.
How many guests? 4.5
Please type a whole number, like 4.
How many guests? 4
Table for 4 booked!
The user typed four, then 4.5, then 4. The break line is only reached when int() succeeds, so the loop ends exactly when the answer is valid.
Why you shouldn't use a bare except
A bare except is except: with no exception name. It catches everything, including your own typos:
try:
totl = 5
print(total)
except:
print("Something went wrong")
Something went wrong
The real problem is a NameError (the variable is spelled totl), but the message hides it completely. A bare except even catches you pressing Ctrl+C to stop a program. Name the exceptions you expect instead. If you truly need a catch-all, use except Exception as e: and print e so the problem is still visible.
⚠️ Be careful
Don't wrap your whole program in one giant try block. Put only the line or two that can fail inside try. Small try blocks make it obvious which line you're protecting and stop you from accidentally hiding bugs.
Common mistakes with try except
1. Catching the wrong exception type
int("abc") raises ValueError, not TypeError. If you're not sure which exception a line raises, run it once without try and read the last line of the traceback.
2. Putting else or finally in the wrong order
The order must be try, except, else, finally. Writing else before except is a SyntaxError.
3. Silently ignoring errors
try:
price = float("free")
except ValueError:
pass
This runs without complaint, but now price was never created, and your program fails later somewhere confusing. At least print a message or set a sensible default value.
4. Using a variable that was never assigned
If the try block fails before a variable is set, that variable doesn't exist in the except block or after it. Set a default first (result = None) or use the variable only in else.
Practice exercise
🏋️ Try it yourself
Write a function get_item(cart, position) that returns cart[position]. If the position doesn't exist, return "No item there". If the position isn't a whole number (for example "2"), return "Position must be a number". Test it with a cart of three items.
Show solution
def get_item(cart, position):
try:
return cart[position]
except IndexError:
return "No item there"
except TypeError:
return "Position must be a number"
cart = ["milk", "eggs", "bread"]
print(get_item(cart, 1))
print(get_item(cart, 7))
print(get_item(cart, "2"))
eggs
No item there
Position must be a number
What's next?
Now you can catch exceptions. Next, learn how to raise exceptions in Python yourself, so your own functions can refuse bad input with a clear error message.
Key takeaways
- Put risky code in a try block and recovery code in an except block so the program does not crash.
- Name the exception you expect, like except ValueError:, and use several except blocks or a tuple for different errors.
- Use except SomeError as e to get the exception object and print its message.
- The else block runs only when the try block raised no exception.
- The finally block always runs, whether or not an error happened, which makes it ideal for clean-up.
- Avoid bare except: and giant try blocks, because they hide real bugs.
Frequently asked questions
How does try except work in Python?
Python runs the code in the try block. If an exception is raised, it skips the rest of the try block and runs the first except block whose type matches. If nothing goes wrong, the except blocks are skipped.
Can you have multiple except blocks in Python?
Yes. Python checks them from top to bottom and runs only the first match. To handle several types the same way, list them in a tuple: except (ValueError, TypeError):.
What is the difference between else and finally in Python?
The else block runs only when the try block finished without an exception. The finally block always runs, whether there was an error or not.
Why is a bare except bad in Python?
A bare except: catches every exception, including typos like NameError and even Ctrl+C. It hides real bugs, so name the specific exceptions you expect instead.
How do I print the error message in Python?
Use except SomeError as e: and then print(e). For the exception type name, use type(e).__name__.
Does finally run if there is a return in try?
Yes. Even if the try block returns a value, Python runs the finally block before the function actually exits.