问题: 什么是装饰器,它的主要作用是什么?
👇 点击展开/折叠 面试背诵模板(建议先背这个)
装饰器本质是一个可调用对象(如函数或类),它接收一个函数作为参数,利用闭包返回一个增强后的新函数,在不修改原函数源码和调用方式的前提下为其扩展功能。主要作用是将日志记录、性能计时、权限校验、缓存等横切关注点(AOP)与核心业务逻辑解耦,提高代码复用性,符合开闭原则。Python 使用 @decorator_name 语法糖进行应用。
---
装饰器的本质与执行流程
装饰器的核心是闭包,@wrapper 语法糖在函数定义阶段即执行,等价于 func = wrapper(func)。这意味着装饰器在模块导入时就会运行,而不仅仅是在调用时。
1 2 3 4 5 6 7 8 9 10 11
| def timer(func): def wrapper(*args, **kwargs): start = time.time() result = func(*args, **kwargs) print(f"耗时: {time.time() - start}") return result return wrapper
@timer def fast(): time.sleep(0.1)
|
带参数的装饰器(三层结构)
当装饰器本身需要接收参数时,需要再嵌套一层函数来接收配置。
1 2 3 4 5 6 7 8 9 10 11 12
| def repeat(times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(times): result = func(*args, **kwargs) return result return wrapper return decorator
@repeat(times=3) def say(): print("Hello")
|
装饰器返回的 wrapper 会覆盖原函数的 __name__、__doc__ 等属性,导致调试困难。使用 @wraps(func) 可将这些属性从原函数复制到包装函数中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| from functools import wraps
def logger(func): @wraps(func) def wrapper(*args, **kwargs): print(f"调用 {func.__name__}") return func(*args, **kwargs) return wrapper
@logger def add(a, b): """求和函数""" return a + b
print(add.__name__) print(add.__doc__)
|
类实现装饰器 vs 函数实现装饰器
| 实现方式 |
实现原理 |
适用场景 |
| 函数装饰器 |
外层返回内层闭包 |
简单装饰,无状态保持 |
| 类装饰器 |
__init__ 接收函数,__call__ 实现包装 |
需保持复杂状态或配置(如计数、统计) |
1 2 3 4 5 6 7 8 9 10 11 12 13
| class Counter: 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)
@Counter def process(): pass
|
多个装饰器的执行顺序
多个装饰器叠加时,从下往上包装,从上往下执行(调用顺序:先执行靠近函数的装饰器逻辑,再执行外层的)。