解密闭包:函数如何记住外部变量

🧠 什么是闭包?

闭包是一个函数对象,它不仅记住它的代码逻辑,还记住了定义它时的自由变量(即非全局也非局部,但被内部函数引用的变量)。即使外部函数已经执行完毕,这些自由变量的值仍然保存在内存中,可以通过闭包访问和使用。

简单来说:

  • 当一个嵌套的函数引用了其外部函数中的变量,并且这个嵌套函数可以在其外部函数之外被调用时,就形成了一个闭包。


✅ 闭包的基本结构

def outer_function(x):def inner_function(y):return x + yreturn inner_function
closure = outer_function(10)
print(closure(5))  # 输出: 15

在这个例子中,inner_functionouter_function 的内部函数,并且引用了 outer_function 的参数 x。当 outer_function 返回 inner_function 时,尽管 outer_function 已经执行结束,但是 inner_function 依然保留了对外部变量 x 的引用,这就形成了一个闭包。


✅ 闭包的工作原理

闭包允许你在一个函数内创建并返回另一个函数,而后者能够“记住”前者内部的变量状态。这种特性对于需要保持某些状态的应用场景特别有用,比如计数器等。

示例:简单的计数器

def make_counter():count = 0def counter():nonlocal count  # 使用 nonlocal 声明 count 是外部函数中的变量count += 1return countreturn counter
counter = make_counter()
print(counter())  # 输出: 1
print(counter())  # 输出: 2
print(counter())  # 输出: 3

在这个例子中,make_counter 函数返回了一个闭包 counter,它可以不断增加并返回一个计数值。注意这里使用了 nonlocal 关键字来表明我们要修改的是外部函数中的 count 变量。


✅ 为什么使用闭包?

  1. 封装:闭包可以帮助我们封装一些数据,避免全局变量的污染。

  2. 状态保持:通过闭包,我们可以轻松地实现带有状态的函数。

  3. 减少命名冲突:由于闭包内部使用的变量对外部不可见,因此减少了命名冲突的风险。


✅ 闭包与装饰器

闭包的一个常见应用场景就是作为装饰器的基础。装饰器本质上也是一个闭包,它接受一个函数作为输入,并返回一个新的函数,通常用于在不改变原函数的情况下添加额外的功能。

示例:简单的装饰器

def decorator(func):def wrapper():print("Something is happening before the function is called.")func()print("Something is happening after the function is called.")return wrapper
@decorator
def say_hello():print("Hello!")
say_hello()

输出:

Something is happening before the function is called.Hello!Something is happening after the function is called.

⚠️ 注意事项

  1. 可变对象:如果闭包中引用的对象是可以变的(如列表),那么对这个对象的任何更改都会反映在闭包中。

  2. 性能问题:虽然闭包很强大,但在某些情况下可能会导致性能问题或增加程序复杂度,所以应谨慎使用。


📌 总结

  • 闭包是由函数及其相关引用环境组合而成的实体。

  • 它允许函数“记住”并访问其定义范围内的变量,即使那个函数在其定义的作用域外被调用。

  • 闭包广泛应用于各种编程模式中,如装饰器、工厂函数等。

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

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

相关文章

I2C协议详解及STM32 HAL库硬件I2C卡死问题分析

一、I2C协议详解 1. I2C协议概述 Inter-Integrated Circuit (I2C) 是由 Philips 半导体(现 NXP 半导体)于 1980 年代设计的一种同步串行通信总线协议。该协议采用半双工通信模式,支持多主从架构,专为短距离、低速率的芯片间通信…

HTTP协议-后端接收请求

起因就是不知道post这个请求体中这些格式有什么区别,后端又怎么去接收这些不同格式的内容 Get请求 get请求是比较简单的一类 正常的直接用参数接收(不写的话名字要匹配)或者RequestParam都可以接收,用对象绑定也可以 resultful…

HTML5 实现的圣诞主题网站源码,使用了 HTML5 和 CSS3 技术,界面美观、节日氛围浓厚。

以下是一个 HTML5 实现的圣诞主题网站源码,使用了 HTML5 和 CSS3 技术,界面美观、节日氛围浓厚。它包括: 圣诞树动画 🎄雪花飘落特效 ❄️圣诞祝福语 🎁响应式布局,适配移动端 你可以将代码保存为 index.…

Spring Cloud Bus 和 Spring Cloud Stream

Spring Cloud Bus 和 Spring Cloud Stream 都是 Spring Cloud 生态中的消息通信组件,但它们的定位和使用场景有显著区别: 1. Spring Cloud Bus 核心定位:分布式系统的消息广播(配置刷新、事件传播)。 典型场景&#x…

磁悬浮轴承位移信号的高精度估计:卡尔曼滤波算法深度解析

无需位移传感器,滤波算法如何实现微米级精度? 磁悬浮轴承作为革命性的非接触式支承技术,凭借无磨损、无需润滑、高转速等优势,在飞轮储能、高速电机、人工心脏泵和航空航天领域获得了广泛应用。其核心控制依赖于对转子位移信号的高精度实时检测,传统电涡流传感器虽能提供位…

DAY 43 预训练模型

