一个例子带你搞懂python作用域中的global、nonlocal和local

在编程中,只要接触过函数的,我相信都理解什么是全局变量和局部变量,概念比较简单,这里就不做解释了。在python中,用global语句就能将变量定义为全局变量,但是最近又发现有个nonlocal,一时搞不太清楚,仔细琢磨之后才搞明白。

首先看看官方文档里面是怎么说的:

global 语句是作用于整个当前代码块的声明。 它意味着所列出的标识符将被解读为全局变量。

nonlocal语句会使得所列出的名称指向之前最近的包含作用域中绑定的除全局变量以外的变量。

注意划重点了,global就是全局变量,这没有问题。至于nonlocal,“之前”、”最近“和“除全局变量以外”,就是最核心的地方,接下来用一个例子说明一下。

下面的示例代码同样来自官方文档

def scope_test():def do_local():spam = "local spam"def do_nonlocal():nonlocal spamspam = "nonlocal spam"def do_global():global spamspam = "global spam"spam = "test spam"do_local()print("After local assignment:", spam)do_nonlocal()print("After nonlocal assignment:", spam)do_global()print("After global assignment:", spam)scope_test()
print("In global scope:", spam)

我们可以看到,这是定义了一个scope_test(),然后它里面又分别定义了三个函数do_local()、do_nonlocal()和do_global()。

输出的结果是什么呢?感兴趣的同学先自己琢磨琢磨,我放一张图提示一下:
在这里插入图片描述
下面正式揭晓答案了,输出结果为:(高亮忽视掉)

After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

我们观察四个print函数,首先,do_local()里面的spam是局部变量(local),这是毫无疑问的,所以它是不能改变spam的内容的,调用它之后,因为之前spam="test spam"了,所以输出为仍然为"After local assignment: test spam"。

然后,do_nonlocal()里面的 spam,因为有nonlocal进行修饰,它的作用范围,就不是局部了,那是哪里呢?正如文档中提到的,“指向之前最近的包含作用域中绑定的除全局变量以外的变量”,在调用do_nonlocal()时,哪个之前的spam离它最近呢?很明显,是spam="test spam"这一个,所以这个spam就变为了spam = "nonlocal spam",后面输出自然就是“After nonlocal assignment: nonlocal spam”。

为了加深理解,我们看看如果把spam = "test spam"搬到函数外面会怎么样。

spam = "test spam"def scope_test():def do_local():spam = "local spam"def do_nonlocal():nonlocal spamspam = "nonlocal spam"def do_global():global spamspam = "global spam"do_local()print("After local assignment:", spam)do_nonlocal()print("After nonlocal assignment:", spam)do_global()print("After global assignment:", spam)scope_test()
print("In global scope:", spam)

此时会报错:

 File "<ipython-input-1-3e4be319dd22>", line 7nonlocal spam^
SyntaxError: no binding for nonlocal 'spam' found

这就充分说明了,nonlocal是不能指向全局变量的。

接着,do_global()里面的spam,很明显就是全局变量,对它进行赋值spam = "global spam",是对全局变量赋值。那影响print("After global assignment:", spam)吗?不影响,因为这句print中的spam是最开始spam = "test spam"中的那个,它被do_nonlocal()赋值为“nonlocal spam”,注意它可不是全局变量,因为在函数scope_test()中。所以说,此spam非彼spam,一个是全局变量,另一个虽然相对于小函数来说,是非局部变量,但毕竟也是大函数的局部变量呀,所以第三个print自然为“After global assignment: nonlocal spam”。

那到了最后,就简单了,因为调用完了函数scope_test(),里面只有do_global()改变了全局变量spam = "global spam",所以自然最后输出“In global scope: global spam"。

总结来说,全局变量global其实是个绝对概念,一旦使用,就会在整个代码文件适用;而local和nonlocal,无非是相对概念,就好像我们每个人自己可能都是学生(local),活到老学到老,只不过相对其他人来说,有的人是老师(非学生nonlocal)而已。

希望这篇文章能帮助大家理解。

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

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

