06_error_handling.py
Python/01_beginner_level/06_error_handling.py
"""
Error Handling - Making Programs Robust
This file contains all the example code from the Error Handling lesson.
"""
# Understanding Errors and Exceptions
# Common exceptions and when they occur (commented out to avoid actual errors)
# ZeroDivisionError
# result = 10 / 0 # This would raise ZeroDivisionError
# ValueError
# number = int("abc") # This would raise ValueError
# TypeError
# result = "hello" + 5 # This would raise TypeError
# IndexError
# my_list = [1, 2, 3]
# value = my_list[5] # This would raise IndexError
# KeyError
# my_dict = {"a": 1, "b": 2}
# value = my_dict["c"] # This would raise KeyError
# FileNotFoundError
# with open("nonexistent.txt", "r") as file: # This would raise FileNotFoundError
# content = file.read()
# AttributeError
# my_string = "hello"
# my_string.append("world") # This would raise AttributeError
# Basic Exception Handling (try/except)
# Simple try/except Block
def safe_divide(a, b):
"""Safely divide two numbers."""
try:
result = a / b
return result
except ZeroDivisionError:
return "Error: Cannot divide by zero"
print("=== Basic Exception Handling ===")
# Test the function
print(safe_divide(10, 2)) # Output: 5.0
print(safe_divide(10, 0)) # Output: Error: Cannot divide by zero
# Handling Multiple Exceptions
def get_user_input():
"""Get and validate user input."""
try:
age = int(input("Enter your age: "))
return age
except ValueError:
print("Error: Please enter a valid number")
return None
except KeyboardInterrupt:
print("\nOperation cancelled by user")
return None
# Test the function (commented out to avoid interactive input)
# age = get_user_input()
# if age is not None:
# print(f"You are {age} years old")
# Catching Multiple Exception Types
def process_data(data, index):
"""Process data with multiple possible errors."""
try:
value = data[index]
result = value * 2
return result
except (IndexError, TypeError):
print("Error: Invalid index or data type")
return None
except ValueError:
print("Error: Invalid value")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
print("\n=== Multiple Exception Types ===")
# Test the function
numbers = [1, 2, 3, 4, 5]
print(process_data(numbers, 2)) # Output: 6
print(process_data(numbers, 10)) # Output: Error: Invalid index or data type
# Advanced Exception Handling
# try/except/else Block
def read_file_safely(filename):
"""Read a file with proper error handling."""
try:
with open(filename, 'r') as file:
content = file.read()
except FileNotFoundError:
print(f"Error: File '{filename}' not found")
return None
except PermissionError:
print(f"Error: Permission denied to read '{filename}'")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
else:
print("File read successfully")
return content
# Test the function
print("\n=== try/except/else ===")
content = read_file_safely("nonexistent.txt") # This will show error message
if content:
print(f"Content length: {len(content)}")
# try/except/finally Block
def process_file(filename):
"""Process a file with cleanup in finally block."""
file = None
try:
file = open(filename, 'r')
content = file.read()
print(f"File content: {content}")
return content
except FileNotFoundError:
print(f"Error: File '{filename}' not found")
return None
except Exception as e:
print(f"Error processing file: {e}")
return None
finally:
if file:
file.close()
print("File closed successfully")
# Test the function
print("\n=== try/except/finally ===")
result = process_file("nonexistent.txt")
# Using with Statement (Context Manager)
def read_file_with_context(filename):
"""Read file using context manager (recommended approach)."""
try:
with open(filename, 'r') as file:
content = file.read()
return content
except FileNotFoundError:
print(f"Error: File '{filename}' not found")
return None
except Exception as e:
print(f"Error reading file: {e}")
return None
# Test the function
print("\n=== Context Manager ===")
content = read_file_with_context("nonexistent.txt")
if content:
print(f"Content: {content}")
# Custom Exceptions
class CustomError(Exception):
"""Base class for custom exceptions."""
pass
class ValidationError(CustomError):
"""Raised when validation fails."""
def __init__(self, message, field=None):
self.message = message
self.field = field
super().__init__(self.message)
class InsufficientFundsError(CustomError):
"""Raised when account has insufficient funds."""
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
self.message = f"Insufficient funds. Balance: {balance}, Required: {amount}"
super().__init__(self.message)
print("\n=== Custom Exceptions ===")
# Using custom exceptions
def validate_age(age):
"""Validate age input."""
if not isinstance(age, int):
raise ValidationError("Age must be an integer", "age")
if age < 0:
raise ValidationError("Age cannot be negative", "age")
if age > 150:
raise ValidationError("Age cannot exceed 150", "age")
return True
def withdraw_money(balance, amount):
"""Withdraw money from account."""
if amount <= 0:
raise ValidationError("Withdrawal amount must be positive")
if balance < amount:
raise InsufficientFundsError(balance, amount)
return balance - amount
# Test custom exceptions
try:
validate_age(-5)
except ValidationError as e:
print(f"Validation error: {e.message} (Field: {e.field})")
try:
new_balance = withdraw_money(100, 150)
except InsufficientFundsError as e:
print(f"Transaction failed: {e.message}")
# Practical Examples
# Example 1: Robust Calculator
def robust_calculator():
"""A calculator with comprehensive error handling."""
def safe_divide(a, b):
"""Safely divide two numbers."""
try:
return a / b
except ZeroDivisionError:
raise ValueError("Cannot divide by zero")
except TypeError:
raise ValueError("Both arguments must be numbers")
def safe_power(base, exponent):
"""Safely calculate power."""
try:
result = base ** exponent
if not isinstance(result, (int, float)):
raise ValueError("Result is not a valid number")
return result
except (OverflowError, ZeroDivisionError):
raise ValueError("Result is too large or invalid")
except TypeError:
raise ValueError("Both arguments must be numbers")
while True:
print("\n=== Robust Calculator ===")
print("1. Add")
print("2. Subtract")
print("3. Multiply")
print("4. Divide")
print("5. Power")
print("6. Square root")
print("7. Exit")
choice = input("Enter your choice: ")
if choice == "7":
print("Goodbye!")
break
if choice in ["1", "2", "3", "4", "5", "6"]:
try:
if choice == "6": # Square root only needs one number
num = float(input("Enter number: "))
else:
num1 = float(input("Enter first number: "))
num2 = float(input("Enter second number: "))
if choice == "1":
result = num1 + num2
elif choice == "2":
result = num1 - num2
elif choice == "3":
result = num1 * num2
elif choice == "4":
result = safe_divide(num1, num2)
elif choice == "5":
result = safe_power(num1, num2)
elif choice == "6":
if num < 0:
raise ValueError("Cannot calculate square root of negative number")
result = num ** 0.5
print(f"Result: {result}")
except ValueError as e:
print(f"Error: {e}")
except KeyboardInterrupt:
print("\nOperation cancelled by user")
except Exception as e:
print(f"Unexpected error: {e}")
else:
print("Invalid choice!")
# Example 2: File Processing with Error Handling
def file_processor():
"""Process files with comprehensive error handling."""
def read_file(filename):
"""Read file content safely."""
try:
with open(filename, 'r', encoding='utf-8') as file:
return file.read()
except FileNotFoundError:
raise FileNotFoundError(f"File '{filename}' not found")
except PermissionError:
raise PermissionError(f"Permission denied to read '{filename}'")
except UnicodeDecodeError:
raise UnicodeDecodeError(f"Cannot decode file '{filename}'")
except Exception as e:
raise Exception(f"Unexpected error reading '{filename}': {e}")
def write_file(filename, content):
"""Write content to file safely."""
try:
with open(filename, 'w', encoding='utf-8') as file:
file.write(content)
return True
except PermissionError:
raise PermissionError(f"Permission denied to write '{filename}'")
except Exception as e:
raise Exception(f"Unexpected error writing '{filename}': {e}")
def process_text_file(filename):
"""Process a text file with various operations."""
try:
# Read file
content = read_file(filename)
# Process content
lines = content.split('\n')
word_count = len(content.split())
char_count = len(content)
# Create report
report = f"""
File Analysis Report for: {filename}
================================
Lines: {len(lines)}
Words: {word_count}
Characters: {char_count}
First 100 characters: {content[:100]}...
"""
# Write report
report_filename = filename.replace('.txt', '_report.txt')
write_file(report_filename, report)
print(f"File processed successfully!")
print(f"Report saved as: {report_filename}")
except (FileNotFoundError, PermissionError, UnicodeDecodeError) as e:
print(f"File error: {e}")
except Exception as e:
print(f"Processing error: {e}")
# Interactive file processor
while True:
print("\n=== File Processor ===")
print("1. Process text file")
print("2. Exit")
choice = input("Enter your choice: ")
if choice == "1":
filename = input("Enter filename (e.g., example.txt): ")
process_text_file(filename)
elif choice == "2":
print("Goodbye!")
break
else:
print("Invalid choice!")
# Example 3: Data Validation System
class ValidationError(Exception):
"""Custom exception for validation errors."""
def __init__(self, message, field=None):
self.message = message
self.field = field
super().__init__(self.message)
def validate_email(email):
"""Validate email format."""
import re
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+[\.[a-zA-Z]{2}]+$' # Regular expression
# conie12313@gmail.com.hk
if not re.match(pattern, email):
raise ValidationError("Invalid email format", "email")
return True
def validate_phone(phone):
"""Validate phone number format."""
import re
# Remove all non-digit characters
digits_only = re.sub(r'\D', '', phone) # +1 (234) 567-8901
if len(digits_only) != 10:
raise ValidationError("Phone number must have exactly 10 digits", "phone")
return True
def validate_age(age):
"""Validate age."""
try:
age = int(age)
if age < 0:
raise ValidationError("Age cannot be negative", "age")
if age > 150:
raise ValidationError("Age cannot exceed 150", "age")
return True
except ValueError:
raise ValidationError("Age must be a number", "age")
def user_registration():
"""User registration with comprehensive validation."""
user_data = {}
print("=== User Registration ===")
# Name validation
while True:
try:
name = input("Enter full name: ").strip()
if not name or len(name) < 2:
raise ValidationError("Name must be at least 2 characters long", "name")
if not name.replace(" ", "").isalpha():
raise ValidationError("Name can only contain letters and spaces", "name")
user_data['name'] = name
break
except ValidationError as e:
print(f"Error: {e.message}")
# Email validation
while True:
try:
email = input("Enter email: ").strip()
validate_email(email)
user_data['email'] = email
break
except ValidationError as e:
print(f"Error: {e.message}")
# Phone validation
while True:
try:
phone = input("Enter phone number: ").strip()
validate_phone(phone)
user_data['phone'] = phone
break
except ValidationError as e:
print(f"Error: {e.message}")
# Age validation
while True:
try:
age = input("Enter age: ").strip()
validate_age(age)
user_data['age'] = int(age)
break
except ValidationError as e:
print(f"Error: {e.message}")
# Password validation
while True:
try:
password = input("Enter password: ")
if len(password) < 8:
raise ValidationError("Password must be at least 8 characters long", "password")
if not any(c.isupper() for c in password):
raise ValidationError("Password must contain at least one uppercase letter", "password")
if not any(c.islower() for c in password):
raise ValidationError("Password must contain at least one lowercase letter", "password")
if not any(c.isdigit() for c in password):
raise ValidationError("Password must contain at least one digit", "password")
confirm_password = input("Confirm password: ")
if password != confirm_password:
raise ValidationError("Passwords do not match", "password")
user_data['password'] = password
break
except ValidationError as e:
print(f"Error: {e.message}")
print("\nRegistration successful!")
print(f"User data: {user_data}")
return user_data
# Best Practices Examples
print("\n=== Best Practices ===")
# 1. Specific Exception Handling
def specific_error_handling():
"""Demonstrate specific exception handling."""
my_dict = {"a": 1, "b": 2}
# Good: Specific exception handling
try:
value = my_dict["c"]
except KeyError:
print("Key not found")
# Avoid: Catching all exceptions (commented out)
# try:
# value = my_dict["c"]
# except Exception: # Too broad
# print("Something went wrong")
specific_error_handling()
# 2. Meaningful Error Messages
def divide_numbers(a, b):
"""Divide two numbers with meaningful error messages."""
try:
return a / b
except ZeroDivisionError:
raise ValueError(f"Cannot divide {a} by zero")
except TypeError:
raise TypeError(f"Both arguments must be numbers, got {type(a)} and {type(b)}")
try:
result = divide_numbers(10, "2")
except (ValueError, TypeError) as e:
print(f"Error: {e}")
# 3. Logging Errors
import logging
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def process_data(data):
"""Process data with logging."""
try:
result = data * 2
logging.info(f"Data processed successfully: {result}")
return result
except Exception as e:
logging.error(f"Error processing data: {e}")
raise
# Test logging
try:
process_data("hello")
except Exception as e:
print(f"Caught error: {e}")
# Uncomment to run any of the interactive examples:
# robust_calculator()
# file_processor()
# user_registration()
相關文章
01_getting_started.py
01_getting_started.py — python source code from the Python learning materials (Python/01_beginner_level/01_getting_started.py).
閱讀文章 →02_core_syntax.py
02_core_syntax.py — python source code from the Python learning materials (Python/01_beginner_level/02_core_syntax.py).
閱讀文章 →03_control_flow.py
03_control_flow.py — python source code from the Python learning materials (Python/01_beginner_level/03_control_flow.py).
閱讀文章 →04_data_structures.py
04_data_structures.py — python source code from the Python learning materials (Python/01_beginner_level/04_data_structures.py).
閱讀文章 →05_functions.py
05_functions.py — python source code from the Python learning materials (Python/01_beginner_level/05_functions.py).
閱讀文章 →exercise.py
exercise.py — python source code from the Python learning materials (Python/01_beginner_level/exercise.py).
閱讀文章 →