目录 一、预训练的概念 二、 经典的预训练模型 2.1 CNN架构预训练模型 2.2 Transformer类预训练模型 2.3 自监督预训练模型 三、常见的分类预训练模型介绍 3.1 预训练模型的发展史 3.2 预训练模型的训练策略 知识点回顾: 预训练的概念常见的分类预训练模型图像…

Redis:事物

🌈 个人主页:Zfox_ 🔥 系列专栏:Redis 🔥 什么是事务 Redis的事务和MySQL的事务概念上是类似的.都是把⼀系列操作绑定成⼀组.让这⼀组能够批量执⾏. 但是注意体会Redis的事务和MySQL事务的区别: 弱化的原⼦性:redi…

CppCon 2018 学习:An allocator is a handle to a heap Lessons learned from std::pmr

“An allocator is a handle to a heap — Lessons learned from std::pmr” 翻译过来就是:“分配器(allocator)是对堆(heap)的一种句柄(handle)——从 std::pmr 中学到的经验”。 基础概念 分…

设备健康实时监测方法演进:从传感网络到AI决策树的工业智能实践

引言:当设备运维遇上AIoT革命 在工业4.0进程中,​毫秒级设备状态捕获能力正成为智能工厂的核心竞争力。传统监测方法因数据滞后、诊断粗放被诟病,本文将深入探讨三大前沿实时监测技术路径,并揭秘中讯烛龙系统如何通过深度强化学习…

剑指offer53_二叉树的深度

二叉树的深度 输入一棵二叉树的根结点,求该树的深度。 从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。 数据范围 树中节点数量 [ 0 , 500 ] [0,500] [0,500]。 样例 输入&#…

探秘AI的秘密:leaked-system-prompts

揭秘:揭秘系统提示合集背后的秘密 在当今这个人工智能技术迅速发展的时代,了解和使用大型语言模型(LLM)已成为技术爱好者、开发者和研究人员的共同目标。而作为核心组成部分,系统提示(system prompts)的设计和应用直接影响了LLM的表现和功能。今天, 我们将为大家揭示一…

Gaming Mode四大功能(VRR、QMS、QFT、ALLM)

HDMI 2.1定义的Gaming Mode四大功能(VRR、QMS、QFT、ALLM)通过协同优化帧传输、刷新率同步与延迟控制,显著提升了游戏和影音的流畅性与响应速度。以下是这些功能的详细解析及其应用价值: 🔄 1. 可变刷新率(…

数据库总结(关系代数-函数依赖-范式)

以下是关系代数中基本操作的详细说明: 并(Union) 关系R和S的并操作表示为R ∪ S,要求R和S具有相同的属性集(并相容性)。结果包含所有属于R或S的元组,自动去除重复项。 示例: R …

react经验:在nextjs中使用motion组件

什么是motion组件? 一种动画组件 motion组件文档 在nextjs中的应用步骤 1.安装motion npm i framer-motion2.在next.config.js中配置转义 export default {transpilePackages: [framer-motion] }3.开始应用 **注意要点:**在服务端渲染不可直接用&am…

怎样大语言模型 遵守规则

如何让应用中的提示工程更能适应未来变化 目录 如何让应用中的提示工程更能适应未来变化怎样大语言模型 遵守规则提示词 很有效:Memorize these rules提示可分为稳定组件和易变组件怎样大语言模型 遵守规则 实验背景:让大语言模型可靠地遵守规则很难,尤其是规则数量增多时。…

如何通过SSL证书配置防止源站IP泄露 - 全面防护指南

问题背景:SSL证书如何导致源站IP泄露 近期多位站长反馈,即使已部署高防CDN并做好源站IP保密工作,服务器仍频繁遭受DDoS攻击。经深入排查,发现问题根源在于SSL证书。当前网络环境中存在大量爬虫工具24小时不间断扫描全网IP地址&am…

医院信息化发展要经过哪几个阶段

目前,几乎所有的医院都离不开信息技术的建设和支持。没有信息技术,医院的业务可能无法继续。医院信息化的发展主要经历三个阶段,即医院管理信息化阶段、临床管理信息化阶段和医疗智能化阶段。从基础设施的角度来看,每个阶段都有不…

【Vscode】Vscode切换成中文语言

安装中文语言包 启动 VSCode。按下Ctrl Shift X(或者点击左侧边栏的扩展图标),打开扩展面板。在搜索框中输入Chinese (Simplified),在搜索结果里找到Chinese (Simplified) Language Pack for Visual Studio Code并点击安装按钮…

【百日精通JAVA | 数据结构篇】 一文了解泛型体系

一、初识泛型 在推出泛型以前,程序员可以创建一个元素类型Object的集合,该集合能够存储任意的数据类型对象,而在使用该集合的过程中,需要明确知道存储每个元素的类型,否则容易引发ClassCastException异常。 泛型是JD…

赋能 Java 工程,飞算科技重新定义智能开发

在数字经济蓬勃发展的当下,软件开发行业正经历着前所未有的变革。飞算科技作为一家自主创新型的数字科技公司,始终以互联网科技、大数据、人工智能等前沿技术为根基。凭借团队在相关领域多年积累的深厚实践经验,公司深度融合技术与应用&#…