Understanding Python Decorators: Concepts, Implementations, and Practical Applications
This article provides a comprehensive guide to Python decorators, covering their basic concept, step‑by‑step implementations of simple, parameterized, class‑based, and utility decorators, practical use‑cases such as logging, timing, permission checks, and how to preserve metadata with functools.wraps.
Decorators are a powerful feature in Python that allow additional functionality to be added to a function dynamically without modifying the original function.
Table of Contents
Basic concept of decorators
Implementation of a simple decorator
Parameterized decorators
Real‑world application scenarios
Class decorators
Using functools.wraps to preserve function metadata
Summary
1. Basic Concept of Decorators
A decorator is essentially a function that takes another function as an argument and returns a new function. Its purpose is to add extra behavior to the original function without changing its code.
2. Simple Decorator Implementation
Example 1: Basic Decorator
Use case: Add logging before and after a function call.
def my_decorator(func):
def wrapper():
print("函数调用前执行")
func() # call original function
print("函数调用后执行")
return wrapper
@my_decorator
def say_hello():
print("Hello, World!")
say_hello()Output:
函数调用前执行
Hello, World!
函数调用后执行Explanation: my_decorator is the decorator, wrapper is the inner function that adds extra logic before and after calling the original function.
3. Parameterized Decorator
Example 2: Decorator Supporting Arguments
Use case: The decorator needs to support functions that accept parameters.
def my_decorator(func):
def wrapper(*args, **kwargs):
print("函数调用前执行")
result = func(*args, **kwargs)
print("函数调用后执行")
return result
return wrapper
@my_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")Output:
函数调用前执行
Hello, Alice!
函数调用后执行Explanation: By using *args and **kwargs , the decorator can handle functions with arbitrary arguments.
4. Real‑World Application Scenarios
Example 3: Measuring Function Execution Time
Use case: Measure how long a function takes to run.
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 执行耗时 {end_time - start_time:.4f} 秒")
return result
return wrapper
@timer
def slow_function():
time.sleep(2)
print("慢函数执行完成")
slow_function()Output:
慢函数执行完成
函数 slow_function 执行耗时 2.0002 秒Explanation: The timer decorator uses the time module to record execution duration.
Example 4: Logging Calls
Use case: Record function call information.
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"调用函数:{func.__name__},参数:{args}{kwargs}")
result = func(*args, **kwargs)
print(f"函数 {func.__name__} 执行完成,返回结果:{result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
print(add(5, 3))Output:
调用函数:add,参数:(5, 3) {}
函数 add 执行完成,返回结果:8
8Explanation: log_decorator records the function name, its arguments, and the return value.
Example 5: Permission Verification
Use case: Verify user permissions before executing a function.
def login_required(func):
def wrapper(*args, **kwargs):
if not is_logged_in():
print("请先登录")
return None
return func(*args, **kwargs)
return wrapper
@login_required
def sensitive_operation():
print("执行敏感操作")
def is_logged_in():
return False # simulate not logged in
sensitive_operation()Output:
请先登录Explanation: login_required checks login status before allowing the original function to run.
Example 6: Repeating Function Execution
Use case: Execute a function multiple times.
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return
return wrapper
return decorator
@repeat(3)
def say_hello():
print("Hello!")
say_hello()Output:
Hello!
Hello!
Hello!Explanation: The repeat decorator uses a nested function to call the target function n times.
5. Class Decorator
Example 7: Class‑Based Decorator
Use case: Implement a decorator using a class.
class CountCalls:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print(f"第 {self.num_calls} 次调用 {self.func.__name__}")
return self.func(*args, **kwargs)
@CountCalls
def test_function():
print("执行测试函数")
test_function()
test_function()Output:
第 1 次调用 test_function
执行测试函数
第 2 次调用 test_function
执行测试函数Explanation: The class implements __call__ to act as a decorator, tracking how many times the function is invoked.
6. Using functools.wraps to Preserve Function Metadata
Example 8: Preserve Name and Docstring
Use case: Prevent a decorator from overwriting the original function’s name and documentation.
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print("函数调用前执行")
return func(*args, **kwargs)
return wrapper
@my_decorator
def example_function():
"""这是一个示例函数"""
print("执行示例函数")
print(example_function.__name__) # output: example_function
print(example_function.__doc__) # output: 这是一个示例函数Explanation: functools.wraps copies the original function’s __name__ and __doc__ attributes to the wrapper.
7. Summary
Decorators are a highly useful feature in Python that enable dynamic addition of functionality to functions without altering their source code. They can be employed for logging, performance monitoring, permission checks, and more complex logic via class‑based implementations. Understanding decorators equips you with a powerful tool for clean and reusable code.
Test Development Learning Exchange
Test Development Learning Exchange
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.