python 作用域和命名空间

本文详细解释了Python中的作用域概念,包括局部、全局、封闭和内建作用域,通过实例说明了变量在不同作用域下的行为,以及global和nonlocal关键字的作用。重点介绍了LEGB规则,即查找变量时的优先级顺序。
摘要由CSDN通过智能技术生成

python



一、什么是作用域

在Python中,作用域是一个命名空间,其中的变量名被映射到了它们的对象。Python的作用域可以分为四种:局部作用域(Local)、封闭作用域(Enclosing)、全局作用域(Global)和内建作用域(Built-in)。

  1. 全局作用域:全局作用域是在模块级别定义的。在一个Python文件(模块)的顶层定义的变量和函数都位于全局作用域。全局作用域在整个模块中都是可见的。

  2. 局部作用域:局部作用域是在函数内部定义的。每当我们调用一个函数,就会创建一个新的局部作用域。局部作用域只在当前函数内部可见。

  3. 封闭作用域:封闭作用域是在嵌套函数中定义的。如果一个函数被另一个函数包围,那么外部函数的命名空间就会成为内部函数的封闭作用域。

  4. 内建作用域:内建作用域是Python内置的命名空间,包含了如listdict等内置函数和异常。

全局变量在整个模块中都是可见的,可以被任何函数访问和修改(除非函数内部定义了同名的局部变量,或使用了global关键字)。但是,全局变量的改变不会影响到局部变量,因为局部变量只在其所在的函数内部可见。

二、举个例子理解

下面是一个官方的例子:

下例演示了如何引用不同作用域和名称空间,以及 globalnonlocal 对变量绑定的影响:

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)


# =====>>>>>输出

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

注意,局部 赋值(这是默认状态)不会改变 scope_testspam 的绑定。 nonlocal 赋值会改变 scope_testspam 的绑定,而 global 赋值会改变模块层级的绑定。

而且,global 赋值前没有 spam 的绑定。

三、帮助理解(重点):

这段代码演示了Python中变量作用域的概念,包括局部作用域、非局部作用域和全局作用域。

在这个例子中,spam变量在scope_test函数内部被定义,所以它的初始作用域是scope_test函数的局部作用域。

do_local函数试图修改spam,但是因为spam是在do_local函数内部被赋值的,所以这个赋值操作只会影响do_local函数的局部作用域,不会影响spamscope_test函数中的值。

do_nonlocal函数使用了nonlocal关键字,这意味着它的赋值操作会影响到最近的外层作用域,也就是scope_test函数的局部作用域,所以这个赋值操作会修改scope_test函数中的spam

do_global函数使用了global关键字,这意味着它的赋值操作会影响到全局作用域,所以这个赋值操作会创建一个全局变量spam

最后,当我们在全局作用域中打印spam时,我们看到的是do_global函数赋予的值,因为这个值被赋予到了全局变量spam

这个例子展示了Python中的作用域规则,以及nonlocalglobal关键字如何改变变量的作用域。

四、总结

global关键字确实改变了全局作用域中的spam值,但它并不会影响到局部作用域或非局部作用域中的spam值。

当我们在do_global函数中使用global spam时,我们创建了一个全局变量spam,并将其值设置为"global spam"。但这并不会影响到scope_test函数内部(一个非全局作用域)的spam值。

所以,当我们在scope_test函数内部执行print("After global assignment:", spam)时,打印的仍然是scope_test函数内部的spam值,即"nonlocal spam",而不是全局的spam值。

然后,当我们在scope_test函数外部(全局作用域)执行print("In global scope:", spam)时,打印的就是全局变量spam的值,即"global spam"

总的来说,global关键字只会影响全局作用域中的变量,而不会影响到局部作用域或非局部作用域中的变量。

五、官方说明

https://docs.python.org/zh-cn/3/tutorial/classes.html#scopes-and-namespaces-example

六、补充-全局变量和局部变量的优先级是怎样的?

在Python中,当我们尝试访问一个变量时,Python会按照以下的顺序在不同的作用域中查找这个变量:

  1. 局部作用域(Local):首先,Python会在当前函数的局部作用域中查找变量。

  2. 封闭作用域(Enclosing):如果在局部作用域中找不到,Python会在任何封闭函数的作用域中查找,从内到外。

  3. 全局作用域(Global):如果在封闭作用域中也找不到,Python会在全局作用域中查找。

  4. 内建作用域(Built-in):如果在全局作用域中还是找不到,Python会在内建作用域中查找。

如果在所有的作用域中都找不到这个变量,Python会抛出一个NameError异常。

这就是Python中的LEGB规则,
即Local -> Enclosing -> Global -> Built-in。
这个规则定义了Python在查找变量时的优先级。

需要注意的是,如果我们在函数内部给一个变量赋值,而这个变量在全局作用域中也存在,那么这个赋值操作会创建一个新的局部变量,而不是修改全局变量。如果我们想在函数内部修改全局变量,我们需要使用global关键字。(上面的例子有说明)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吊肩三角裤

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>