Python 闭包和nonlocal声明

news2024/11/17 9:30:15

闭包是针对嵌套函数环境的概念,它的作用是延伸函数的作用域。简单来说,闭包就是一个函数,但它可以保存着上层函数作用域中的变量,使得这些变量可以在函数中使用。而nonlocal声明的作用就是允许函数重新绑定局部作用域以外且非全局作用域当中的变量。

目录

  • 一、变量作用域
    • 1.1 局部变量
    • 1.2 全局变量
  • 二、闭包的概念
  • 三、nonlocal声明

一、变量作用域

Python中的变量根据作用域可以分为全局变量和局部变量,而变量在代码中赋值的位置决定了其作用域。

1.1 局部变量

默认情况下,在函数中被赋值的对象,是这个函数的局部变量,且仅在函数运行期间存在,当函数返回时,变量就消失了。

示例:变量b是全局变量,变量a是函数f的局部变量,函数f(1)运行输出1(局部变量a)和2(全局变量b)。函数运行完a就消失了,再次输入a会告诉你变量未定义:

b = 2
def f(a):
    print(a)    # 打印局部变量a
    print(b)    # 没有局部变量b,向上搜索,找到全局变量b
f(1)

在这里插入图片描述

1.2 全局变量

上面的例子,我们在print(b)语句之后增加1个赋值语句b=3,其他保持不变,再次运行。print(a)成功打印出1,但print(b)出错,提示本地变量b未赋值。这里出错的原因就是后面新增了b=3赋值语句,赋值操作导致在编译时将b转换成了局部变量(变量在代码中赋值的位置决定了其作用域)。

b = 2
def f(a):
    print(a)    # 打印局部变量a
    print(b)    # 运行报错,提示b未赋值
    b = 3      # 赋值语句将b变为局部变量
f(1)

在这里插入图片描述

如果要使用全局变量b,需要用global关键字进行声明。global b意味引用全局变量中的b:

b = 2
def f(a):
    global b    # 声明引用全局变量b
    print(a)   
    print(b)    # 打印全局变量b
    b = 3      # 将全局变量赋值为3
f(1)
b

在这里插入图片描述

二、闭包的概念

闭包是针对嵌套函数环境的概念,它的作用是延伸函数的作用域。简单来说,闭包就是一个函数,但它可以保存着上层函数作用域中的变量,使得这些变量可以在函数中使用。

我们通过一个示例来演示,现在定义一个函数,计算所有累计输入数字的平均值,函数avger中定义一个变量numbers,嵌套函数clac向这个变量内累加值后并求平均值:

def avger():
    numbers = []
    def calc(n):
        numbers.append(n)
        return sum(numbers)/len(numbers)
    return calc

avg = avger()
avg(1)    # 1/1
avg(2)    # (1+2)/2
avg(3)    # (1+2+3)/3 每次函数调用都会在历史计算结果上累加

在这里插入图片描述

仔细思考一下,上面代码中,numbers是函数avger()的本地变量而不是calc的本地变量,在函数avg = avger()调用后就消失了,我们可以尝试调用一下numbers,可以发现其未定义,但为什么avg可以一直使用?

numbers    # 未定义,因为在avger()函数返回后就消失了
avg(4)    # (1+2+3+4)/4 依然可以使用numbers变量

在这里插入图片描述

这里的概念就是闭包,闭包指延伸了作用域的函数,它包含了不在函数体内的非全局变量,这种变量叫自由变量。即它(calc)能访问定义体之外定义的非全局变量(numbers),用一个示意图解释如下:

  • 橙色方框是calc本地作用域
  • 绿色方框是闭包,相当于延伸了作用域的calc函数
  • 红色是全局作用域
    在这里插入图片描述

三、nonlocal声明

我们把上面的例子再修改一下,用数字count, total分别记录数量和总和,累加后求平均数。但换了变量后发现闭包失效了,count无法引用:

def avger():
    count = 0
    total = 0
    def calc(n):
        count += 1
        total += n
        return total/count
    return calc
avg = avger()
avg(1)    # 报错,变量count未赋值

