上一篇
Python带参数装饰器详解 - 深入理解与应用
- Python
- 2025-08-05
- 1194
Python带参数装饰器详解
掌握高阶Python技巧:创建和使用带参数装饰器
装饰器基础回顾
装饰器是Python中一种强大的语法特性,允许在不修改原函数代码的情况下增强其功能。带参数的装饰器则更进一步,提供了更大的灵活性。
装饰器的基本结构
标准装饰器是一个接受函数作为参数并返回新函数的可调用对象:
def decorator(func):
def wrapper(*args, **kwargs):
# 在调用函数前的操作
result = func(*args, **kwargs)
# 在调用函数后的操作
return result
return wrapper
@decorator
def my_function():
pass
为什么需要带参数的装饰器?
当我们希望装饰器本身可以接受参数来定制其行为时,就需要带参数的装饰器。例如:
- 指定重试操作的次数
- 设置缓存过期时间
- 自定义日志格式
- 控制权限级别
带参数装饰器的实现原理
带参数装饰器实际上是一个返回装饰器的函数:
def decorator_with_args(arg1, arg2):
def actual_decorator(func):
def wrapper(*args, **kwargs):
# 使用arg1, arg2
result = func(*args, **kwargs)
return result
return wrapper
return actual_decorator
@decorator_with_args('value1', 'value2')
def my_function():
pass
这种三层嵌套结构是带参数装饰器的关键:
- 最外层函数接收装饰器参数
- 中间层函数接收被装饰的函数
- 最内层函数实现装饰逻辑
示例1:重试装饰器
创建一个带参数的重试装饰器,在函数执行失败时自动重试指定次数:
def retry(max_attempts=3, delay=1):
def decorator(func):
import time
def wrapper(*args, **kwargs):
attempts = 0
while attempts < max_attempts:
try:
return func(*args, **kwargs)
except Exception as e:
attempts += 1
print(f"Attempt {attempts} failed: {e}")
if attempts < max_attempts:
time.sleep(delay)
raise RuntimeError(f"Function failed after {max_attempts} attempts")
return wrapper
return decorator
# 使用带参数的装饰器
@retry(max_attempts=5, delay=2)
def connect_to_database():
# 模拟数据库连接
import random
if random.random() < 0.7:
raise ConnectionError("Database connection failed")
return "Connected successfully"
# 测试
print(connect_to_database())
示例2:带单位的计时装饰器
创建一个计时装饰器,可以指定时间单位:
import time
def timer(unit='seconds'):
def decorator(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
duration = end - start
# 根据单位转换时间
if unit == 'milliseconds':
duration *= 1000
unit_str = 'ms'
elif unit == 'microseconds':
duration *= 1000000
unit_str = 'μs'
else:
unit_str = 's'
print(f"{func.__name__} executed in {duration:.4f} {unit_str}")
return result
return wrapper
return decorator
# 使用带参数的装饰器
@timer(unit='milliseconds')
def calculate_sum(n):
return sum(range(n))
# 测试
print(calculate_sum(1000000))
示例3:权限控制装饰器
创建一个权限控制装饰器,根据用户角色控制函数访问:
def requires_role(role):
def decorator(func):
def wrapper(user, *args, **kwargs):
if user.get('role') != role:
raise PermissionError(f"User does not have {role} role")
return func(user, *args, **kwargs)
return wrapper
return decorator
# 定义用户数据
admin_user = {'name': 'Alice', 'role': 'admin'}
regular_user = {'name': 'Bob', 'role': 'user'}
# 使用带参数的装饰器
@requires_role('admin')
def delete_user(user, user_id):
print(f"User {user['name']} deleted user {user_id}")
return True
# 测试
try:
# 管理员可以删除用户
delete_user(admin_user, 1001)
# 普通用户尝试删除会抛出异常
delete_user(regular_user, 1002)
except PermissionError as e:
print(f"Error: {e}")
带参数装饰器的应用场景
调试与日志
创建带日志级别参数的装饰器,控制不同情况下的日志输出详细程度。
性能监控
创建带阈值参数的装饰器,仅在执行时间超过指定阈值时发出警告。
API限流
创建带速率限制参数的装饰器,控制函数在指定时间内的最大调用次数。
缓存管理
创建带过期时间参数的装饰器,自动缓存函数结果并在指定时间后失效。
使用带参数装饰器的注意事项
- 保留函数元数据:使用
@functools.wraps
保留原始函数的名称和文档字符串 - 避免过度嵌套:三层嵌套结构可能影响可读性,考虑使用类实现装饰器
- 参数顺序:装饰器参数必须位于函数参数之前
- 调试复杂性:带参数装饰器增加了调试难度,确保添加清晰的日志
- 性能影响:装饰器会增加函数调用开销,在性能敏感场景需谨慎使用
本文由SikongLing于2025-08-05发表在吾爱品聚,如有疑问,请联系我们。
本文链接:https://www.521pj.cn/20257373.html
发表评论