深入浅出讲解python闭包

一、定义

在 Python 中,当一个函数内部定义的函数引用了外部函数的局部变量时,就形成了一个闭包。这个内部函数可以访问并修改外部函数的局部变量,而这些局部变量的状态会一直被保存在闭包中,即使外部函数已经执行完毕。

这种机制使得闭包可以实现一些特殊的功能,例如记忆化(Memoization)和实现私有变量等。闭包可以在函数内部保存一些状态,并且这些状态对外部是不可见的,从而实现了一定程度上的信息隐藏和封装。

def outer_function():x = 10def inner_function():nonlocal x  # 声明使用外部函数的局部变量 xx += 5return xreturn inner_function
​
closure = outer_function()
print(closure())  # 输出结果为 15
print(closure())  # 输出结果为 20

在这个示例中,inner_function 就是一个闭包,它引用了外部函数 outer_function 中的局部变量 x。每次调用 closure() 都会修改并返回 x 的值,而这个状态是被保存在闭包中的。


二、通过一个例子全面剖析一下闭包这个概念。

需求:实现银行系统的余额变化。

方式一:全局变量+函数

balance = 1000
def deposit(amount):global balancebalance += amountprint(f"成功存入 {amount} 元,当前余额为 {balance} 元")
​
def withdraw(amount):global balanceif amount <= balance:balance -= amountprint(f"成功取出 {amount} 元,当前余额为 {balance} 元")else:print("余额不足,取款失败")
​
def check_balance():print(f"当前余额为 {balance} 元")
​
# 存款和取款操作
deposit(500)  # 存入 500 元
withdraw(200)  # 取出 200 元
balance=10
deposit(500)  # 存入 500 元
check_balance()  # 查看余额

结果

成功存入 500 元,当前余额为 1500 元

成功取出 200 元,当前余额为 1300 元

成功存入 500 元,当前余额为 510 元

当前余额为 510 元

缺点:全局变量不安全,可以被随意访问和修改。

使用全局变量的方式虽然可以实现功能,但存在一些潜在问题:

  1. 可变性:全局变量的值是可变的,任何函数都可以直接修改它,这增加了程序出错的可能性,尤其在大型程序中更容易出现问题。

  2. 可见性:全局变量对整个程序都是可见的,这意味着任何部分都可以修改它,从而导致程序行为难以预测。

  3. 扩展性:如果需要管理多个账户,全局变量的方式就显得力不从心,因为很难将多个账户的信息独立地封装起来。


方案二:类

class BankAccount:def __init__(self, initial_balance):self.balance = initial_balance
​def deposit(self, amount):self.balance += amountprint(f"成功存入 {amount} 元,当前余额为 {self.balance} 元")
​def withdraw(self, amount):if amount <= self.balance:self.balance -= amountprint(f"成功取出 {amount} 元,当前余额为 {self.balance} 元")else:print("余额不足,取款失败")
​def check_balance(self):print(f"当前余额为 {self.balance} 元")
​
# 创建账户
account = BankAccount(1000)
account.balance=550
# 存款和取款操作
account.deposit(500)  # 存入 500 元
account.withdraw(200)  # 取出 200 元
account.check_balance()  # 查看余额

结果

成功存入 500 元,当前余额为 1050 元

成功取出 200 元,当前余额为 850 元

当前余额为 850 元

缺点:共有属性也能被对象访问修改,不安全。


方案三:类+私有属性

class BankAccount:def __init__(self, initial_balance):self.__balance = initial_balance
​def deposit(self, amount):self.__balance += amountprint(f"成功存入 {amount} 元,当前余额为 {self.__balance} 元")
​def withdraw(self, amount):if amount <= self.__balance:self.__balance -= amountprint(f"成功取出 {amount} 元,当前余额为 {self.__balance} 元")else:print("余额不足,取款失败")
​def check_balance(self):print(f"当前余额为 {self.__balance} 元")
​
account = BankAccount(1000)
account.deposit(500)
​
account.withdraw(200)
account.check_balance()

结果:

成功存入 500 元,当前余额为 1500 元

成功取出 200 元,当前余额为 1300 元

当前余额为 1300 元

问题得到解决。


方案四:闭包

def create_account(initial_balance):balance = initial_balancedef deposit(amount):nonlocal balancebalance += amountprint(f"成功存入 {amount} 元,当前余额为 {balance} 元")
​def withdraw(amount):nonlocal balanceif amount <= balance:balance -= amountprint(f"成功取出 {amount} 元,当前余额为 {balance} 元")else:print("余额不足,取款失败")
​def check_balance():print(f"当前余额为 {balance} 元")
​return deposit, withdraw, check_balance
​
# 创建账户
deposit, withdraw, check_balance = create_account(1000)
​
# 存款和取款操作
deposit(500)  # 存入 500 元
print(deposit)
withdraw(200)  # 取出 200 元
check_balance()  # 查看余额
​
# 创建账户
deposit1, withdraw1, check_balance1 = create_account(10000)
# 存款和取款操作
deposit1(500)  # 存入 500 元
print(deposit1)
withdraw1(200)  # 取出 200 元
check_balance1()  # 查看余额

