Functions as values; writing a decorator
In Python, functions are ordinary values: you can pass a function to another function and return a new one. A decorator is exactly that — a function that takes your function and returns a wrapped version, adding behaviour around it without touching what's inside.
@timed
def load_features(path):
...
The @timed line is just shorthand for load_features = timed(load_features). Decorators are how production code attaches cross-cutting concerns — timing, logging, retries, caching — once, and reuses them everywhere.
Here's a decorator that reports how long any function it wraps takes to run:
from functools import wraps
import time
def timed(fn):
@wraps(fn) # keep fn's real name and docstring
def inner(*args, **kwargs):
t0 = time.perf_counter()
out = fn(*args, **kwargs)
print(f"{fn.__name__}: {time.perf_counter() - t0:.4f}s")
return out
return inner
The @wraps(fn) matters: without it the wrapper would masquerade under its own name, and the original function would lose its identity for debugging and documentation. Always include it.
leads into “Memoization with lru_cache, safely”.*
Related cards
Tasks
Card Info
- Topic: Python for Data Science
- Difficulty: Advanced
- Completed: 0 users