Python Decorators – Wrap, Enhance, and Reuse Functions
Introduction – What Are Python Decorators?
In Python, decorators are a powerful feature that lets you modify or extend the behavior of a function or class—without changing its actual code.
They are commonly used for logging, authentication, timing functions, and more. Python decorators leverage closures and higher-order functions, making them a go-to tool for writing cleaner, DRY (Don’t Repeat Yourself) code.
In this guide, you’ll learn:
- What decorators are and how they work
- How to define and apply decorators
- The role of
@syntax andfunctools.wraps - Real-world examples and best practices
What Is a Decorator?
A decorator is a function that takes another function as input and returns a new function that usually enhances or wraps the original.
def decorator(func):
def wrapper():
print("Before function runs")
func()
print("After function runs")
return wrapper
Applying a Decorator
@decorator
def say_hello():
print("Hello!")
say_hello()
Output:
Before function runs
Hello!
After function runs
Explanation:
The @decorator is shorthand for say_hello = decorator(say_hello).
Real-World Decorator Example: Logger
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args} and {kwargs}")
return func(*args, **kwargs)
return wrapper
@logger
def greet(name):
return f"Hello, {name}"
print(greet("Alice"))
Using *args and **kwargs in Decorators
Use *args and **kwargs to accept functions with any number of arguments, keeping your decorators reusable and flexible.
functools.wraps – Preserve Metadata
from functools import wraps
def smart_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("Decorated function running...")
return func(*args, **kwargs)
return wrapper
Always use @wraps(func) inside decorators to preserve:
- Function name
- Docstring
- Signature
Chaining Multiple Decorators
@decorator1
@decorator2
def my_func():
pass
Python applies them bottom-up, so decorator2 wraps my_func, and then decorator1 wraps the result.
Built-in Decorators You Should Know
| Decorator | Purpose |
|---|---|
@staticmethod | Define a method without self |
@classmethod | Takes cls instead of self |
@property | Make method behave like an attribute |
Common Pitfalls
| Mistake | Fix |
|---|---|
Not returning wrapper() | Always return the nested function |
Forgetting @wraps | Use @wraps(func) to retain metadata |
Not using *args, **kwargs | Needed for flexibility in decorators |
Best Practices
- Always use
functools.wrapsinside decorators - Use decorators for cross-cutting concerns like logging, validation, caching
- Keep decorators small and focused
- Avoid complex logic inside decorators—prefer clarity over cleverness
Summary – Recap & Next Steps
Python decorators are a clean and elegant way to enhance or modify function behavior without changing their code. By using closures and higher-order functions, decorators help build flexible, maintainable, and reusable components.
Key Takeaways:
- Decorators wrap functions using the
@decoratorsyntax. -
*argsand**kwargsallow decorators to work with any function signature. - Use
functools.wrapsto retain original function metadata. - Great for logging, timing, authentication, and more.
Real-World Relevance:
Decorators are widely used in Flask/Django, unit testing, and API rate-limiting, allowing clean and modular code enhancements across production-grade applications.
FAQ Section – Python Decorators
What is a decorator in Python?
A decorator is a function that wraps another function to extend or modify its behavior without altering the function’s code directly.
How do I create a custom decorator?
Define a function that takes another function as an argument and returns a wrapper function:
def decorator(func):
def wrapper():
return func()
return wrapper
Why use *args and **kwargs in decorators?
To ensure your decorator works with functions of any number of positional and keyword arguments.
What does @functools.wraps do?
It preserves the metadata (like name, docstring, signature) of the original function, making debugging and introspection easier.
Can I use multiple decorators on one function?
Yes. Decorators are stacked from bottom to top and applied in that order:
@first
@second
def func():
pass
Share Now :
