π What is a Python Decorator?
A Python decorator is a function that modifies another function or class without changing its original code.
β
It adds extra functionality (e.g., logging, authentication, caching) to functions or methods.
β
Uses the @decorator_name
syntax to wrap a function.
β Basic Example of a Python Decorator
π Without a decorator (Manual way):
def uppercase_decorator(func):
def wrapper():
result = func()
return result.upper()
return wrapper
def say_hello():
return "hello world"
# Manually applying decorator
say_hello = uppercase_decorator(say_hello)
print(say_hello()) # Output: "HELLO WORLD"
β Problem: We have to manually wrap say_hello
inside uppercase_decorator
.
π With a decorator (Cleaner way):
def uppercase_decorator(func):
def wrapper():
result = func()
return result.upper()
return wrapper
@uppercase_decorator # β
This automatically applies the decorator
def say_hello():
return "hello world"
print(say_hello()) # Output: "HELLO WORLD"
β Why is this better?
- Less manual wrapping.
- Easier to read and maintain.
β How Decorators Work (Step-by-Step)
@uppercase_decorator
def say_hello():
return "hello world"
1οΈβ£ Python sees @uppercase_decorator
and applies it to say_hello
.
2οΈβ£ uppercase_decorator(say_hello)
is called automatically.
3οΈβ£ It returns the wrapper()
function that modifies say_hello()
output.
4οΈβ£ say_hello()
now returns "HELLO WORLD"
instead of "hello world"
.
β Real-World Examples of Decorators
πΉ Example 1: Logging Decorator
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__} with {args} {kwargs}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(5, 3)
π‘ Output:
Calling add with (5, 3) {}
add returned 8
β Why Use This?
- Automatically logs function calls and results without modifying the function itself.
πΉ Example 2: Authentication Decorator in FastAPI
from fastapi import FastAPI, Depends, HTTPException
app = FastAPI()
def auth_required(func):
def wrapper(username: str):
if username != "admin":
raise HTTPException(status_code=403, detail="Unauthorized")
return func(username)
return wrapper
@app.get("/secure-data")
@auth_required # β
Protects this route
def secure_data(username: str):
return {"message": "Secure data accessed!"}
# Now only "admin" can access this route
β Why Use This?
- Ensures only authenticated users can access certain API routes.
πΉ Example 3: Time Execution Decorator
import time
def time_it(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
@time_it
def slow_function():
time.sleep(2)
return "Finished"
slow_function()
π‘ Output:
slow_function took 2.0001 seconds
β Why Use This?
- Measures execution time of a function (useful for performance optimization).
β Summary: Why Use Python Decorators?
Feature | Why It's Useful? |
---|---|
Code Reusability | Add extra behavior without modifying function code. |
Readability |
@decorator_name makes it clear that the function is modified. |
Flexibility | Can be applied to multiple functions easily. |
Used in Frameworks | FastAPI, Django, Flask, TensorFlow all use decorators. |
Top comments (0)