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