草根学Python(十五) 闭包(解决一个需求了解闭包流程)

Python --闭包详解 一、Python变量作用域问题 time = 0 #-----全局变量 def insert_time(min): time = time + min #----局部变量 return time print(insert_time(2)) print(insert_time(10)) UnboundLocalError: local variable 'time' referenced before assignment time为全局变量,函数中使用了该同名变量,且更改了该 阅读详情

网络上介绍 Python 闭包的文章已经很多了,本文将通过解决一个需求问题来了解闭包。

这个需求是这样的,我们需要一直记录自己的学习时间,以分钟为单位。就好比我学习了 2 分钟,就返回 2 ,然后隔了一阵子,我学习了 10 分钟,那么就返回 12 ,像这样把学习时间一直累加下去。

面对这个需求,我们一般都会创建一个全局变量来记录时间,然后用一个方法来新增每次的学习时间,通常都会写成下面这个形式:

time = 0

def insert_time(min):
    time = time + min
    return  time

print(insert_time(2))
print(insert_time(10))

认真想一下,会不会有什么问题呢?

其实,这个在 Python 里面是会报错的。会报如下错误:

UnboundLocalError: local variable 'time' referenced before assignment

那是因为,在 Python 中,如果一个函数使用了和全局变量相同的名字且改变了该变量的值,那么该变量就会变成局部变量,那么就会造成在函数中我们没有进行定义就引用了,所以会报该错误。

如果确实要引用全局变量,并在函数中对它进行修改,该怎么做呢?

我们可以使用 global 关键字,具体修改如下:

time = 0


def insert_time(min):
    global  time
    time = time + min
    return  time

print(insert_time(2))
print(insert_time(10))

输出结果如下:

2
12

可是啊,这里使用了全局变量,我们在开发中能尽量避免使用全局变量的就尽量避免使用。因为不同模块,不同函数都可以自由的访问全局变量,可能会造成全局变量的不可预知性。比如程序员甲修改了全局变量 time 的值,然后程序员乙同时也对 time 进行了修改,如果其中有错误,这种错误是很难发现和更正的。

全局变量降低了函数或模块之间的通用性,不同的函数或模块都要依赖于全局变量。同样,全局变量降低了代码的可读性,阅读者可能并不知道调用的某个变量是全局变量。

那有没有更好的方法呢?

这时候我们使用闭包来解决一下,先直接看代码:

time = 0


def study_time(time):
    def insert_time(min):
        nonlocal  time
        time = time + min
        return time

    return insert_time


f = study_time(time)
print(f(2))
print(time)
print(f(10))
print(time)

输出结果如下:

2
0
12
0

这里最直接的表现就是全局变量 time 至此至终都没有修改过,这里还是用了 nonlocal 关键字,表示在函数或其他作用域中使用外层(非全局)变量。那么上面那段代码具体的运行流程是怎样的。我们可以看下下图:

Python 闭包解决

这种内部函数的局部作用域中可以访问外部函数局部作用域中变量的行为,我们称为: 闭包。更加直接的表达方式就是,当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包。k

闭包避免了使用全局变量,此外,闭包允许将函数与其所操作的某些数据(环境)关连起来。而且使用闭包,可以使代码变得更加的优雅。而且下一篇讲到的装饰器,也是基于闭包实现的。

到这里,就会有一个问题了,你说它是闭包就是闭包了?有没有什么办法来验证一下这个函数就是闭包呢?

有的,所有函数都有一个 __closure__ 属性,如果函数是闭包的话,那么它返回的是一个由 cell 组成的元组对象。cell 对象的 cell_contents 属性就是存储在闭包中的变量。

我们打印出来体验一下:

time = 0


def study_time(time):
    def insert_time(min):
        nonlocal  time
        time = time + min
        return time

    return insert_time


f = study_time(time)
print(f.__closure__)
print(f(2))
print(time)
print(f.__closure__[0].cell_contents)
print(f(10))
print(time)
print(f.__closure__[0].cell_contents)

