Python之函数高级:一篇文章彻底搞懂什么是“闭包”
引言在编程中有一个让一些新手望而却步的概念——“闭包”。一方面, 闭包的定义以及作用机制着实略微有那么点复杂, 另一方面, 这个概念好像更倾向于数学、理论的范畴, 对于新手而言, 好像并没有太多的应用场景。不管怎样, 因由前面已阐述过的, 像是函数对象相关, 函数具备一等公民属性这件事还有高阶函数部分, 以及针对函数对象内部细节展开的深入探究等种种情况。我坚信去领会并熟练掌握“闭包”所涵盖的概念以及运用方式, 会朝着更为简易的方向发展, 这属于那种“顺理成章、自然而然就达成”的状况。本文的主要内容有1、探究“闭包”概念背后的本质2、一个闭包实例3、闭包的作用机制探究“闭包”概念背后的本质我们在前面的文章里, 曾提到编程学习之中的两大核心, 也就是“数据的表达”以及“数据的处理”, 那也能够表示成“数据结构”还有“算法”, 实际上, 这是一种极其简单的表达。从更加完整的角度去看, 每一个程序更为完整的构成, 都必然要有以下几个部分:1、输入数据的集合2、内部状态的集合3、计算规则的集合4、输出数据的集合这实际上同样是计算机科学背后那个图灵机的一种抽象, 从这个抽象层面来讲, 要是去看平常的编程语言里的函数, 我们能够发觉, 好像是图灵机的一个删减版本, 被删减的部分乃是“内部状态的集合”, 也就是说呀, 纯粹的函数是更着重于计算规则, 而不存在内部状态的那般的图灵机。然而, 存在某些时段, 我们的确必要内部状态, 鉴于内部状态各异, 对相同输入而言, 函数会给出不同输出。便是这样, “闭包”的概念出现了, 闭包能够大致被理解成“存在内部状态的函数”, 它是一种组合, 是一个函数跟与其相关的上下文环境状态的组合了。像这样去看的话, 闭包实际上就是一个单纯简省的物体, 该种物体仅仅拥有一项办法。反过来进行观察, 对象能够被视作是几个有着共享内部状况的闭包, 这样的一种说法同样不存在不合理之处, 是能够站得住脚的。故而, 闭包以及对象, 存有这样一种关系, 即看似是两个不同的概念, 实则又紧密相连, 从本质层面来讲, 它们就是同一个事物。依据此情况, 我们能够再进一步推导得出, 函数式编程跟面向对象编程, 在底层的基础层面上同样是属于一致的这一最终结论。要是处于别的函数式编程语言里面, 领会函数, 明白闭包, 理解对象好像还有些繁杂。然而, 要是我们将关注点汇聚到中去看, 因“一切皆对象”这个处于底层的“一”的存有, 在中的函数属于对象, 其自身同样是具备状态也就是属性的。那么, 于中好像我们又无需严格去区分啥是函数、啥是闭包了。因为在中的函数皆是对象, 都存有状态, 有状态的函数便是闭包, 所以在中一切函数似乎也皆是闭包了。的确没错, 上文提及的仅仅是依据底层观念而开展的某些推导罢了。于真实的编程语法层面而言, 平常的函数与闭包存在微微的差异。关联上一篇文章里头, 针对函数对象内里构成的探寻, 我们能够获取如下的论断:1、中的函数全都是对象, 因而, 从宽泛的意义来讲, 中的函数都能够是具备状态的函数。2、中的函数状态就是其定义执行的上下文环境。3、中的普通函数, 它的内部状态, 即其定义所在的全局命名空间, 此状态存在于函数对象内, 能够借助属性予以读写。4、里边的特殊函数对象, 专门指的是“闭包”, 它的内部状态, 除了属性对应的全局命名空间之外, 还有一个属性存储的, 是“闭包”所独有的内部状态。暂且中断对于概念的阐述, 只要存有一定理念性质的感知就行, 之后, 我们借助实际的代码去进一步展现这些概念。一个闭包实例给定一个带初始值的累加器的实现作为例子, 分别去看普通函数的使用情况, 并且去看闭包的使用情况, 进而对闭包的特点展开分析, 同时对闭包在特定场景里的优势所在进行比较。在真正使用闭包之前我们先看一下普通的有状态的函数的使用首先定义一个模块m1.pytotal 20def acc(step):totaltotal step然后我们在入口文件中导入m1模块进行函数调用m1print(f初始值为{m1.total})print(f函数内部状态{m1.acc.})m1.acc(5)print(f加5之后变为{m1.total})print(f函数内部状态{m1.acc.})m1.acc(10)以格式化方式输出, 输出内容为: 又加了10之后变为: 加上变量m1中的total属性的值。print(f函数内部状态{m1.acc.})执行结果来看执行结果, 中所定义的平常函数的确是存有状态的, 并且达成了累加器的成效。但是, 我们也应当认识到, 普通函数的状态, 从本质上来看, 并非仅仅归属于函数自身, 而是与函数所属模块里的所有函数、代码块共同分享的模块自身的全局命名空间。所以, 这个状态明显是欠缺安全性的, 毕竟全局变量里所贮存的状态, 其被更改的渠道颇为多样。除此之外在于, 因状态共享致使的不安全存在着, 我们是没有办法去达成多个不一样状态的累加器能够同时存在的这种情况的。下面我们通过闭包实现这个累加器的需求def acc(total20):def inner(step):totaltotal steptotalinneracc1 acc(0)print(acc1.)print(f初始状态{acc1..})print(f加10之后变为{acc1(10)})print(f加10之后变为{acc1(100)})acc2 acc(100)print(acc2.)print(f初始状态{acc2..})print(f加10之后变为{acc2(10)})print(f加10之后变为{acc2(100)})print(acc1)print(acc2)执行结果分析执行结果可知, 这般“闭包”的形式实实在在达成了各异累加器对象的同时存在, 闭包所特有的内在状态被存储于函数对象的属性里面。闭包的作用机制我们现粗略给出一个“闭包”的定义所谓“闭包”, 是指在嵌套定义的函数里, 有一个内部函数引用了外部函数中的局部变量, 而且该外部函数的作用域已然结束, 这种内部函数和它所应用的外部函数的变量一同构成了闭包。闭包可以保存和访问它创建时的环境即使在外部函数结束之后。前面曾经提及过, 高阶函数存在两个条件, 只要满足其中一个便属于高阶函数也就是说, 要么把函数当作参数来进行传递, 要么返回一个函数对象。闭包明显是满足第二个条件的高阶函数。下面我们来简单概括一下创建一个闭包所需要的条件1、存在嵌套定义的函数。2、内部函数引用了其外部函数中的变量。3、有一个外部函数存在, 它返回了这样一个对象, 此对象是内部函数对象, 要注意, 这里返回的是函数对象, 并非是内部函数完成调用之后所产生的结果, 是有区别的。同时满足上面的3个条件就可以创建闭包了。从本质的角度来讲, 每一个函数都存在着自身所特有的局部具有限定范围的命名空间, 同时也有着归其所属的全局性的命名空间。一旦, 当闭包得以创建的条件达到了满足的状态时, 就必然会生成一个全新的命名空间, 也就是被称作闭包命名空间的那部分空间。只要是在嵌套函数定义里, 内部函数引用了外部函数那一块儿的局部变量, 这样子才会被添加到闭包命名空间范围中, 这是一定要做到的, 对此是严谨规定的, 有着明确要求的。再次看一下定义能瞧见, 函数对象里, 指向闭包命名空间的属性, 是个元组, 其元素类型, 为_Cell, 而那_Cell对象, 是有属性的。所以, 在上面代码里, 对闭包命名空间中所存储的内部状态进行访问, 是借助..得以实现的。此外, 倘若要 在内部函数作用域里, 尝试去修改外部函数当中定义的局部变量, 需知外部函数的形参同样是外部函数的局部变量, 那么就需要借助关键字来对变量展开声明, 不然的话就会被解释器认定为是在定义一个内部函数里的局部变量, 并且还会给其赋上初始值。在前面函数的局部作用域里, 当我们尝试去修改全局变量时, 碰到过类似关键字声明的情况, 也就是关键字。从和这两个被称作关键字的玩意儿当中, 同样是能够瞧得出来闭包作用域那尴尬之处的, 因为并没有使用关键字, 所以并非全局命名空间, 也就是并非local 它可不是局部命名空间。处于全局命名空间以及局部命名空间夹缝中间的那一部分, 暂且权且把它叫作闭包命名空间好了。从名字解析所依照的LEGB规则来看, 能发现, Llocal与G之间的E, 此前未曾展开提及, 实际上就是这个闭包命名空间, 其中的名字解析契合就近原则, 内部的能够覆盖外部的。实际上, 于我而言, 没必要专门对“闭包”的概念予以着重强调, 只要可以明白函数自身身为对象, 已然自然而然地拥有内部状态这样的特性。明白了这些底层的作用运行机制, 就已然充分了。总结本文对闭包的定义予以了详尽阐释, 对其本质也进行了细致说明, 还针对函数、闭包、对象这几个范畴的区别与联系作出了解释, 与此同时, 介绍了闭包得以成立的条件以及与之相关的内部状态的存储机制。在对闭包有了理解的基础之上, 又一次回顾了LEGB规则。感谢您的拨冗阅读希望对您理解中的闭包能有所帮助。

