Handle errors gracefully to prevent your program from crashing.
# Basic try-except
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
# Multiple exception types
try:
number = int(input("Enter a number: "))
result = 10 / number
print(f"Result: {result}")
except ValueError:
print("Please enter a valid number")
except ZeroDivisionError:
print("Cannot divide by zero")
# Catching multiple exceptions
try:
# Some risky operation
pass
except (ValueError, TypeError, ZeroDivisionError) as e:
print(f"An error occurred: {e}")
# Custom exception classes
class InsufficientFundsError(Exception):
def __init__(self, balance, amount):
self.balance = balance
self.amount = amount
super().__init__(f"Insufficient funds: ${balance} < ${amount}")
class InvalidAgeError(Exception):
pass
# Using custom exceptions
class BankAccount:
def __init__(self, balance=0):
self.balance = balance
def withdraw(self, amount):
if amount > self.balance:
raise InsufficientFundsError(self.balance, amount)
self.balance -= amount
return f"Withdrew ${amount}. Balance: ${self.balance}"
# Handling custom exceptions
account = BankAccount(100)
try:
print(account.withdraw(150))
except InsufficientFundsError as e:
print(f"Transaction failed: {e}")
print(f"Available balance: ${e.balance}")
# Complete try-except structure
def process_file(filename):
file = None
try:
file = open(filename, 'r')
content = file.read()
# Process content
return content.upper()
except FileNotFoundError:
print(f"File {filename} not found")
return None
except PermissionError:
print(f"Permission denied for {filename}")
return None
else:
# Runs only if no exception occurred
print("File processed successfully")
finally:
# Always runs, regardless of exceptions
if file:
file.close()
print("File closed")
# Better approach using context managers
def process_file_better(filename):
try:
with open(filename, 'r') as file:
content = file.read()
return content.upper()
except FileNotFoundError:
print(f"File {filename} not found")
return None
except PermissionError:
print(f"Permission denied for {filename}")
return None
else:
print("File processed successfully")
# Raising built-in exceptions
def validate_age(age):
if not isinstance(age, int):
raise TypeError("Age must be an integer")
if age < 0:
raise ValueError("Age cannot be negative")
if age > 150:
raise ValueError("Age seems unrealistic")
return True
# Re-raising exceptions
def divide_numbers(a, b):
try:
return a / b
except ZeroDivisionError:
print("Logging: Division by zero attempted")
raise # Re-raise the same exception
# Using assertions
def calculate_square_root(number):
assert number >= 0, "Number must be non-negative"
return number ** 0.5
try:
validate_age(-5)
except ValueError as e:
print(f"Validation error: {e}")
try:
result = divide_numbers(10, 0)
except ZeroDivisionError:
print("Division by zero handled")
# Exception chaining with 'from'
def parse_config(config_string):
try:
import json
return json.loads(config_string)
except json.JSONDecodeError as e:
raise ValueError("Invalid configuration format") from e
def load_user_settings(config_string):
try:
config = parse_config(config_string)
return config['user_settings']
except ValueError as e:
raise RuntimeError("Failed to load user settings") from e
# Using exception chaining
try:
settings = load_user_settings("invalid json")
except RuntimeError as e:
print(f"Error: {e}")
print(f"Caused by: {e.__cause__}")
print(f"Original error: {e.__cause__.__cause__}")
import logging
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def safe_divide(a, b):
try:
result = a / b
logging.info(f"Division successful: {a} / {b} = {result}")
return result
except ZeroDivisionError:
logging.error(f"Division by zero: {a} / {b}")
return None
except Exception as e:
logging.exception(f"Unexpected error in division: {a} / {b}")
return None
# Error handling with context
class DatabaseConnection:
def __enter__(self):
logging.info("Connecting to database")
# Simulate connection
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
logging.error(f"Database error: {exc_val}")
logging.info("Closing database connection")
return False # Don't suppress exceptions
def query(self, sql):
if "DROP" in sql.upper():
raise ValueError("DROP statements not allowed")
return f"Results for: {sql}"
# Using the context manager
try:
with DatabaseConnection() as db:
result = db.query("SELECT * FROM users")
print(result)
except ValueError as e:
logging.error(f"Query error: {e}")