What Are Exceptions?
Exceptions are errors that occur during program execution. Without handling, they crash your program with a traceback message. Error handling lets you anticipate problems and respond gracefully.
# This crashes the program
number = int("hello") # ValueError: invalid literal for int()
# This file might not exist
file = open("missing.txt") # FileNotFoundError
Try/Except Basics
Wrap risky code in a try block and handle errors in except:
try:
number = int(input("Enter a number: "))
print(f"You entered: {number}")
except ValueError:
print("That's not a valid number!")
If the code in try raises a ValueError, Python jumps to the
except block instead of crashing.
Common Exception Types
# ValueError — wrong value type
int("hello")
# TypeError — wrong operation for type
"hello" + 5
# ZeroDivisionError — division by zero
10 / 0
# FileNotFoundError — file doesn't exist
open("nonexistent.txt")
# KeyError — dictionary key not found
d = {"a": 1}
d["b"]
# IndexError — list index out of range
lst = [1, 2, 3]
lst[10]
# NameError — variable not defined
print(undefined_var)
# AttributeError — object has no such attribute
"hello".nonexistent_method()
Catching Multiple Exceptions
# Separate handlers for different errors
try:
value = int(input("Enter a number: "))
result = 100 / value
print(f"Result: {result}")
except ValueError:
print("Please enter a valid number.")
except ZeroDivisionError:
print("Cannot divide by zero!")
# Catch multiple types in one handler
try:
data = process_input()
except (ValueError, TypeError, KeyError) as e:
print(f"Input error: {e}")
The Full Try/Except Structure
try:
file = open("data.txt", "r")
content = file.read()
number = int(content)
except FileNotFoundError:
print("File not found!")
number = 0
except ValueError:
print("File doesn't contain a valid number!")
number = 0
else:
# Runs ONLY if no exception occurred
print(f"Successfully read number: {number}")
finally:
# ALWAYS runs, whether or not an exception occurred
print("Operation complete.")
else runs only on success — use it for code that should only execute
if no errors occurred. finally always runs — use it for cleanup tasks
like closing connections or releasing resources.
Accessing Exception Details
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error type: {type(e).__name__}") # ZeroDivisionError
print(f"Error message: {e}") # division by zero
Raising Exceptions
Use raise to throw your own exceptions:
def set_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age seems unrealistic")
return age
try:
user_age = set_age(-5)
except ValueError as e:
print(f"Invalid age: {e}") # Invalid age: Age cannot be negative
Custom Exception Classes
class InsufficientFundsError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(
f"Cannot withdraw ${amount}. Balance: ${balance}"
)
def withdraw(balance, amount):
if amount > balance:
raise InsufficientFundsError(balance, amount)
return balance - amount
try:
new_balance = withdraw(100, 150)
except InsufficientFundsError as e:
print(e) # Cannot withdraw $150. Balance: $100
print(e.balance) # 100
print(e.amount) # 150
Best Practices
except:
Catching all exceptions hides bugs and makes debugging impossible. Always catch specific exception types.
# BAD — catches everything, hides bugs
try:
do_something()
except:
pass
# BAD — too broad
try:
do_something()
except Exception:
pass
# GOOD — catch specific errors
try:
do_something()
except (ValueError, KeyError) as e:
print(f"Known error: {e}")
# GOOD — catch broad only when logging
try:
do_something()
except Exception as e:
print(f"Unexpected error: {e}")
raise # Re-raise so the error isn't silently swallowed
Practical Examples
Safe User Input
def get_integer(prompt, min_val=None, max_val=None):
while True:
try:
value = int(input(prompt))
if min_val is not None and value < min_val:
print(f"Must be at least {min_val}")
continue
if max_val is not None and value > max_val:
print(f"Must be at most {max_val}")
continue
return value
except ValueError:
print("Please enter a valid number.")
age = get_integer("Enter your age: ", min_val=0, max_val=150)
Safe File Reader
def read_config(filename):
try:
with open(filename, "r") as file:
config = {}
for line in file:
line = line.strip()
if "=" in line and not line.startswith("#"):
key, value = line.split("=", 1)
config[key.strip()] = value.strip()
return config
except FileNotFoundError:
print(f"Config file '{filename}' not found, using defaults.")
return {}
except PermissionError:
print(f"No permission to read '{filename}'.")
return {}
settings = read_config("app.conf")
Summary
try/exceptcatches and handles exceptions instead of crashing- Always catch specific exception types, not bare
except: elseruns on success;finallyalways runs (cleanup)raisethrows exceptions; create custom classes for domain-specific errors- Use
as eto access the error message and details - Common types:
ValueError,TypeError,FileNotFoundError,KeyError,IndexError
Your programs are now resilient to unexpected inputs and failures. Next up: classes and objects — the foundation of object-oriented programming in Python.