Advanced Error Handling

Python Error HandlingFree Lesson

Advertisement

Advanced Error Handling

Custom exceptions, exception chaining, context managers, and error patterns.

Overview

Master advanced error handling techniques.

Custom Exceptions

# Base exception
class AppError(Exception):
    """Base application exception"""
    def __init__(self, message, code=None):
        super().__init__(message)
        self.code = code
        self.message = message

# Specific exceptions
class ValidationError(AppError):
    def __init__(self, field, message):
        super().__init__(f"Validation error: {field} - {message}")
        self.field = field

class NotFoundError(AppError):
    def __init__(self, resource, identifier):
        super().__init__(f"{resource} not found: {identifier}")
        self.resource = resource
        self.identifier = identifier

# Usage
def validate_age(age):
    if not isinstance(age, int):
        raise ValidationError("age", "Must be integer")
    if age < 0 or age > 150:
        raise ValidationError("age", "Must be between 0 and 150")
    return True

try:
    validate_age(200)
except ValidationError as e:
    print(f"{e.field}: {e.message}")

Exception Chaining

# Implicit chaining
def process_file(filename):
    try:
        with open(filename) as f:
            data = json.load(f)
    except FileNotFoundError as e:
        raise AppError(f"Cannot process {filename}") from e

# Explicit chaining
def fetch_data(url):
    try:
        response = requests.get(url)
        return response.json()
    except requests.RequestException as e:
        raise AppError("Failed to fetch data") from e

Context Managers

# Class-based
class DatabaseConnection:
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.connection = None
    
    def __enter__(self):
        print(f"Connecting to {self.host}:{self.port}")
        self.connection = "Connected"
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        print("Closing connection")
        self.connection = None
        return False

# Usage
with DatabaseConnection("localhost", 5432) as db:
    print(db.connection)

# Function-based context manager
from contextlib import contextmanager

@contextmanager
def managed_resource():
    resource = "acquired"
    try:
        yield resource
    except Exception as e:
        print(f"Error: {e}")
    finally:
        print("Releasing resource")

with managed_resource() as r:
    print(f"Using {r}")

Error Patterns

# Retry pattern
import time

def retry(max_attempts=3, delay=1):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for attempt in range(max_attempts):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if attempt == max_attempts - 1:
                        raise
                    time.sleep(delay)
        return wrapper
    return decorator

@retry(max_attempts=3, delay=1)
def unreliable_function():
    import random
    if random.random() < 0.5:
        raise ValueError("Random failure")
    return "Success"

# Fallback pattern
def with_fallback(primary_func, fallback_func):
    def wrapper(*args, **kwargs):
        try:
            return primary_func(*args, **kwargs)
        except Exception:
            return fallback_func(*args, **kwargs)
    return wrapper

Practice

Create a custom exception hierarchy for an e-commerce application.

Advertisement

Need Expert Python Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement