news 2026/4/23 12:45:09

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进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 0:23:28

14、Mac OS X 网络连接管理与资源访问指南

Mac OS X 网络连接管理与资源访问指南 1. 网络连接管理 在 Mac OS X 系统中,几乎所有网络连接方面的操作都可以通过命令行工具进行配置、检查和监控。 1.1 查看网络连接状态 使用 netstat 命令可以查看网络连接的详细信息,例如: c24e0000 tcp4 0 0 127.…

作者头像 李华
网站建设 2026/4/22 17:28:14

17、系统安全与文本编辑实用指南

系统安全与文本编辑实用指南 系统日志管理 大多数BSD系统会对系统上发生的许多活动进行日志记录。这些活动记录会被写入位于 /var/log 目录或其子目录下的日志文件中,此日志记录由Syslog工具完成。 在FreeBSD中, syslogd (系统日志守护进程)作为基本安装系统的一部分…

作者头像 李华
网站建设 2026/4/23 11:27:12

掌握Ant Design Landing模板开发:从零构建企业级网页设计系统

掌握Ant Design Landing模板开发:从零构建企业级网页设计系统 【免费下载链接】ant-design-landing :mountain_bicyclist: Landing Pages of Ant Design System 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-landing 在现代网页开发领域&#xf…

作者头像 李华
网站建设 2026/4/23 11:26:27

神经网络基础

把输入层的特征进行加权求和,通过sigmod映射前面的加权求和结果神经元死亡问题 如何选择激活函数: 隐藏层:ReLU > Leaky ReLU > PReLU > Tanh > Sigmoid输出层:二分类: Sigmoid BCELoss 或 Softmax CrossEntropyLoss(内部自动做 softmax&a…

作者头像 李华
网站建设 2026/4/23 10:08:41

Oracle PL/SQL 过程与游标实战分享:马拉松赛事管理系统

一、引言在企业级数据库应用开发中,PL/SQL 作为 Oracle 数据库的过程化扩展语言,承担着业务逻辑封装、数据操作优化和系统性能提升的重要角色。本文基于一个完整的马拉松赛事管理系统的 PL/SQL 实现,分享过程、游标、函数等核心技术的实战应用…

作者头像 李华
网站建设 2026/4/19 23:43:48

大众桑塔纳 AJR 电控汽油发动机实训台

一、产品概述大众桑塔纳 AJR 电控汽油发动机实训台是汽车专业教学领域的经典设备,采用真实的大众桑塔纳 2000GSi 时代超人 / AJR 型电控汽油发动机总成,集成于可移动台架上,完整展示电控发动机的结构原理和工作过程。该实训台可实现起动、加速…

作者头像 李华