打印的结果为:

(<cell at 0x0000000000410C48: int object at 0x000000001D6AB420>,)
2
0
2
12
0
12

从打印结果可见,传进来的值一直存储在闭包的 cell_contents 中,因此,这也就是闭包的最大特点,可以将父函数的变量与其内部定义的函数绑定。就算生成闭包的父函数已经释放了,闭包仍然存在。

闭包的过程其实好比类(父函数)生成实例(闭包),不同的是父函数只在调用时执行,执行完毕后其环境就会释放,而类则在文件执行时创建,一般程序执行完毕后作用域才释放,因此对一些需要重用的功能且不足以定义为类的行为,使用闭包会比使用类占用更少的资源,且更轻巧灵活。

欢迎打开微信扫一扫,关注微信公众号:

微信公众号

计组实验5:cache大小测量与 cache line 大小测量 前言 今天做了实验5,通过 c 语言测 cache 参数。其实按理来说挺简单的,只是我们班没给代码,纯靠自己。听说别的班有给代码 emm 因为《深入理解计算机系统》这本书上面给的代码是 Linux 平台下的,而且需要一个 fcyc2 头文件,可以在 https://github.com/fabiensanglard/CpuCacheMountainViewer 这里找到。 ⚠ 我没有在 Linux 下试过课本上面的代码。。。 我是在 win10 下测试的。。。 所以 。。。 我并不确定我的代码是否正确。 阅读详情

相关推荐

3D Slicer:从入门到精通——数据模块之DICOM

该模块允许导入、导出和网络传输DICOM数据。Slicer支持DICOM功能的常用子集,其特定功能由临床研究的需求驱动:从磁盘读取和写入数据集,并通过DIMSE和DICOMweb网络协议进行网络传输——查询检索发送和接收数据集。医学数字成像和通信(DICOM)是信息交换数字放射学的广泛使用标准。在大多数情况下,医院使用的成像设备(CT和MR扫描仪)将生成保存为DICOM对象的图像。DICOM按以下层次结构组织数据患者… 可以有1个或多个研究(单次成像检查) … 可以有1个或多个系列。

walt3433的博客 6062

c++ log函数_vue组件通信,通过闭包函数在父组件中向自定义事件传参

本文转载于SegmentFault社区作者:青荼前言用vue进行开发的过程中,我们常常会用到父子组件通信来支持我们的一些应用场景。在子组件中通过触发自定义事件,并向上层组件传递一定的参数(暂且称为事件参数),但有时候我们也想要在父组件向监听函数传入一定的参数(暂且称为自定义参数)。比如在同一页面内需要重复使用相同的组件,并且具有事件传参时,我们希望能够传入自定义参数对不同的组件进行区别。...

weixin_39635373的博客 219

聚类分析(超全超详细版)

聚类分析是一种典型的无监督学习, 用于对未知类别的样本进行划分,将它们按照一定的规则划分成若干个类族,把相似(距高相近)的样本聚在同一个类簇中, 把不相似的样本分为不同类簇,从而揭示样本之间内在的性质以及相互之间的联系规律 聚类算法在银行、零售、保险、医学、军事等诸多领域有着广泛的应用 聚类分析基础 聚类分析的概念 聚类分析是根据在数据中发现的描述对象及其关系的信息,将数据对象分组。目的是...

Gfqwy2021 22万+

五分钟完全弄懂JS闭包

这里先来看一下闭包的定义,分成两个:在计算机科学中和在JavaScript中。在计算机科学中对闭包的定义(维基百科):闭包的概念出现于60年代,最早实现闭包的程序是 Scheme,那么我们就可以理解为什么JavaScript中有闭包:我们再来看一下MDN对JavaScript闭包的解释:那么我的理解和总结:如果我们编写了如下的代码,它一定是形成了闭包的: 1、创建GO对象,创建全局执行上下文并压入执行上下文栈中 注意:在此之前,是存在内存泄漏的,因为foo函数执行结束了,但是foo函数的AO对象并没有被销毁

