Advanced Error Handling
Raising Exceptions
Developers can manually raise exceptions using the raise
keyword to create custom error scenarios.
def validate_age(age):
if age < 0:
raise ValueError("Age cannot be negative")
return age
try:
user_age = validate_age(-5)
except ValueError as e:
print(f"Validation Error: {e}")
Context Managers and Error Handling
Using with
Statement
class ResourceManager:
def __enter__(self):
print("Acquiring resource")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("Releasing resource")
if exc_type is not None:
print(f"An exception occurred: {exc_type}")
return False
def process_resource():
with ResourceManager():
raise RuntimeError("Simulated error")
try:
process_resource()
except RuntimeError:
print("Caught runtime error")
Error Handling Flow
graph TD
A[Start] --> B{Try Block}
B --> |Exception Occurs| C{Matching Except?}
C --> |Yes| D[Handle Exception]
C --> |No| E[Propagate Exception]
D --> F[Continue Execution]
E --> G[Terminate Program]
Advanced Exception Techniques
Chaining Exceptions
try:
try:
## Primary operation
result = 10 / 0
except ZeroDivisionError as original_error:
## Raise a new exception with context
raise RuntimeError("Calculation failed") from original_error
except RuntimeError as e:
print(f"Caught: {e}")
print(f"Original cause: {e.__cause__}")
Exception Handling Patterns
Pattern |
Description |
Use Case |
Explicit Handling |
Catch and handle specific exceptions |
Targeted error management |
Logging |
Record exception details |
Debugging and monitoring |
Retry Mechanism |
Attempt operation multiple times |
Handling transient errors |
Graceful Degradation |
Provide alternative functionality |
Maintaining system reliability |
Decorators for Error Handling
def retry(max_attempts=3):
def decorator(func):
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
print(f"Attempt {attempts} failed: {e}")
raise Exception("Max retry attempts exceeded")
return wrapper
return decorator
@retry(max_attempts=3)
def unstable_operation():
## Simulating an unreliable operation
import random
if random.random() < 0.7:
raise ValueError("Random failure")
return "Success"
try:
result = unstable_operation()
print(result)
except Exception as e:
print(f"Operation failed: {e}")
Logging Exceptions in LabEx Environment
import logging
logging.basicConfig(
level=logging.ERROR,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
def complex_calculation(x, y):
try:
result = x / y
return result
except ZeroDivisionError:
logging.error("Division by zero attempted")
return None
complex_calculation(10, 0)
Best Practices
- Use specific exception types
- Provide meaningful error messages
- Log exceptions for debugging
- Implement proper error recovery mechanisms
- Avoid silent error suppression
By mastering advanced error handling techniques, Python developers can create more robust, reliable, and maintainable applications in the LabEx environment.