What Is a Decorator in Python? A Practical Guide
SkillVeris Team
Engineering Team

A decorator is a function that takes another function as input and returns a new function with added behavior.
In this guide, you'll learn:
- Decorators use the @ symbol placed directly above a function definition as shorthand for wrapping it.
- Common uses include logging, timing, access control, caching, and input validation without touching the original function's code.
- Python's functools.wraps preserves the original function's name and docstring when writing a decorator.
- Decorators can accept their own arguments by adding an extra layer of nested functions.
1What Is a Decorator in Python?
A decorator in Python is a function that takes another function as an argument, wraps it with extra behavior, and returns the wrapped version, all without modifying the original function's code.
Decorators rely on the fact that functions in Python are first-class objects: they can be passed around, assigned to variables, and returned from other functions just like any other value.
2The @ Symbol Explained
The @ symbol placed above a function definition is syntactic sugar for passing that function into a decorator and reassigning the result back to the same name.
- @my_decorator above def my_function(): is equivalent to my_function = my_decorator(my_function).
- The decorator runs once, at the time the function is defined, not each time it is called.
- Multiple decorators can be stacked, and they apply from the bottom one upward.
3Writing a Simple Decorator
A basic decorator is a function that defines an inner wrapper function, calls the original function inside it, and returns the wrapper.
- def logger(func):
- def wrapper(*args, **kwargs):
- print(f"Calling {func.__name__}")
- result = func(*args, **kwargs)
- return result
- return wrapper
- @logger
- def greet(name):
- return f"Hello, {name}"
4Preserving Function Metadata with functools.wraps
Without extra care, a decorated function loses its original name and docstring because the wrapper function replaces it entirely.
The functools.wraps decorator copies that metadata from the original function onto the wrapper, so tools like help() and debuggers still show accurate information.
- from functools import wraps
- def logger(func):
- @wraps(func)
- def wrapper(*args, **kwargs):
- return func(*args, **kwargs)
- return wrapper
5Decorators That Take Arguments
A decorator that needs its own configuration, such as a retry count or a cache size, requires an extra outer function that accepts those arguments and returns the actual decorator.
- def repeat(times):
- def decorator(func):
- def wrapper(*args, **kwargs):
- for _ in range(times):
- result = func(*args, **kwargs)
- return result
- return wrapper
- return decorator
- @repeat(3)
- def say_hi():
- print("hi")
6Common Real-World Use Cases
Decorators show up constantly in production Python code because they cleanly separate a function's core logic from cross-cutting concerns.
- Logging: recording when a function runs and with what arguments.
- Timing: measuring how long a function takes to execute.
- Access control: checking permissions before allowing a function to run.
- Caching: storing results of expensive calls so repeated calls return instantly.
- Validation: checking input types or ranges before the main logic runs.
💡
7Class-Based Decorators
A decorator does not have to be a function; any object that implements __call__ can act as one, which is useful when the decorator needs to hold its own internal state, such as a call counter.
8Practical Next Steps
Once decorators feel comfortable, the natural next topics are context managers, generators, and how frameworks combine decorators to build request pipelines.
Working through structured Python study notes and practicing by writing a small logging or timing decorator from scratch is the fastest way to internalize the pattern.
Related Reading
Get The Print Version
Download a PDF of this article for offline reading.
About the Publisher
SkillVeris Team
Engineering Team
Our engineering writers turn abstract code concepts into hands-on, project-driven learning experiences.
View all postsRelated Posts
Never miss an update
Get the latest tutorials and guides delivered to your inbox.
No spam. Unsubscribe anytime.