What are decorators and how do they work?medium
A decorator wraps a function to add behaviour without modifying its body. Functions are first-class objects, so a decorator takes a function, defines a wrapper that adds logic, and returns the wrapper. The @syntax is shorthand for fn = decorator(fn).
The foundation is that Python functions are objects — assignable and passable as arguments. A closure is an inner function that remembers variables from its enclosing scope. Always use @functools.wraps(fn) inside your decorator to preserve __name__ and __doc__ — without it, debugging and stack traces break. For decorators with arguments like @retry(n=3), you need a triple-nested pattern: a function receiving arguments that returns the actual decorator. Stacked decorators apply bottom-up: @a @b def f means a(b(f)), so @b wraps first.