Decorators wrap functions to add behaviour without changing their code. Use @decorator_name above the function. Built-in decorators include @staticmethod, @classmethod, and @property. Use @functools.wraps inside custom ones.
Function Decorators
import time
def timer(fn):
def wrapper(*args, **kwargs):
start = time.time()
result = fn(*args, **kwargs)
print(f"{fn.__name__} took {time.time()-start:.4f}s")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
slow_function() # slow_function took 1.0003s