大家好欢迎来到我的技术博客 在这里我会分享学习笔记、实战经验与技术思考力求用简单的方式讲清楚复杂的问题。 本文将围绕Python进阶这个话题展开希望能为你带来一些启发或实用的参考。 无论你是刚入门的新手还是正在进阶的开发者希望你都能有所收获文章目录Python进阶装饰器的执行顺序——从下到上装饰从上到下执行 什么是装饰器 多个装饰器的叠加从下到上“装饰”从上到下“执行” 示例两个装饰器叠加✅ 输出结果 为什么是这样背后的机制解析 装饰器链的构建过程 用 Mermaid 图表可视化执行流程 更复杂的例子三个装饰器嵌套 输出结果 分析⚠️ 常见误区与陷阱❌ 误解一装饰器顺序等于执行顺序❌ 误解二装饰器可以改变函数名或文档 实际应用场景权限控制 日志记录 缓存 输出 拓展阅读Python 官方文档与社区资源 总结掌握装饰器顺序的黄金法则 最佳实践建议 附加思考装饰器 vs 装饰器模式Design Pattern 结语Python进阶装饰器的执行顺序——从下到上装饰从上到下执行在学习 Python 的过程中装饰器Decorator是一个非常强大且优雅的特性。它不仅让代码更简洁还能在不修改原函数逻辑的前提下动态地增强函数的功能。但当你开始深入使用多个装饰器时一个关键问题就浮出水面装饰器的执行顺序到底是什么今天我们就来彻底搞清楚这个看似简单却充满玄机的问题。✨ 什么是装饰器首先让我们快速回顾一下装饰器的基本概念。在 Python 中装饰器是一种设计模式允许你在不修改原函数代码的情况下为函数添加额外功能。它的本质是高阶函数——接受一个函数作为参数并返回一个新的函数。defmy_decorator(func):defwrapper():print(Before the function is called.)func()print(After the function is called.)returnwrappermy_decoratordefsay_hello():print(Hello!)say_hello()输出结果Before the function is called. Hello! After the function is called.这里my_decorator就是装饰器语法糖等价于say_hellomy_decorator(say_hello)✅ 装饰器的核心思想把函数当作数据来处理通过包装实现功能扩展。 多个装饰器的叠加从下到上“装饰”从上到下“执行”当我们在一个函数上叠加多个装饰器时装饰器的“装饰”顺序和“执行”顺序是相反的这听起来有点绕我们来用一个生动的例子说明。 示例两个装饰器叠加defdecorator_a(func):print(Decorator A: 定义阶段)defwrapper(*args,**kwargs):print(A: 执行前)resultfunc(*args,**kwargs)print(A: 执行后)returnresultreturnwrapperdefdecorator_b(func):print(Decorator B: 定义阶段)defwrapper(*args,**kwargs):print(B: 执行前)resultfunc(*args,**kwargs)print(B: 执行后)returnresultreturnwrapperdecorator_adecorator_bdefgreet():print(Hi from greet!)greet()✅ 输出结果Decorator B: 定义阶段 Decorator A: 定义阶段 A: 执行前 B: 执行前 Hi from greet! B: 执行后 A: 执行后 重点观察定义阶段先打印Decorator B再打印Decorator A→ 从下到上装饰。执行阶段A先执行前然后B执行前最后B执行后A执行后 → 从上到下执行。 这就是核心规律装饰器从下到上“装饰”定义阶段从上到下“执行”调用阶段。 为什么是这样背后的机制解析要理解这一点我们必须深入到函数调用链的形成过程。 装饰器链的构建过程假设我们有如下写法decorator_adecorator_bdeffunc():pass这等价于funcdecorator_a(decorator_b(func)) 注意括号从内向外展开首先decorator_b(func)被调用 → 返回一个包装后的函数记作wrapped_b然后decorator_a(wrapped_b)被调用 → 返回最终的wrapped_a所以最终的调用流程是wrapped_a()# 相当于: decorator_a(decorator_b(func))()而当wrapped_a()被调用时wrapper_a开始执行 → 打印 “A: 执行前”调用wrapped_b→wrapper_b执行 → 打印 “B: 执行前”执行原始func→ 打印 “Hi from greet!”wrapper_b结束 → 打印 “B: 执行后”wrapper_a结束 → 打印 “A: 执行后” 所以执行顺序是从外层最上面的装饰器到内层最下面的装饰器依次执行。 用 Mermaid 图表可视化执行流程我们用 Mermaid 来画一张图直观展示这一过程。被 decorator_b 包装被 decorator_a 包装调用原始函数Wrapper BWrapper AWrapper A 执行A: 执行前Wrapper B 执行B: 执行前原始函数执行B: 执行后A: 执行后结束 这张图清晰展示了装饰顺序从下往上func → decorator_b → decorator_a执行顺序从上往下A 前 → B 前 → func → B 后 → A 后这就是为什么说“从下到上装饰从上到下执行”。 更复杂的例子三个装饰器嵌套让我们来一个更具挑战性的例子加深理解。deflog_time(func):print(LogTime: 定义)defwrapper(*args,**kwargs):importtime starttime.time()print(f[LOG]{func.__name__}开始执行)resultfunc(*args,**kwargs)endtime.time()print(f[LOG]{func.__name__}执行耗时:{end-start:.4f}s)returnresultreturnwrapperdefretry(max_attempts3):print(Retry: 定义)defdecorator(func):defwrapper(*args,**kwargs):forattemptinrange(max_attempts):try:print(f[RETRY] 尝试第{attempt1}次)returnfunc(*args,**kwargs)exceptExceptionase:ifattemptmax_attempts-1:raiseeprint(f[RETRY] 失败重试...)returnNonereturnwrapperreturndecoratordeftiming(func):print(Timing: 定义)defwrapper(*args,**kwargs):print([TIMING] 函数开始)resultfunc(*args,**kwargs)print([TIMING] 函数结束)returnresultreturnwrappertimingretry(max_attempts2)log_timedefslow_function():importtime time.sleep(0.5)print(✅ 模拟耗时操作完成)slow_function() 输出结果LogTime: 定义 Retry: 定义 Timing: 定义 [TIMING] 函数开始 [LOG] slow_function 开始执行 [RETRY] 尝试第 1 次 ✅ 模拟耗时操作完成 [RETRY] 失败重试... [LOG] slow_function 执行耗时: 0.5023s [TIMING] 函数结束 分析装饰顺序log_time→retry→timing从下到上执行顺序timing执行前log_time执行前retry执行前原函数执行retry执行后log_time执行后timing执行后 即使retry有重试逻辑它也是在log_time内部执行的因为它是更内层的装饰器。⚠️ 常见误区与陷阱❌ 误解一装饰器顺序等于执行顺序很多人误以为a b就是先执行a再执行b但实际上定义阶段从下到上执行阶段从上到下 一定要记住装饰器的“装饰”顺序和“执行”顺序是反向的。❌ 误解二装饰器可以改变函数名或文档如果装饰器没有正确传递元信息会导致函数的__name__、__doc__等属性丢失。defmy_decorator(func):defwrapper(*args,**kwargs):print(Before)returnfunc(*args,**kwargs)returnwrappermy_decoratordefhello():这是一个测试函数print(Hello)print(hello.__name__)# output: wrapperprint(hello.__doc__)# output: None✅ 解决方案使用functools.wrapsfromfunctoolsimportwrapsdefmy_decorator(func):wraps(func)# 保留原函数的元信息defwrapper(*args,**kwargs):print(Before)returnfunc(*args,**kwargs)returnwrappermy_decoratordefhello():这是一个测试函数print(Hello)print(hello.__name__)# output: helloprint(hello.__doc__)# output: 这是一个测试函数 建议所有自定义装饰器都应使用wraps(func)。 实际应用场景权限控制 日志记录 缓存让我们看一个真实场景一个 API 接口需要记录日志log_time检查用户权限require_auth缓存结果cachedimporttimefromfunctoolsimportwrapsdeflog_time(func):wraps(func)defwrapper(*args,**kwargs):starttime.time()print(f⏱️ [LOG]{func.__name__}开始)resultfunc(*args,**kwargs)endtime.time()print(f⏱️ [LOG]{func.__name__}耗时:{end-start:.4f}s)returnresultreturnwrapperdefrequire_auth(func):wraps(func)defwrapper(*args,**kwargs):tokenkwargs.get(token)ifnottokenortoken!secret123:print( 无权访问)return{error:Unauthorized}print( 身份验证通过)returnfunc(*args,**kwargs)returnwrapperdefcached(func):cache{}wraps(func)defwrapper(*args,**kwargs):keystr(args)str(sorted(kwargs.items()))ifkeyincache:print( 缓存命中)returncache[key]print( 缓存未命中计算中...)resultfunc(*args,**kwargs)cache[key]resultreturnresultreturnwrapperlog_timerequire_authcacheddefget_user_data(user_id,tokenNone):time.sleep(0.3)return{user_id:user_id,name:fUser-{user_id}}# 测试调用print(get_user_data(123,tokensecret123))print(get_user_data(123,tokensecret123))# 缓存命中 输出⏱️ [LOG] get_user_data 开始 身份验证通过 缓存未命中计算中... {user_id: 123, name: User-123} ⏱️ [LOG] get_user_data 耗时: 0.3021s ⏱️ [LOG] get_user_data 开始 身份验证通过 缓存命中 {user_id: 123, name: User-123} ⏱️ [LOG] get_user_data 耗时: 0.0001s 顺序分析cached→require_auth→log_time装饰顺序执行时log_time→require_auth→cached执行顺序✅ 完美符合“从下到上装饰从上到下执行”原则。 拓展阅读Python 官方文档与社区资源如果你想进一步深入推荐阅读以下资料 Python 官方文档 - Functions 全面讲解函数、闭包、装饰器等核心概念。 Real Python - Decorators Tutorial 通俗易懂的图文教程适合进阶学习。 Python Decorator Library (PEP 318) 装饰器提案原文了解其设计哲学。 总结掌握装饰器顺序的黄金法则✅从下到上装饰从上到下执行✅ 装饰器链是“从内到外”构建的✅ 执行链是“从外到内”调用的✅ 使用wraps保持函数元信息✅ 用 Mermaid 可视化执行流程加深理解 最佳实践建议装饰器顺序很重要将最外层的逻辑放在最上方如日志、缓存。避免副作用装饰器不要修改外部状态除非明确意图。保持可读性不要堆叠过多装饰器必要时可封装为组合类。善用functools.wraps防止函数属性丢失。 附加思考装饰器 vs 装饰器模式Design Pattern虽然 Python 的装饰器和设计模式中的“装饰器模式”名称相同但它们并不完全一样。Python 装饰器是语法糖作用于函数/方法。设计模式装饰器是面向对象的设计通过继承或组合动态添加职责。 了解更多Wikipedia - Decorator Pattern 结语装饰器是 Python 中最优雅的特性之一但它的“执行顺序”常常让人困惑。通过本文的深入剖析、代码示例和 Mermaid 可视化图表你已经掌握了核心规律装饰器从下到上“装饰”从上到下“执行”。现在无论你面对多少层装饰器嵌套都能从容应对写出清晰、高效、可维护的代码。 记住这句话它会伴随你一路前行“从下到上装饰从上到下执行。” 你已经完成了 Python 装饰器进阶之旅继续探索你会发现更多 Python 的奇妙之处。 感谢你读到这里 技术之路没有捷径但每一次阅读、思考和实践都在悄悄拉近你与目标的距离。 如果本文对你有帮助不妨 点赞、收藏、分享给更多需要的朋友 欢迎在评论区留下你的想法、疑问或建议我会一一回复我们一起交流、共同成长 关注我不错过下一篇干货我们下期再见✨