In Python, decorators are special functions that allow you to modify or extend the behavior of other functions or methods without changing their source code.
They are commonly used for logging, authentication, caching, performance measurement, and more.
Example: Logging Decorator
def log(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log
def add(a, b):
return a + b
print(add(2, 3))
Here,
log
is a decorator function that accepts another function (func
) as input.- Inside
log
, a new functionwrapper
is defined. This function:- Prints the function name and arguments before calling the actual function.
- Calls the original function (
func(*args, **kwargs)
) and stores the result. - Prints the result before returning it.
- The line
@log
applies the decorator to theadd
function. This is shorthand for writing:add = log(add)
- When
add(2, 3)
is called, it actually runs wrapper, adding the extra logging functionality.
Output:
Calling add with (2, 3)
add returned 5
5
Why Use Decorators?
- Add extra functionality without modifying original code
- Keep code clean and reusable
- Great for cross-cutting concerns like logging, access control, validation
Best Practices
- Always use
functools.wraps
to preserve the original function’s metadata. - Keep decorators small and reusable.
- Avoid nesting too many decorators for readability.
When to Use Decorators
- Logging and debugging
- Authentication and authorization
- Measuring performance (timing functions)
- Input validation
- Caching results of expensive computations
👉 Next tutorial: Python Class Methods