📌 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)