相关新闻

如何通过Sunshine自托管游戏串流服务器实现跨平台游戏体验

如何通过Sunshine自托管游戏串流服务器实现跨平台游戏体验

如何通过Sunshine自托管游戏串流服务器实现跨平台游戏体验 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 你是否曾想过将高性能PC上的游戏无缝串流到平板、手机或客厅电视上&…

2026/9/26 0:12:41 阅读更多 →
当围棋遇见AI:我与LizzieYzy的七天探索之旅

当围棋遇见AI:我与LizzieYzy的七天探索之旅

当围棋遇见AI:我与LizzieYzy的七天探索之旅 【免费下载链接】lizzieyzy LizzieYzy - GUI for Game of Go 项目地址: https://gitcode.com/gh_mirrors/li/lizzieyzy "围棋不是关于赢棋的游戏,而是关于理解的艺术。"——但理解从何而来&am…

2026/9/28 11:12:35 阅读更多 →
SolidWorks齿轮阵列与修剪技术实战指南

SolidWorks齿轮阵列与修剪技术实战指南

1. SolidWorks齿轮阵列与修剪的核心价值齿轮作为机械传动系统的核心部件,其建模精度直接影响运动仿真和加工质量。传统逐个绘制齿轮齿形的方法不仅效率低下,更难以保证齿距均匀性。我在汽车变速箱设计项目中实测发现,使用图形阵列配合修剪技术…

