Python 闭包的高级用法详解

    所谓闭包,就是指内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程,这个内函数称之为闭包函数。可以理解为是函数式编程中的封装。



    内部函数可以使用外部函数定义的属性:外部函数调用后,返回内部函数的地址,完成内部函数的调用。

在这里插入图片描述



def outer():num = 100def inner():return numreturn innerresult = outer()
print(f'外部函数调用后,返回内部函数的地址:{result}')
print('通过内部函数的地址,完成内部函数的调用,使用外部函数定义的属性值为:', result())


    一般写法和闭包写法的对比:



    一般写法,在 传入的 x 和 y 不变情况下,每次调用函数时,都要重复传入相同的 x、y 参数。



在这里插入图片描述



def cal(x,y,z):print(x+y+z)cal(2,3,4)
cal(2,3,5)
cal(2,3,6)
cal(2,3,7)
cal(2,3,8)


    闭包写法,在x、y固定的情况下,只需要通过调用内部函数去传 z参数就可以了。如果要计算的结果太多,要传的 z 可能好多,也可以通过循环去实现传参,减少重复调用函数。



在这里插入图片描述



def cal(x,y):def cal_in(z):print(x+y+z)return cal_inresult = cal(2,3)
result(4)
result(5)
result(6)
result(7)
result(8)


    全局变量对闭包函数调用时所引用的变量究竟有没有影响?



    可见,当调用闭包函数时,是直接调用了外部函数变量
n = 3, 而不是全局变量 n = 4, 因此结果为 27。也证明了执行函数时,它的优先级是先搜索内部作用域的变量,全局变量对闭包函数的执行并没有影响。



在这里插入图片描述



def pow1():n = 3def pow2(x):return x ** nreturn pow2n = 4result = pow1()
print(result(3))


    closure是内部函数的一个属性,用来保存环境变量,返回的是一个元组,每一项都是闭包函数引用的外部变量。可以通过cell_contents 将被引用的变量打印出来。



    首先打印 result 的类型,可见是一个函数类型,证明在这个函数里面,我们可以将另外一个函数作为这个函数的返回值去进行返回的。 打印 closure, 得出内部函数的属性所对应的环境变量,可见它是一个元组类型。最后通过 cell_contents去获取变量的值。要注意的是,由于环境变量是一个元组,cell_contents是没有元组直接获取变量值的属性,因此必须先通过索引去获取你要的数据,否则会有报错。



在这里插入图片描述



    假设把 n = 3 放到最外层,变成全局变量,结果会一样吗?



    可见结果已经有刚才的 27 变成了 81。由于 n = 3 已经由局部变量变成了全局变量,当调用 pow2(x)时,并没有引用 pow1() 的变量,因此它并不是闭包函数,只是一个普通的嵌套函数,当pow2(x)搜索内部作用域没找到 n 的变量,就会搜索全局变量,由于全局变量同时存在 n = 3 和 n = 4, 这时变量就相当于 n = 4, 结果就是 3的4次方为81,而不是刚才执行闭包函数时的27了。



在这里插入图片描述



    同样,根据刚才介绍的 closure 概念,我们可以通过打印 closure 去验证是否闭包。



    可见结果为 None, 证明这不是闭包函数。



在这里插入图片描述



    当 n 未定义的情况下出现的报错:



在这里插入图片描述



def pow1():n = 3def pow2(x):n +=1return x ** nreturn pow2result = pow1()
print(result(3))


    解决报错的方法:可以用 nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。



    可见添加 nonlocal后,闭包函数可以正常调用 n = 3 并执行累加。因此当调用第一次时,结果为 81, 调用第二次时,结果为 243, n 相当于变成了5



在这里插入图片描述



    再看另外一个循环的例子,循环中变量分别是1、2,但实际最终返回的结果为4,4。 原因是返回的函数引用了变量i,但它并非立刻执行。等到2个函数都返回时,它们所引用的变量i已经变成了2。从打印 cell_contents 结果可见。

在这里插入图片描述



def pow1():n=2L = []for i in range(1,3):def pow2():return i ** nL.append(pow2)return Lf1,f2 = pow1()
print(f1())
print(f2())
print(f1.__closure__)
print(f2.__closure__)
print(f1.__closure__[0].cell_contents)
print(f2.__closure__[0].cell_contents)


    要改变分别执行变量1、2, 让pow2() 形成闭包。可见被引用的变量也分别是1,2,返回的结果就是我们预期的1,4



在这里插入图片描述



def pow1():n=2L = []for i in range(1,3):def extra(i):def pow2():return i ** nreturn pow2L.append(extra(i))return Lf1,f2 = pow1()
print(f1())
print(f2())
print(f1.__closure__)
print(f2.__closure__)
print(f1.__closure__[0].cell_contents)
print(f2.__closure__[0].cell_contents)


    关于更多闭包的高级用法疑问,欢迎留言!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/15154.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux_web控制台-cockpit

1、安装cockpit [rootlocalhost ~]# dnf install cockpit -y 2、启动cockpit服务并查运行状态 [rootlocalhost ~]# systemctl start cockpit [rootlocalhost ~]# systemctl status cockpit 2、设置开机启动 [rootlocalhost ~]# vim /usr/lib/systemd/system/cockpit.servi…

局域网桌面监控软件哪个好用?良心推荐

如何有效地监控和管理内部员工的计算机使用行为,防范潜在的安全风险,提高工作效率,是众多企业管理者关注的焦点。 而一款优秀的局域网桌面监控软件无疑能为企业的IT治理提供有力支撑。 小编在此给大家推荐一款好用的局域网桌面监控软件——域…

5. C++网络编程-UDP协议的实现