结果

成功存入 500 元,当前余额为 1500 元

<function create_account.<locals>.deposit at 0x0000020DCC711990>

成功取出 200 元,当前余额为 1300 元

当前余额为 1300 元

成功存入 500 元,当前余额为 10500 元

<function create_account.<locals>.deposit at 0x0000020DCC711A20>

成功取出 200 元,当前余额为 10300 元

当前余额为 10300 元

完美解决了问题


三、辨析

闭包和类是两种不同的概念,它们在编程中有着不同的用途和特点。

闭包(Closure)是指可以在其词法作用域之外执行的函数,但仍然保持对其作用域内变量的引用。换句话说,闭包是函数及其相关的引用环境的组合。闭包可以用来封装状态、实现私有变量等功能。在 Python 中,当一个函数内部定义的函数引用了外部函数的局部变量时,就形成了一个闭包。

类(Class)则是面向对象编程中的重要概念,它用来描述具有相似属性和行为的对象的模板。类由属性(成员变量)和方法(成员函数)组成,可以通过实例化来创建对象,并且支持继承、多态等面向对象的特性。类的主要作用是封装数据和操作数据的方法,以及实现代码复用和抽象。

下面是闭包和类的一些区别:

  1. 封装方式不同:闭包是一种函数式编程的封装方式,通过函数和其引用环境来封装状态和行为;类是一种面向对象编程的封装方式,通过属性和方法来封装数据和操作。

  2. 状态的保存方式不同:闭包通过引用环境来保存状态,而类通过实例变量和类变量来保存状态。

  3. 范围不同:闭包通常用于封装一些局部状态,提供函数式编程的功能;类则通常用于描述对象的行为和属性,提供面向对象编程的特性。

总的来说,闭包和类都是用于封装和抽象的工具,但其应用场景和实现方式有所不同。在实际编程中,可以根据具体的需求和问题选择合适的工具来实现相应的功能。

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

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

相关文章

springboot上传文件后显示权限不足

前言&#xff1a; 最近一个老项目迁移&#xff0c;原本一直好好的&#xff0c;迁移后上传文件的功能使用不正常&#xff0c;显示文件没有可读取权限&#xff0c;这个项目并不是我们开发和配置的&#xff0c;由第三方开发的&#xff0c;我们只是接手一下。 前端通过api上传文件…

深度学习人脸表情识别算法 - opencv python 机器视觉 计算机竞赛

文章目录 0 前言1 技术介绍1.1 技术概括1.2 目前表情识别实现技术 2 实现效果3 深度学习表情识别实现过程3.1 网络架构3.2 数据3.3 实现流程3.4 部分实现代码 4 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习人脸表情识别系…

16位 (MCU) R7F101G6G3CSP、R7F101G6E3CSP、R7F101G6G2DSP、R7F101G6E2DSP是新一代RL78通用微控制器

产品描述 RL78/G24微控制器具有RL78系列MCU的最高处理性能&#xff0c;CPU工作频率高达48MHz&#xff0c;设有灵活的应用加速器 (FAA)。FAA是一款专门用于算法运算的协处理器&#xff0c;可以独立于CPU运行&#xff0c;提供更高处理能力。RL78/G24 MCU具有增强的模拟功能和大量…

SQL零基础入门教程,贼拉详细!贼拉简单! 速通数据库期末考!(九)

UNION ALL UNION ALL 用于合并两个或多个 SELECT 语句的结果。 请注意&#xff0c;UNION ALL 合并的每个 SELECT 语句必须是查询相同数量&#xff0c;相同数据类型的字段&#xff0c;且顺序也必须一致。另外结果集中的列名总是等于 UNION ALL 中第一个 SELECT 语句中的列名。 …

xlua源码分析(三)C#访问lua的映射

xlua源码分析&#xff08;三&#xff09;C#访问lua的映射 上一节我们主要分析了lua call C#的无wrap实现。同时我们在第一节里提到过&#xff0c;C#使用LuaTable类持有lua层的table&#xff0c;以及使用Action委托持有lua层的function。而在xlua的官方文档中&#xff0c;推荐使…

Vatee万腾科技创新之舟:Vatee数字化力量引领未来的独特路径

在数字化的大潮中&#xff0c;Vatee万腾如一艘科技创新之舟&#xff0c;在未来的海洋中翱翔。vatee万腾以强大的数字化力量为桨&#xff0c;引领着行业向着新的、独特的路径前行&#xff0c;塑造着数字时代的未来。 Vatee万腾不仅仅是一家科技公司&#xff0c;更是一艘创新之舟…

光伏拉晶厂RFID智能化生产工序管理

一、项目背景 随着全球能源短缺和气候变暖的挑战日益突显&#xff0c;清洁能源已成为国内能源发展的主要目标之一&#xff0c;作为清洁能源的重要组成部分&#xff0c;光伏行业在过去几十年中取得了巨大的发展&#xff0c;成为我国的战略性新兴产业之一。在智能制造的大环境下…

Linux:安装软件的两种方式rpm和yum

