Python Decorators
1. What is a Decorator?
A decorator in Python is a function that takes another function (or method) as an argument, adds some functionality, and returns a new function that typically calls the original one. Decorators are often used to modify or enhance the behavior of functions or methods without permanently modifying them.
Code Example
-
original_function is the function being decorated.-
wrapper_function is the new function that wraps around the original one.- It adds behavior (e.g., print statement) before calling the original function.
2. Functions are First-Class Citizens
In Python, functions are first-class citizens, which means they can be:
- Assigned to variables
- Passed as arguments to other functions
- Returned from other functions
Code Example
Here,greet is assigned to hello, which is then called like a function.This flexibility is the foundation for decorators.
3. Nested Functions and Closures
Python allows defining functions inside other functions. These are called nested functions. When the inner function captures variables from the outer function’s scope, it's called a closure.
Code Example
-
outer defines msg and returns inner.-
inner remembers the value of msg even after outer has finished.- This is a closure — an important concept for decorators.
4. Creating a Simple Decorator
Let’s create a decorator manually and see how it wraps a function.
Code Example
-
simple_decorator takes say_hello as input.- It wraps it with
wrapper, adding print statements before and after.- When
decorated() is called, it runs the wrapper logic.
5. Using @ Syntax (Pythonic View)
Python provides a shorthand @decorator_name to apply a decorator to a function.
Code Exmample
This is equivalent tosay_hi = simple_decorator(say_hi).It’s cleaner and more readable.
6. Decorators with Arguments
To handle functions with arguments, use *args and **kwargs in the wrapper.
Code Example
-
*args captures positional arguments.-
**kwargs captures keyword arguments.- This makes the decorator flexible to decorate any function.
7. Chaining Multiple Decorators
You can apply multiple decorators to one function. They are executed from bottom to top.
Code Example
-
italic is applied first.- Then
bold wraps that result.
8. functools.wraps – Preserving Metadata
When decorating, the original function’s name and docstring are lost. Use functools.wraps to preserve them.
Code Example
9. Class-Based Decorators (Advanced)
Instead of functions, you can use classes to define decorators. This is useful when you need to maintain state.
Code Example
- The
__call__ method makes an instance callable like a function.- State (
self.count) is maintained across calls.
10. Summary
| Concept | Description |
|---|---|
| Decorator | Function that wraps another function |
@decorator |
Syntactic sugar for applying decorators |
*args, **kwargs |
Allow decorators to handle any arguments |
functools.wraps |
Preserves metadata of original function |
| Real-world uses | Logging, timing, access control, caching |
Real World Use Cases