Lesson 12 of 20

Functions & Classes

Error Handling

3 min read

Robust error handling is critical for AI applications. APIs fail, rate limits hit, and responses can be malformed. Learn to handle these gracefully.

Try-Except Basics

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")
    result = 0

Catching Multiple Exceptions

import json

def parse_response(text):
    try:
        data = json.loads(text)
        return data["content"]
    except json.JSONDecodeError:
        print("Invalid JSON response")
        return None
    except KeyError:
        print("Missing 'content' field")
        return None

The Full Try-Except-Else-Finally

def fetch_data(url):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
    except requests.Timeout:
        print("Request timed out")
        return None
    except requests.HTTPError as e:
        print(f"HTTP error: {e}")
        return None
    else:
        # Runs only if no exception occurred
        print("Request successful!")
        return response.json()
    finally:
        # Always runs (cleanup)
        print("Request completed")

Accessing Exception Information

try:
    data = json.loads('{"invalid}')
except json.JSONDecodeError as e:
    print(f"Error: {e}")           # Full error message
    print(f"Line: {e.lineno}")     # Line number
    print(f"Column: {e.colno}")    # Column number

Raising Exceptions

def validate_temperature(temp):
    if not 0 <= temp <= 2:
        raise ValueError(f"Temperature must be 0-2, got {temp}")
    return temp

try:
    validate_temperature(3.0)
except ValueError as e:
    print(e)

Custom Exceptions

class APIError(Exception):
    """Base exception for API errors."""
    pass

class RateLimitError(APIError):
    """Raised when API rate limit is exceeded."""

    def __init__(self, retry_after=60):
        self.retry_after = retry_after
        super().__init__(f"Rate limited. Retry after {retry_after}s")

class AuthenticationError(APIError):
    """Raised when API authentication fails."""
    pass

# Using custom exceptions
def call_api():
    response_code = 429
    if response_code == 429:
        raise RateLimitError(retry_after=30)
    elif response_code == 401:
        raise AuthenticationError("Invalid API key")

try:
    call_api()
except RateLimitError as e:
    print(f"Waiting {e.retry_after} seconds...")
except AuthenticationError:
    print("Check your API key")

Practical AI Pattern: Retry with Backoff

import time

def api_call_with_retry(func, max_retries=3):
    """Retry an API call with exponential backoff."""
    for attempt in range(max_retries):
        try:
            return func()
        except RateLimitError as e:
            if attempt < max_retries - 1:
                wait_time = e.retry_after * (2 ** attempt)
                print(f"Rate limited. Waiting {wait_time}s...")
                time.sleep(wait_time)
            else:
                raise
        except APIError:
            raise  # Don't retry other API errors

# Usage
result = api_call_with_retry(lambda: call_openai_api())

You've completed the Functions & Classes module! Next, we'll learn to work with APIs. :::

Quiz

Module 3: Functions & Classes

Take Quiz