Python 装饰器入门:3 个案例让你彻底理解

Python 装饰器是一种强大的语法特性,允许你修改函数或类的行为而不改变其源代码。它基于高阶函数的概念:装饰器本身是一个函数,它接受另一个函数作为输入,并返回一个新函数。这种机制常用于添加日志、缓存、权限检查等功能。本指南将通过三个逐步深入的案例,帮助你彻底理解装饰器的原理和应用。所有代码都使用 Python 语法,并确保可运行。

核心概念:装饰器的工作原理

在 Python 中,装饰器使用 @decorator_name 语法糖来应用。本质上,它等价于: $$ \text{new_func} = \text{decorator}(\text{original_func}) $$ 其中,decorator 是一个函数,它接收 original_func 作为参数,并返回一个包装后的函数 new_func。当调用 original_func 时,实际执行的是 new_func 的逻辑。这利用了闭包特性:新函数可以访问外部作用域的变量。理解这一点是掌握装饰器的关键。

下面,我们通过三个案例逐步构建你的理解。每个案例都包括代码实现、解释和运行示例。


案例 1:简单装饰器——函数执行计时器

这个案例展示一个基础装饰器,用于测量任何函数的执行时间。它不改变原函数的功能,只是添加计时逻辑。

import time

def timer_decorator(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:.6f} 秒")
        return result
    return wrapper

# 使用装饰器
@timer_decorator
def calculate_sum(n):
    """计算 1 到 n 的和"""
    return sum(range(1, n+1))

# 测试
print(calculate_sum(100000))  # 输出: 5000050000 和计时信息

解释和运行结果:

  • 工作原理timer_decorator 是一个装饰器函数。它定义了一个内部函数 wrapper,该函数在调用原函数 calculate_sum 前后添加计时逻辑。*args**kwargs 确保它能处理任意参数。
  • 运行示例:当你调用 calculate_sum(100000) 时,输出类似:
    函数 calculate_sum 执行耗时: 0.005123 秒
    5000050000
    

  • 关键点:装饰器通过闭包捕获 func 变量,确保每次调用都正确计时。这展示了装饰器的非侵入性:无需修改 calculate_sum 的代码。

案例 2:带参数的装饰器——智能缓存系统

这个案例扩展了装饰器功能,允许传递参数。我们实现一个缓存装饰器,根据参数缓存函数结果,避免重复计算。

def cache_decorator(max_size=3):
    """带参数的装饰器,max_size 控制缓存大小"""
    cache = {}  # 缓存字典
    def decorator(func):
        def wrapper(*args):
            if args in cache:  # 检查缓存
                print(f"缓存命中: {func.__name__}{args} -> {cache[args]}")
                return cache[args]
            result = func(*args)  # 执行原函数
            if len(cache) >= max_size:  # 缓存满时移除最早条目
                oldest_key = next(iter(cache))
                del cache[oldest_key]
            cache[args] = result  # 更新缓存
            print(f"计算并缓存: {func.__name__}{args} -> {result}")
            return result
        return wrapper
    return decorator

# 使用带参数的装饰器
@cache_decorator(max_size=2)  # 设置缓存大小为 2
def fibonacci(n):
    """计算斐波那契数列第 n 项"""
    if n <= 1:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

# 测试
print(fibonacci(5))  # 输出: 5 (会多次调用,但缓存优化)

解释和运行结果:

  • 工作原理cache_decorator 是一个工厂函数,它返回真正的装饰器 decoratormax_size 参数控制缓存大小。内部使用 cache 字典存储结果,wrapper 函数处理缓存逻辑。
  • 运行示例:调用 fibonacci(5) 时,输出类似:
    计算并缓存: fibonacci(1) -> 1
    计算并缓存: fibonacci(0) -> 0
    计算并缓存: fibonacci(2) -> 1
    缓存命中: fibonacci(1) -> 1
    计算并缓存: fibonacci(3) -> 2
    缓存命中: fibonacci(2) -> 1
    计算并缓存: fibonacci(4) -> 3
    缓存命中: fibonacci(3) -> 2
    计算并缓存: fibonacci(5) -> 5
    5
    

  • 关键点:带参数的装饰器通过嵌套函数实现。这增强了灵活性,例如 max_size 可配置。数学上,这类似于函数组合:$ \text{decorator} = \text{cache_decorator}(\text{max_size}) $,然后应用于 $ \text{fibonacci} $。

案例 3:类装饰器——用户认证系统

这个案例演示装饰器用于类方法,实现权限检查。它检查用户是否有权限执行特定操作,适合 Web 应用或 API。

class AuthDecorator:
    """类装饰器,用于认证用户权限"""
    def __init__(self, required_role):
        self.required_role = required_role  # 所需角色,如 'admin'

    def __call__(self, func):
        def wrapper(user, *args, **kwargs):
            if user.get('role') != self.required_role:
                raise PermissionError(f"用户 {user['name']} 无权限执行 {func.__name__}")
            return func(user, *args, **kwargs)
        return wrapper

# 使用类装饰器
class UserSystem:
    @AuthDecorator(required_role='admin')  # 装饰器应用于方法
    def delete_user(self, user, target_user):
        print(f"用户 {target_user} 已被删除")
        return True

# 测试
system = UserSystem()
admin_user = {'name': 'Alice', 'role': 'admin'}
normal_user = {'name': 'Bob', 'role': 'user'}

print(system.delete_user(admin_user, 'Bob'))  # 输出: 用户 Bob 已被删除
try:
    system.delete_user(normal_user, 'Alice')  # 抛出异常
except PermissionError as e:
    print(e)  # 输出: 用户 Bob 无权限执行 delete_user

解释和运行结果:

  • 工作原理AuthDecorator 是一个类,实现了 __call__ 方法,使其行为像函数装饰器。__init__ 接收参数(如 required_role),__call__ 返回包装函数 wrapper,该函数检查用户角色。
  • 运行示例
    • 使用 admin_user 调用 delete_user 成功,输出:用户 Bob 已被删除True
    • 使用 normal_user 调用时,抛出 PermissionError,输出:用户 Bob 无权限执行 delete_user
  • 关键点:类装饰器适用于状态管理(如角色配置)。这体现了装饰器的通用性:它不仅能修饰函数,还能修饰类方法。数学上,装饰器可以视为一个映射:$ \text{原函数} \mapsto \text{增强函数} $。

总结:彻底掌握装饰器

通过以上三个案例,你已经从基础到高级理解了 Python 装饰器:

  1. 简单装饰器(案例1):添加额外功能(如计时),不改变原函数。
  2. 带参数装饰器(案例2):通过工厂函数实现可配置行为(如缓存大小)。
  3. 类装饰器(案例3):用于类方法,支持复杂状态管理(如认证)。

装饰器的优势

  • 代码复用:避免重复代码,例如多个函数共享日志逻辑。
  • 模块化:功能增强独立于业务逻辑。
  • 灵活性:支持参数化和组合,例如 $ \text{@decorator1} \circ \text{@decorator2} $。

练习建议:尝试自己实现装饰器,如添加日志或重试机制。掌握装饰器后,你将能更高效地编写 Python 代码。如果有疑问,欢迎提供具体场景,我会进一步解析!

Logo

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

更多推荐