Understanding Decorators in Python : Their Role and Practical Usage
By PythonTimes content writer, specialized in Python.

Python is an incredibly robust programming language with many powerful functions and capabilities lurking behind its elegant syntax. Among these, a particular feature that stands out due to its unique handling and vast potential is Python’s concept of ‘Decorators’.
What are Decorators in Python?
In its essence, a decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. They are a very powerful tool, permitting the user to modify the behavior of a function or class. Technically, Python’s decorators allow us to wrap another function in order to extend the behavior of the wrapped function, without permanently modifying it.
But, before understanding decorators in depth, let’s get a grasp of what functions are.
Understanding Functions
In Python, functions are first-class objects. This means that functions can be passed around, used as arguments, or used as return values just like any other object (like a string or a list).
Here’s a simple example. We can define a function, affect it to a variable, and also define another function inside it:
def hello(msg):
def greet():
return "Hello, "
return greet() + msg
say_hello = hello("Pythonists!")
print(say_hello) # outputs: Hello, Pythonists!
In Python, we can also define a function inside other function, known as a nested function.
def hello(msg):
def greet():
return "Hello, "
return greet() + msg
print(hello("Pythonists!")) # outputs: Hello, Pythonists!
Higher-order Functions
A function is considered ‘Higher Order’ if it takes a function as an argument or returns a function as a result. The built-in Python functions map() and filter() are perfect examples of higher-order functions. They take a function and an iterable and provide their result.
Check the below code :
# An example with map
def multiply_by_two(x):
return x * 2
result = map(multiply_by_two, [1, 2, 3, 4])
list(result) # outputs : [2, 4, 6, 8]
Leaning towards decorators
Having grasped the understanding of functions and higher-order functions, decorators are a step away.
In Python, we define a decorator as a higher-order function that takes one function as an input and returns another function, often extending or modifying the input function’s behavior.
Now, let’s define a decorator!
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello)
Here, we’ve defined a decorator my_decorator and a function say_hello. Now what my_decorator(say_hello)
does is a wrap say_hello
with something is happening before
and something is happening after
. If we call say_hello()
, it won’t print just “Hello!”, but the other sentences as well.
The Syntactic Sugar!
Python simplifies how we apply a decorator to a function using ‘@’.
@my_decorator
def say_hello():
print("Hello!")
We have just seen an example of a decorator that wraps a function without any arguments. Sometimes we need to pass arguments to our function. For that, we can use *args
and **kwargs
in our inner wrapper function. Below is an example for the same.
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Something is happening before the function is called.")
func(*args, **kwargs)
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello_to(name):
print(f"Hello {name}!")
say_hello_to("John")
# outputs:
# Something is happening before the function is called.
# Hello John!
# Something is happening after the function is called.
Decorators in the Real World
In practice, Python’s decorators are used extensively for several useful tasks: – Logging: Decorators can be used effectively to log function usage details, be it function arguments, the time when it was called, or execution time. – Access Control and Authentication: Certain Python web frameworks leverage decorators to regulate page access, check if a user is logged in, has certain permissions, or not. – Caching: Python decorators can be used to cache expensive function call results, thereby improving the application’s performance. – Timing: A common usage of decorators is checking how much time a function takes to run, which helps in performance testing.
Conclusion
Decorators are a powerful, high-level feature of Python. They facilitate us with an elegant way to modify the functionality of our code without changing our source code. Though they might seem a bit daunting initially, understanding decorators can significantly improve our efficiency in Python coding.
Recognizing the real power of decorators comes with practice and implementation in real-world tasks. So, Happy Pythoning!
Author: PythonTimes Writer