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 A S VINAY KUMAR directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