UDP是无连接的。 UDP Server网络编程基本步骤 创建socket,指定使用UDP协议将socket与地址和端口绑定使用recv/send接收/发送数据 由于UDP是无连接的,直接侦听就行使用close关闭连接 这个UDP接收数据的时候用的API是recvfrom,发送数据是sendto

Python——获取DataFrame的表头列表

# 获取表头列表 header_list df_data.columns.tolist()

MCS-51伪指令

上篇我们讲了汇编指令格式,寻址方式和指令系统分类,这篇我们讲一下单片机伪指令。 伪指令是汇编程序中用于指示汇编程序如何对源程序进行汇编的指令。伪指令不同于指令,在汇编时并不翻译成机器代码,只是会汇编过程进行相应的控制…

已有yarn集群部署spark

已有yarn集群的情况下,部署spark只需要部署客户端。 一、前提条件 已部署yarn集群,部署方式参考:https://blog.csdn.net/weixin_39750084/article/details/136750613?spm1001.2014.3001.5502,我部署的hadoop版本是3.3.6已安装j…

Android Compose 九:常用组件列表 简单使用

遇事不决 先看官方文档 列表和网格 如果不需要任何滚动,通过Column 或 Row可以使用verticalScroll() 使Column滚动 Column(modifier Modifier.verticalScroll(rememberScrollState())) {for (i in 0..50){Text(text "条目>>${i}")}}显示大量列表…

13、设计模式之观察者模式

观察者模式 观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern&#x…

从0开始linux(3)——如何读写文件

欢迎来到博主的专栏——从0开始linux 博主ID:代码小豪 文章目录 创建普通文件用文本编辑器nano写入文件如何读取文件cat命令less命令head和tail 我们前面已经了解和如何操作文件,但是目前认识的文件类型分为两类,一类是目录文件、另一类是普通…

【C#上位机应用开发实战】—— 通信模块的基础与实践

🚀 引言 在工业自动化、设备监控、物联网(IoT)等领域,上位机软件扮演着至关重要的角色。作为连接人与设备的桥梁,上位机软件不仅需要提供友好的用户界面,更需要具备高效、稳定的通信能力。今天&#xff0c…

ASP+ACCESS教师档案管理系统

3.1 系统功能模块图 3.2 E-R模型图 3.3 系统使用流程图 3.4 各个模块功能简介: 本系统分为五个功能模块,它们分别是教师信息录入模块、教师信息修改模块、教师信息查询模块、教师信息打印模块。 下面分别介绍各个模块的功能用途&#x…

第 398 场 LeetCode 周赛题解

A 特殊数组 I 模拟&#xff1a;遍历数组判断是否是一个特殊数组 class Solution { public:bool isArraySpecial(vector<int>& nums) {int r 0;while (r 1 < nums.size() && nums[r 1] % 2 ! nums[r] % 2)r;return r nums.size() - 1;} };B 特殊数组 I…

计网(部分在session学习章)

TCP/UDP TCP:面向连接,先三次握手建立连接,可靠传输。 UDP:无连接,不可靠,传递的快。 TCP可靠传输 1.分块编号传输; 2.校验和,校验首部和数据的检验和,检测数据在传输中的变化; 3.丢弃重复数据; 4.流量控制,TCP 利⽤滑动窗⼝实现流量控制。TCP的拥塞控制采⽤…

如何解决VSCode Git插件差异查看器 无法读取文件 Error: 无法解析不存在的文件 的问题

问题描述 问题&#xff1a;在使用VSCode的Git插件中的差异查看器时&#xff0c;有时会出现如下报错信息&#xff1a; 无法读取文件 git:/d:/Desktop//UIInput.js?{"path":"d:\\Desktop\\UIInput.js","ref":"~"} (Error: 无法解析不…

如何用正则表达式匹配中文和英文

在文本处理和自然语言处理的领域&#xff0c;准确地分割和匹配单词是至关重要的任务之一。对于处理包含多种语言&#xff08;如中英文混合&#xff09;的文本&#xff0c;常见的分词方法可能不够准确&#xff0c;特别是对汉字和英文单词的处理。本文将介绍如何使用正则表达式&q…

基于Matlab卷积神经网络人脸识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 人脸识别作为计算机视觉领域的关键技术之一&#xff0c;具有广泛的应用前景&#xff0c;如安全…

Add object from object library 从对象库中添加内置器件

Add object from object library 从对象库中添加内置器件 正文正文 对于 Lumerical,有些时候我们在使用中,可能需要从 Object library 中添加器件,通常我们的做法是手动添加。如下图所示,我们添加一个 Directional Coupler 到我们的工程文件中: 但是这种操作方式不够智能…

基于HTML5和CSS3搭建一个Web网页(二)

倘若代码中有任何问题或疑问&#xff0c;欢迎留言交流~ 网页描述 创建一个包含导航栏、主内容区域和页脚的响应式网页。 需求: 导航栏: 在页面顶部创建一个导航栏&#xff0c;包含首页、关于我们、服务和联系我们等链接。 设置导航栏样式&#xff0c;包括字体、颜色和背景颜…

会话机制:Cookie

1、cookie的作用 cookie和session机制其实都是为了保存会话的状态。 cookie是将会话的状态保存在浏览器客户端上。&#xff08;cookie数据存储在浏览器客户端上的。&#xff09; session是将会话的状态保存在服务器端上。&#xff08;session对象是存储在服务器上。&#xff…

上门服务系统开发|东邻到家系统|上门服务系统开发流程

上门服务小程序的开发流程是一个复杂且精细的过程&#xff0c;涉及到需求分析、设计规划、开发实施、测试验收以及上线运营等多个环节。下面将详细介绍上门服务小程序的开发流程&#xff0c;帮助读者全面了解并掌握其中的关键步骤。 一、需求分析 在开发上门服务小程序之前&am…