浮游的博客 1468

元数据管理:DataHub和OpenMetadata对比分析

DataHub和OpenMetadata都试图解决数据编目,搜索,发现,治理和质量方面的相同问题。这两种工具都是出于为需要支持大量数据源、团队和用例的大型组织解决这些问题而诞生的。尽管这些工具在发布历史和成熟度方面略有不同,但它们的功能存在显着重叠。

weixin_38030820的博客 6632

用Python绘制DCA曲线详解及示例代码

在这篇文章中,我们将详细解释如何使用Python绘制DCA曲线,并提供示例代码。通过使用上述的示例代码和解释,你可以自己尝试不同的投资金额、期数和增长率来绘制自定义的DCA曲线。通过运行上述代码,我们将得到一个绘制了DCA曲线的图表。该图表将显示出DCA投资策略在给定投资金额、投资期数和增长率下的投资价值随时间的变化情况。在上述代码中,我们使用一个循环来计算每个投资期的DCA曲线值。现在,我们可以使用上述函数来计算DCA曲线的值,并将其绘制成图表。最后,我们返回计算得到的DCA曲线值列表。

TechPr的博客 1407

闭包(1)-闭包的详细执行过程

视频:https://ke.qq.com/course/231577?taid=3983676656552089 闭包:但凡是内部的函数被保存到了外部,一定生成闭包。 function a(){ var num = 100; function b(){ num ++; console.log(num); } return b; } v...

abraham的博客 1552

TC3XX - MCAL知识点(二十九):FLS MCAL配置及代码实战(英飞凌DFLASH)

FLS驱动程序为DFlash 0的初始化、读取、写入和擦除提供了定义良好的配置和标准服务。除此之外,我们还提供一些非autosar服务示例 Fls_17_Dmu_CompareWordsSync、Fls_17_Dmu_CancelNonEraseJobs、Fls_17_Dmu_VerifyErase,LFls_17_Dmu_VerifySectorErase、Fls_17_Dmu_GetNotifCaller等。用户通过FLS驱动程序获得对底层DFlash0的封装访问。

梦想技术家 2363

python--closure闭包

python–closure闭包 1、就是当某个函数被当成对象返回时,夹带了外部变量,就形成了一个闭包 2、闭包函数相对与普通函数会多出一个__closure__的属性 里面定义了一个元组用于存放所有的cell对象,每个cell对象一一保存了这个闭包中所有的外部变量 例子 def make_printer(msg): def printer(): print(msg) ...

huangwencai123的博客 341

OpenSpec 完全指南 config.yaml文件

不管是项目内还是全局存放,自定义工作流都要遵守以下规则,否则会导致OpenSpec无法识别,新手一定要记牢:一个文件夹 = 一个工作流:工作流文件夹的名称,就是中schema字段要填写的名称;每个工作流文件夹必须包含:这是工作流的核心定义文件,没有它,OpenSpec无法识别这个工作流;模板文件统一放templates/目录:如果需要自定义生成文件的模板(比如统一的提案模板、任务模板),就放在工作流文件夹下的templates/里,OpenSpec会自动识别;

h a 6 6 6 c k 为 你解决复杂难题! 1416

YOLOv8极速瘦身实战:LAMP剪枝让模型又快又准

一个庞大的模型虽然强大,但在实际部署,尤其是资源受限的边缘设备(如无人机、移动电话、嵌入式系统)上,却面临着严峻的挑战:高昂的内存占用、巨大的计算量以及随之而来的高延迟和高能耗。本教程从LAMP剪枝的深刻理论出发,详细解释了它如何通过最小化最坏情况下的L2失真,并借助巧妙的数学简化,最终推导出一种高效、无超参数、层自适应的剪枝策略。它如同为臃肿的模型进行一次精准的“瘦身手术”,通过移除网络中冗余或不重要的权重、神经元甚至整个结构,来显著降低模型的参数量和计算量(FLOPs),从而实现推理加速和资源节约。

