Decorators in Python: A Complete Guide

Introduction to Decorators
Decorators in Python are a powerful tool that allows modifying or extending the behavior of functions without altering their actual implementation. They make code more readable, reusable, and maintainable by allowing modifications to functions in a clean and efficient way.
Why Use Decorators?
Code Reusability: Avoid repeating code for similar functionalities.
Separation of Concerns: Keeps function logic independent of additional behavior.
Enhanced Readability: Makes functions cleaner by abstracting modifications.
Useful for Logging, Authentication, Timing Functions, and More.
Basic Syntax of a Decorator
A decorator is a function that takes another function as input and extends its behavior.
Step 1: Creating a Basic Decorator
def my_decorator(func):
def wrapper():
print("Something before the function runs.")
func()
print("Something after the function runs.")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()
Output:
Something before the function runs.
Hello, World!
Something after the function runs.
How It Works
my_decorator(func)
receives the functionsay_hello()
.wrapper()
adds additional behavior before and after callingfunc()
.@my_decorator
applies the decorator tosay_hello()
, modifying its behavior.
Decorators with Arguments
If the decorated function takes arguments, use *args
and **kwargs
inside the wrapper.
def smart_decorator(func):
def wrapper(*args, **kwargs):
print("Executing decorated function...")
result = func(*args, **kwargs)
print("Finished execution.")
return result
return wrapper
@smart_decorator
def add(a, b):
return a + b
print(add(5, 3))
Output:
Executing decorated function...
Finished execution.
8
Built-in Decorators in Python
Python provides several built-in decorators, commonly used for modifying methods in classes.
1. @staticmethod
Defines a function inside a class that doesnโt require access to instance attributes.
class MathOperations:
@staticmethod
def add(a, b):
return a + b
print(MathOperations.add(5, 3)) # Output: 8
2. @classmethod
Allows methods to receive the class itself (cls
) instead of instance (self
).
class MyClass:
class_var = "Hello"
@classmethod
def show_class_var(cls):
return cls.class_var
print(MyClass.show_class_var()) # Output: Hello
3. @property
Used to define read-only properties in a class.
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
p = Person("Mahesh")
print(p.name) # Output: Mahesh
Using Multiple Decorators
You can stack multiple decorators on a single function:
def decorator1(func):
def wrapper():
print("Decorator 1 before function")
func()
print("Decorator 1 after function")
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2 before function")
func()
print("Decorator 2 after function")
return wrapper
@decorator1
@decorator2
def hello():
print("Hello, World!")
hello()
Output:
Decorator 1 before function
Decorator 2 before function
Hello, World!
Decorator 2 after function
Decorator 1 after function
Real-World Applications of Decorators
1. Logging Function Execution
import time
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Executing {func.__name__} at {time.strftime('%X')}")
return func(*args, **kwargs)
return wrapper
@log_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Mahesh")
2. Checking User Authentication
def requires_authentication(func):
def wrapper(user, *args, **kwargs):
if user == "admin":
return func(*args, **kwargs)
else:
print("Access Denied")
return wrapper
@requires_authentication
def secure_action():
print("Performing secure action...")
secure_action("user") # Output: Access Denied
secure_action("admin") # Output: Performing secure action...
3. Timing Function Execution
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} took {end_time - start_time:.4f} seconds")
return result
return wrapper
@timer_decorator
def slow_function():
time.sleep(2)
print("Finished processing.")
slow_function()
Output:
Finished processing.
slow_function took 2.0001 seconds
Subscribe to my newsletter
Read articles from Naveen Pn directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Naveen Pn
Naveen Pn
I am a Tech Enthusiast having 13+ years of experience in ๐๐ as a ๐๐จ๐ง๐ฌ๐ฎ๐ฅ๐ญ๐๐ง๐ญ, ๐๐จ๐ซ๐ฉ๐จ๐ซ๐๐ญ๐ ๐๐ซ๐๐ข๐ง๐๐ซ, ๐๐๐ง๐ญ๐จ๐ซ, with 12+ years in training and mentoring in ๐๐จ๐๐ญ๐ฐ๐๐ซ๐ ๐๐ง๐ ๐ข๐ง๐๐๐ซ๐ข๐ง๐ , ๐๐๐ญ๐ ๐๐ง๐ ๐ข๐ง๐๐๐ซ๐ข๐ง๐ , ๐๐๐ฌ๐ญ ๐๐ฎ๐ญ๐จ๐ฆ๐๐ญ๐ข๐จ๐ง ๐๐ง๐ ๐๐๐ญ๐ ๐๐๐ข๐๐ง๐๐. I have ๐๐๐๐๐๐๐ ๐๐๐๐ ๐๐๐๐ 10,000+ ๐ฐ๐ป ๐ท๐๐๐๐๐๐๐๐๐๐๐๐ and ๐๐๐๐ ๐๐๐๐๐ ๐๐๐๐ ๐๐๐๐ 500+ ๐๐๐๐๐๐๐๐ ๐๐๐๐๐๐๐๐ in the areas of ๐๐จ๐๐ญ๐ฐ๐๐ซ๐ ๐๐๐ฏ๐๐ฅ๐จ๐ฉ๐ฆ๐๐ง๐ญ, ๐๐๐ญ๐ ๐๐ง๐ ๐ข๐ง๐๐๐ซ๐ข๐ง๐ , ๐๐ฅ๐จ๐ฎ๐, ๐๐๐ญ๐ ๐๐ง๐๐ฅ๐ฒ๐ฌ๐ข๐ฌ, ๐๐๐ญ๐ ๐๐ข๐ฌ๐ฎ๐๐ฅ๐ข๐ณ๐๐ญ๐ข๐จ๐ง๐ฌ, ๐๐ซ๐ญ๐ข๐๐ข๐๐ข๐๐ฅ ๐๐ง๐ญ๐๐ฅ๐ฅ๐ข๐ ๐๐ง๐๐ ๐๐ง๐ ๐๐๐๐ก๐ข๐ง๐ ๐๐๐๐ซ๐ง๐ข๐ง๐ . I am interested in ๐ฐ๐ซ๐ข๐ญ๐ข๐ง๐ ๐๐ฅ๐จ๐ ๐ฌ, ๐ฌ๐ก๐๐ซ๐ข๐ง๐ ๐ญ๐๐๐ก๐ง๐ข๐๐๐ฅ ๐ค๐ง๐จ๐ฐ๐ฅ๐๐๐ ๐, ๐ฌ๐จ๐ฅ๐ฏ๐ข๐ง๐ ๐ญ๐๐๐ก๐ง๐ข๐๐๐ฅ ๐ข๐ฌ๐ฌ๐ฎ๐๐ฌ, ๐ซ๐๐๐๐ข๐ง๐ ๐๐ง๐ ๐ฅ๐๐๐ซ๐ง๐ข๐ง๐ new subjects.