news 2026/1/14 9:01:56

Python闭包与解释器全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python闭包与解释器全解析

一、全局变量和局部变量

1.作用域

在python中,作用域分为全局作用域和局部作用域.

2.变量的作用域

在局部定义的变量---->局部变量

在全局定义的变量---->全局变量

3.全局变量与局部变量的访问范围

① 在全局作用域中可以访问全局变量,在局部作用域中可以访问局部变量

# 全局作用域(全局变量) num1 = 10 def func(): # 局部作用域(局部变量) num2 = 20 # ① 在局部访问局部变量 print(num2) # ① 在全局访问全局变量 print(num1) # 调用函数 func()

② 在局部作用域中可以访问全局变量

# 全局作用域(全局变量) num1 = 10 def func(): # 局部作用域(局部变量) # ② 在局部作用域中可以访问全局变量 print(num1) # 调用函数 func()

③ 在全局作用域中不能访问局部变量

# 全局作用域(全局变量) num1 = 10 def func(): # 局部作用域(局部变量) num2 = 20 # 调用函数 func() # 在全局作用域中调用局部变量num2 print(num2)

这里运行会报错显示 num2 is not defined

4.问题:为什么在全局作用域中无法访问局部变量

主要原因在于,在Python的底层存在一个“垃圾回收机制”,主要的作用就是回收内存空间。加快计算机的运行。我们在Python代码中定义的变量也是需要占用内存的,所以Python为了回收已经被已经过的内存,会自动将函数运行以后的内部变量和程序直接回收。

二、闭包

1.闭包的作用

在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。

2.闭包的构成条件

三个必要条件:有嵌套,有引用,有返回

def func(): num = 20 # 局部变量 def inner(): print(num) return inner # 实际上inner函数并没有执行,只是返回了inner函数在内存中的地址 f = func() # 相当于把inner在内存中的地址0x...赋值给变量f f() # 找到inner函数的内存地址,并执行器内部的代码(num=20),在于闭包函数保留了num=20这个局部变量

闭包的作用:正常情况下,当执行func()的时候,函数内部的变量num = 20,会随着函数的func函数的结束而被垃圾回收机制所回收。所以闭包的真正作用:就是可以在全局作用域中,实现间接对局部变量进行访问。

注意:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。

3.在闭包的内部实现对外部变量的修改

使用nolocal和global

def outer(): num = 10 def inner(): # 这种写法无法实现通过闭包修改外部的局部变量' nonlocal num num = 20 print('outer函数中的num:', num) # 10 inner() # 执行函数inner,让num=20生效 print('outer函数中的num:', num) # 20 return inner f = outer() f()

4.闭包的综合案例

闭包的作用:可以在全局作用域中间接访问局部变量(在函数执行以后)

''' 闭包编写三步走:① 有嵌套 ② 有引用 ③ 有返回 分析: 执行f = func()的时候,result赋值为0,然后定义inner,返回inner,最终结果f = inner函数的内存地址 执行f(1),相当于执行inner函数,nonlocal引用局部变量result=0,然后进行+1操作,弹出0+1=1 继续执行 执行f(2),相当于执行inner函数,声明nonlocal result,代表还是引用外部的局部变量,由于此时外部的result已经被 f(1)更改为1了,所以由于局部变量一直没有消失,所以此时result=1,执行+2操作,最终结果为3 ''' def func(): result = 0 def inner(num): nonlocal result result += num print(result) return inner f = func() f(1) # 1 f(2) # 3

二、装饰器

1.什么是装饰器

在不改变现有函数源代码以及函数调用方式的前提下,实现给函数增加额外的功能。

装饰器的本质就是一个特殊的闭包函数,他在拥有闭包的特点的同时,又必须多一个添加额外功能的条件.

2.装饰器的雏形

# 要求:把登录功能封装起来(比如封装成一个函数,添加这个登录不能影响现有功能函数) ''' 装饰器:本质是一个闭包,有嵌套、有引用、有返回(返回的是函数的内存地址) 参数fn在check中也是一个局部变量 参数fn:就是要装饰的函数的函数名,如comment,如download ''' def check(fn): def inner(): # 开发登录功能 print('登录功能') # 调用原函数 fn() return inner # 评论功能(前提:登录) def comment(): print('评论功能') comment = check(comment) comment() # 下载功能(前提:登录) def download(): print('下载功能') download = check(download) download()

3.装饰器的定义

''' 装饰器:本质就是一个闭包 ① 有嵌套 ② 有引用 ③ 有返回 ''' def check(fn): def inner(): # 开发登录验证功能 print('验证登录') # 执行原有函数 fn() return inner @check def comment(): print('发表评论') comment()

