Python Decorators Learning Path
Decorators are one of Python's most expressive features. The @ syntax looks deceptively simple, but understanding what happens underneath -- closures, higher-order functions, function objects, and the execution order when stacking -- is what separates developers who use decorators confidently from those who copy patterns without knowing why they work.
This collection covers the full decorator landscape: from writing your first wrapper function through functools.wraps, parameterized decorators, class-based decorators, and the built-in patterns like @property, @staticmethod, and @classmethod. Each article includes working code you can run and modify.
Foundations and Syntax
13 articlesPython Decorators Demystified: From First Principles to Real-World Patterns
How decorators work under the hood, building your own from scratch, using arguments, stacking decorators, and applying real-world patterns like timing, logging, authentication, and rate limiting.
What is a Python Decorator
What a Python decorator is from the ground up: first-class functions, closures, the @ syntax, writing custom decorators, handling arguments, functools.wraps, stacking, built-in decorators, and practical examples.
Python Decorator Syntax
Python decorator syntax from the ground up: the @ symbol, first-class functions, closures, functools.wraps, stacking, parameterized decorators, and class-based decorators with complete code examples.
When Should I Use Python Decorators
When to use Python decorators and when to avoid them, covering logging, caching, retry logic, authentication, input validation, and rate limiting with full code examples.
Python Decorators: Use Case Examples
Ten practical Python decorator use cases with full code: execution timing, call logging, memoization, input validation, rate limiting, access control, retry logic, singleton pattern, deprecation warnings, and debug tracing.
TypeError: wrapper() takes 0 positional arguments but 1 was given
Fix the Python TypeError where wrapper() takes 0 positional arguments but 1 was given, covering all six causes: missing *args/**kwargs, missing self in class methods, parameterized decorator mistakes, class-based decorators, and shadowed builtins.
What Does the @ Symbol Do in Python
The @ symbol in Python has two distinct uses: decorator syntax for wrapping functions and the matrix multiplication operator introduced in Python 3.5, with full code examples for both.
The Fundamental Rule That Allows Functions to Be Passed as Arguments
Why Python functions can be passed as arguments, assigned to variables, and returned from other functions, covering the object model, PyObject internals, callable protocol, closures, and higher-order function patterns.
A Decorator Is Simply a Function That Takes Another Function as an Argument
A Python decorator is a function that takes another function as its argument, adds behavior, and returns a new function. This beginner guide builds the concept from first-class functions through closures to the full decorator pattern.
Python Decorators: Higher-Order Functions
How Python decorators are higher-order functions, covering functions as arguments, functions as return values, map/filter/sorted patterns, function factories, and how decorators combine both higher-order patterns into a single mechanism.
Python Decorator Closures
How closures power Python decorators, covering free variables, cell objects, __closure__ inspection, nonlocal for mutable state, parameterized decorator closures, and the variable lookup chain with runnable code examples.
Python Decorator Execution Order
The two-phase execution order of a single Python decorator: decoration time vs call time, what the @ syntax desugars to, which code runs at module import, which runs on every call, and how to trace execution with print statements.
Python Decorator Function Objects: The Attributes That Make Decorators Work
Python functions are objects with attributes like __name__, __doc__, __code__, __closure__, and __dict__. How decorators interact with these attributes, why decoration disrupts them, and how functools.wraps restores identity.
functools and Preserving Metadata
18 articlesfunctools.pipe — The Case for Function Composition in Python's Standard Library
The proposed functools.pipe utility for Python, tracing the full history of function composition debates, PEP proposals, and how to implement robust pipelines in your code today.
What is functools in Python
A complete guide to Python's functools module covering lru_cache, cache, cached_property, partial, reduce, wraps, total_ordering, singledispatch, and the Placeholder sentinel added in Python 3.14.
How to Preserve Function Name and Docstring in Python Decorators
How to preserve function name, docstring, and metadata in Python decorators using functools.wraps, what __wrapped__ does, why inspect.signature follows it, and what breaks when metadata is lost.
Why Does My Decorated Function Show "wrapper" as Its Name?
Why Python decorated functions lose their original name and show wrapper instead, how to fix it with functools.wraps, access the original via __wrapped__, and handle edge cases in stacked and class-based decorators.
How to Use @functools.wraps(func) Inside a Decorator
Step-by-step guide to using @functools.wraps(func) inside every type of Python decorator: simple, parameterized, class-based, stacked chains, and async wrappers, with a complete boilerplate template.
Python Decorator Losing Original Function Metadata Fix
Fix the common Python problem where decorators cause functions to lose their __name__, __doc__, and signature. Diagnose metadata loss, apply functools.wraps, verify the fix, and handle edge cases in stacked and class-based decorators.
How to Access the Original Function from a Decorated Function Using __wrapped__
How to access the original function from a decorated function using Python's __wrapped__ attribute, covering functools.wraps, inspect.unwrap, bypassing decorators in tests, lru_cache bypass, and stacked chains.
Difference Between functools.wraps and functools.update_wrapper
The difference between functools.wraps and functools.update_wrapper in Python, which to use for function decorators, class-based decorators, and partial objects with complete code examples and CPython source analysis.
Fixing Broken help() Output for Decorated Python Functions
Why help() shows the wrong name, signature, and docstring for decorated Python functions, and how to fix it with functools.wraps, update_wrapper, and the wrapt library.
Using functools.wraps with Class-Based Decorators
How to preserve function metadata in Python class-based decorators using functools.update_wrapper, covering stateful decorators, parameterized class decorators, the descriptor protocol for method binding, and comparison with function-based decorators.
Python functools.wraps Equivalent for Classes
How to preserve function metadata in class-based decorators using functools.update_wrapper, the equivalent of functools.wraps for classes, covering the descriptor protocol, __get__ for method binding, and decorating classes themselves.
Standard Template for Well-Behaved Python Decorators
Five copy-ready Python decorator templates covering the basic pattern, parameterized decorators, optional-argument decorators, class-based decorators, and type-safe decorators using ParamSpec from PEP 612.
Using functools.wraps with Decorators That Take Arguments
How to correctly apply functools.wraps inside parameterized Python decorators that accept arguments, covering the three-layer nesting pattern, where to place @wraps, common mistakes, and real-world examples.
functools.wraps vs decorator Module for Signature Preservation
Comparing functools.wraps, the decorator module, wrapt, and boltons.funcutils for preserving function signatures in Python decorators, with code examples, error message comparisons, and a decision guide.
How to Copy Custom Attributes from Wrapped Function to Decorator
How to copy custom attributes from a wrapped function to a decorator wrapper in Python, covering __dict__ merging, timing issues, adding new attributes, extending WRAPPER_ASSIGNMENTS, and building attribute-aware decorators.
Debugging Decorated Functions with Missing Metadata in Stack Traces
How to debug Python decorated functions that show "wrapper" in stack traces, logging output, help(), pdb, and pickle. Fix missing metadata with functools.wraps, diagnose broken chains, and build diagnostic utilities.
How to Use functools.wraps to Preserve Metadata in Complex Stacks
How functools.wraps propagates metadata through multi-decorator stacks, how the __wrapped__ chain works with inspect.unwrap, where wraps must be placed in parameterized and class-based decorators, and how to extend WRAPPER_ASSIGNMENTS for custom attributes.
Using functools.partial to Simplify Decorator Syntax
How functools.partial eliminates triple-nested functions in Python decorators. Build decorators that work with and without arguments using partial to pre-fill parameters, with full code examples.
Parameterized and Stacked Decorators
17 articlesWriting Parameterized Decorators in Python: The Three-Layer Factory Pattern Explained
How to write parameterized decorators using the three-layer factory pattern, closures, functools.wraps, optional-argument decorators, class-based factories, ParamSpec type hints, and production patterns like retry, rate limiting, and access control.
How Python Decorator Stacking Works: Execution Order, Binding, and the Onion Model
How stacked Python decorators bind bottom-up at definition time and execute top-down at call time, the onion model, functools.wraps across the stack, and ordering patterns for authentication, caching, and logging chains.
What is Python Decorator Stacking
What Python decorator stacking is, how bottom-up binding and top-down execution work, why order matters, and how to compose decorator chains correctly with practical code examples.
Building a Python @retry Decorator with Exponential Backoff and Configurable Exceptions
Build a production-grade Python @retry decorator with exponential backoff, configurable exceptions, jitter, and logging, with full code examples and comparisons with tenacity and backoff libraries.
Python Decorator Patterns for Logging, Caching, and Rate Limiting in Production Code
Production-ready Python decorator patterns for structured logging, result caching, and rate limiting with full code examples, comparison tables, and best practices using functools.wraps.
Nesting Multiple Decorators in Python Order of Execution
The two-phase model of stacked Python decorators: bottom-to-top wrapping at definition time and top-to-bottom execution at call time, with code traces, real-world ordering mistakes, and Flask-specific rules.
Python Decorators: Common Backend Tasks
Production-ready Python decorators for six common backend tasks: structured logging, authentication, input validation, caching with TTL, retry with exponential backoff, and execution timing with complete annotated code.
Real World Examples of Python Decorators for Logging and Auth
Production-ready Python decorator examples for structured logging, execution timing, audit trails, JWT authentication, role-based access control, and API key validation with complete code.
Troubleshooting Decorator Arguments vs Function Arguments
Troubleshoot the common confusion in Python decorators: which arguments belong to the decorator and which belong to the decorated function, covering two-layer vs three-layer nesting, missing parentheses, and a visual layer map.
Understanding How Stacking Decorators Affects the Final Function
How stacking multiple Python decorators affects the final function, covering bottom-to-top application order, top-to-bottom execution flow, the @classmethod descriptor trap, metadata propagation, and practical stacking patterns.
Python Decorators: Execution of the "Before" Code
How Python decorator "before" code executes prior to the wrapped function call, covering pre-execution patterns for logging, validation, authentication, timing, and conditional gating with full code examples.
How to Chain Decorators in Python
How to chain multiple Python decorators on a single function, covering stacking syntax, application order vs execution order, parameterized chains, metadata preservation, and production patterns.
Implementing Decorators That Can Be Used Both With and Without Parentheses
How to build Python decorators that work both with and without parentheses using callable detection, functools.partial, keyword-only arguments, and class-based patterns with full code examples.
Chained Decorator Execution Order
How Python evaluates chained decorators from bottom-to-top during wrapping and top-to-bottom during execution, covering the onion model, functools.wraps, parameterized chains, class-based decorators, and real-world ordering pitfalls.
Python Syntax Required to Pass Custom Parameters Into the Decorator Itself
The exact Python syntax for passing custom parameters into a decorator, covering the three-level nested function pattern, decorator factories, class-based decorators with arguments, the functools.partial shortcut, and common mistakes.
Python Decorator Factory with Arguments
How Python decorator factories use three layers of nested functions to accept arguments and return configurable decorators, covering closures, functools.wraps, the optional-arguments pattern, class-based factories, and type-safe factories with ParamSpec.
Python Decorator for Timing Function Execution
Build a Python timing decorator from scratch using time.perf_counter, covering basic to advanced implementations including logging integration, threshold filtering, statistics collection, async support, and context manager hybrids.
Class-Based Decorators and Built-Ins
20 articlesPython @classmethod: What cls Does, Factory Methods, and When to Use It
What cls really is, how class methods differ from static methods, how factory methods work, and why inheritance changes everything about how @classmethod behaves.
Python @dataclass: The Decorator That Writes Your Boilerplate For You
How @dataclass generates __init__, __repr__, and __eq__ from type annotations, the field() function, __post_init__ validation, frozen and slotted dataclasses, kw_only fields, inheritance patterns, and when to reach for dataclasses vs Pydantic.
What It Means to Shadow a Class Method in Python
How instance attributes can silently block access to a @classmethod, why @classmethod is a non-data descriptor, how Python's attribute lookup order makes this possible, and how to avoid it.
Python Class Decorators vs Metaclasses Use Cases
When to use Python class decorators vs metaclasses with practical code examples covering singletons, registries, validation, method wrapping, and the modern __init_subclass__ alternative.
How to Use @property Decorator for Getters and Setters
How to use Python's @property decorator to create managed attributes with getter, setter, and deleter methods, covering computed properties, read-only attributes, validation, inheritance, and the underlying descriptor protocol.
Difference Between @staticmethod and @classmethod in Python
The difference between @staticmethod and @classmethod in Python with code examples, covering when to use each, how they work as descriptors, factory methods, inheritance behavior, and common mistakes.
Python @dataclass vs Manual __init__ Boilerplate
Side-by-side comparison of Python @dataclass decorator versus manually writing __init__, __repr__, and __eq__, covering auto-generated methods, field defaults, __post_init__, frozen and slotted dataclasses, and when to use each approach.
How to Make a Class Instance Behave Like a Callable Decorator
How to build class-based decorators in Python using __call__, covering stateful decorators, functools.update_wrapper, parameterized class decorators, the descriptor protocol for method support, and when to choose classes over closures.
Class-Based Decorator with Arguments vs Function Decorator
Comparing class-based decorators with arguments against function-based decorator factories in Python, with side-by-side code showing __init__/__call__ versus triple-nested functions, state management, testing, and when to choose each.
Differentiating How a Class-Based Decorator Handles the self Argument in Instance Methods
Why class-based decorators lose the instance self argument when decorating methods, how the descriptor protocol fixes it with __get__, and how to build decorators that work on both standalone functions and instance methods.
Standard List of Built-in and Core Module Decorators in Python
Complete reference of every built-in and standard library decorator in Python, organized by module, covering builtins, functools, dataclasses, contextlib, abc, typing, and atexit with code examples for each.
Python Decorator: Ways to Speed Up Recursions Using Built-in Caching
Speed up recursive Python functions using built-in caching decorators, covering functools.lru_cache and functools.cache, manual memoization, cache_info and cache_clear, the typed parameter, recursion depth limits, and bounded vs unbounded caching.
Python Decorators: Built-in Functions (Global Scope)
A complete reference to Python's built-in decorators available in global scope without imports: @property, @staticmethod, and @classmethod, plus standard library functools decorators including @wraps, @lru_cache, @cached_property, and @total_ordering.
@contextmanager: Create a with Statement Context Manager Using a Simple Generator Function
How Python's @contextmanager decorator converts a generator function into a with statement context manager, covering the yield contract, exception handling, yielding values, using context managers as decorators, and async support.
@abstractmethod: Requiring Subclasses to Implement a Method Before They Can Be Instantiated
How Python's @abstractmethod decorator forces subclasses to implement required methods before instantiation, covering ABC inheritance, abstract properties, combining with @classmethod and @staticmethod, and abstract vs duck typing.
Register a Function to Be Executed Automatically When the Python Interpreter Exits with @register
How to use Python's atexit.register as a decorator to automatically execute cleanup functions when the interpreter exits, covering LIFO execution order, unregister(), and practical examples for temp file cleanup and connection management.
Core Standard Library Decorators
A thorough technical guide to Python's core standard library decorators from functools, covering @wraps, @lru_cache, @cache, @cached_property, @singledispatch, and @total_ordering with real code examples.
Python Specialized Utility Decorators
A guide to Python's specialized utility decorators including functools.lru_cache, functools.singledispatch, functools.total_ordering, functools.cached_property, contextlib.contextmanager, and custom patterns for retry logic, rate limiting, and type enforcement.
Python @unique: Ensuring No Two Members in an Enum Class Have the Same Value
How Python's @unique decorator enforces distinct member values in Enum classes by raising a ValueError when duplicate values create aliases, with code examples for IntEnum, StrEnum, and the newer @verify(UNIQUE) pattern.
Python @unittest.mock.patch: Replacing Real Objects with Mock Objects During a Test Run
How Python @unittest.mock.patch works: temporarily replacing real objects with mock objects during a test run, covering patch targets, context managers, patch.object, patch.dict, autospec, side_effect, and return_value.
How to Learn Python Decorators
Learn How Functions Work as Objects
Before writing a decorator, you need to understand that functions in Python are first-class objects. They can be assigned to variables, passed as arguments, and returned from other functions. This is the foundation that makes decorators possible.
Understand Closures and Higher-Order Functions
A closure is a nested function that captures variables from its enclosing scope. A higher-order function is a function that takes another function as an argument or returns one. Decorators rely on both of these mechanisms to wrap behavior around existing functions.
Write Your First Decorator Using the @ Syntax
Start by writing a simple wrapper function that accepts a function, defines an inner function, and returns it. Apply it using the @decorator_name syntax above a function definition. This is syntactic sugar for reassigning the function to the decorator's return value.
Preserve Metadata with functools.wraps
Without @functools.wraps, a decorated function loses its original __name__, __doc__, and other metadata. Always apply @functools.wraps(func) to the inner wrapper function to copy these attributes from the original function to the wrapper.
Explore Parameterized, Stacked, and Class-Based Patterns
Once you are comfortable with basic decorators, move on to parameterized decorators (which require an extra layer of nesting), stacking multiple decorators on a single function (execution order matters), and class-based decorators using __call__. Then study built-in decorators like @property, @staticmethod, @classmethod, and @dataclass.
Frequently Asked Questions
What is a Python decorator?
A decorator is a function that takes another function as its argument, extends or modifies its behavior, and returns the modified function. The @ syntax placed above a function definition is shorthand for passing that function through the decorator and reassigning the result to the same name.
Why do I need functools.wraps in my decorators?
When you wrap a function inside a decorator, the wrapper replaces the original function's identity. Without @functools.wraps, the decorated function's __name__, __doc__, and __qualname__ all point to the inner wrapper instead of the original function. This causes problems with debugging tools, documentation generators, serialization with pickle, and any code that relies on function introspection.
What is the difference between @staticmethod and @classmethod?
@staticmethod defines a method that does not receive the instance (self) or the class (cls) as its first argument. It behaves like a plain function that happens to live inside a class. @classmethod receives the class itself as its first argument (cls), which means it can access and modify class-level state and works correctly with inheritance, since cls refers to the subclass when called on one.
How does decorator stacking order affect execution?
When you stack multiple decorators on a function, the decorator closest to the function definition is applied first, and the outermost decorator wraps everything. At call time, execution flows from the outermost wrapper inward to the original function, then back out. The order you list decorators directly determines the order in which their pre-call and post-call logic runs.
What is a parameterized decorator and how does it work?
A parameterized decorator is a decorator that accepts its own arguments, such as @retry(max_attempts=3). It requires an extra layer of nesting: the outermost function accepts the parameters, returns a decorator function that accepts the target function, which in turn returns the inner wrapper. This three-level structure allows you to configure decorator behavior at the point of application.
When should I use @dataclass instead of writing __init__ manually?
Use @dataclass when your class is primarily a container for data with typed fields. The decorator generates __init__, __repr__, and __eq__ automatically from your type annotations, which eliminates boilerplate and reduces errors. For classes with complex initialization logic, custom validation beyond what __post_init__ supports, or behavior that diverges significantly from a data container pattern, writing __init__ manually gives you more control.