相关文章

初识ABP vNext(10):ABP设置管理

点击上方蓝字"小黑在哪里"关注我吧定义设置使用设置前言上一篇介绍了ABP模块化开发的基本步骤&#xff0c;完成了一个简单的文件上传功能。通常的模块都有一些自己的配置信息&#xff0c;比如上篇讲到的FileOptions类&#xff0c;其中配置了文件的上传目录&#xff0…

类加载机制(整个过程详解)

一:背景 类加载机制是在我们的真个java的运行阶段中的其中一个阶段。 二:什么是快乐星球(类加载机制) 我们编写的 Java 文件都是以.java 为后缀的文件&#xff0c;编译器会将我们编写的.java 的文件编译成.class 文件&#xff0c;简单来说类加载机制就是jvm从文件系统将一系…

每天一小时python官方文档学习(一)————python的简单介绍

我们都知道&#xff0c;python的官方文档写得十分详尽&#xff0c;也是每一个学习python的人都绕不开的。 所以从今天开始&#xff0c;我每天都会用一小时学习python的官方文档&#xff0c;按照文档目录的顺序&#xff0c;摘录一些有用的语句&#xff0c;写下一些个人心得放在博…

leetcode860. 柠檬水找零

一:论语 这里的小不忍指的是一方面我们受到挫折而控制不住自己而大发脾气&#xff0c;还有一方面指的是我们的过于优柔寡断&#xff0c;对于自己或者他人的过失&#xff0c;不忍心加以责罚。 二:题目 三:上码 class Solution { public:bool lemonadeChange(vector<int&g…

跟我一起学.NetCore之Asp.NetCore启动流程浅析

前言一个Asp.NetCore项目&#xff0c;知道大概的启动流程是有必要的&#xff0c;比如后续遇见配置信息覆盖等相关问题时也大概知道是什么原因&#xff0c;了解原因之后&#xff0c;再去搜索引擎找答案&#xff0c;否则目标不明确&#xff0c;茫茫人海怎么会一下找到自己想要的&…

每天一小时python官方文档学习(二)————流程控制工具

4. 其他流程控制工具 4.1. if 语句 大多数人都很熟悉的if语句&#xff1a; if condition1:pass elif condition2:pass else condition3:pass注意python中没有switch或case语句&#xff0c;所以一个 if ... elif ... elif ... 序列可以看作是其他语言中的 switch 或 case 语句…

leetcode406. 根据身高重建队列

一&#xff1a;你不一定逆风翻盘&#xff0c;但请一定向阳而生 二&#xff1a;题目 三&#xff1a;上码 class Solution { public:/**解析题意:这个给出的people的数组中,我们需要根据其元素people[i] [hi,ki];然后根据其ki来表示大于hi身高的人的个数&#xff0c;来进行排序…

.NET Core 下使用 RabbitMQ

介绍RabbitMQ是一个开源的,基于AMQP(Advanced Message Queuing Protocol)协议的完整,可复用的企业级消息队列(Message Queue 一种应用程序与应用程序之间的一种通信方法)系统,RabbitMQ可以实现点对点,发布订阅等消息处理模式官网&#xff1a;https://www.rabbitmq.com/dotnet.h…

每天一小时python官方文档学习(三)————函数

上一天看到第四章的一半&#xff0c;介绍了一些常用的流程控制工具&#xff0c;也就是常用语句&#xff0c;主要是if、for、range()、break、continue、else和pass。今天把第四章剩下的看完&#xff0c;讲的是如何在python中定义和使用函数。函数其实就是一种对代码的封装&…

leetcode452. 用最少数量的箭引爆气球

一:论语 少些自我感动&#xff0c;多谢反思&#xff0c;时刻警惕自己是否在假装很努力&#xff0c;自己懂不懂 自己会不会 自己想要什么 只有自己 最清楚 二&#xff1a;题目 三:上码 class Solution { public:/**思路:1.这道题类似无重叠空间,我们先按每个气球的右边界升序…