在这里插入图片描述

出错的原因就出在count的数据类型上。count是数字,而python中数字类型是不可以变的。count +=1 实际上是count = count+1,python隐式创建了一个新对象然后赋值给了count,而不是原地改变。正是这个赋值操作将count变成了本地变量(和上面1.2全局变量演示的错误原因相同)。

这时就轮到nonlocal声明了,它的作用是将变量标记为自由变量,即使重新赋值也不会影响。下面将count, total用nonlocal声明后,代码即可顺利运行:

def avger():
    count = 0
    total = 0
    def calc(n):
        nonlocal count, total
        count += 1
        total += n
        return total/count
    return calc
avg = avger()
avg(1)
avg(2)

在这里插入图片描述

以上即是Python中闭包和nonlocal的概念,其经常用在变量共享及函数装饰器场景。

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

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

相关文章

3、鸿蒙学习-在AGC创建HarmonyOS 项目或应用

项目和应用介绍 关于项目 项目是资源、应用的组织实体。资源包括服务器、数据库、存储,以及您的应用、终端用户的数据等。在您使用部分服务时,您是数据的控制者,数据将按照您设置的数据处理位置来存储在指定区域。 通常,您不需…

paraview处理openfoam对称模型

paraview处理openfoam对称模型 步骤如下: 导入对称模型,以openfoam中xx\tutorials\incompressible\SRFSimpleFoam\mixer中的搅拌器为例;使用ctrl+space,查找transform,在Filters中也能找到;经过三次transform,可以移动旋转出对称的其他3部分;经过此三次移动旋转,并不能…

电路基础笔记——电路的等效变换

线性电阻的等效 线性电阻串联:RR1R2 分压公式:Uk(Rk/R)*U 线性电阻并联:1/R1/R11/R2 GG1G2 分流公式:Ik(Gk/G)*I 独立电源的等效 电压源与电压源串联 UsUs1Us2 电压源与电压源并联 U…

Maven简单入门

Maven 一:什么是Maven: Maven是一个项目管理工具,用于构建和管理Java项目。它可以帮助开发人员自动化构建过程,管理项目依赖关系,并协助项目的发布和部署。通过Maven,开发人员可以定义项目的结构、依赖关…

kakfa模拟仿真篇之spark-submit在linux运行 (更贴近真实场景)

源码在上篇 地址在这 :Kafka模拟器产生数据仿真-集成StructuredStreaming做到”毫秒“级实时响应StreamData落地到mysql-CSDN博客 这里分享一下一些新朋友不知道spark-submit 指令后 的参数怎么写 看这篇绝对包会 声明: 此项目是基于 maven 打包的说明…

VBA技术资料MF129:批量删除及重命名文件夹

我给VBA的定义:VBA是个人小型自动化处理的有效工具。利用好了,可以大大提高自己的工作效率,而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套,分为初级、中级、高级三大部分,教程是对VBA的系统讲解&#…

柚见第十期(后端队伍接口详细设计)

创建队伍 用户可以 创建 一个队伍,设置队伍的人数、队伍名称(标题)、描述、超时时间 P0 队长、剩余的人数 聊天? 公开 或 private 或加密 信息流中不展示已过期的队伍 请求参数是否为空?是否登录,未登录不…

Apache Doris 2.1.0 版本发布:开箱盲测性能大幅优化,复杂查询性能提升 100%

亲爱的社区小伙伴们,我们很高兴地向大家宣布,在 3 月 8 日我们引来了 Apache Doris 2.1.0 版本的正式发布,欢迎大家下载使用。 在查询性能方面, 2.1 系列版本我们着重提升了开箱盲测性能,力争不做调优的情况下取得较好…

【黑马程序员】Python文件、异常、模块、包

文章目录 文件操作文件编码什么是编码为什么要使用编码 文件的读取openmodel常用的三种基础访问模式读操作相关方法 文件的写入注意代码示例 异常定义异常捕获捕获指定异常捕获多个异常捕获所有异常异常else异常finally 异常的传递 python 模块定义模块的导入import模块名from …

