6 months, 1 week ago | 11 min Read | 166
If you're a Python developer, you’ve probably come across decorators, or at least heard of them. They’re one of those concepts that seem mysterious at first, but once you understand how they work, they can make your code much cleaner and more efficient. In this post, we'll break down Python decorators, explain how they work, and show you practical ways to use them to simplify repetitive tasks in your code.
In simple terms, a decorator in Python is a function that takes another function and extends its behavior without modifying it directly. Think of it as “wrapping” a function with additional functionality.
Decorators allow you to add extra logic to your code, such as logging, authentication checks, or timing, without cluttering the original function. They're like a bonus feature for your functions!
Let’s look at a basic example to see how this works.
Here’s a simple function that prints a message:
def greet():
print("Hello, World!")
Now, suppose we want to add extra behavior, like printing a message before and after the greeting, without touching the original greet()
function. Enter decorators.
First, let's create a decorator that does just that:
def my_decorator(func):
def wrapper():
print("Before the greeting...")
func()
print("After the greeting...")
return wrapper
The my_decorator
function takes the greet
function as an argument, wraps it with new behavior in the wrapper()
function, and then returns the wrapper
.
To apply this decorator to the greet
function, we can use the @
symbol, like this:
@my_decorator
def greet():
print("Hello, World!")
Now, when we call greet()
, it actually calls the wrapper()
function inside the decorator:
greet()
Output:
Before the greeting...
Hello, World!
After the greeting...
See how the decorator added behavior before and after the greet()
function without changing the original logic? That’s the power of decorators.
Decorators help you avoid code repetition by extracting common functionality into a reusable function. They’re perfect when you need to add logging, access control, or timing logic across multiple functions.
Let’s take a look at some common use cases.
If you want to track when a function is called, you can create a logging decorator:
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__}")
return func(*args, **kwargs)
return wrapper
Apply this decorator to any function:
@log_decorator
def add(a, b):
return a + b
Now, every time you call add()
, the function call will be logged:
add(5, 3)
Output:
Calling function add
8
Want to measure how long a function takes to run? A timing decorator can help:
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Function {func.__name__} took {end_time - start_time} seconds")
return result
return wrapper
Decorate any function and see how long it takes to execute:
@timer_decorator
def slow_function():
time.sleep(2)
slow_function()
Output:
Function slow_function took 2.002034 seconds
You can use decorators to restrict access to certain functions. For example, you might have a function that should only be run by an admin:
def require_admin(func):
def wrapper(user_role):
if user_role != 'admin':
print("Access denied!")
else:
return func(user_role)
return wrapper
Apply the decorator:
@require_admin
def access_sensitive_data(user_role):
print("Accessing sensitive data...")
Test it out:
access_sensitive_data('user')
access_sensitive_data('admin')
Output:
Access denied!
Accessing sensitive data...
When you decorate a function, you’re essentially replacing the original function with the wrapper
function defined in the decorator. That’s why when you call greet()
, it actually runs the code inside wrapper()
.
Here’s a quick breakdown of what happens:
greet()
is passed as an argument to my_decorator
.my_decorator
returns the wrapper()
function.wrapper()
is now the function that gets called whenever you call greet()
.@decorator_name
notation.If you’ve followed along this far, writing your own decorators should now feel approachable. Here’s a quick template you can use:
def your_decorator(func):
def wrapper(*args, **kwargs):
# Do something before the function call
result = func(*args, **kwargs)
# Do something after the function call
return result
return wrapper
You can now apply @your_decorator
to any function and extend its behavior without modifying the original code.
Decorators are a powerful feature in Python that can simplify your code by removing repetitive tasks and keeping your functions clean and focused. Whether you're adding logging, measuring execution time, or handling authentication, decorators allow you to do it elegantly.
Once you get the hang of it, decorators will become one of your go-to tools in your Python toolbox. So go ahead, experiment with decorators in your projects, and simplify your code like a pro!
Hello! My name is Jatin Yadav and I enjoy creating websites I completed my graduation on june ,2018 and I want to be a professional web developer. The word which
Read More >