FJN110的博客 257

深入贯彻闭包思想,全面理解JS闭包形成过程

写这篇文章之前,我对闭包的概念及原理模糊不清,一直以来都是以通俗的外层函数包裹内层....来欺骗自己。并没有说这种说法的对与错,我只是不想拥有从众心理或者也可以说如果我们说出更好更低层的东西,逼格会提升好几个档次。。。 谈起闭包,它可是JavaScript两个核心技术之一(异步和闭包),在面试以及实际应用当中,我们都离不开它们,甚至可以说...

weixin_34198762的博客 357

外骨骼机器人(五):步态分析之正常步态

研究病理步态之前,需要了解正常步态,作为判断标准。但是需要记住两个问题:1.“正常”因人而异,性别、年龄、身体情况都需要考虑在内,因此,需要对不同的个体选择合适的正常标准;2.即使病人的步态与正常步态有某种不同,这也不能说明这是不可取的,也不能说明应该把它变成“正常”步态。许多步态异常是对病人的一些问题的一种补偿,尽管异常,但它们仍然是有用的。步态周期的定义是连续为两次发生重复行走事件之间的时间间隔。尽管可以选择任何事件来定义步态周期,但通常使用一只脚接触地面的瞬间(“初始接触”)是方便的。

行者无疆的博客 1991

闭包如何产生内存消耗及性能消耗

  在《高性能JavaScript》这本书中,对“闭包如何产生内存消耗及性能消耗”这个专题做了比较清晰的解释。如下(内容摘自此书的第二章数据访问中的“闭包,作用域,和内存”)——     1.先说标识符识别性能——   标识符识别不是免费的,事实上没有哪种电脑操作可以不产生性能开销。在运行期上下文的作用域链中,一个标识符所处的位置越深,它的读写速度就越慢。所以,函数中局部变量的访...

weixin_38166852的博客 440

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Python: 闭包程序示例

今天被Python震撼了,NB from time import time def logged(which): def log(f,*args,**kargs): print(''' 'Called: function:%s args:%r kargs:%r ' '''%(f,args,kargs)) def ...

cquyyang的专栏 257

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Python 代码规范

前言Python 学习之旅,先来看看 Python 的代码规范,让自己先有个意识,而且在往后的学习中慢慢养成习惯目录一、简明概述1、编码 如无特殊情况, 文件一律使用 UTF-8 编码 如无特殊情况, 文件头部必须加入#-*-coding:utf-8-*-标识 2、代码格式2.1、缩进 统一使用 4 个空格进行缩进 2.2、行宽每行代码尽量不超过 80 个字符(在特殊情况下可以略微超过 80 ,但最

GitHubClub 5720

草根学Python(六) 函数

前言前天创了个 Python 微信讨论群,以为没人进的,哈哈,想不到还真有小伙伴进群学习讨论。如果想进群,可以加我微信: androidwed ,拉进群,就不贴微信群二维码了,一是会失效,二影响文章。目录一、Python 自定义函数的基本步骤函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。自定义函数,基本有以下规则步骤: 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号

GitHubClub 3552

草根学Python(五) 条件语句和循环语句

