Python 装饰器详解:让代码更简洁高效

装饰器是Python中强大的语法特性,它允许在不修改原函数代码的情况下动态增强功能。本质上,装饰器是高阶函数:接受函数作为参数,返回新函数。


一、装饰器核心原理
  1. 函数是第一类对象

    • 函数可被赋值给变量:func = original_function
    • 函数可作为参数传递:execute(func)
    • 函数可作为返回值:return wrapper
  2. 闭包机制

    def decorator(func):
        def wrapper(*args, **kwargs):  # 闭包捕获func
            # 增强功能
            result = func(*args, **kwargs) 
            # 增强功能
            return result
        return wrapper
    


二、基础装饰器实现
# 1. 定义装饰器
def timer_decorator(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)  # 执行原函数
        end = time.time()
        print(f"{func.__name__} 执行耗时: {end-start:.4f}秒")
        return result
    return wrapper

# 2. 应用装饰器
@timer_decorator  # 语法糖等价于:my_func = timer_decorator(my_func)
def my_func(n):
    return sum(range(n))

# 3. 调用增强后的函数
my_func(1000000)  # 输出: my_func 执行耗时: 0.0412秒


三、装饰器进阶技巧
  1. 带参数的装饰器

    def repeat(num_times):  # 外层接收参数
        def decorator(func):
            def wrapper(*args, **kwargs):
                for _ in range(num_times):
                    result = func(*args, **kwargs)
                return result
            return wrapper
        return decorator
    
    @repeat(num_times=3)
    def greet(name):
        print(f"Hello, {name}!")
    

  2. 类装饰器

    class CountCalls:
        def __init__(self, func):
            self.func = func
            self.call_count = 0
        
        def __call__(self, *args, **kwargs):  # 实现可调用对象
            self.call_count += 1
            print(f"第{self.call_count}次调用")
            return self.func(*args, **kwargs)
    
    @CountCalls
    def example():
        print("执行函数")
    

  3. 保留元数据

    import functools
    def decorator(func):
        @functools.wraps(func)  # 关键:保留原函数信息
        def wrapper(*args, **kwargs):
            ...
        return wrapper
    


四、实际应用场景
场景 实现效果 示例装饰器
性能监控 函数执行时间统计 @timer_decorator
权限验证 检查用户登录状态 @login_required
缓存加速 存储重复计算结果 @lru_cache
错误重试 网络请求失败自动重试 @retry(times=3)
日志记录 自动记录函数调用参数 @log_execution

五、数学视角:函数组合

装饰器本质是函数组合运算: $$ \text{decorated} = \text{decorator} \circ \text{original} $$ 其中 $\circ$ 表示函数复合,满足: $$ (\text{decorator} \circ \text{original})(x) = \text{decorator}(\text{original}(x)) $$


六、最佳实践
  1. 使用functools.wraps保留函数元信息
  2. 避免装饰器副作用(如修改全局状态)
  3. 复杂逻辑优先使用类装饰器
  4. 装饰器链顺序:从下往上执行
    @deco1
    @deco2
    def func(): ...  # 等价 deco1(deco2(func))
    

装饰器通过正交性设计(功能分离)显著提升代码复用率。统计显示,合理使用装饰器可减少$30%$重复代码量,同时保持核心逻辑纯净性。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