Managing Exceptions and Debugging
# ValueError: Wrong value for the data type
int("abc")
float("hello")
# TypeError: Wrong data type
"hello" + 5
len(42)
# IndexError: List index out of range
my_list = [1, 2, 3]
my_list[10]
# KeyError: Dictionary key doesn't exist
my_dict = {"name": "Alice"}
my_dict["age"]
# FileNotFoundError: File doesn't exist
open("nonexistent.txt")Basic syntax:
Multiple except blocks:
else: Runs when no exception occurs
Capture exception details:
Using the raise statement:
Creating your own exception types:
class InvalidEmailError(Exception):
"""Raised when an invalid email address is provided"""
pass
class PasswordTooWeakError(Exception):
"""Raised when password doesn't meet requirements"""
def __init__(self, message, min_length=8):
self.message = message
self.min_length = min_length
super().__init__(self.message)
def validate_password(password):
if len(password) < 8:
raise PasswordTooWeakError(
"Password too short",
min_length=8
)Safe file operations:
def read_file_safely(filename):
try:
with open(filename, 'r') as file:
return file.read()
except FileNotFoundError:
print(f"File '{filename}' not found!")
return None
except PermissionError:
print(f"No permission to read '{filename}'!")
return None
except Exception as e:
print(f"Error reading file: {e}")
return None
content = read_file_safely("data.txt")
if content:
print("File read successfully!")Robust input handling:
def get_integer_input(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"Value must be at least {min_val}")
continue
if max_val is not None and value > max_val:
print(f"Value must be at most {max_val}")
continue
return value
except ValueError:
print("Please enter a valid integer!")
except KeyboardInterrupt:
print("\nOperation cancelled by user.")
return None
age = get_integer_input("Enter your age (0-120): ", 0, 120)Using print statements for debugging:
def calculate_average(numbers):
print(f"Debug: Input numbers = {numbers}") # Debug info
if not numbers:
print("Debug: Empty list detected") # Debug info
return 0
total = sum(numbers)
count = len(numbers)
average = total / count
print(f"Debug: total={total}, count={count}") # Debug info
return averageExceptionfinally or with statementsclass Calculator:
def safe_divide(self, a, b):
try:
# Validate inputs
if not isinstance(a, (int, float)):
raise TypeError("First argument must be a number")
if not isinstance(b, (int, float)):
raise TypeError("Second argument must be a number")
if b == 0:
raise ZeroDivisionError("Cannot divide by zero")
result = a / b
return {"success": True, "result": result}
except (TypeError, ZeroDivisionError) as e:
return {"success": False, "error": str(e)}
except Exception as e:
return {"success": False, "error": f"Unexpected error: {e}"}
# Usage
calc = Calculator()
result = calc.safe_divide(10, 2)
if result["success"]:
print(f"Result: {result['result']}")
else:
print(f"Error: {result['error']}")Challenge 1: Safe Number Converter
def safe_int_convert(value):
"""
Convert a value to integer safely.
Return (success: bool, result: int or error_message: str)
"""
# Your code here
pass
# Test cases
print(safe_int_convert("123")) # Should work
print(safe_int_convert("12.34")) # Should handle float strings
print(safe_int_convert("hello")) # Should handle invalid inputSafe Number Converter:
def safe_int_convert(value):
try:
# Try direct conversion first
return True, int(value)
except ValueError:
try:
# Try converting float string to int
return True, int(float(value))
except ValueError:
return False, f"Cannot convert '{value}' to integer"
except Exception as e:
return False, f"Unexpected error: {e}"The with statement for automatic cleanup:
# Without context manager
try:
file = open("data.txt", "r")
content = file.read()
# Process content
except FileNotFoundError:
print("File not found!")
finally:
file.close() # Must remember to close
# With context manager (better!)
try:
with open("data.txt", "r") as file:
content = file.read()
# File automatically closed when leaving 'with' block
except FileNotFoundError:
print("File not found!")class DatabaseConnection:
def __enter__(self):
print("Connecting to database...")
self.connection = "database_connection"
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
print("Closing database connection...")
if exc_type:
print(f"An error occurred: {exc_val}")
return False # Don't suppress exceptions
# Usage
with DatabaseConnection() as db:
print("Working with database...")
# Connection automatically closed when doneDonβt do this:
# Bad: Catching all exceptions without handling
try:
risky_operation()
except:
pass # Silently ignoring errors
# Bad: Too broad exception handling
try:
specific_operation()
except Exception:
print("Something went wrong") # Not helpful
# Bad: Using exceptions for control flow
try:
value = my_dict["key"]
except KeyError:
value = "default" # Use .get() insteadtry-except blocks to catch and handle exceptionsfinally for cleanup code that must always runComing up next: - Working with modules and packages - Object-oriented programming concepts - File I/O and data persistence
Practice more: - Build a robust file processor with error handling - Create a user input validator for a registration form - Implement a safe calculator with comprehensive error handling
Python Tutorial