Decorators in Python
Learn how Python decorators can add extra functionality to an existing function without changing its original code.
What is a Decorator?
A decorator is a function that adds extra behavior to another function.
Decorators allow us to modify or extend the behavior of a function without changing the original function code.
Decorator Flow
Original Function
The function contains the main logic.
Decorator
Adds extra functionality around the function.
Modified Behavior
The function runs with the additional behavior.
Basic Syntax
def decorator(function):
def wrapper():
function()
return wrapper
@decorator
def welcome():
print("Welcome to Python")
The @decorator syntax tells Python to apply
the decorator to the function.
Simple Decorator Example
def message_decorator(function):
def wrapper():
print("Before function")
function()
print("After function")
return wrapper
@message_decorator
def welcome():
print("Welcome to Python")
welcome()
Output:
Before function
Welcome to Python
After function
The decorator adds statements before and after the original function.
Applying Decorator Without @
A decorator can also be applied directly by assigning the decorated function.
def decorator(function):
def wrapper():
print("Before")
function()
print("After")
return wrapper
def welcome():
print("Welcome")
welcome = decorator(welcome)
welcome()
Output:
Before
Welcome
After
Decorator with Function Parameters
A decorator can also work with functions that receive parameters.
def decorator(function):
def wrapper(name):
print("Welcome message")
function(name)
return wrapper
@decorator
def greet(name):
print("Hello", name)
greet("Rahul")
Output:
Welcome message
Hello Rahul
Decorator with Multiple Arguments
We can use *args and **kwargs
when the decorated function may receive different
numbers of arguments.
def decorator(function):
def wrapper(*args, **kwargs):
print("Function started")
result = function(*args, **kwargs)
print("Function completed")
return result
return wrapper
@decorator
def add(a, b):
return a + b
print(add(10, 20))
Output:
Function started
Function completed
30
Decorator with Return Value
A decorator can return the result produced by the original function.
def decorator(function):
def wrapper(a, b):
result = function(a, b)
return result
return wrapper
@decorator
def multiply(a, b):
return a * b
print(multiply(5, 4))
Output:
20
Practical Example: Login Check
Decorators can be used to perform a check before allowing a function to execute.
def login_required(function):
def wrapper(user):
if user == "admin":
return function(user)
else:
print("Access denied")
return wrapper
@login_required
def dashboard(user):
print("Welcome to dashboard")
dashboard("admin")
Output:
Welcome to dashboard
Multiple Decorators
More than one decorator can be applied to the same function.
def first(function):
def wrapper():
print("First decorator")
function()
return wrapper
def second(function):
def wrapper():
print("Second decorator")
function()
return wrapper
@first
@second
def welcome():
print("Welcome")
welcome()
Output:
First decorator
Second decorator
Welcome
Preserving Function Information
The functools.wraps function can be used
when we want to preserve information about the original
function.
from functools import wraps
def decorator(function):
@wraps(function)
def wrapper():
return function()
return wrapper
@decorator
def welcome():
print("Welcome to Python")
welcome()
This is commonly used when creating reusable decorators.
Common Uses of Decorators
Authentication
Check whether a user is allowed to access a function.
Logging
Record when functions are executed.
Validation
Validate conditions before executing a function.
Advantages of Decorators
Code Reusability
The same decorator can be used with multiple functions.
Less Repetition
Common logic does not need to be repeated in every function.
Clean Code
Additional behavior can be separated from the main function logic.
Best Practices
Keep Decorators Small
Keep the decorator focused on one responsibility.
Use Meaningful Names
Give decorators clear and descriptive names.
Use wraps
Use functools.wraps when the original function information should be preserved.
Common Mistakes
- Forgetting to return the wrapper function.
- Forgetting to return the result of the original function.
- Not handling function arguments correctly.
- Creating very complicated decorators for simple tasks.
-
Forgetting to use
functools.wrapswhen function metadata needs to be preserved.
Practice Programs
- Create a decorator that prints a message before a function runs.
- Create a decorator that prints a message after a function runs.
- Create a decorator that accepts function arguments.
- Create a decorator for checking user login.
- Create a decorator that calculates the execution time of a function.
Summary
A decorator is a function that adds extra functionality to another function without changing its original code. Decorators are useful for logging, authentication, validation and reusable common functionality. They can work with arguments, return values and multiple decorators can be applied to the same function.