Python Tutorial / Understand Decorators and Context Managers
A decorator wraps a function’s calling behavior, while a context manager controls setup and cleanup around a block. They can extract repeated infrastructure, but the original return and exception contracts must remain deliberate.
Separate wrapping behavior from lifetime management
@decorator binds the function name to the result of passing the defined function to the decorator. It is executable behavior rather than a comment. with invokes entry and exit handling and can arrange cleanup when the body raises an exception.
functools.wraps helps preserve metadata such as the wrapped function’s name and documentation. It does not automatically prove that the wrapper preserves every type, security or error-handling guarantee.
For the relevant APIs and platform requirements, see Understand Decorators and Context Managers documentation.
Run a wrapper and temporary collection
Save the complete code below as wrappers.py in a separate practice folder, using UTF-8. Run python wrappers.py in a terminal with your project virtual environment selected. Outside a virtual environment on macOS or Ubuntu, use python3 when that is your interpreter command.
from functools import wraps
from contextlib import contextmanager
def announce(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("start")
return func(*args, **kwargs)
return wrapper
@contextmanager
def temporary_items():
items = []
try:
yield items
finally:
items.clear()
print("cleared")
@announce
def total(amounts):
return sum(amounts)
with temporary_items() as items:
items.extend([3500, 8000])
print(total(items))
print(total.__name__)
print(items)
Expected output:
start 11500 cleared total []
Trace values and exceptions through the layers
A contextmanager generator yields once to supply the with body’s value. On exit, control returns to its cleanup path. Putting cleanup in finally makes it run even when the body fails. Catching and swallowing an exception can conceal that failure, so propagate it unless suppression is intentional.
A wrapper that omits return changes the original function’s result to None. Check argument forwarding, return values and exception propagation rather than relying only on the wrapper’s printed message.
Test cleanup and choose an appropriate abstraction
- Raise ValueError deliberately inside the with block and verify that cleared is printed.
- Inspect the list after cleanup.
- Temporarily remove return from the wrapper, inspect the changed result and restore it.
A retry decorator may repeat a state-changing request and create duplicate transactions. Keep retry policy separate from resource cleanup. A one-off small operation may be clearer without a new abstraction. The exception guide provides the cleanup and propagation foundations.




