ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python中的作用域、global与nonlocal

2022-02-10 22:01:15  阅读:191  来源: 互联网

标签:作用域 global nonlocal Python len print def


以下,以Python 3来介绍作用域相关的内容。

python 作用域分类

Python有四类作用域(Scope)。

  1. 局部(Local)作用域)
  2. 封闭(Enclosing)作用域(例如函数内部)
  3. 全局(Global)作用域
  4. 内置(Built-in)作用域

LEGB规则

在作用域中按名称去寻找对象(Python中一切皆对象)时,会按照LEGB规则去查找。 如果发生重名,也会按照LEGB规则,谁先被找到就用谁。

所谓LEGB规则,很简单,就是作用域查找顺序为:

Local -> Enclosing -> Global -> Built-in

以下,用示例代码来解释LEGB作用域,及其规则。

len = len([])       # (1)

def a():
    len = 1         # (2)

    def b():
        len = 2     # (3)
        print(len)  # (4)

    b()

a()

len原本是Python的一个内置函数,在以上代码中被重新定义了三次。
在(1)中,右边的len([]),就是内置的len函数。 而左边的len =,则是新定义的全局变量,值为0。
在(2)中,又重新定义了len = 1。 这里是函数a的本地作用域,而对嵌套的函数b来说,则是Enclosing作用域。
在(3)中,再次重新定义了len = 2。 这是函数b的本地作用域。
在(4)中,打印len时,遵循LEGB规则,会打印Local的2。 如果没有(3),会打印Enclosing,也就是函数a里的1。 如果没有(2),会打印Global里的0。 如果没有(1),会打印< built-in function len >。

Python没有块级作用域(与其它语言不同点)

Python里是没有块级作用域(Block scope)的。以下述代码为例:

for i in range(10):
    pass

print(i)

以上代码会打印出9。
这里是一个比较糟糕的设计。 如果有块级作用域,那么在for块结束后,就不应该能访问i。 而现在,会得到i的最后一个值。
更糟糕的是,如果range()里是0,那么for循环会直接退出。 这时再print(i),结果就是:

NameError: name ‘i’ is not defined

所以,虽然Python没有块级作用域,但是建议就当它有。 不要在代码块以外,使用代码块内定义的东西。

关键词global

前面只是谈及跨作用域的读取,还没谈及跨作用域的写入。

i = 0

def a():
    i = 1
    print('local:', i)

a()
print('global:', i)

以上代码的输出结果为:

local: 1
global: 0

也就是说,a函数里的i = 1,是定义一个新的局部变量,而非对全局变量的修改。
如果需要对全局变量i进行修改,则需要使用Python的global关键字。代码修改如下:

i = 0

def a():
    global i
    i = 1
    print('local:', i)

a()
print('global:', i)

以上代码输出结果为:

local: 1
global: 1

关键词nonlocal

修改Global变量的问题,可以用global关键字来解决; 修改Enclosing变量的问题,就需要使用nonlocal关键字。

i = 0

def a():
    i = 1

    def b():
        nonlocal i
        i = 2

    b()
    print(i)

a()

以上代码的输出结果为2,这就是nonlocal的功效。
nonlocal不能代替global。 如果在上述代码的函数a中,就只能使用global。 因为,外层就是Global作用域了。
在多重嵌套中,nonlocal只会上溯一层; 而如果上一层没有,则会继续上溯。

def a():
    i = 1
    def b():
        # i = 2
        def c():
            nonlocal i
            i = 3

        c()
        print('b:', i)

    b()
    print('a:', i)

a()

以上代码输出结果:

b: 3
a: 3

因为函数b中没有i,所以nonlocal上溯到了函数a中。
(注意:如果a中也没有,就回到了Global作用域,nonlocal会报错。)
如果以上代码中,函数b里的注释# i = 2去掉,则输出变为:

b: 3
a: 1

因为nonlocal只会上溯一层,到函数b,所以函数a中的i没有被修改。

标签:作用域,global,nonlocal,Python,len,print,def
来源: https://blog.csdn.net/m0_64204369/article/details/122869913

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有