Python Decorators: A complete guide to decorators in Python
Quick answer: A Python decorator is a function that takes another function, wraps it with extra behavior, and returns the new version without changing the original code. Writing @timer above a function is shorthand for func = timer(func). Decorators work because Python functions are first-class objects (they can be passed and returned like any value) and because inner functions form closures that remember the original function. A well-written decorator uses *args and **kwargs to accept any arguments, returns the wrapped function’s result, and applies @functools.wraps to keep the original name and docstring. To pass settings, such as @timer(unit="ms"), you add an outer layer called a decorator factory. Multiple decorators stack bottom-up, so @a above @b means a(b(func)). Decorators can also be classes with a __call__ method (useful for keeping state), can wrap methods and whole classes, need an async wrapper for async functions, and power built-ins like @property, @staticmethod, @classmethod, and @functools.lru_cache. This guide explains each concept with one running example: a slow weather-fetching function that we time, log, count, and cache.