Python基础知识:什么是非局部语句?
admin
2023-07-31 00:39:46
0

有同学曾在微信中问小编什么是非局部语句(nonlocal statement),本文就是对此的回答,希望没有发的太晚。
非局部语句是Python 3.x中新引入的特性,可以让你给外层但非全局作用域中的变量赋值。官方文档中的说法是,非局部语句可以让所列的标识符(identifier)指向最近的嵌套作用域(enclosing scope)中已经绑定过的变量,全局变量除外。

如果没有非局部语句

一般来说,嵌套函数对于其外层作用域中的变量是有访问权限的。

123456789101112 >>> def outside():        msg = \”Outside!\”         def inside():            print(msg)         inside()        print(msg) >>> outside()Outside!Outside!

我们在outside函数中声明了msg变量,并赋值为“Outside!”。然后,在inside函数中打印msg的值。结果证明,inside成功获得了外层作用域中msg的值。

但是如果我们想给外层作用域中的变量赋值时,是不是按照平常的赋值操作就可以修改它的值呢?

1234567891011 >>> def outside():        msg = \”Outside!\”        def inside():            msg = \”Inside!\”            print(msg)        inside()        print(msg) >>> outside()Inside! # inside函数打印的msgOutside! # outside函数打印的msg

inside函数中,我们想给msg变量赋值为”Inside!”。运行outside时,inside函数中msg的值为”Inside!”,但是在outside函数中却保留了原先的值!

之所以出现这个情况,是因为在inside函数中,Python实际上并没有为之前已经创建的msg变量赋值,而是在inside函数的局部作用域(local scope)中创建了一个名叫msg的新变量,但是这样就和外层作用域(outer scope)中的变量重名了。

这说明,嵌套函数对外层作用域中的变量其实只有只读访问权限。如果我们在这个示例中的inside函数的顶部再加一个print(msg)语句,那么就会出现UnboundLocalError: local variable \'msg\' referenced before assignment这个错误。

非局部语句的引入,就是要尽量减少这种变量名冲突情况的出现,同时也让嵌套函数更加方便的操作外层函数中的变量。更加详细的原因,请看参考资料部分的PEP-3104。

使用非局部语句之后

接下来,我们引入nonlocal语句。

123456789101112 >>> def outside():        msg = \”Outside!\”        def inside():            nonlocal msg            msg = \”Inside!\”            print(msg)        inside()        print(msg) >>> outside()Inside!Inside!

现在,我们在inside函数的顶部添加了nonlocal msg语句。这个语句的作用,就是告诉Python解释器在碰到为msg赋值的语句时,应该向外层作用域的变量赋值,而不是声明一个重名的新变量。这样,两个函数的打印结果就一致了。

nonlocal的用法和global非常类似,只是前者针对的是外层函数作用域的变量,后者针对的则是全局作用域的变量。

什么时候该使用非局部语句

有时候,你可能会疑惑什么时候才应该使用nonlocal。以下面的函数为例:

1234567891011 >>> def outside():        d = {\”outside\”: 1}        def inside():            d[\”inside\”] = 2            print(d)        inside()        print(d) >>> outside(){\’inside\’: 2, \’outside\’: 1}{\’inside\’: 2, \’outside\’: 1}

你可能会想,因为没有使用nonlocalinside函数中往字典d中插入的\"inside\": 2键值对(key-value pair)不会体现在outside函数中。你这么想挺合理,但却是错的。因为字典插入并不是赋值操作,而是方法调用(method call)。事实上,往字典中插入一个键值对相当于调用字典对象中的__setitem__方法。

1234 >>> d = {}>>> d.__setitem__(\”inside\”, 2)>>> d{\’inside\’: 2}

所以,这个示例中我们可以不使用nonlocal,就能直接操作外层作用域中的变量。

小结

其实在许多Python程序中,很少用到非局部语句。但是,有了这种语句之后,我们就可以减少不同作用域之间变量名的冲突。非局部语句,也让我们更加容易地访问、操作外层作用域中的变量。不过,这在一定程度上也让语法变得更加复杂。

有关变量、语句等术语的基础知识,还可以参考《Think Python 2e》的第二章:量、表达式和语句。

参考资料

  1. Simple Statements
  2. PEP-3104
  3. Global-Nonlocal
  4. PyTips


相关内容

热门资讯

500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
python绘图库Matplo... 本文简单介绍了Python绘图库Matplotlib的安装,简介如下: matplotlib是pyt...
Prometheus+Graf... 一,Prometheus概述 1,什么是Prometheus?Prometheus是最初在Sound...