Docs

error handling

08 - Error & Exception Handling

šŸ“Œ What You'll Learn

  • •What are exceptions
  • •try-except blocks
  • •Handling specific exceptions
  • •else and finally clauses
  • •Raising exceptions
  • •Custom exceptions
  • •Best practices

āŒ What are Exceptions?

Exceptions are errors that occur during program execution. Without handling, they crash your program.

# This will crash!
print(10 / 0)  # ZeroDivisionError

# This too!
int("hello")   # ValueError

# And this!
my_list = [1, 2, 3]
print(my_list[10])  # IndexError

šŸ›”ļø try-except Block

Catch and handle exceptions gracefully.

# Basic try-except
try:
    result = 10 / 0
except:
    print("An error occurred!")

# Better: catch specific exception
try:
    result = 10 / 0
except ZeroDivisionError:
    print("Cannot divide by zero!")

šŸŽÆ Handling Specific Exceptions

try:
    value = int(input("Enter a number: "))
    result = 10 / value
    print(f"Result: {result}")
except ValueError:
    print("That's not a valid number!")
except ZeroDivisionError:
    print("Cannot divide by zero!")

Multiple Exceptions in One Block

try:
    # code that might fail
    pass
except (ValueError, TypeError):
    print("Value or Type error occurred!")

Get Exception Details

try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"Error: {e}")
    print(f"Error type: {type(e).__name__}")

šŸ“‹ Common Exceptions

ExceptionCause
ZeroDivisionErrorDivision by zero
ValueErrorWrong value type
TypeErrorWrong type operation
IndexErrorIndex out of range
KeyErrorDict key not found
FileNotFoundErrorFile doesn't exist
AttributeErrorInvalid attribute
ImportErrorImport failure
NameErrorVariable not defined
PermissionErrorPermission denied

āœ… else Clause

The else block runs if no exception occurred.

try:
    value = int("42")
except ValueError:
    print("Invalid number")
else:
    print(f"Success! Value is {value}")

šŸ”’ finally Clause

The finally block always runs, whether exception occurred or not.

try:
    file = open("data.txt", "r")
    data = file.read()
except FileNotFoundError:
    print("File not found")
finally:
    print("Cleanup code runs here")
    # Close file if it was opened

Complete Structure

try:
    # Code that might raise an exception
    result = risky_operation()
except SomeException as e:
    # Handle specific exception
    print(f"Error: {e}")
except AnotherException:
    # Handle another exception
    print("Another error")
else:
    # Runs if no exception occurred
    print("Success!")
finally:
    # Always runs (cleanup code)
    print("Cleaning up...")

šŸš€ Raising Exceptions

Use raise to throw an exception.

def validate_age(age):
    if age < 0:
        raise ValueError("Age cannot be negative")
    if age > 150:
        raise ValueError("Age seems unrealistic")
    return True

try:
    validate_age(-5)
except ValueError as e:
    print(f"Validation error: {e}")

Re-raising Exceptions

try:
    risky_operation()
except Exception as e:
    print(f"Logging error: {e}")
    raise  # Re-raise the same exception

šŸŽØ Custom Exceptions

Create your own exception classes.

# Define custom exception
class InsufficientFundsError(Exception):
    """Raised when account has insufficient funds."""

    def __init__(self, balance, amount):
        self.balance = balance
        self.amount = amount
        self.message = f"Cannot withdraw ${amount}. Balance is ${balance}"
        super().__init__(self.message)

# Use custom exception
class BankAccount:
    def __init__(self, balance):
        self.balance = balance

    def withdraw(self, amount):
        if amount > self.balance:
            raise InsufficientFundsError(self.balance, amount)
        self.balance -= amount
        return amount

# Handle custom exception
try:
    account = BankAccount(100)
    account.withdraw(150)
except InsufficientFundsError as e:
    print(f"Error: {e}")
    print(f"Tried to withdraw: ${e.amount}")
    print(f"Available balance: ${e.balance}")

🌳 Exception Hierarchy

BaseException
ā”œā”€ā”€ SystemExit
ā”œā”€ā”€ KeyboardInterrupt
ā”œā”€ā”€ GeneratorExit
└── Exception
    ā”œā”€ā”€ StopIteration
    ā”œā”€ā”€ ArithmeticError
    │   ā”œā”€ā”€ ZeroDivisionError
    │   └── OverflowError
    ā”œā”€ā”€ LookupError
    │   ā”œā”€ā”€ IndexError
    │   └── KeyError
    ā”œā”€ā”€ OSError
    │   ā”œā”€ā”€ FileNotFoundError
    │   └── PermissionError
    ā”œā”€ā”€ ValueError
    ā”œā”€ā”€ TypeError
    └── ... (many more)
# Catch all exceptions (use carefully!)
try:
    risky_code()
except Exception as e:  # Catches most exceptions
    print(f"Error: {e}")

# Don't do this (catches SystemExit, KeyboardInterrupt too!)
# except BaseException:

šŸ”§ Best Practices

1. Be Specific

# āŒ Bad - too broad
try:
    do_something()
except:
    pass

# āœ… Good - specific exception
try:
    do_something()
except ValueError as e:
    handle_value_error(e)

2. Don't Silence Exceptions

# āŒ Bad - hides bugs
try:
    process_data()
except Exception:
    pass

# āœ… Good - at least log it
try:
    process_data()
except Exception as e:
    logging.error(f"Error processing data: {e}")

3. Use Context Managers

# āŒ Okay but verbose
try:
    f = open('file.txt')
    data = f.read()
finally:
    f.close()

# āœ… Better - context manager
with open('file.txt') as f:
    data = f.read()

4. EAFP vs LBYL

# LBYL (Look Before You Leap)
if 'key' in dictionary:
    value = dictionary['key']

# EAFP (Easier to Ask Forgiveness than Permission) - Pythonic!
try:
    value = dictionary['key']
except KeyError:
    value = default_value

# Even better for dicts:
value = dictionary.get('key', default_value)

šŸ’” assert Statement

Assert conditions that should always be true.

def calculate_average(numbers):
    assert len(numbers) > 0, "List cannot be empty"
    return sum(numbers) / len(numbers)

# Assertions can be disabled with -O flag
# Don't use for input validation in production!

šŸ”— Chained Exceptions

Show the cause of an exception.

try:
    value = int("abc")
except ValueError as e:
    raise RuntimeError("Failed to parse value") from e

šŸŽÆ Next Steps

After mastering exceptions, proceed to 09_oop to learn Object-Oriented Programming!

Error Handling - Python Tutorial | DeepML