2026/10/11 15:16:25 阅读更多 →

最新新闻

GWO优化LSSVM超参数:回归预测的自动化参数寻优实战

GWO优化LSSVM超参数:回归预测的自动化参数寻优实战

用过回归预测的人,十有八九会在某个阶段撞上这么一堵墙:模型手里一大把,真正能把误差压到目标水平、又不至于跑偏过拟合的,反而不多。我曾经接过一个跨设备访问趋势的回归任务,样本只有几百条,特征之间存在…

2026/10/14 4:29:51 阅读更多 →
VMware Tools安装与故障排查指南:从官方版到open-vm-tools

VMware Tools安装与故障排查指南:从官方版到open-vm-tools

1. 为什么VMware Tools总让我又爱又恨——先说它到底解决了什么问题先从一个我踩过很多次的场景说起:你高高兴兴建好一台新的虚拟机,装完操作系统,发现鼠标在窗口里挪不动道,想从宿主机拖个文件过去怎么都拖不进去,屏幕…

2026/10/14 4:29:51 阅读更多 →
拓扑量子比特争议背后:马约拉纳束缚态与容错量子计算的距离

拓扑量子比特争议背后:马约拉纳束缚态与容错量子计算的距离

量子计算的新闻这两年有个规律:越是看起来里程碑式的结果,越要小心拆开看。微软2025年拿出的那套拓扑量子计算机方案,恰好就是一个非常典型的样本——官方表述是“已造出可分立的拓扑量子比特芯片”,媒体报道是“冲向百万量子比特…

2026/10/14 4:29:51 阅读更多 →
空间证明PoSpace原理与实操:从P盘到出块,绿色挖矿全解析

空间证明PoSpace原理与实操:从P盘到出块,绿色挖矿全解析

空间证明(PoSpace)这个概念,我第一次接触是在好几个年前,当时脑子里第一反应是“用硬盘挖矿?这玩意儿靠谱吗”。那阵子整个圈子都在讨论工作量证明(PoW)的能耗问题,动不动就是“一个…

2026/10/14 4:29:51 阅读更多 →
ML Kit设备端AI实战:从图像识别到自定义模型

ML Kit设备端AI实战:从图像识别到自定义模型

ML Kit是谷歌推出的移动端机器学习套件,但它并不是一个“云服务”,而是把模型压缩、量化、推理引擎都塞进手机本地运行的设备端AI框架。第18章讲的就是这个:怎么在Android/iOS上不依赖网络、不把用户数据上传服务器,直接调用现成的…

2026/10/14 4:29:51 阅读更多 →
基于炬芯ATS308X CPU方式实现opus解码算法实现

基于炬芯ATS308X CPU方式实现opus解码算法实现

实时录音由 zephyr/drivers/audio/shell/audio_driver_shell.c 处理:DMA 回调把每个已完成的 512 B 半缓冲复制到 8 KiB 环形暂存区,后台写入器每次取最多 4 KiB,同时写入 PCM 并交给 opus_stream_feed()。这样写盘期间 DMA 缓冲变化也不会丢…

2026/10/14 4:28:51 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →