Functions, *args / **kwargs & Decorators (@functools.wraps)
1Concept
*args captures positional arguments as a tuple; **kwargs captures keyword arguments as a dict. Decorators are higher-order functions that wrap other functions to add behavior (logging, timing, auth).
2Architecture Diagram
@my_decorator def target(): pass # Identical to: target = my_decorator(target)
3Code Example
Stage 0 Language Foundations
import functools
import time
def timing_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"[{func.__name__}] executed in {elapsed:.6f}s")
return result
return wrapper
@timing_decorator
def compute_sum(n: int) -> int:
return sum(range(n))
print(f"Result: {compute_sum(100_000)}")4Expected Output
[compute_sum] executed in 0.002145s Result: 4999950000
5Key Takeaways
- ✓Always use @functools.wraps(func) in decorators to preserve original function metadata.
- ✓*args must precede **kwargs in function definitions.
- ✓Functions in Python are first-class citizens that can be passed as arguments.