这是一个非常经典且重要的Python进阶知识点。一句话理解装饰器就是一个“给函数增加额外功能但不修改函数内部代码”的工具。就像给手机套上手机壳——手机本身没变但多了防摔功能。1. 基础认知一切皆函数在讲装饰器前先记住两点Python中函数可以被当作参数传给另一个函数。Python中函数可以嵌套定义。2. 手动实现一个最简单的装饰器假设你想知道一个函数运行了多长时间但不想在每个函数里都写计时代码。import time # 这是一个装饰器函数 def timer(func): def wrapper(*args, **kwargs): # *args, **kwargs 保证能接收任意参数 start time.time() result func(*args, **kwargs) # 真正执行原函数 end time.time() print(f函数 {func.__name__} 运行了 {end - start:.4f} 秒) return result return wrapper # 使用装饰器语法糖 timer def slow_function(): time.sleep(1) return 完成 # 调用时完全无感知 print(slow_function()) # 输出函数 slow_function 运行了 1.0002 秒 # 完成背后原理timer等价于执行了slow_function timer(slow_function)也就是把原函数替换成了wrapper。3. 带参数的装饰器三层结构如果你的装饰器本身需要接收参数比如指定超时时间需要再包装一层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(times3) # 调用时带上参数 def say_hello(): print(Hello) say_hello() # 会打印 3 次 Hello4. 保留原函数的元信息重要使用装饰器后原函数的__name__、__doc__等会被wrapper覆盖调试时会困惑。标准做法是加上functools.wrapsfrom functools import wraps def timer(func): wraps(func) # 这一行把原函数的信息复制给 wrapper def wrapper(*args, **kwargs): # ... 计时逻辑 return func(*args, **kwargs) return wrapper5. 类装饰器用类来实现除了用函数还可以用类来实现装饰器通过__call__魔法方法class CountCalls: 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) CountCalls def test(): print(执行) test() # 第 1 次调用 test() # 第 2 次调用6. 实际开发中最常用的场景场景说明登录校验检查用户是否登录未登录则跳转权限控制检查当前用户是否有权限执行该操作日志记录自动记录函数的入参、返回值、异常缓存如lru_cache对相同参数直接返回缓存结果重试机制函数报错时自动重试 N 次路由注册Flask/FastAPIapp.route(/)就是装饰器7. 一个常见的坑装饰器顺序多个装饰器叠加时执行顺序是自下而上从靠近函数的开始a b c def func(): pass # 实际执行顺序func a(b(c(func)))8. 如果你刚接触给你一个万能模板以后写任何装饰器直接套这个模板不会出错from functools import wraps def my_decorator(func): wraps(func) def wrapper(*args, **kwargs): # 在调用前做点什么 result func(*args, **kwargs) # 在调用后做点什么 return result return wrapper最后送你一个思考装饰器本质上是“面向切面编程”AOP的一种实现它把业务逻辑核心功能和辅助逻辑日志、计时、校验分离开让代码更干净。