Language 5 of 10 · Topic 0.7

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.