← View series: python tutorials
~/blog
Error Handling
Introduction
In this tutorial, you'll learn how to handle errors and exceptions in Python. Error handling allows your programs to deal with unexpected situations gracefully instead of crashing.
What You'll Learn
- What are exceptions
- The try-except block
- Multiple except blocks
- The else and finally clauses
- Raising exceptions
- Creating custom exceptions
What are Exceptions?
Exceptions are events that disrupt the normal flow of a program. They occur when something goes wrong (like dividing by zero or accessing a file that doesn't exist).
Common Exceptions
| Exception | Description |
|---|---|
ZeroDivisionError | Dividing by zero |
TypeError | Wrong data type |
ValueError | Wrong value |
FileNotFoundError | File doesn't exist |
IndexError | List index out of range |
KeyError | Dictionary key not found |
Example of an Exception
# This will cause an error
result = 10 / 0Output:
Traceback (most recent call last):
File "main.py", line 1, in <module>
result = 10 / 0
ZeroDivisionError: division by zero
The try-except Block
Handle exceptions using try-except:
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")Basic Structure
try:
# Code that might cause an error
result = 10 / 0
except ZeroDivisionError:
# What to do if error occurs
print("Cannot divide by zero!")Catching the Exception Message
try:
result = 10 / 0
except ZeroDivisionError as e:
print(f"Error: {e}")Multiple Except Blocks
Handle different types of exceptions:
try:
num = int(input("Enter a number: "))
result = 10 / num
except ValueError:
print("That's not a valid number!")
except ZeroDivisionError:
print("Cannot divide by zero!")Catch All Exceptions
try:
# Risky code
result = 10 / 0
except Exception as e:
print(f"Something went wrong: {e}")⚠️ Warning: Catching all exceptions with bare
exceptis generally discouraged as it can hide real problems.
The else Clause
The else block runs only if no exceptions occur:
try:
number = int(input("Enter a number: "))
result = 10 / number
except ValueError:
print("Invalid input!")
except ZeroDivisionError:
print("Cannot divide by zero!")
else:
print(f"Result: {result}")
print("Success! No errors occurred.")The finally Clause
The finally block always runs, whether there's an error or not:
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("File not found!")
finally:
print("This always runs.")
# Good for cleanup
if 'file' in locals():
file.close()When to Use finally
- Closing files
- Releasing resources
- Cleaning up connections
Raising Exceptions
You can raise exceptions intentionally:
def divide(a, b):
if b == 0:
raise ValueError("Divisor cannot be zero!")
return a / b
try:
result = divide(10, 0)
except ValueError as e:
print(f"Error: {e}")Practical Examples
Example 1: Safe Division Function
def safe_divide(a, b):
"""Divide two numbers, handling errors"""
try:
result = a / b
return result
except ZeroDivisionError:
return "Error: Cannot divide by zero"
except TypeError:
return "Error: Invalid types for division"
# Test
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # Error: Cannot divide by zero
print(safe_divide("10", 2)) # Error: Invalid types for divisionExample 2: Password Validator
def validate_password(password):
"""Validate password meets requirements"""
if len(password) < 8:
raise ValueError("Password must be at least 8 characters")
if not any(c.isupper() for c in password):
raise ValueError("Password must contain uppercase letter")
if not any(c.islower() for c in password):
raise ValueError("Password must contain lowercase letter")
if not any(c.isdigit() for c in password):
raise ValueError("Password must contain a number")
return "Password is valid"
# Test
passwords = ["short", "alllowercase", "ALLUPPERCASE", "NoNumbers!", "Valid1Pass"]
for pwd in passwords:
try:
result = validate_password(pwd)
print(f"'{pwd}': {result}")
except ValueError as e:
print(f"'{pwd}': Error - {e}")Example 3: Reading User Input with Validation
def get_positive_number():
"""Get a positive number from user"""
while True:
try:
number = float(input("Enter a positive number: "))
if number <= 0:
print("Please enter a positive number!")
continue
return number
except ValueError:
print("Invalid input. Please enter a number.")
# Use it
num = get_positive_number()
print(f"You entered: {num}")Custom Exceptions
Create your own exception classes:
# Define custom exception
class InvalidAgeError(Exception):
def __init__(self, age, message="Age must be between 0 and 150"):
self.age = age
self.message = message
super().__init__(self.message)
def set_age(age):
if age < 0 or age > 150:
raise InvalidAgeError(age)
return age
# Use it
try:
set_age(200)
except InvalidAgeError as e:
print(f"Invalid age: {e.age}")
print(e.message)Exception Hierarchy
class ValidationError(Exception):
"""Base exception for validation errors"""
pass
class InvalidEmailError(ValidationError):
"""Raised when email is invalid"""
pass
class InvalidPhoneError(ValidationError):
"""Raised when phone is invalid"""
pass
def validate_email(email):
if "@" not in email:
raise InvalidEmailError(f"Invalid email: {email}")
def validate_phone(phone):
if len(phone) < 10:
raise InvalidPhoneError(f"Invalid phone: {phone}")
# Catch all validation errors
try:
validate_email("invalid-email")
validate_phone("123")
except ValidationError as e:
print(f"Validation failed: {e}")Best Practices
| Practice | Why |
|---|---|
| Be specific with exceptions | Catch only what you can handle |
| Don't hide exceptions | At least log the error |
| Use finally for cleanup | Ensure resources are released |
| Don't use bare except | Catch specific exceptions |
| Include helpful messages | Make debugging easier |
Summary
In this tutorial, you learned:
- ✅ What are exceptions
- ✅ The try-except block
- ✅ Multiple except blocks
- ✅ The else and finally clauses
- ✅ Raising exceptions
- ✅ Creating custom exceptions
🧑💻 Practice Exercise
Create a program that:
- Takes two numbers and an operator (+, -, *, /) as input
- Performs the calculation using try-except
- Handles: ValueError (invalid input), ZeroDivisionError, and any other errors
- Uses finally to always print "Calculation complete"
Click to see solution
pythondef calculator():
"""Simple calculator with error handling"""
try:
# Get input
num1 = float(input("Enter first number: "))
num2 = float(input("Enter second number: "))
operator = input("Enter operator (+, -, *, /): ")
# Perform calculation
if operator == "+":
result = num1 + num2
elif operator == "-":
result = num1 - num2
elif operator == "*":
result = num1 * num2
elif operator == "/":
result = num1 / num2
else:
raise ValueError(f"Unknown operator: {operator}")
print(f"Result: {num1} {operator} {num2} = {result}")
except ValueError as e:
print(f"Input Error: {e}")
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
print("Calculation complete.")
# Run the calculator
calculator()
Sample Output:
Enter first number: 10
Enter second number: 2
Enter operator (+, -, *, /): /
Result: 10.0 / 2.0 = 5.0
Calculation complete.
def calculator():
"""Simple calculator with error handling"""
try:
# Get input
num1 = float(input("Enter first number: "))
num2 = float(input("Enter second number: "))
operator = input("Enter operator (+, -, *, /): ")
# Perform calculation
if operator == "+":
result = num1 + num2
elif operator == "-":
result = num1 - num2
elif operator == "*":
result = num1 * num2
elif operator == "/":
result = num1 / num2
else:
raise ValueError(f"Unknown operator: {operator}")
print(f"Result: {num1} {operator} {num2} = {result}")
except ValueError as e:
print(f"Input Error: {e}")
except ZeroDivisionError:
print("Error: Cannot divide by zero!")
except Exception as e:
print(f"An unexpected error occurred: {e}")
finally:
print("Calculation complete.")
# Run the calculator
calculator()What's Next
In the next tutorial, we'll learn about File Operations - how to read and write files in Python.