ASP.NET Core 3.x启动时运行异步任务(一)

这是一个大的题目&#xff0c;需要用几篇文章来说清楚。这是第一篇。一、前言在我们的项目中&#xff0c;有时候我们需要在应用程序启动前执行一些一次性的逻辑。比方说&#xff1a;验证配置的正确性、填充缓存、或者运行数据库清理/迁移等。如何合理、有效、优雅地完成这个任务…

每天一小时python官方文档学习(四)————数据结构之列表

终于进入到第五章数据结构部分了&#xff0c;python中常用的容器有列表、元组、集合和字典&#xff0c;今天主要了解的是最为常用的列表。 5. 数据结构 5.1. 列表的更多特性 对于列表的操作有很多&#xff0c;具体操作看官方文档就行&#xff0c;但是我们对列表有什么操作&a…

leetcode435. 无重叠区间

一&#xff1a;论语 道不同 不相为谋 我们没有理由拿着自己的评判标准 去看待别人所经历的事情&#xff0c;重来就没有真正的感同身受&#xff0c;我们能做的就是尊重他人的看法 &#xff0c;保留自己的态度。 二&#xff1a;题目 三:上码 class Solution { public:/**思路:…

Swagger扩展为你添油加气

关注架构师高级俱乐部开启架构之路不定期福利发放哦~Leon读完需要4分钟速读仅需 2 分钟介绍一款Swagger扩展日常接口开发中都需要用到Swagger来生成接口文档并用 Swagger 自带支持的模拟请求进行测试&#xff0c;但是需要支持认证或者上传文件等操作需要自行去按接口进行开发才…

leetcode763. 划分字母区间

一&#xff1a;论语 保留自己的态度&#xff0c;尊重别人的看法&#xff0c;不强迫别人按照自己的意愿做事。 二:题目 三:上码 class Solution { public:vector<int> partitionLabels(string s) {/**思路:1.在这里我们选取的数据结构是map容器,我们只要下记录每个字母…

每天一小时python官方文档学习(五)————数据结构之元组、集合与字典

昨天介绍完了最常用的列表&#xff0c;之后就是次常用的元组、集合与字典了。 5.3. 元组和序列 元组和之前讲过的列表有很多共同特性&#xff0c;例如索引和切片操作。实际上&#xff0c;他们是 序列 数据类型&#xff08;list, tuple, range&#xff09;中的两种。 一个元组…

跟我一起学.NetCore之依赖注入

前言现阶段而言&#xff0c;依赖注入相关组件如果不会用一两个&#xff0c;感觉在Code的世界里肯定是落伍了&#xff0c;最起码得有工厂模式的思想&#xff0c;知道这样做的好处&#xff1b;提及到依赖注入&#xff0c;通常会关联出两个概念&#xff1a;Ioc(控制反转)和DI(依赖…

每天一小时python官方文档学习(六)————循环和条件控制的进阶用法

学习完数据结构之后&#xff0c;我们就能够对之前在第二天中讲过的流程控制工具&#xff0c;添加更多的用法了&#xff0c;这里主要介绍的是for循环语句和if与while条件判断语句。 5.6. 循环的技巧 我们学过的遍历序列for i in range() 、for i in list() 和 for i in tuple(…

跟我一起学.NetCore之依赖注入作用域和对象释放

前言上一小节简单阐述了依赖注入及Asp.NetCore中自带依赖注入组件的常规用法&#xff0c;其中提到容器管控了自己创建对象的生命周期&#xff0c;包含了三种生命周期&#xff1a;Singleton、Scoped、Transient&#xff0c; 对于Singleton、Transient相对于Scoped来说比较好理解…

leetcode738. 单调递增的数字

一:芭比Q了 又掉一个粉 啊呜呜呜呜呜 如果作为一个领导者来说&#xff0c;首先就是要以身作则&#xff0c;自己都做不到 &#xff0c;那就没什么威信去要求手下人按照要求去做 二:题目 三:上码 class Solution { public:int monotoneIncreasingDigits(int n) {/**思路:1.这…