Python中的装饰器是如何工作的 装饰器在Python中有哪些常见用途

Python中的装饰器是如何工作的 装饰器在Python中有哪些常见用途
最新回答
醒着做梦≈

2021-07-14 06:39:21

Python中的装饰器通过包装原始函数,在不修改其代码的情况下增加功能,其工作原理和常见用途如下

装饰器的工作原理
  1. 定义装饰器函数装饰器是一个接收函数作为参数并返回新函数的高阶函数。例如:

    def my_decorator(func): def wrapper(): print("函数执行前") func() print("函数执行后") return wrapper
  2. 内部定义包装函数包装函数(如wrapper)会在调用原始函数前后执行额外操作(如日志、权限检查雹余冲等)。

  3. 返回包装函数装饰器最终返回包装函数,替代原始函数。

  4. 使用@语法应用装饰器通过@装饰器名将装饰器绑定到目标函数,等价于函数 = 装饰器(函数)。示例:

    @my_decoratordef say_hello(): print("Hello!")say_hello()

    输出

    函数执行前Hello!函数执行后
  5. 支持带参数的装饰器若装饰器需接受参数,需通过三层嵌套实现:

    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}!")greet("Alice")

    输出

    Hello, Alice!Hello, Alice!Hello, Alice!
装饰器的常见用途
  1. 日志记录记录函数执行时间、参数或调用次数,便于调试和性能分析。示例:

    import timedef log_time(func): def wrapper(*args, kwargs): start = time.time() result = func(*args, kwargs) print(f"{func.__name__} 执行耗时: {time.time()-start:.2f}秒") return result return wrapper@log_timedef slow_function(): time.sleep(1)slow_function()
  2. 权限验证检查源歼用户权限(如登录状态、角色)后再执行函数。示例:

    def requires_admin(func): def wrapper(*args, kwargs): if not is_admin(): # 假设存在权限检查函数 return "无权限访问" return func(*args, kwargs) return wrapper@requires_admindef delete_data(): print("数据已删除")
  3. 缓存(Memoization)缓存函数结果,避免重复计算。示例:

    import functoolsdef memoize(func): cache = {} @functools.wraps(func) # 保留原始函数元数据 def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper@memoizedef fibonacci(n): if n < 2: return n return fibonacci(n-1) + fibonacci(n-2)
  4. 重试机制函数失败时自动重试,适用于网络请求毁握等不稳定操作。示例:

    def retry(max_attempts): def decorator(func): def wrapper(*args, kwargs): for attempt in range(max_attempts): try: return func(*args, kwargs) except Exception as e: print(f"尝试 {attempt+1} 失败: {e}") return "重试次数耗尽" return wrapper return decorator@retry(max_attempts=3)def unreliable_api_call(): import random if random.random() < 0.7: raise Exception("API调用失败") return "成功"
调试装饰器的技巧
  1. 使用functools.wraps保留原始函数的__name__、__doc__等元数据,避免调试时信息丢失。

  2. 插入print语句在包装函数中打印关键变量或执行流程,跟踪装饰器行为。

  3. 使用调试器(如pdb)在包装函数内设置断点,单步执行代码并检查变量。示例:

    import pdbdef debug_decorator(func): def wrapper(*args, kwargs): pdb.set_trace() # 设置断点 return func(*args, kwargs) return wrapper@debug_decoratordef add(a, b): return a + badd(2, 3)
总结

装饰器通过“函数包装”实现代码复用和功能扩展,常见用途包括日志、权限控制、缓存和重试。掌握装饰器能显著提升代码的简洁性和可维护性,尤其适合处理横切关注点(Cross-cutting Concerns)。