python如何实现一个装饰器_python装饰器原理与实现方法详解

python如何实现一个装饰器_python装饰器原理与实现方法详解
最新回答
╭⌒浅浅笑

2026-10-24 11:42:20

Python装饰器是一种强大的工具,通过“包裹”函数为其添加额外功能,而无需修改原函数代码。其核心原理基于函数是一等公民和闭包特性,利用@语法糖简化调用流程。以下是详细实现方法与原理分析:

一、基础装饰器实现

核心结构:外部函数接收被装饰函数,返回嵌套的wrapper函数,wrapper执行额外逻辑并调用原函数。

import functoolsdef log_calls(func): @functools.wraps(func) # 保留原函数元信息 def wrapper(*args, kwargs): print(f"调用函数: {func.__name__},参数: {args}, {kwargs}") result = func(*args, kwargs) print(f"函数 {func.__name__} 返回: {result}") return result return wrapper@log_callsdef add(a, b): return a + b

执行流程:

  1. @log_calls等价于add = log_calls(add),add指向wrapper函数。
  2. 调用add(1, 2)时,实际执行wrapper(1, 2),记录日志后调用原add函数。
二、带参数的装饰器(装饰器工厂)

场景:需动态配置装饰器行为(如日志级别、计时单位)。实现方法:外层函数接收参数,返回真正的装饰器函数。

import timeimport functoolsdef timer(unit="seconds"): def decorator(func): @functools.wraps(func) def wrapper(*args, kwargs): start = time.perf_counter() result = func(*args, kwargs) duration = time.perf_counter() - start if unit == "milliseconds": duration *= 1000 unit_str = "ms" else: unit_str = "s" print(f"耗时: {duration:.4f} {unit_str}") return result return wrapper return decorator@timer(unit="milliseconds")def complex_calc(n): return sum(i*i for i in range(n))

执行流程:

  1. @timer(unit="milliseconds")先调用timer("milliseconds"),返回decorator函数。
  2. complex_calc = decorator(complex_calc),将unit参数通过闭包传递给wrapper。
三、类装饰器

适用场景:需维护状态或共享资源(如调用次数统计、连接池管理)。核心要求:类实现__call__方法,使实例可调用。

import functoolsclass CallCounter: def __init__(self, func): functools.update_wrapper(self, func) # 保留元信息 self.func = func self.count = 0 def __call__(self, *args, kwargs): self.count += 1 print(f"{self.func.__name__} 调用次数: {self.count}") return self.func(*args, kwargs)@CallCounterdef greet(name): return f"Hello, {name}!"

执行流程:

  1. @CallCounter等价于greet = CallCounter(greet),greet变为CallCounter实例。
  2. 调用greet("Alice")时,实际执行CallCounter.__call__,更新计数后调用原函数。
四、关键原理与注意事项
  1. 闭包机制:

    wrapper函数捕获外部函数的变量(如func),即使外部函数已执行完毕,仍能通过闭包访问这些变量。

    示例:log_calls中的wrapper通过闭包记住func,实现不修改原函数的情况下扩展行为。

  2. functools.wraps的作用:

    保留原函数的__name__、__doc__等元信息,避免装饰后函数显示为wrapper。

    对比:无@functools.wraps时,add.__name__会返回"wrapper"。

  3. 装饰器执行顺序:

    多个装饰器按从下到上的顺序应用(如@dec1 @dec2 func等价于dec1(dec2(func)))。

五、应用场景示例
  1. 权限验证:

    def require_auth(role): def decorator(func): @functools.wraps(func) def wrapper(user, *args, kwargs): if user.role != role: raise PermissionError("无权访问") return func(user, *args, kwargs) return wrapper return decorator@require_auth("admin")def delete_data(user): print("数据已删除")
  2. 缓存装饰器:

    def cache(func): cache_dict = {} @functools.wraps(func) def wrapper(*args): if args not in cache_dict: cache_dict[args] = func(*args) return cache_dict[args] return wrapper
总结

Python装饰器通过函数嵌套和闭包实现行为扩展,其核心优势在于不修改原函数代码即可添加功能。根据需求选择函数装饰器(简单逻辑)或类装饰器(状态管理),并善用functools.wraps保留元信息。理解闭包与一等函数特性后,可灵活实现日志、计时、权限控制等横切关注点。