深入浅出讲解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.hqwc.cn/news/197556.html

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

相关文章

苹果签名应用掉签频繁原因排查,以及如何避免

作为一个对iOS生态有着深厚理解的实用技术博主&#xff0c;我明白苹果签名应用掉签对我们的开发和使用带来的困扰。签名在苹果设备中扮演着至关重要的角色&#xff0c;它不仅确保了应用来源的合法性&#xff0c;也影响着应用的顺畅运行。 今天&#xff0c;我将和您一同探讨苹果…

如何使用$APPEALS法,分析用户期待?

$APPEALS分析法是一种用于分析用户期待和需求的方法&#xff0c;它可以帮助企业全方位多角度地了解客户对产品的期望&#xff0c;有助于企业多维度有侧重地调整市场规划和产品改进策略&#xff0c;帮助企业打造优势产品&#xff0c;提高市场竞争力。 下面是使用$APPEALS分析法来…

运动耳机什么牌子好?十大运动蓝牙耳机品牌排行榜

​运动耳机需求各有不同&#xff0c;对于我们每个人来说&#xff0c;选择最适合自己的耳机是一项重要任务。在这个耳机类型繁多&#xff0c;五花八门的时代&#xff0c;如何找到一款适合自己的运动耳机呢&#xff1f;选对运动耳机很重要&#xff0c;所以接下来安利五款相当不错…

实时监控电脑屏幕的软件丨同时查看12台电脑屏幕

Hello 大家好 又见面啦 今天给大家推荐两款比较实用的监控电脑使用情况、屏幕的软件&#xff01; 软件一 实时性能监控 从软件名就可以看出来&#xff0c;这是一款电脑性能监测工具。它可以实时监测内存、CPU、磁盘占用情况&#xff0c;也能一键结束进程&#xff0c;给电脑提…

8 Redis与Lua

LUA脚本语言是C开发的&#xff0c;类似存储过程,是为了实现完整的原子性操作&#xff0c;可以用来补充redis弱事务的缺点. 1、LUA脚本的好处 2、Lua脚本限流实战 支持分布式 import org.springframework.core.io.ClassPathResource; import org.springframework.data.redis…

[一周AI简讯]OpenAI宫斗;微软Bing Chat更名Copilot;Youtube测试音乐AI

OpenAI宫斗&#xff0c;奥特曼被解雇&#xff0c;董事会内讧 Sam Altman被解雇&#xff0c;不再担任CEO&#xff0c;董事会的理由是奥特曼在与董事会的沟通中始终不坦诚&#xff0c;阻碍了董事会履行职责的能力。原首席技术官Mira Murati担任新CEO。OpenAI宫斗剧远未结束&…

HandBrake :MacOS专业视频转码工具

handbrake 俗称大菠萝&#xff0c;是一款免费开源的视频转换、压缩软件&#xff0c;它几乎支持目前市面上所能见到的所有视频格式&#xff0c;并且支持电脑硬件压缩&#xff0c;是一款不可多得的优秀软件 优点 ∙Windows, Linux, Mac 三平台支持 ∙开源、免费、无广告 ∙支…

快手运营的必备的10个工具

一、引言 快手作为短视频领域的佼佼者&#xff0c;为众多创作者提供了广阔的舞台。要想在快手运营中取得成功&#xff0c;掌握一些必备的工具是必不可少的。本文将为您介绍快手运营的10个必备工具&#xff0c;帮助您提高工作效率&#xff0c;优化内容创作。 二、工具推荐 1. …

工作经验总结之 Eslint 报错和开发技巧。

报错&#xff1a;Expected to return a value in "yuJiaoFeiShow" computed property.eslintvue/return-in-computed-property yuJiaoFeiShow计算属性语句中没有 default默认值 ,因此如果都无法匹配的话&#xff0c;那就没有返回值。 解决办法&#xff1a; 给计算属…

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

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

Swifit学习第一天

学到了什么&#xff1a; 布局&#xff1a;ZStack 、HStack、VStack、Image 其它&#xff1a;点击事件、属性包装器ClampedValue、三目运算 1、图片缩放 2、属性包装器

ICCV 2023|小红书 4 篇入选论文亮点解读,「开集视频目标分割」获得 Oral

近日&#xff0c;ICCV 正式揭晓 2023 年论文接收结果&#xff0c;小红书技术团队共有 4 篇论文入选&#xff0c;其中 1 篇为 Oral 论文&#xff08;Oral 接收率仅为 1.88%&#xff09;&#xff0c;最新科研成果涵盖了视频目标分割、3D 数字人重建、人体运动预测、视频分析等领域…