Decorators in Python: A Complete Guide

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.
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_decoratorapplies 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



