深入浅出讲解python闭包

news2024/9/23 1:36:41

一、定义

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

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

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

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


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

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

方式一:全局变量+函数

balance = 1000
def deposit(amount):
    global balance
    balance += amount
    print(f"成功存入 {amount} 元,当前余额为 {balance} 元")
​
def withdraw(amount):
    global balance
    if amount <= balance:
        balance -= amount
        print(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 += amount
        print(f"成功存入 {amount} 元,当前余额为 {self.balance} 元")
​
    def withdraw(self, amount):
        if amount <= self.balance:
            self.balance -= amount
            print(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 += amount
        print(f"成功存入 {amount} 元,当前余额为 {self.__balance} 元")
​
    def withdraw(self, amount):
        if amount <= self.__balance:
            self.__balance -= amount
            print(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_balance
    def deposit(amount):
        nonlocal balance
        balance += amount
        print(f"成功存入 {amount} 元,当前余额为 {balance} 元")
​
    def withdraw(amount):
        nonlocal balance
        if amount <= balance:
            balance -= amount
            print(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.coloradmin.cn/o/1228929.html

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

相关文章

GreatSQL社区与Amazon、Facebook、Tencent共同被MySQL致谢

一、来自MySQL官方的感谢 在 2023-10-25 MySQL 官方发布的 8.2 版本 Release Notes 中&#xff0c;GreatSQL 社区核心开发者 Richard Dang 和 Hao Lu &#xff0c;分别收到了来自 MySQL 官方的贡献感谢&#xff0c;与Amazon、Facebook(Meta)、Tencent等一并出现在感谢清单中。…

【数据结构】详解链表结构

目录 引言一、链表的介绍二、链表的几种分类三、不带头单链表的一些常用接口3.1 动态申请一个节点3.2 尾插数据3.3 头插数据3.4 尾删数据3.5 头删数据3.6 查找数据3.7 pos位置后插入数据3.8 删除pos位置数据3.9 释放空间 四、带头双向链表的常见接口4.1创建头节点&#xff08;初…

everything的高效使用方法

目录 前言1 everything的简单介绍2 常用搜索3 语法搜索4 正则表达式搜索5 服务器功能 前言 本文介绍everything软件的高效使用方法&#xff0c;everything是一款在系统中快速搜索文件的软件&#xff0c;能够帮助人们快速定位需要查找的文件。首先介绍everything软件的作用和使…

摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…

【开源】基于Vue.js的高校宿舍调配管理系统

项目编号&#xff1a; S 051 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S051&#xff0c;文末获取源码。} 项目编号&#xff1a;S051&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能需求2.1 学生端2.2 宿管2.3 老师端 三、系统…

【Python进阶】近200页md文档14大体系知识点,第4篇:linux命令和vim使用

本文从14大模块展示了python高级用的应用。分别有Linux命令&#xff0c;多任务编程、网络编程、Http协议和静态Web编程、htmlcss、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。 全套Python进阶笔记地址…

OFDM通信系统仿真之交织技术

文章目录 前言一、交织1、概念2、图形举例3、交织的位置 二、MATLAB仿真1、MATLAB 程序2、仿真结果 前言 之前的博客&#xff1a;OFDM深入学习及MATLAB仿真 中有对交织的概念进行讲解&#xff0c;但讲解还是比较浅显&#xff0c;且仿真实现时并没有加入交织及解交织流程&#…

【电路笔记】-欧姆定律

欧姆定律 文章目录 欧姆定律1、概述2、AC电路的等效性2.1 输入电阻2.2 输入电感2.3 输入电容 3、欧姆定律的局部形式3.1 介绍和定义3.2 德鲁德模型(Drude Model)3.3 局部形式表达式 4、电阻和宏观欧姆定律5、总结 电流、电压和电阻之间的基本关系被称为欧姆定律&#xff0c;可能…

解决龙芯loongarch64服务器编译安装Python后yum命令无法使用的问题“no module named ‘dnf‘”

引言 在使用Linux系统时,我们经常会使用yum来管理软件包。然而,有时候我们可能会遇到yum不可用的情况,其中一个原因就是Python的问题。本文将介绍Python对yum可用性的影响,并提供解决方案。 问题引发 正常情况下,安装linux系统后,yum命令是可用状态,升级Python版本后,…

CPU版本的pytorch安装

1.安装&#xff1a;Anaconda3 2.安装&#xff1a;torch-2.0.1cpu-cp311 2.安装&#xff1a;torchvision-0.15.2cpu-cp311-cp311-win_amd64 测试是否安装成功 cmd 进入python import torch print(torch.__version__) print(torch.cuda.is_available())

使用Docker/K8S/Helm部署项目流程

假设项目已经开发完成&#xff0c;部署流程如下&#xff1a; 一、制作镜像&#xff1a; 1、创建nginx配置文件default.conf server {listen 80;server_name localhost; # 修改为docker服务宿主机的iplocation / {root /usr/share/nginx/html;index index.html ind…

服务器端请求伪造(SSRF)

概念 SSRF(Server-Side Request Forgery&#xff0c;服务器端请求伪造) 是一种由攻击者构造形成的由服务端发起请求的一个安全漏洞。一般情况下&#xff0c;SSRF是要攻击目标网站的内部系统。&#xff08;因为内部系统无法从外网访问&#xff0c;所以要把目标网站当做中间人来…

盼望许久的百度熊终于收到了

文|洪生鹏 我怀着激动的心情&#xff0c;终于收到了百度熊礼品。 在我想象中&#xff0c;这只熊应该很大&#xff0c;能够填满我的怀抱。 但当我打开礼盒的那一刻&#xff0c;我有些惊讶。 它居然这么小&#xff0c;与我预期的相差甚远。 不过&#xff0c;当我们仔细一看&#…

大厂数仓专家实战分享:企业级埋点管理与应用

一.什么是埋点 埋点&#xff08;Event Tracking&#xff09;&#xff0c;是互联网数据采集工作中的一个俗称&#xff0c;正式应该叫事件跟踪&#xff0c;英文为 Event Tracking&#xff0c;它主要是针对特定用户行为或事件进行捕获、处理和发送的相关技术及其实施过程。 二.埋…

中国互联网格局改变的重点,在于真正走向海外,打破美国垄断

媒体报道指字节跳动上半年的营收达到540亿美元&#xff0c;超过了其他互联网企业&#xff0c;这是国内互联网行业格局发生重大变化的证明&#xff0c;那么是什么原因导致了这一格局的改变呢&#xff1f; 中国互联网的发展也有20多年了&#xff0c;这20多年涌现了一大批互联网企…

文件夹改名:批量随机重命名文件夹,让整理更轻松

在日常生活和工作中&#xff0c;文件夹重命名是一件非常常见的事情。有时候&#xff0c;可能需要批量处理文件夹&#xff0c;为其加上统一的名称&#xff0c;或者按照某种特定的规则来重命名。然而&#xff0c;当我们手动进行这些操作时&#xff0c;会消耗大量的时间和精力。这…

Redis:Java客户端

前言 "在当今大数据和高并发的应用场景下&#xff0c;对于数据缓存和高效访问的需求日益增长。而Redis作为一款高性能的内存数据库&#xff0c;以其快速的读写能力和丰富的数据结构成为众多应用的首选。与此同时&#xff0c;Java作为广泛应用于企业级开发的编程语言&…

三极管-开关电路-电路电子-嵌入式开发-物联网开发-电子元件

一、概述 本文我们主要讲解电子电路中十分重要的元件--三极管。三极管常常被用来当作开关或作为放大电流的作用&#xff0c;下面我们将主要围绕着其作为开关电路的使用来介绍三极管。 二、分类 学习三极管前&#xff0c;我们必须认识三极管的三级&#xff0c;包含箭头的一端为发…

【论文阅读笔记】Deep learning for time series classification: a review

【论文阅读笔记】Deep learning for time series classification: a review 摘要 在这篇文章中&#xff0c;作者通过对TSC的最新DNN架构进行实证研究&#xff0c;探讨了深度学习算法在TSC中的当前最新性能。文章提供了对DNNs在TSC的统一分类体系下在各种时间序列领域中的最成功…

(1)(1.17) Maxbotix 模拟声纳

文章目录 前言 1 连接到Pixhawk 2 通过Mission Planner进行设置 3 测试传感器 4 参数说明 前言 XL-Maxbotix-EZ 系列模拟声纳&#xff08;XL-MaxSonar-EZ0、EZ4 和 EZL0&#xff09;是相对便宜的短距离&#xff08;7m 至 10m&#xff09;测距仪&#xff0c;主要设计用于室…