Exception Handling
Checking access...
Exceptions are Python’s mechanism for handling errors at runtime.
Basic Exception Handling
try: result = 10 / 0except ZeroDivisionError: print("Cannot divide by zero!")
# Multiple except blockstry: num = int(input("Enter a number: ")) result = 100 / numexcept ValueError: print("That's not a valid number!")except ZeroDivisionError: print("Number cannot be zero!")Catching Exception Details
try: file = open("missing.txt")except FileNotFoundError as e: print(f"Error: {e}") # Error: [Errno 2] No such file or directory: 'missing.txt' print(f"Errno: {e.errno}") # Errno: 2The else and finally Clauses
# else — runs if no exception occurred# finally — ALWAYS runs
def divide_safe(a, b): try: result = a / b except ZeroDivisionError: print("Cannot divide by zero") return None else: print(f"Result: {result}") return result finally: print("Cleanup complete") # Always runs
divide_safe(10, 2)# Result: 5.0# Cleanup complete
divide_safe(10, 0)# Cannot divide by zero# Cleanup completeRaising Exceptions
def withdraw(balance, amount): if amount <= 0: raise ValueError("Amount must be positive") if amount > balance: raise ValueError("Insufficient funds") return balance - amount
try: withdraw(100, 200)except ValueError as e: print(f"Withdrawal failed: {e}")
# Re-raisingtry: withdraw(100, -5)except ValueError: print("Logging error...") raise # Re-raises the same exceptionCustom Exceptions
class BankError(Exception): """Base exception for bank operations.""" pass
class InsufficientFundsError(BankError): def __init__(self, balance, amount): self.balance = balance self.amount = amount super().__init__(f"Insufficient funds: ${balance} < ${amount}")
class AccountFrozenError(BankError): pass
class InvalidTransactionError(BankError): pass
def transfer(sender_balance, amount, account_frozen=False): if account_frozen: raise AccountFrozenError("Account is frozen") if amount <= 0: raise InvalidTransactionError("Amount must be positive") if amount > sender_balance: raise InsufficientFundsError(sender_balance, amount) return sender_balance - amount
try: transfer(100, 200)except InsufficientFundsError as e: print(f"Failed: {e}") print(f"Balance: ${e.balance}, Needed: ${e.amount}")except BankError as e: print(f"Bank error: {e}")Exception Hierarchy
BaseException├── SystemExit├── KeyboardInterrupt└── Exception ├── ArithmeticError │ ├── ZeroDivisionError │ └── FloatingPointError ├── LookupError │ ├── IndexError │ └── KeyError ├── ValueError ├── TypeError ├── OSError │ └── FileNotFoundError └── RuntimeErrorTip
Catch Exception, not BaseException, to avoid catching SystemExit and KeyboardInterrupt.
Exception Chaining
# Implicit chaintry: int("not a number")except ValueError as e: raise RuntimeError("Conversion failed") from e
# Suppress chaintry: int("not a number")except ValueError: raise RuntimeError("Conversion failed") from NoneContext Managers with with
# File automatically closes after the blockwith open("data.txt", "r") as file: content = file.read()# File is closed here, even if an exception occurredCreating Context Managers
class ManagedFile: def __init__(self, filename, mode="r"): self.filename = filename self.mode = mode
def __enter__(self): self.file = open(self.filename, self.mode) return self.file
def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() # Return False to propagate exceptions, True to suppress return False
with ManagedFile("test.txt", "w") as f: f.write("Hello!")
# Using contextlibfrom contextlib import contextmanager
@contextmanagerdef managed_file(filename, mode="r"): f = open(filename, mode) try: yield f finally: f.close()
with managed_file("test.txt") as f: print(f.read())Best Practices
# ✅ Good: catch specific exceptionstry: data = json.loads(text)except json.JSONDecodeError as e: print(f"Invalid JSON: {e}")
# ❌ Bad: bare except catches everythingtry: risky_operation()except: pass
# ✅ Good: minimal try blockstry: config = load_config()except FileNotFoundError: config = DEFAULT_CONFIG
# ✅ Good: use finally for cleanupconn = database.connect()try: conn.execute(query)finally: conn.close()Key Takeaways
- Use
try/exceptto handle expected errors, not for control flow - Catch specific exception types, not bare
except: elseruns on success;finallyalways runs (cleanup)- Create custom exceptions by inheriting from
Exception - Use
raise ... from efor exception chaining - Context managers (
withstatement) handle setup/cleanup automatically - Minimal
tryblocks — only wrap the code that might fail