Python course menu
Python Exceptions: try, except, else, finally and raise
Learn Python exception handling: read tracebacks, catch errors with try/except, handle specific exceptions, use else and finally, access the error message, raise your own exceptions, and create custom exception classes.
On this page
Things go wrong in real programs: a user types letters instead of a number, a file is missing, a website does not respond. When Python hits an error it cannot handle, it raises an exception, and if nothing catches it, the program stops. Exception handling lets your program respond sensibly instead of crashing.
An unhandled exception#
print(10 / 0)ZeroDivisionError: division by zeroThe last line of the traceback names the exception type (ZeroDivisionError) and a message.
try and except#
Put code that might fail in a try block, and the response in an except block:
try:
result = 10 / 0
except ZeroDivisionError:
print("You can't divide by zero")
print("Program continues")You can't divide by zero
Program continuesWhen the error happens, Python jumps straight to the matching except block, and the program keeps running afterwards.
A practical example: user input#
try:
age = int(input("Age: "))
print(f"Next year: {age + 1}")
except ValueError:
print("Please enter a whole number")Age: abc
Please enter a whole numberCommon exception types#
data = {"name": "Asha"}
try:
print(data["email"])
except KeyError as e:
print("Missing key:", e)
items = [1, 2]
try:
items[5]
except IndexError as e:
print("IndexError:", e)Missing key: 'email'
IndexError: list index out of rangeGetting the error message#
except SomeError as e stores the exception object in e:
try:
int("xyz")
except ValueError as e:
print("Error:", e)
print(type(e).__name__)Error: invalid literal for int() with base 10: 'xyz'
ValueErrorSeveral excepts, else and finally#
def safe_divide(a, b):
try:
result = a / b
except ZeroDivisionError:
return None
except TypeError:
return "numbers only"
else:
return round(result, 2) # only if no exception happened
finally:
print(f"divide({a!r}, {b!r}) attempted") # always runs
print(safe_divide(10, 3))
print(safe_divide(1, 0))
print(safe_divide("a", 2))divide(10, 3) attempted
3.33
divide(1, 0) attempted
None
divide('a', 2) attempted
numbers onlyYou can also catch several types in one block: except (ValueError, TypeError):.
Keep going after bad data#
Handling errors inside a loop lets you skip bad items and process the rest:
values = ["10", "x", "30", "", "5"]
total = 0
bad = []
for v in values:
try:
total += int(v)
except ValueError:
bad.append(v)
print(total, bad)45 ['x', '']Raising exceptions#
Your own functions can raise exceptions when they receive invalid input:
def withdraw(balance, amount):
if amount > balance:
raise ValueError(f"Insufficient funds: balance {balance}, requested {amount}")
return balance - amount
print(withdraw(500, 200))
try:
withdraw(500, 900)
except ValueError as e:
print(e)300
Insufficient funds: balance 500, requested 900Raising an exception is often better than returning a special value like None, because the caller cannot accidentally ignore it.
Custom exceptions#
Define your own exception type by creating a class that inherits from Exception:
class InsufficientFundsError(Exception):
pass
try:
raise InsufficientFundsError("Balance too low")
except InsufficientFundsError as e:
print(f"{type(e).__name__}: {e}")InsufficientFundsError: Balance too lowCustom types let callers catch exactly the errors they expect. You will learn about classes in OOP.
Common mistakes#
Practice#
Practice exercise
Write read_number(text) that returns the text converted to a float, or None if it is not a valid number. Test it on "3.5", "-2", "abc" and "1e3".
Show hint
Return float(text) inside try, and None in except ValueError.
Show solution
def read_number(text):
try:
return float(text)
except ValueError:
return None
for t in ["3.5", "-2", "abc", "1e3"]:
print(t, read_number(t))3.5 3.5
-2 -2.0
abc None
1e3 1000.0"1e3" is scientific notation for 1,000, which float() understands.
Key takeaway#
Finished this lesson?