基本概念
装饰器(Decorator)是 Python 中一种强大的设计模式,它允许在不修改原函数代码的情况下,为函数添加额外的功能。装饰器本质上是一个接受函数作为参数并返回一个新函数的函数。
工作原理
1. 装饰器的语法糖
python@decorator def my_function(): pass
上面的代码等价于:
pythonmy_function = decorator(my_function)
2. 简单装饰器示例
pythondef simple_decorator(func): def wrapper(): print("函数执行前") func() print("函数执行后") return wrapper @simple_decorator def say_hello(): print("Hello, World!") say_hello()
输出:
shell函数执行前 Hello, World! 函数执行后
3. 带参数的装饰器
pythondef decorator_with_args(func): def wrapper(*args, **kwargs): print(f"参数: args={args}, kwargs={kwargs}") result = func(*args, **kwargs) return result return wrapper @decorator_with_args def add(a, b): return a + b print(add(3, 5)) # 输出: 参数: args=(3, 5), kwargs={} \n 8
4. 带自定义参数的装饰器
pythondef repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator @repeat(3) def greet(name): print(f"Hello, {name}!") greet("Python") # 会打印三次
5. 使用 functools.wraps 保留元数据
pythonfrom functools import wraps def logging_decorator(func): @wraps(func) def wrapper(*args, **kwargs): print(f"调用函数: {func.__name__}") return func(*args, **kwargs) return wrapper @logging_decorator def calculate(x, y): """计算两个数的和""" return x + y print(calculate.__name__) # 输出: calculate print(calculate.__doc__) # 输出: 计算两个数的和
实际应用场景
1. 计时装饰器
pythonimport time from functools import wraps def timer(func): @wraps(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) return "完成" slow_function()
2. 缓存装饰器
pythonfrom functools import wraps def memoize(func): cache = {} @wraps(func) def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper @memoize def fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2) print(fibonacci(100)) # 快速计算
3. 权限验证装饰器
pythonfrom functools import wraps def require_permission(permission): def decorator(func): @wraps(func) def wrapper(*args, **kwargs): user_permissions = kwargs.get('permissions', []) if permission in user_permissions: return func(*args, **kwargs) else: raise PermissionError(f"需要 {permission} 权限") return wrapper return decorator @require_permission('admin') def delete_user(user_id, permissions): print(f"删除用户 {user_id}") delete_user(1, permissions=['admin']) # 正常执行 delete_user(1, permissions=['user']) # 抛出权限错误
类装饰器
pythonclass CountCalls: def __init__(self, func): self.func = func self.count = 0 def __call__(self, *args, **kwargs): self.count += 1 print(f"调用次数: {self.count}") return self.func(*args, **kwargs) @CountCalls def say_hi(): print("Hi!") say_hi() # 调用次数: 1 say_hi() # 调用次数: 2
多个装饰器的执行顺序
pythondef decorator1(func): def wrapper(): print("装饰器1 - 前") func() print("装饰器1 - 后") return wrapper def decorator2(func): def wrapper(): print("装饰器2 - 前") func() print("装饰器2 - 后") return wrapper @decorator1 @decorator2 def my_function(): print("函数执行") my_function()
输出:
shell装饰器1 - 前 装饰器2 - 前 函数执行 装饰器2 - 后 装饰器1 - 后
关键要点
- 装饰器本质:是一个接受函数并返回新函数的函数
- 语法糖:
@decorator是func = decorator(func)的简写 - 参数传递:使用
*args, **kwargs确保装饰器适用于任何函数 - 元数据保留:使用
@wraps(func)保留原函数的元数据 - 执行顺序:多个装饰器时,从下往上应用,从上往下执行
- 闭包:装饰器利用闭包特性访问外部变量
- 类装饰器:通过实现
__call__方法实现
装饰器是 Python 中实现横切关注点(如日志、缓存、权限验证)的优雅方式,遵循开放封闭原则,使代码更加模块化和可维护。