Real Programs
Exceptions
Handle errors gracefully with try, except, else and finally, read tracebacks, raise your own errors, and define custom exception classes.
When something goes wrong, Python raises an exception. If nothing handles it, the program stops and prints a traceback — read it from the bottom up: the last line names the error.
Python
marks = [80, 90]
print(marks[5])Output
Traceback (most recent call last):
File "main.py", line 2, in <module>
print(marks[5])
~~~~~^^^
IndexError: list index out of rangetry / except
Python
def ask_and_divide():
try:
n = int(input("Divide 100 by: "))
print("Result:", 100 / n)
except ValueError:
print("That was not a whole number.")
except ZeroDivisionError:
print("You cannot divide by zero.")
for _ in range(3):
ask_and_divide()Output
Divide 100 by: ten That was not a whole number. Divide 100 by: 0 You cannot divide by zero. Divide 100 by: 4 Result: 25.0
Sample input is includedTry it Yourself
else and finally
elseruns only if thetryblock raised no exception.finallyruns always — perfect for cleanup.
Python
def read_number(text):
try:
value = float(text)
except ValueError as e: # 'as e' gives the exception object
print(f" error: {e}")
return None
else:
print(" parsed fine")
return value
finally:
print(" (finished trying", repr(text) + ")")
print(read_number("3.5"))
print(read_number("abc"))Output
parsed fine (finished trying '3.5') 3.5 error: could not convert string to float: 'abc' (finished trying 'abc') None
Common built-in exceptions
| Exception | Raised when |
|---|---|
ValueError |
right type, wrong value: int("abc") |
TypeError |
wrong type: "5" + 5 |
ZeroDivisionError |
dividing by zero |
IndexError |
list index out of range |
KeyError |
missing dictionary key |
AttributeError |
missing attribute: None.upper() |
NameError |
using an undefined name |
FileNotFoundError |
opening a file that does not exist |
RecursionError |
recursion too deep |
Python
tests = [lambda: int("x"), lambda: "5" + 5, lambda: [1][3], lambda: {}["k"], lambda: undefined_name]
for t in tests:
try:
t()
except Exception as e: # catch any normal exception
print(f"{type(e).__name__:15} {e}")Output
ValueError invalid literal for int() with base 10: 'x' TypeError can only concatenate str (not "int") to str IndexError list index out of range KeyError 'k' NameError name 'undefined_name' is not defined
raise
Raise an exception yourself when input is invalid:
Python
def set_age(age):
if not isinstance(age, int):
raise TypeError("age must be an integer")
if age < 0 or age > 150:
raise ValueError(f"impossible age: {age}")
return age
for value in (21, -4, "twenty"):
try:
print("ok:", set_age(value))
except (TypeError, ValueError) as e:
print("rejected:", e)Output
ok: 21 rejected: impossible age: -4 rejected: age must be an integer
Custom exceptions
Python
class InsufficientBalance(Exception):
def __init__(self, needed):
super().__init__(f"need Rs {needed} more")
self.needed = needed
class Wallet:
def __init__(self, balance):
self.balance = balance
def pay(self, amount):
if amount > self.balance:
raise InsufficientBalance(amount - self.balance)
self.balance -= amount
w = Wallet(500)
for amount in (200, 450):
try:
w.pay(amount)
print(f"paid {amount}, balance {w.balance}")
except InsufficientBalance as e:
print("payment failed:", e, "| short by", e.needed)Output
paid 200, balance 300 payment failed: need Rs 150 more | short by 150
EAFP vs LBYL
Python style often prefers EAFP — "Easier to Ask Forgiveness than Permission" — try the operation and handle failure, rather than LBYL ("Look Before You Leap") with many if checks:
Python
config = {"theme": "dark"}
# LBYL
size = config["size"] if "size" in config else 12
# EAFP
try:
size = config["size"]
except KeyError:
size = 12
print(size, config.get("size", 12)) # get() is the simplest hereOutput
12 12
Test yourself
4 questions · pick an answer to check it instantly
- 1
When does the
elseblock of atrystatement run?elseholds code that should run only on success. - 2
Which exception does
int("12a")raise?The type (str) is acceptable toint(), but the value cannot be converted. - 3
What is printed?
Pythontry: print("A") x = 1 / 0 print("B") except ZeroDivisionError: print("C") finally: print("D")After the error, "B" is skipped; the handler prints C andfinallyprints D. - 4
How do you create a custom exception?
Custom exceptions are ordinary classes deriving fromException.