三、装饰器进阶

1.带有参数的装饰器

''' 带有参数的装饰器:① 有嵌套 ② 有引用 ③ 有返回 ''' def logging(fn): def inner(*args, **kwargs): # 添加装饰器代码(输出日志信息) print('-- 日志信息:正在努力计算机 --') # 执行要修饰的函数 fn(*args, **kwargs) # sum_num(a, b) return inner @logging def sum_num(*args, **kwargs): result = 0 # *args代表不定长元组参数,args = (10, 20) for i in args: result += i # **kwargs代表不定长字典参数, kwargs = {a:30, b:40} for i in kwargs.values(): result += i print(result) # sum_num带4个参数,而且类型不同,10和20以元组形式传递,a=30,b=40以字典形式传递 sum_num(10, 20, a=30, b=40)

2.带有返回值的装饰器

''' 带有返回值的装饰器:① 有嵌套 ② 有引用 ③ 有返回 如果一个函数执行完毕后,没有return返回值,则默认返回None ''' def logging(fn): def inner(*args, **kwargs): print('-- 日志信息:正在努力计算 --') return fn(*args, **kwargs) # fn() = sub_num(20, 10) = result return inner @logging def sub_num(a, b): result = a - b return result print(sub_num(20, 10))

3.装饰器高级:使用装饰器传递参数

''' 通用装饰器:① 有嵌套 ② 有引用 ③ 有返回 ④ 有不定长参数 ⑤ 有return返回值 真正问题:通过装饰器传递参数,我们应该如何接收这个参数呢? 答:在logging方法的外侧在添加一个函数,专门用于接收传递过来的参数 ''' def logging(flag): # flag = + 或 flag = - def decorator(fn): def inner(*args, **kwargs): if flag == '+': print('-- 日志信息:正在努力进行加法运算 --') elif flag == '-': print('-- 日志信息:正在努力进行减法运算 --') return fn(*args, **kwargs) return inner return decorator @logging('+') def sum_num(a, b): result = a + b return result @logging('-') def sub_num(a, b): result = a - b return result print(sum_num(10, 20)) print(sub_num(100, 80))

四、结语

今天讲的闭包和装饰器,可能有的小细节没有讲的很透彻,大家在看的时候有哪些还不懂得地方可以私信我.

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/12 20:54:42

3大精准流量控制策略:Apache APISIX限流技术的完整实战指南

在微服务架构中,API限流是保护后端服务免受恶意攻击和突发流量冲击的关键防线。没有合适的限流机制,你的系统可能面临网络攻击、资源耗尽和服务质量下降等严重问题。Apache APISIX作为高性能API网关,提供了一套完整的限流解决方案&#xff0c…

作者头像 李华
网站建设 2025/12/30 10:54:20

19、Perl入门:网站链接检查脚本详解

Perl入门:网站链接检查脚本详解 1. Perl简介 Perl是由Larry Wall在20世纪80年代末发明的。当时,他需要一种比shell脚本功能更强大,但又比C等结构化语言更灵活的编程语言,于是Perl应运而生。Perl是一种让人又爱又恨的语言,很少有人对它持中立态度。不过,它作为一种胶水语…

作者头像 李华
网站建设 2026/1/10 11:18:18

MultiPost Extension:一键同步发布内容到10+平台的终极解决方案

MultiPost Extension:一键同步发布内容到10平台的终极解决方案 【免费下载链接】MultiPost-Extension 项目地址: https://gitcode.com/gh_mirrors/mu/MultiPost-Extension 在当今内容为王的时代,内容创作者面临着巨大的挑战:如何高效…

作者头像 李华
网站建设 2025/12/29 20:15:54

5分钟掌握LightVAE:AI视频生成的终极效率革命

5分钟掌握LightVAE:AI视频生成的终极效率革命 【免费下载链接】Autoencoders 项目地址: https://ai.gitcode.com/hf_mirrors/lightx2v/Autoencoders 在AI视频生成技术快速发展的今天,LightVAE系列模型通过架构优化与知识蒸馏技术,为开…

作者头像 李华
网站建设 2025/12/16 20:38:26

2025年12月一区SCI-朗之万方程优化算法LangEvin Equation-附Matlab免费代码

引言 近年来,在合理框架内求解优化问题的元启发式算法的发展引起了全球科学界的极大关注。本期介绍一种新的创新算法——朗之万方程优化算法LangEvin Equation,LEE。该算法是一种基于物理定律和种群动态的新型优化框架。LEE利用LangEvin方程的数学原理来…

作者头像 李华