Daily Tech Brief

Top startup stories in your inbox

Subscribe Free

Β© 2026 rakrisi Daily

Exception Basics - Your Safety Net

Exception Basics: Your Safety Net

Welcome to Exception Basics! Think of exceptions as warning signals that something unexpected happened. Instead of crashing your program, Python raises an exception that you can catch and handle.

What Are Exceptions?

Exceptions are Python’s way of saying β€œHey, something went wrong!” They’re like emergency brakes that stop your program before it causes more damage.

Exceptions vs Syntax Errors

# Syntax Error - caught during parsing
print("Hello World"  # Missing parenthesis - SYNTAX ERROR

# Exception - occurs during execution
print(10 / 0)  # ZeroDivisionError - EXCEPTION

Basic Try-Except Blocks

The Basic Structure

try:
    # Code that might cause an exception
    risky_code()
except ExceptionType:
    # Code to handle the exception
    handle_error()

Simple Example

# Without error handling - crashes
number = int(input("Enter a number: "))
result = 100 / number
print(f"Result: {result}")

# With error handling - graceful
try:
    number = int(input("Enter a number: "))
    result = 100 / number
    print(f"Result: {result}")
except ZeroDivisionError:
    print("Cannot divide by zero!")
except ValueError:
    print("Please enter a valid number!")

Common Exception Types

ValueError - Invalid Data Type

# Converting invalid string to int
try:
    age = int("twenty-five")  # Can't convert text to number
except ValueError:
    print("Please enter a valid number for age")
    age = 0

ZeroDivisionError - Division by Zero

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

FileNotFoundError - Missing File

try:
    with open("nonexistent.txt", "r") as file:
        content = file.read()
except FileNotFoundError:
    print("File not found, creating a new one")
    with open("nonexistent.txt", "w") as file:
        file.write("Default content")

IndexError - List Index Out of Range

numbers = [1, 2, 3]
try:
    print(numbers[5])  # Index 5 doesn't exist
except IndexError:
    print("Index out of range")

KeyError - Dictionary Key Not Found

person = {"name": "Alice", "age": 25}
try:
    print(person["salary"])  # Key doesn't exist
except KeyError:
    print("Salary information not available")

Multiple Exception Types

Handling Multiple Exceptions

def safe_divide(a, b):
    try:
        result = a / b
        return result
    except ZeroDivisionError:
        print("Cannot divide by zero")
        return 0
    except TypeError:
        print("Both arguments must be numbers")
        return 0
    except Exception as e:
        print(f"An unexpected error occurred: {e}")
        return 0

# Test the function
print(safe_divide(10, 2))    # 5.0
print(safe_divide(10, 0))    # Cannot divide by zero, returns 0
print(safe_divide(10, "2"))  # TypeError, returns 0

Catching Multiple Exceptions Together

try:
    # Code that might raise different exceptions
    value = int(input("Enter a number: "))
    result = 100 / value
except (ValueError, ZeroDivisionError) as e:
    print(f"Invalid input: {e}")
    result = 0

The Else Clause

Using Else with Try-Except

def read_file_safely(filename):
    try:
        with open(filename, "r") as file:
            content = file.read()
    except FileNotFoundError:
        print(f"File '{filename}' not found")
        return None
    else:
        # Only executed if no exception occurred
        print(f"Successfully read {len(content)} characters")
        return content

# Test
content = read_file_safely("existing_file.txt")  # Success
content = read_file_safely("missing_file.txt")   # Error

The Finally Clause

Cleanup Code with Finally

def process_file(filename):
    file = None
    try:
        file = open(filename, "r")
        content = file.read()
        # Process content...
        print(f"Processed {len(content)} characters")
    except FileNotFoundError:
        print(f"File '{filename}' not found")
    finally:
        # Always executed, even if exception occurred
        if file:
            file.close()
            print("File closed")

# Test
process_file("existing_file.txt")  # File closed
process_file("missing_file.txt")   # File closed (even though file was never opened)

Finally for Resource Management

def database_operation():
    connection = None
    try:
        connection = connect_to_database()
        # Perform database operations
        result = connection.execute("SELECT * FROM users")
        return result
    except DatabaseError as e:
        print(f"Database error: {e}")
        return None
    finally:
        # Always close the connection
        if connection:
            connection.close()
            print("Database connection closed")

Exception Objects

Accessing Exception Information

try:
    numbers = [1, 2, 3]
    print(numbers[10])
except IndexError as e:
    print(f"Error type: {type(e).__name__}")
    print(f"Error message: {e}")
    print(f"Full exception: {repr(e)}")

Exception Hierarchy

# All exceptions inherit from BaseException
# Most user exceptions inherit from Exception

try:
    # Some risky operation
    pass
except Exception as e:
    # Catches most exceptions (but not SystemExit, KeyboardInterrupt, etc.)
    print(f"Caught exception: {e}")
except BaseException as e:
    # Catches everything including system exits
    print(f"Caught base exception: {e}")

Practical Examples

Example 1: Safe Calculator

def safe_calculator():
    """A calculator that handles errors gracefully."""
    while True:
        try:
            # Get user input
            expression = input("Enter calculation (or 'quit' to exit): ")

            if expression.lower() == 'quit':
                break

            # Evaluate the expression
            result = eval(expression)
            print(f"Result: {result}")

        except ZeroDivisionError:
            print("Error: Cannot divide by zero")
        except (ValueError, SyntaxError):
            print("Error: Invalid mathematical expression")
        except NameError:
            print("Error: Unknown variable or function")
        except Exception as e:
            print(f"Unexpected error: {e}")

# Run the calculator
safe_calculator()

Example 2: Safe File Reader

def safe_read_file(filename, default_content=""):
    """Read a file safely with fallback content."""
    try:
        with open(filename, "r", encoding="utf-8") as file:
            content = file.read()
            print(f"Successfully read file: {filename}")
            return content
    except FileNotFoundError:
        print(f"File '{filename}' not found, using default content")
        return default_content
    except PermissionError:
        print(f"Permission denied reading '{filename}'")
        return default_content
    except UnicodeDecodeError:
        print(f"Encoding error reading '{filename}'")
        return default_content
    except Exception as e:
        print(f"Unexpected error reading file: {e}")
        return default_content

# Test the function
content1 = safe_read_file("existing_file.txt")
content2 = safe_read_file("missing_file.txt", "Default text")
content3 = safe_read_file("readonly_file.txt")

Example 3: User Input Validation

def get_valid_age():
    """Get a valid age from user input."""
    while True:
        try:
            age_str = input("Enter your age: ")
            age = int(age_str)

            if age < 0:
                print("Age cannot be negative")
                continue
            elif age > 150:
                print("Age seems too high")
                continue

            return age

        except ValueError:
            print("Please enter a valid number")
        except KeyboardInterrupt:
            print("\nOperation cancelled")
            return None

def get_valid_email():
    """Get a valid email address."""
    while True:
        try:
            email = input("Enter your email: ").strip()

            if not email:
                print("Email cannot be empty")
                continue
            elif "@" not in email:
                print("Email must contain @ symbol")
                continue
            elif "." not in email.split("@")[1]:
                print("Email must have a valid domain")
                continue

            return email

        except KeyboardInterrupt:
            print("\nOperation cancelled")
            return None

# Test the functions
age = get_valid_age()
email = get_valid_email()

if age and email:
    print(f"User is {age} years old with email: {email}")

Example 4: Configuration Loader

import json
import os

def load_config(filename="config.json"):
    """Load configuration with error handling."""
    default_config = {
        "debug": False,
        "max_connections": 10,
        "timeout": 30
    }

    if not os.path.exists(filename):
        print(f"Config file '{filename}' not found, using defaults")
        return default_config

    try:
        with open(filename, "r") as file:
            config = json.load(file)

        # Validate required fields
        required_fields = ["debug", "max_connections", "timeout"]
        for field in required_fields:
            if field not in config:
                print(f"Missing required field '{field}', using default")
                config[field] = default_config[field]

        print(f"Configuration loaded from '{filename}'")
        return config

    except json.JSONDecodeError as e:
        print(f"Invalid JSON in config file: {e}")
        print("Using default configuration")
        return default_config
    except PermissionError:
        print(f"Permission denied reading '{filename}'")
        return default_config
    except Exception as e:
        print(f"Unexpected error loading config: {e}")
        return default_config

# Test
config = load_config("config.json")
print(f"Debug mode: {config['debug']}")
print(f"Max connections: {config['max_connections']}")

Best Practices

1. Be Specific with Exception Types

# βœ… Specific exception handling
try:
    result = int(input("Number: ")) / int(input("Divisor: "))
except ValueError:
    print("Invalid number")
except ZeroDivisionError:
    print("Cannot divide by zero")

# ❌ Too broad - catches everything
try:
    result = int(input("Number: ")) / int(input("Divisor: "))
except Exception:
    print("Something went wrong")

2. Use Finally for Cleanup

# βœ… Proper resource cleanup
file = None
try:
    file = open("data.txt", "r")
    data = file.read()
finally:
    if file:
        file.close()

3. Don’t Ignore Exceptions

# ❌ Bad - silently ignores errors
try:
    risky_operation()
except:
    pass  # Never do this!

# βœ… Good - handle or log the error
try:
    risky_operation()
except Exception as e:
    print(f"Error occurred: {e}")
    # Or log to file, send notification, etc.

4. Use Context Managers

# βœ… Automatic resource management
with open("file.txt", "r") as file:
    content = file.read()
# File automatically closed

# Equivalent to:
file = None
try:
    file = open("file.txt", "r")
    content = file.read()
finally:
    if file:
        file.close()

Practice Exercises

Exercise 1: Safe Division Calculator

Create a calculator that:

  • Takes two numbers as input
  • Performs division safely
  • Handles all possible errors
  • Shows appropriate error messages

Exercise 2: File Backup System

Build a file backup function that:

  • Copies a file to backup location
  • Handles file not found errors
  • Handles permission errors
  • Handles disk space errors
  • Provides clear error messages

Exercise 3: User Registration System

Create a user registration system that:

  • Validates username (length, characters)
  • Validates email format
  • Validates password strength
  • Handles all validation errors gracefully
  • Provides helpful error messages

Exercise 4: Data Processor

Build a data processing function that:

  • Reads data from a file
  • Processes the data (e.g., calculate averages)
  • Handles file errors
  • Handles data format errors
  • Handles calculation errors

Exercise 5: Network Request Handler

Create a function that:

  • Makes HTTP requests
  • Handles connection errors
  • Handles timeout errors
  • Handles invalid URL errors
  • Retries failed requests

Summary

Exception handling is your safety net:

Basic Structure:

try:
    # Risky code
except SpecificException:
    # Handle specific error
except Exception as e:
    # Handle general errors
finally:
    # Cleanup code (always runs)

Common Exceptions:

  • ValueError - Invalid data conversion
  • ZeroDivisionError - Division by zero
  • FileNotFoundError - Missing file
  • IndexError - List index out of range
  • KeyError - Dictionary key not found

Best Practices:

  • Be specific with exception types
  • Use finally for cleanup
  • Don’t ignore exceptions
  • Use context managers when possible
  • Provide helpful error messages

Next: Advanced Exception Handling - taking it to the next level! πŸš€