Linux - 安装 nacos(详细教程)

目录 一、简介二、安装前准备三、下载与安装四、基本配置五、单机模式 一、简介 官网:https://nacos.io/ GitHub:https://github.com/alibaba/nacos Nacos 是阿里巴巴推出的一个新开源项目,它主要是一个更易于构建云原生应用的动态服务发现…

单目测距+姿态识别+yolov8界面+车辆行人跟踪计数

yolov5单目测距速度测量目标跟踪(算法介绍和代码) 1.单目测距实现方法 在目标检测的基础上,我们可以通过计算物体在图像中的像素大小来估计其距离。具体方法是,首先确定某个物体的实际尺寸,然后根据该物体在图像中的像…

CVE-2022-1310:RegExp[@@replace] missing write barrier lead a UAF

文章目录 环境搭建漏洞分析漏洞利用漏洞触发链RCE原语构造 总结参考 环境搭建 嗯,这里不知道是不是环境搭建的有问题,笔者最后成功的实现了任意地址读写,但是任意读写的存在限制,任意写 wasm 的 RWX 区域时会直接报错&#xff0c…

安卓通过termux部署ChatGLM

一、安装Termux并进行相关配置 1、安装termux Termux 是一个 Android 终端仿真应用程序,用于在 Android 手机上搭建一个完整的 Linux 环境。 不需要 root 权限 Termux 就可以正常运行。Termux 基本实现 Linux 下的许多基本操作。可以使用 Termux 安装 python&…

【Python数据结构与判断7/7】数据结构小结

目录 序言 整体回忆 定义方式 访问元素 访问单个元素 访问多个与元素 修改元素 添加元素 列表里添加元素 字典里添加元素 删除元素 in运算符 实战案例 总结 序言 今天将对前面学过的三种数据结构:元组(tuple)、列表(…

什么是制作视频内容?如何搞好视频内容制作?

写在前面 视频内容已成为希望吸引数字观众的企业、品牌和创作者的必备资产。事实上,根据NogenTech的一份报告,在2023年,91%的营销部门使用了这种动态内容。 视频内容创作和优化性能的技巧和窍门的增加绝非巧合。TikTok以及Instagram Reels和…

天地图全国幼儿园数据下载与处理分析

概述 在看天地图服务资源的时候看到有个“幼儿园”的数据,好奇点开看了下,下载下来数据差看了下,数据质量还不错。本篇文章给大家分享一下这个数据的处理以及一些简单的统计分析结果。 数据下载 通过地址https://service.tianditu.gov.cn/…

谷歌网络营销要做什么?

想做谷歌网络营销,广告是不能跳过的一环,花钱买广告位是最最实在的方法了,别人一搜相关的东西,你的产品或者服务就能跳出来,这样感兴趣的用户就会点进去,可以说是最实用的方法,唯一需要考虑的毫…

嵌入式常用5种通信协议

简介: 嵌入式常用五种通信协议为:UART、RS232、RS485、IIC、SPI。 由于这几种通信协议十分相似又有区别,所以分组记忆,红色的为一组,蓝色的为一组。 ①组都有两条线,且都是异步通信没得时钟线&#xff0c…

RuoYi开源项目1-下载并实现运行RuoYi项目

下载并实现运行RuoYi项目 环境需要下载项目项目配置后端项目配置前端项目配置 启动后前端登录页面截图 环境需要 JDK > 8MySQL >5.7Maven > 3.0Node > 12Redis > 3 下图是我的环境配置 下载项目 若依官网 1.进入官网,下载版本如下图RuoYi-Vue前后…

【pyautogui】PyAutoGUI 的简单使用

文章目录 1 简介2 通用功能2.1 暂停/休眠/耗时2.2 自动防故障功能 3 鼠标控制3.1 移动鼠标3.2 获取鼠标指针位置3.3 点击鼠标3.4 拖动鼠标3.5 滚动鼠标3.6 常用方法 4 键盘控制4.1 输入字符串 write4.2 按键操作 press4.3 按下 & 释放4.4 组合键 hotkey4.5 键名 5 屏幕图像…