Interview question
How do you chain multiple decorators? What is the order of execution? Multiple decorators को कैसे chain करते हैं? Execution order क्या है?
Answer
Multiple decorators are applied bottom-up during definition but executed top-down during function call. Understanding the order is critical to avoid bugs.
// Simple Decorator Chain
def decorator1(func):
print("D1 decorated")
def wrapper(*args, **kwargs):
print("D1 before")
result = func(*args, **kwargs)
print("D1 after")
return result
return wrapper
def decorator2(func):
print("D2 decorated")
def wrapper(*args, **kwargs):
print("D2 before")
result = func(*args, **kwargs)
print("D2 after")
return result
return wrapper
// Order of execution
@decorator1
@decorator2
def my_function():
print("Function executed")
my_function()
// EXECUTION OUTPUT:
// D2 decorated (bottom decorator applied first)
// D1 decorated (top decorator applied second)
// D1 before (top decorator executes first)
// D2 before
// Function executed
// D2 after
// D1 after (top decorator executes last)
// Django Example - Multiple Permissions
from django.contrib.auth.decorators import login_required, permission_required
@login_required
@permission_required("myapp.can_edit_books")
def edit_book(request, book_id):
return JsonResponse({"status": "editing"})
// EXECUTION ORDER:
// 1. Check if user is authenticated (login_required)
// 2. Check if user has permission (permission_required)
// 3. Execute edit_book view
// Practical Django Example
def timing_decorator(func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
print(f"Execution time: {time.time() - start}s")
return result
return wrapper
def auth_decorator(func):
def wrapper(request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect("login")
return func(request, *args, **kwargs)
return wrapper
@timing_decorator
@auth_decorator
def dashboard(request):
return render(request, "dashboard.html")
// EXECUTION ORDER on call:
// 1. auth_decorator checks authentication
// 2. dashboard executes
// 3. timing_decorator measures time
// Complex Chain with Caching
from functools import wraps
def cache_result(timeout=300):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
cache_key = f"{func.__name__}_{str(args)}_{str(kwargs)}"
result = cache.get(cache_key)
if result is None:
result = func(*args, **kwargs)
cache.set(cache_key, result, timeout)
return result
return wrapper
return decorator
def log_execution(func):
@wraps(func)
def wrapper(*args, **kwargs):
logger.info(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@log_execution
@cache_result(timeout=600)
def expensive_operation(n):
time.sleep(2)
return n * 2
// EXECUTION:
// 1. log_execution wrapper called
// 2. cache_result wrapper checks cache
// 3. expensive_operation executes (if not cached)
// 4. result cached and returnedMultiple decorators bottom-up apply होते हैं लेकिन top-down execute होते हैं।
@decorator1
@decorator2
def my_func():
print("Function")
// Definition order:
// D2 applied, then D1
// Execution order:
// D1 runs first, then D2, then function, then D2, then D1
// Output:
// D1 before
// D2 before
// Function
// D2 after
// D1 afterWas this answer clear?