前言第一次建学习群,而且是 Python 的学习群,虽然之前深入学习和工作都是 Android 相关的,最近学起来 Python ,真的很好玩,所以创了个微信群,希望童鞋们进群学习讨论。也可以直接加我微androidwed拉进群。也欢迎大家在 Gitbook 中提出文章的不足。目录一、条件语句Python 条件语句跟其他语言基本一致的,都是通过一条或多条语句的执行结果( True 或者 False

GitHubClub 3054

草根学Python(七) 迭代器和生成器

前言这篇博客写了很久,其实写每一篇博客用的时间还是挺长的,不够这有利于自己的学习,也想分享一下。之前也说了创建了一个微信群,Python 学习讨论群,现在只有 40 个左右的小伙伴,如果有兴趣加入学习讨论的话,可以加我微信:androidwed,拉你进群。想看回之前的文章,也可以通过 Gitbook 查看,欢迎提出问题和点下 star,及时查看更新。目录一、迭代什么叫做迭代?比如在 Java 中,我

GitHubClub 2979

草根学Python(三) List 和 Tuple

前言继续更新,可以通过 https://www.readwithu.com/ 来看之前的文章。目录一、List(列表)Python 内置的一种数据类型是列表:list。 list 是一种有序的集合,可以随时添加和删除其中的元素。1、创建 List(列表)创建一个列表,只要把逗号分隔的不同的数据项使用方括号括起来即可,且列表的数据项不需要具有相同的类型list1=['两点水','twowter','l

GitHubClub 2739

草根学Python(四) Dict 和 Set

前言上一篇文章出现了个明显的知识点错误,不过感谢有个网友的提出,及时进行了修改。也希望各位多多包涵。新建了一个 Python 学习讨论的微信群,如果有兴趣的童鞋们,加群讨论下吧。也可以加我个人微信,拉你进群目录一、字典(Dictionary)经过之前的学习,我们可以知道 list 和 tuple 可以用来表示有序集合,之前我们那个例子是用 list 来存储了用户的昵称user=['liangdian

GitHubClub 2607

草根学Python(二)基本数据类型和变量

前言最近要开始新的项目,工作又开始忙起来了,不过还是每天要抽时间来写博客,但不可能做到日更,因为一篇博客,写的时间还是挺长的。Gitbook 同时更新喔。目录一、Python 语法的简要说明每种语言都有自己的语法,不管是自然语言还是我们的计算机编程语言,Python 也不例外,编辑器或者解析器根据符合语法的程序代码转换成 CPU 能够执行的机器码,然后执行。Python 的语法比较简单,采用缩进方式

GitHubClub 2597

草根学Python(一)第一个Python程序

前言一时冲动,就开始把 Python 的知识点做个总结归纳了。gitbook 同时更新。目录一、Python 简介Python 是著名的“龟叔” Guido van Rossum 在 1989 年圣诞节期间,为了打发无聊的圣诞节而编写的一个编程语言。牛人就是牛人,为了打发无聊时间竟然写了一个这么牛皮的编程语言。现在,全世界差不多有 600 多种编程语言,但流行的编程语言也就那么 20 来种。不知道你

GitHubClub 2220

草根学Python(八) 模块与包

前言之前的文章都是使用Sublime Text来编写 Python 的,主要是为了更好的熟悉和了解 Python ,可是开发效率不高,也不方便,从这章开始,改为使用 Pycharm 了,在之前的篇节集成开发环境(IDE): PyCharm中介绍了 PyCharm ,如果如要激活软件可以通过授权服务器来激活,具体看这个网址。JetBrains激活(http://www.imsxm.com/jetbra

GitHubClub 1735

草根学Python(十一)枚举类

前言虽然没多少阅读,可是还是坚持写下去。对 Python 感兴趣的童鞋可以加入 Python 学习讨论微信群喔。可以先加我微信,然后拉进群。本人微信:目录一、枚举类的使用实际开发中,我们离不开定义常量,当我们需要定义常量时,其中一个办法是用大写变量通过整数来定义,例如月份:JAN = 1 FEB = 2 MAR = 3 ... NOV = 11 DEC = 12当然这样做简单快捷,缺点是类型是 in

GitHubClub 1667
上一篇: 互联网彩票产品分析(沉静两年的互联网彩票开始迎来属于它的春天)
下一篇: 草根学Python(十六) 装饰器(逐步演化成装饰器)
Two_Water
博客等级 码龄12年 573粉丝 134原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值