Decorators in Python are a powerful feature that allows you to modify or extend the behavior of functions without changing their actual code. In this blog post, we’ll explore two examples: a basic decorator to add behavior around a function and a more practical one to simulate access control. Let’s get started!
1. Basic Decorator Example
Here’s a simple decorator that adds some behavior before and after a function call:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("1. Before function call")
result = func(*args, **kwargs)
print("2. After function call")
return result
return wrapper
@my_decorator
def add(x, y):
print(" → Inside function: Adding numbers") # Step 3.1
return x + y
print("START")
result = add(3, 4)
print(f"RESULT: {result}")
print("END")
Output:
START
1. Before function call
→ Inside function: Adding numbers
2. After function call
RESULT: 7
END
Order of Execution
Let’s break down the order in which the code is executed:

2. Practical Example: Access Control Decorator
Now, let’s create a more useful decorator that simulates restricting access to a function based on a condition (e.g., user authentication). This is a simplified version of what you might see in web frameworks like Flask.
def require_auth(func):
def wrapper(user, *args, **kwargs):
# Simulate checking if the user is authenticated
if user.get("is_authenticated", False): # Check if user is authenticated
print("1. Access granted!")
return func(user, *args, **kwargs) # Call the original function
else:
print("1. Access denied: Please log in.")
return None # Return None if access is denied
return wrapper
@require_auth
def view_profile(user):
print(" → Inside function: Fetching profile data")
return f"Profile: {user['username']}"
# Test with an unauthenticated user
user1 = {"username": "Alice", "is_authenticated": False}
print("START")
result = view_profile(user1)
print(f"RESULT: {result}")
print("END")
# Test with an authenticated user
user2 = {"username": "Bob", "is_authenticated": True}
print("\nSTART")
result = view_profile(user2)
print(f"RESULT: {result}")
print("END")
Output:
START
1. Access denied: Please log in.
RESULT: None
END
START
1. Access granted!
→ Inside function: Fetching profile data
RESULT: Profile: Bob
END
Order of Execution (for user2)
- Step 1: @require_auth — The view_profile function is wrapped by require_auth.
- Step 2: print(“START”) — Prints “START” before calling the function.
- Step 3: result = view_profile(user2) → calls wrapper — The decorator runs before view_profile().
- Step 4: if user.get(“is_authenticated”, False) — Checks if the user is authenticated (True for user2).
- Step 5: print(“1. Access granted!”) — Prints “Access granted!” since the condition is met.
- Step 6: func(user, *args, **kwargs) → Calls view_profile — The original function view_profile is called with user2.
- Step 7: print(“ → Inside function: Fetching profile data”) — Prints inside view_profile().
- Step 8: return f”Profile: {user[‘username’]}” — Returns “Profile: Bob” to wrapper.
- Step 9: return func(…) — wrapper returns the result to result.
- Step 10: print(f”RESULT: {result}”) — Prints “RESULT: Profile: Bob”.
- Step 11: print(“END”) — Prints “END”.
For user1: The decorator stops at step 4, prints “Access denied: Please log in.”, and returns None.
Decorators are incredibly versatile! The access control example shows how they’re used in frameworks to manage permissions. Try tweaking the require_auth decorator to log failed attempts or add more conditions! 😊
'Python Intermediate and Advanced' 카테고리의 다른 글
Python Intermediate_008: Understanding Generators in Python (0) | 2025.03.10 |
---|---|
Python Intermediate_007: Understanding @property and Setter Decorators in Python (0) | 2025.03.09 |
Python Intermediate_005: Type Hinting in Python (0) | 2025.02.08 |
Python Intermediate_004_ Nested Classes (0) | 2025.01.12 |
Python Intermediate_005: Working with the Requests Library (3) | 2025.01.04 |