18.1.Errors & Exceptions in Python
11.Resource Management & Cleanup
Always release resources. Use context managers for cleanup. contextlib provides helpers like suppress and ExitStack.
12. Logging vs Exceptions
Exceptions control flow; logging records context. Combine them effectively for diagnostics.
13. Common Exceptions (and when to use/catch)
ValueError, TypeError, KeyError, IndexError, FileNotFoundError, PermissionError, TimeoutError, ConnectionError, ImportError, NotImplementedError.
14.Anti-Patterns to Avoid
Avoid bare except, overbroad catches, huge try blocks, using exceptions for normal control flow, and assert for runtime validation.
15.Special Cases
KeyboardInterrupt and SystemExit should not be caught accidentally. sys.exit() raises SystemExit. Generators and async tasks propagate exceptions differently.
16 .Designing a Clean Error API (for Libraries)
Define a base exception for your package, derive specific exceptions, validate inputs early, wrap and chain low-level errors.
17.Mini Recipes
Examples: safe division utility, config loader with chained exceptions, suppress cleanup errors, custom context manager, async error collection.
18.Quick Checklist
Catch specific exceptions, keep try blocks small, use else and finally appropriately, prefer EAFP, raise correct types, use chaining, avoid assert for validation, don’t call sys.exit() in libraries.
19.Practice Exercises
Exercises: safe_div, load_config, suppress cleanup errors, temporary_chdir context manager, async error collection.
20.Summary
Exceptions are Python’s principled way to report and handle runtime problems. By choosing the right exception types, handling them narrowly, preserving context, and cleaning up resources reliably, your programs become robust and maintainable.
Ready-to-Paste Code Blocks
Custom exceptions scaffold
class TutorialError(Exception):
“””Base class for tutorial-related errors.”””
class InputMissingError(TutorialError):
pass
class InputInvalidError(TutorialError):
pass
With else and finally
def parse_positive_int(text):
f = None
try:
value = int(text)
except ValueError as e:
raise InputInvalidError(“Expected an integer”) from e
else:
if value <= 0:
raise InputInvalidError(“Expected a positive integer”)
return value
finally:
if f is not None:
f.close()
Context manager recipe
from contextlib import contextmanager
import os
@contextmanager
def temporary_chdir(path):
old = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(old)