Exception Handling
Handling errors gracefully with try-except blocks and custom exceptions.
Try-Except Basics
- Exceptions are errors that occur during program execution.
- Use try-except to catch and handle errors.
- Program continues running after handling exception.
- Prevents crashes from unexpected errors.
# Without exception handling (crashes)
# result = 10 / 0 # ZeroDivisionError
# With exception handling
try:
result = 10 / 0
except ZeroDivisionError:
print("Cannot divide by zero!")
result = None
print("Program continues...")
Multiple Exceptions
- Catch different exception types separately.
- More specific exceptions first, general ones last.
- Use Exception to catch all exceptions.
def divide(a, b):
try:
result = a / b
return result
except ZeroDivisionError:
print("Cannot divide by zero!")
return None
except TypeError:
print("Invalid types for division!")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
print(divide(10, 2)) # 5.0
print(divide(10, 0)) # Cannot divide by zero!
print(divide(10, "2")) # Invalid types for division!
Else and Finally
- else: Runs if no exception occurred
- finally: Always runs, even if exception occurred
- Use finally for cleanup (closing files, connections)
try:
file = open("data.txt", "r")
content = file.read()
except FileNotFoundError:
print("File not found!")
else:
print("File read successfully!")
print(content)
finally:
print("Cleanup code runs here")
# file.close() # Always close file
# Better with 'with' statement
try:
with open("data.txt", "r") as file:
content = file.read()
except FileNotFoundError:
print("File not found!")
Raising Exceptions
- Use 'raise' to throw exceptions intentionally.
- Useful for input validation.
- Can raise built-in or custom exceptions.
def check_age(age):
if age < 0:
raise ValueError("Age cannot be negative!")
if age < 18:
raise ValueError("Must be 18 or older!")
return "Access granted"
try:
result = check_age(15)
print(result)
except ValueError as e:
print(f"Error: {e}")
# Re-raising exceptions
try:
x = int("abc")
except ValueError:
print("Invalid number!")
raise # Re-raise the same exception
Custom Exceptions
- Create custom exception classes for specific errors.
- Inherit from Exception or specific exception types.
- Add custom attributes and methods.
# Define custom exception
class InsufficientFundsError(Exception):
pass
# Use custom exception
class BankAccount:
def __init__(self, initial):
self.balance = initial
def withdraw(self, requested):
if requested > self.balance:
raise InsufficientFundsError("Not enough funds!")
self.balance = self.balance - requested
return self.balance
# Test it
account = BankAccount(100)
try:
account.withdraw(150)
except InsufficientFundsError as e:
print(f"Error: {e}") # Error: Not enough funds!