Python进阶 闭包与装饰器原理、语法与实战一. 闭包 (Closure)01. 函数地址传递和局部变量生命周期函数名本质函数名不加括号本质是函数地址可传递、可赋值。局部变量生命周期函数调用开始创建函数结束后默认销毁。课堂问题引入如果想让函数结束后仍保留函数内变量应该怎么办结论需要闭包机制让内部函数“记住”外部函数变量。02. 闭包的三大构成条件条件1有嵌套函数中再定义函数。条件2有引用内部函数使用外部函数变量含形参。条件3有返回外部函数返回内部函数名返回函数地址。03. [熟悉] 闭包语法格式def外部函数名(外部参数):def内部函数名(内部参数):# 使用外部函数变量...return内部函数名语义理解return 内部函数名不是执行内部函数而是把“可调用能力”交出去。04. 使用闭包改变变量生命周期闭包作用保存外部函数变量延长其生命周期。案例快递柜def快递柜(包裹):def取件():returnf取出了{包裹}return取件 我的取件码快递柜(《流畅的Python》)print(我的取件码())# 取出了《流畅的Python》现象解释快递柜执行结束后包裹变量仍被取件函数引用因此没有立即销毁。05. nonlocal 声明修改的是外部函数变量global声明并修改全局变量。nonlocal声明并修改外层非全局函数变量。案例deffunc_out():a100deffunc_inner():nonlocala a1print(f修改结果:{a})returnfunc_inner易错点未写nonlocal时在内部函数直接赋值会被当成新局部变量。06. [小结] 闭包模块核心结论闭包的本质是“函数 被捕获的外部环境”。闭包三条件有嵌套、有引用、有返回。闭包最重要价值保存状态、延长局部变量生命周期。需要修改外层变量时优先使用nonlocal。二. 装饰器基础 (Decorator)01. [记忆] 装饰器的作用与本质作用在不修改原函数源码的前提下给函数增加额外功能。本质装饰器是一个闭包函数接收函数返回新函数。典型场景登录校验、日志记录、权限控制、耗时统计。关键词不改源码功能增强。02. 装饰器的四大构成条件在闭包三条件基础上新增第4点有额外功能。四条件分别是有嵌套有引用有返回有额外功能“有额外功能”进阶解释和闭包区分闭包只要求“内部函数引用外部变量并被返回”外部变量不一定是函数。装饰器除了满足闭包条件还要求在某一层接收原函数并返回包装后的新函数。普通装饰器最外层直接接收函数deco。带参数装饰器最外层先接收装饰器参数再返回“接收函数”的那一层deco(x)。所以装饰器的本质链路是接收函数 - 增强逻辑 - 返回函数带参数时前面会多一层参数工厂。对比记忆闭包重在“记住变量”。装饰器重在“增强函数”。最小示例体现“接收函数并返回函数”defdeco(fn):# 接收原函数definner():print(登录校验)# 增强逻辑额外功能fn()returninner# 返回新函数带参数装饰器形态最外层先收参数defdeco_with_arg(flag):# 先收装饰器参数defdeco(fn):# 这一层才收原函数definner(*args,**kwargs):print(flag)# 额外功能returnfn(*args,**kwargs)returninnerreturndeco补充说明装饰器不一定在第一层接收函数但一定存在一层专门接收被装饰函数。结论所有装饰器都是闭包但不是所有闭包都是装饰器。03. 传统方法的装饰器使用原始方式函数名 装饰器名(函数名)课堂示例defcheck(fn):definner():print(请先登录...)fn()returninnerdefcomment():print(发表评论)commentcheck(comment)comment()04. 使用语法糖装饰函数语法糖写法装饰器名等价关系check等价于comment check(comment)。结论语法糖更常用原始方法更利于理解。05. 装饰器适配有参有返回值函数核心原则原函数怎么收参内部函数就怎么收参原函数有返回内部函数就要返回。通用写法推荐*args, **kwargsreturn func(*args, **kwargs)。总结通用装饰器可一次适配四类函数签名维护成本最低。三. 装饰器进阶应用01. 多个装饰器修饰同一个函数装饰顺序离函数最近的装饰器先装饰由内到外包裹。执行顺序理解书写是从上到下包裹/执行链路是从下到上再回到外层。提示顺序理解错误时功能叠加结果会与预期相反。02. 带参数装饰器及两种方式区别需求场景同一个装饰器按不同参数生成不同附加逻辑如加法/减法提示。方式一原始方式fn decorator(fn, flag)便于看懂流程。方式二语法糖方式logging()本质是外面再套一层函数“先接收参数再返回装饰器”。结构口诀语法糖方式,三层嵌套外层收参数 - 中层收原函数 - 内层执行业务包装。03. [小结] 今日装饰器核心结论装饰器就是“可复用的函数增强器”。通用装饰器推荐*args, **kwargs并记得return。多装饰器看顺序要先看“离函数最近的是谁”。带参数装饰器语法糖一定是“三层结构”。四. 补充能力点A. 装饰器适配四类函数四类函数无参无返回有参无返回无参有返回有参有返回含不定长参数统一口诀参数对齐、返回对齐。推荐模板defdecorator(func):definner(*args,**kwargs):# 额外功能resultfunc(*args,**kwargs)returnresultreturninnerB. 带参数装饰器专业命名便于后续阅读框架源码外层函数参数工厂接收装饰器参数。中层函数decorator接收被装饰函数。内层函数wrapper/inner执行附加逻辑并调用原函数。闭包三大条件是有嵌套、有引用、有返回缺任意一个都不是完整闭包。因为内部函数持续引用外层变量导致变量随闭包一起被保留生命周期被延长。global作用于全局变量nonlocal作用于外层非全局函数变量。装饰器实现必须依赖“接收函数并返回内部函数”的闭包结构所以装饰器本质是闭包的应用形态。两者完全等价解释器遇到decorator时会执行func decorator(func)。为了适配不同函数签名避免为每个参数形态单独写装饰器。装饰过程由内到外离函数最近的先装饰执行时也体现为先进入最内层逻辑。因为语法糖先要接收装饰器参数再返回真正接收原函数的装饰器函数。五. 今日反馈1) 能够知道闭包的构成条件答闭包构成条件是有嵌套、有引用、有返回。有嵌套创造了一个封闭的局部作用域空间。有引用让内层函数和外层函数的变量产生了“羁绊”。有返回把内层函数扔到全局去让这个“羁绊”得以在外部存活。例子体现三条件Pythondef outer(): # 条件1有嵌套 (外层) name AI def inner(): # 条件1有嵌套 (内层) print(name) # 条件2有引用 (内部用了外部的 name) return inner # 条件3有返回 (返回内层函数地址)2) 能够知道定义闭包的语法格式答外层函数里定义内层函数内层函数引用外层变量外层return内层函数名。扩充这里最容易踩坑的地方是return inner和return inner()的区别。闭包的语法格式要求返回的是函数名即函数在内存中的地址而不是函数的执行结果。这就好比我给了你一把钥匙函数地址而不是直接帮你把门打开函数调用。3) 能够知道闭包的作用答闭包可以保存外层函数变量并延长其生命周期。扩充正常情况下函数一旦执行完毕里面的局部变量就会被内存回收机制清理掉。但因为闭包的内层函数一直“拽着”外层变量不放导致外层变量无法被回收。它的核心作用就是在不使用全局变量避免污染全局环境的情况下安全地保存状态。例子保存状态Pythondef counter(): count 0 # 这个变量会被保存 def add(): nonlocal count # 声明修改外层变量 count 1 return count return add my_count counter() print(my_count()) # 输出 1 print(my_count()) # 输出 2 (count的状态被保留了)4) 能够掌握定义装饰器的语法格式答装饰器是“接收函数并返回内部函数”的闭包结构可用原始方式或语法糖。扩充所有的装饰器本质上都是闭包但装饰器有一个专属特征它的外层函数接收的参数一定是一个函数被装饰的函数。它的核心价值观是“开放封闭原则”——对扩展功能开放对修改源码封闭。最简例子通用装饰器模板Pythondef decorator(func): # 接收原函数 def inner(*args, **kwargs): # 适配所有参数 print( 执行增强逻辑) # 额外功能 return func(*args, **kwargs) # 适配原函数返回值 return inner # 返回新函数5) 能够独立完成装饰器的使用答可以用decorator或func decorator(func)完成函数增强。扩充语法糖只是 Python 提供的一种便捷写法它在代码运行时的底层动作就是把紧跟在它下面的函数当做参数传给装饰器然后再把装饰器返回的新函数重新赋值给原函数名。例子等价对比Python# 写法一语法糖日常开发推荐 decorator def play(): print(玩游戏) # 写法二原始写法等价于语法糖的底层逻辑 def play(): print(玩游戏) play decorator(play)6) 能够知道多个装饰器修饰同一个函数的执行顺序答离函数最近的装饰器先装饰整体是由内到外的包裹过程大白话来说代码里也就是从下到上运行。扩充想象一下“穿衣服”的过程。被装饰的函数是你本人离你最近的装饰器是“内衣”外面的装饰器是“外套”。装饰的过程穿衣服是从内衣到外套从下到上。但执行的过程别人看你则是先看到外套再看到内衣最后才看到你本人外层增强逻辑 - 内层增强逻辑 - 原函数。最简例子Python# 假设有两个装饰器make_bold 和 make_italic make_bold # 2. 然后套上 bold 外套 make_italic # 1. 离 text 最近先套上 italic 内衣 def text(): return Hello # 最终结果相当于make_bold(make_italic(text))7) 能够写出带有参数的装饰器答带参数装饰器通常采用三层函数结构外层收参数、中层收原函数、内层执行包装。扩充为什么普通装饰器是两层带参数的必须是三层因为像logging()这样的代码Python 解释器会先执行logging()。这个执行的结果必须返回一个真正的、两层的装饰器去接收下面的函数。所以最外面那一层就是一个“装饰器制造工厂”。例子三层结构deflogger(symbol):# 第一层接收装饰器参数defdecorator(func):# 第二层接收被装饰的函数definner(*args,**kwargs):# 第三层执行包装逻辑print(symbol*10)# 使用了第一层的参数 symbolreturnfunc(*args,**kwargs)returninnerreturndecoratorlogger(*)# 动态传入参数defshow():print(展示内容)show()# 输出:# **********# 展示内容
Python进阶 闭包和装饰器
发布时间:2026/6/1 5:39:03
Python进阶 闭包与装饰器原理、语法与实战一. 闭包 (Closure)01. 函数地址传递和局部变量生命周期函数名本质函数名不加括号本质是函数地址可传递、可赋值。局部变量生命周期函数调用开始创建函数结束后默认销毁。课堂问题引入如果想让函数结束后仍保留函数内变量应该怎么办结论需要闭包机制让内部函数“记住”外部函数变量。02. 闭包的三大构成条件条件1有嵌套函数中再定义函数。条件2有引用内部函数使用外部函数变量含形参。条件3有返回外部函数返回内部函数名返回函数地址。03. [熟悉] 闭包语法格式def外部函数名(外部参数):def内部函数名(内部参数):# 使用外部函数变量...return内部函数名语义理解return 内部函数名不是执行内部函数而是把“可调用能力”交出去。04. 使用闭包改变变量生命周期闭包作用保存外部函数变量延长其生命周期。案例快递柜def快递柜(包裹):def取件():returnf取出了{包裹}return取件 我的取件码快递柜(《流畅的Python》)print(我的取件码())# 取出了《流畅的Python》现象解释快递柜执行结束后包裹变量仍被取件函数引用因此没有立即销毁。05. nonlocal 声明修改的是外部函数变量global声明并修改全局变量。nonlocal声明并修改外层非全局函数变量。案例deffunc_out():a100deffunc_inner():nonlocala a1print(f修改结果:{a})returnfunc_inner易错点未写nonlocal时在内部函数直接赋值会被当成新局部变量。06. [小结] 闭包模块核心结论闭包的本质是“函数 被捕获的外部环境”。闭包三条件有嵌套、有引用、有返回。闭包最重要价值保存状态、延长局部变量生命周期。需要修改外层变量时优先使用nonlocal。二. 装饰器基础 (Decorator)01. [记忆] 装饰器的作用与本质作用在不修改原函数源码的前提下给函数增加额外功能。本质装饰器是一个闭包函数接收函数返回新函数。典型场景登录校验、日志记录、权限控制、耗时统计。关键词不改源码功能增强。02. 装饰器的四大构成条件在闭包三条件基础上新增第4点有额外功能。四条件分别是有嵌套有引用有返回有额外功能“有额外功能”进阶解释和闭包区分闭包只要求“内部函数引用外部变量并被返回”外部变量不一定是函数。装饰器除了满足闭包条件还要求在某一层接收原函数并返回包装后的新函数。普通装饰器最外层直接接收函数deco。带参数装饰器最外层先接收装饰器参数再返回“接收函数”的那一层deco(x)。所以装饰器的本质链路是接收函数 - 增强逻辑 - 返回函数带参数时前面会多一层参数工厂。对比记忆闭包重在“记住变量”。装饰器重在“增强函数”。最小示例体现“接收函数并返回函数”defdeco(fn):# 接收原函数definner():print(登录校验)# 增强逻辑额外功能fn()returninner# 返回新函数带参数装饰器形态最外层先收参数defdeco_with_arg(flag):# 先收装饰器参数defdeco(fn):# 这一层才收原函数definner(*args,**kwargs):print(flag)# 额外功能returnfn(*args,**kwargs)returninnerreturndeco补充说明装饰器不一定在第一层接收函数但一定存在一层专门接收被装饰函数。结论所有装饰器都是闭包但不是所有闭包都是装饰器。03. 传统方法的装饰器使用原始方式函数名 装饰器名(函数名)课堂示例defcheck(fn):definner():print(请先登录...)fn()returninnerdefcomment():print(发表评论)commentcheck(comment)comment()04. 使用语法糖装饰函数语法糖写法装饰器名等价关系check等价于comment check(comment)。结论语法糖更常用原始方法更利于理解。05. 装饰器适配有参有返回值函数核心原则原函数怎么收参内部函数就怎么收参原函数有返回内部函数就要返回。通用写法推荐*args, **kwargsreturn func(*args, **kwargs)。总结通用装饰器可一次适配四类函数签名维护成本最低。三. 装饰器进阶应用01. 多个装饰器修饰同一个函数装饰顺序离函数最近的装饰器先装饰由内到外包裹。执行顺序理解书写是从上到下包裹/执行链路是从下到上再回到外层。提示顺序理解错误时功能叠加结果会与预期相反。02. 带参数装饰器及两种方式区别需求场景同一个装饰器按不同参数生成不同附加逻辑如加法/减法提示。方式一原始方式fn decorator(fn, flag)便于看懂流程。方式二语法糖方式logging()本质是外面再套一层函数“先接收参数再返回装饰器”。结构口诀语法糖方式,三层嵌套外层收参数 - 中层收原函数 - 内层执行业务包装。03. [小结] 今日装饰器核心结论装饰器就是“可复用的函数增强器”。通用装饰器推荐*args, **kwargs并记得return。多装饰器看顺序要先看“离函数最近的是谁”。带参数装饰器语法糖一定是“三层结构”。四. 补充能力点A. 装饰器适配四类函数四类函数无参无返回有参无返回无参有返回有参有返回含不定长参数统一口诀参数对齐、返回对齐。推荐模板defdecorator(func):definner(*args,**kwargs):# 额外功能resultfunc(*args,**kwargs)returnresultreturninnerB. 带参数装饰器专业命名便于后续阅读框架源码外层函数参数工厂接收装饰器参数。中层函数decorator接收被装饰函数。内层函数wrapper/inner执行附加逻辑并调用原函数。闭包三大条件是有嵌套、有引用、有返回缺任意一个都不是完整闭包。因为内部函数持续引用外层变量导致变量随闭包一起被保留生命周期被延长。global作用于全局变量nonlocal作用于外层非全局函数变量。装饰器实现必须依赖“接收函数并返回内部函数”的闭包结构所以装饰器本质是闭包的应用形态。两者完全等价解释器遇到decorator时会执行func decorator(func)。为了适配不同函数签名避免为每个参数形态单独写装饰器。装饰过程由内到外离函数最近的先装饰执行时也体现为先进入最内层逻辑。因为语法糖先要接收装饰器参数再返回真正接收原函数的装饰器函数。五. 今日反馈1) 能够知道闭包的构成条件答闭包构成条件是有嵌套、有引用、有返回。有嵌套创造了一个封闭的局部作用域空间。有引用让内层函数和外层函数的变量产生了“羁绊”。有返回把内层函数扔到全局去让这个“羁绊”得以在外部存活。例子体现三条件Pythondef outer(): # 条件1有嵌套 (外层) name AI def inner(): # 条件1有嵌套 (内层) print(name) # 条件2有引用 (内部用了外部的 name) return inner # 条件3有返回 (返回内层函数地址)2) 能够知道定义闭包的语法格式答外层函数里定义内层函数内层函数引用外层变量外层return内层函数名。扩充这里最容易踩坑的地方是return inner和return inner()的区别。闭包的语法格式要求返回的是函数名即函数在内存中的地址而不是函数的执行结果。这就好比我给了你一把钥匙函数地址而不是直接帮你把门打开函数调用。3) 能够知道闭包的作用答闭包可以保存外层函数变量并延长其生命周期。扩充正常情况下函数一旦执行完毕里面的局部变量就会被内存回收机制清理掉。但因为闭包的内层函数一直“拽着”外层变量不放导致外层变量无法被回收。它的核心作用就是在不使用全局变量避免污染全局环境的情况下安全地保存状态。例子保存状态Pythondef counter(): count 0 # 这个变量会被保存 def add(): nonlocal count # 声明修改外层变量 count 1 return count return add my_count counter() print(my_count()) # 输出 1 print(my_count()) # 输出 2 (count的状态被保留了)4) 能够掌握定义装饰器的语法格式答装饰器是“接收函数并返回内部函数”的闭包结构可用原始方式或语法糖。扩充所有的装饰器本质上都是闭包但装饰器有一个专属特征它的外层函数接收的参数一定是一个函数被装饰的函数。它的核心价值观是“开放封闭原则”——对扩展功能开放对修改源码封闭。最简例子通用装饰器模板Pythondef decorator(func): # 接收原函数 def inner(*args, **kwargs): # 适配所有参数 print( 执行增强逻辑) # 额外功能 return func(*args, **kwargs) # 适配原函数返回值 return inner # 返回新函数5) 能够独立完成装饰器的使用答可以用decorator或func decorator(func)完成函数增强。扩充语法糖只是 Python 提供的一种便捷写法它在代码运行时的底层动作就是把紧跟在它下面的函数当做参数传给装饰器然后再把装饰器返回的新函数重新赋值给原函数名。例子等价对比Python# 写法一语法糖日常开发推荐 decorator def play(): print(玩游戏) # 写法二原始写法等价于语法糖的底层逻辑 def play(): print(玩游戏) play decorator(play)6) 能够知道多个装饰器修饰同一个函数的执行顺序答离函数最近的装饰器先装饰整体是由内到外的包裹过程大白话来说代码里也就是从下到上运行。扩充想象一下“穿衣服”的过程。被装饰的函数是你本人离你最近的装饰器是“内衣”外面的装饰器是“外套”。装饰的过程穿衣服是从内衣到外套从下到上。但执行的过程别人看你则是先看到外套再看到内衣最后才看到你本人外层增强逻辑 - 内层增强逻辑 - 原函数。最简例子Python# 假设有两个装饰器make_bold 和 make_italic make_bold # 2. 然后套上 bold 外套 make_italic # 1. 离 text 最近先套上 italic 内衣 def text(): return Hello # 最终结果相当于make_bold(make_italic(text))7) 能够写出带有参数的装饰器答带参数装饰器通常采用三层函数结构外层收参数、中层收原函数、内层执行包装。扩充为什么普通装饰器是两层带参数的必须是三层因为像logging()这样的代码Python 解释器会先执行logging()。这个执行的结果必须返回一个真正的、两层的装饰器去接收下面的函数。所以最外面那一层就是一个“装饰器制造工厂”。例子三层结构deflogger(symbol):# 第一层接收装饰器参数defdecorator(func):# 第二层接收被装饰的函数definner(*args,**kwargs):# 第三层执行包装逻辑print(symbol*10)# 使用了第一层的参数 symbolreturnfunc(*args,**kwargs)returninnerreturndecoratorlogger(*)# 动态传入参数defshow():print(展示内容)show()# 输出:# **********# 展示内容