上一篇
Python带参数装饰器详解 - 如何编写和使用带参数的Python装饰器
- Python
- 2025-08-02
- 1409
Python带参数装饰器详解
掌握Python高级编程技巧:编写和使用带参数的装饰器
什么是装饰器?
装饰器是Python中一种强大的功能,允许在不修改原始函数代码的情况下扩展其行为。它们本质上是接受函数作为参数并返回新函数的函数。
为什么需要带参数的装饰器?
标准装饰器适用于所有函数使用相同配置的情况。但当我们需要根据情况调整装饰器的行为时,就需要带参数的装饰器。例如:
- 根据日志级别记录不同信息
- 设置不同的超时时间
- 根据环境切换缓存策略
- 为不同用户设置访问权限级别
基础装饰器回顾
在深入带参数的装饰器之前,先回顾一下普通装饰器的结构:
def simple_decorator(func):
def wrapper(*args, **kwargs):
print("函数执行前操作")
result = func(*args, **kwargs)
print("函数执行后操作")
return result
return wrapper
@simple_decorator
def greet(name):
print(f"Hello, {name}!")
# 调用
greet("Alice")
这个装饰器为函数添加了前后操作,但所有使用它的函数都会执行相同的操作。
带参数装饰器的结构
带参数的装饰器需要三层嵌套函数:
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
结构解析:
- 外层函数:接受装饰器的参数,返回实际装饰器
- 中间层:接受被装饰的函数,返回包装函数
- 内层函数:执行装饰逻辑,调用原始函数
实用示例
示例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"尝试 {attempts}/{max_attempts} 失败,{delay}秒后重试...")
if attempts == max_attempts:
raise
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=5, delay=2)
def fetch_data(url):
# 模拟可能失败的操作
if "example" not in url:
raise ValueError("无效URL")
return "数据获取成功"
# 测试
print(fetch_data("https://test.com")) # 会重试5次
print(fetch_data("https://example.com/data")) # 成功
示例2:权限验证装饰器
def requires_role(role="user"):
def decorator(func):
def wrapper(user, *args, **kwargs):
if user.get("role") != role:
raise PermissionError(f"需要{role}权限,当前是{user.get('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):
print(f"{user['name']} 删除了用户")
# 测试
delete_user(admin_user) # 成功
try:
delete_user(regular_user) # 抛出异常
except PermissionError as e:
print(f"错误: {e}")
高级应用
基于环境的装饰器
def environment_aware(prod_action, dev_action="bypass"):
def decorator(func):
import os
def wrapper(*args, **kwargs):
env = os.getenv("APP_ENV", "development")
if env == "production":
# 在生产环境执行特定操作
print(f"生产环境操作: {prod_action}")
else:
# 在开发环境执行不同操作
print(f"开发环境操作: {dev_action}")
return func(*args, **kwargs)
return wrapper
return decorator
@environment_aware(prod_action="严格验证", dev_action="跳过验证")
def process_request(request):
print("处理请求:", request)
# 设置环境变量
import os
os.environ["APP_ENV"] = "production"
process_request("重要请求") # 生产环境模式
os.environ["APP_ENV"] = "development"
process_request("测试请求") # 开发环境模式
注意事项与最佳实践
1. 保留函数元数据
使用@functools.wraps保留原始函数的元数据:
import functools
def debug_decorator(log_level="INFO"):
def decorator(func):
@functools.wraps(func) # 保留元数据
def wrapper(*args, **kwargs):
print(f"[{log_level}] 调用 {func.__name__}")
return func(*args, **kwargs)
return wrapper
return decorator
2. 装饰器堆叠顺序
当使用多个装饰器时,顺序很重要:
@decorator1
@decorator2
def my_function():
pass
# 等同于
my_function = decorator1(decorator2(my_function))
3. 避免过度使用
装饰器虽强大,但过度使用会使代码难以理解和调试。仅在确实能简化代码或提高可维护性时使用。
本文由JiJieJuan于2025-08-02发表在吾爱品聚,如有疑问,请联系我们。
本文链接:http://521pj.cn/20257153.html
发表评论