一、rpm方式 1、简单介绍 RPM是RedHat Package Manager的缩写&#xff0c;它是Linux上打包和安装的工具。通过rpm打包的文件扩展名是.RPM。这个安装包就类似Windows系统中的.exe文件。rpm工具实现Linux上软件的离线安装。 2、软件相关信息的查询命令 查询Linux系统上所有已…

IIC总线逻辑

一、 我们习以为常的IIC通常是什么样子&#xff1f; 在我们研发/应用工程师眼中&#xff0c;IIC的形象通常是如图这样的吧&#xff1f;&#xff08;你们说是不是&#xff1f;&#xff09; 是的&#xff0c;对于理想的硬件调程序&#xff0c;这个层…

HarmonyOS4.0系列——01、下载、安装、配置环境、搭建页面以及运行示例代码

HarmonyOS4.0应用开发 安装编辑器 这里安装windows版本为例 安装依赖 打开DevEco Studio 这八项全部打钩即可开始编写代码&#xff0c;如果存在x&#xff0c;需要安装正确的库即可 开发 点击Create Project 选择默认模板——next Model部分分为Stage和FA两个应用模型&…

【广州华锐互动】VR防溺水安全内容体验提高群众防溺水意识

在全球各地&#xff0c;溺水是导致儿童和青少年死亡的主要原因之一。据世界卫生组织的统计&#xff0c;全球每年有超过36万人因溺水而死亡&#xff0c;其中大部分是儿童和青少年。因此&#xff0c;提供有效的防溺水教育和培训至关重要。随着科技的发展&#xff0c;虚拟现实&…

数据库系统原理与实践 笔记 #9

文章目录 数据库系统原理与实践 笔记 #9存储管理与索引文件和记录的组织文件组织定长记录变长记录分槽的页结构文件中记录的组织顺序文件组织多表聚簇文件组织 数据库系统原理与实践 笔记 #9 存储管理与索引 文件和记录的组织 文件组织 数据库是以一系列文件的形式存储的。…

Hive调优

1.参数配置优化 设定Hive参数有三种方式&#xff1a; &#xff08;1&#xff09;配置Hive文件 当修改配置Hive文件的设定后&#xff0c;对本机启动的所有Hive进程都有效&#xff0c;因此配置是全局性的。 一般地&#xff0c;Hive的配置文件包括两部分&#xff1a; a&#xff…

【网络】OSI模型 与 TCP/IP模型 对比

一、OSI模型 OSI模型包含7个层次&#xff0c;从下到上分别是&#xff1a; 1. 物理层&#xff08;Physical Layer&#xff09; - 功能&#xff1a;处理与电子设备物理接口相关的细节&#xff08;如电压、引脚布局、同步&#xff0c;等等&#xff09;。 - 协议&#xff1a;以…

mac苹果电脑需要安装杀毒软件吗?

随着数字时代的发展&#xff0c;计算机安全问题变得越来越重要。而在计算机安全领域中&#xff0c;杀毒软件是一个被广泛讨论的话题。苹果电脑需要安装杀毒软件吗&#xff1f;对于苹果电脑用户来说&#xff0c;他们常常会疑惑自己是否需要安装杀毒软件来保护自己的电脑。本文将…

ATTCK 十大免费 工具和资源

01 eBook: Getting Started with ATT&CK 这本免费电子书将有关威胁情报、检测和分析、对手模拟和红队以及评估和工程的博客文章中的内容汇集到一个方便的软件包中。 02 CALDERA CALDERA是一个网络安全平台&#xff0c;旨在轻松自动化对手仿真&#xff0c;协助手动红队并自…

第二证券:庄家会出现在十大流通股东吗?

近年来&#xff0c;跟着股市投资者的增多和信息的流通&#xff0c;庄家这一概念备受注重。庄家是指具有健旺资金实力、掌控金融商场的财团或个人&#xff0c;运用商场上的信息优势&#xff0c;通过投机办法获取高额收益。那么&#xff0c;庄家会出现在十大流通股东里面吗&#…

Zabbix实现故障自愈

一、简介 Zabbix agent 可以运行被动检查和主动检查。 在被动检查模式中 agent 应答数据请求。Zabbix server&#xff08;或 proxy&#xff09;询求数据&#xff0c;例如 CPU load&#xff0c;然后 Zabbix agent 返还结果。 主动检查处理过程将相对复杂。Agent 必须首先从 Z…

C++初阶 | [四] 类和对象(下)

摘要&#xff1a;初始化列表&#xff0c;explicit关键字&#xff0c;匿名对象&#xff0c;static成员&#xff0c;友元&#xff0c;内部类&#xff0c;编译器优化 类是对某一类实体(对象)来进行描述的&#xff0c;描述该对象具有哪些属性、哪些方法&#xff0c;描述完成后就形成…

HarmonyOS ArkTS语言,运行Hello World(二)

一、认识DevEco Studio界面 进入IDE后&#xff0c;我们首先了解一下基础的界面。整个IDE的界面大致上可以分为四个部分&#xff0c;分别是代码编辑区、通知栏、工程目录区以及预览区。 代码编辑区 1、中间的是代码编辑区&#xff0c;你可以在这里修改你的代码&#xff0c;以…