python
一、什么是作用域
在Python中,作用域是一个命名空间,其中的变量名被映射到了它们的对象。Python的作用域可以分为四种:局部作用域(Local)、封闭作用域(Enclosing)、全局作用域(Global)和内建作用域(Built-in)。
-
全局作用域:全局作用域是在模块级别定义的。在一个Python文件(模块)的顶层定义的变量和函数都位于全局作用域。全局作用域在整个模块中都是可见的。
-
局部作用域:局部作用域是在函数内部定义的。每当我们调用一个函数,就会创建一个新的局部作用域。局部作用域只在当前函数内部可见。
-
封闭作用域:封闭作用域是在嵌套函数中定义的。如果一个函数被另一个函数包围,那么外部函数的命名空间就会成为内部函数的封闭作用域。
-
内建作用域:内建作用域是Python内置的命名空间,包含了如
list、dict等内置函数和异常。
全局变量在整个模块中都是可见的,可以被任何函数访问和修改(除非函数内部定义了同名的局部变量,或使用了global关键字)。但是,全局变量的改变不会影响到局部变量,因为局部变量只在其所在的函数内部可见。
二、举个例子理解
下面是一个官方的例子:
下例演示了如何引用不同作用域和名称空间,以及 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)
# =====>>>>>输出
# After local assignment: test spam
# After nonlocal assignment: nonlocal spam
# After global assignment: nonlocal spam
# In global scope: global spam
注意,局部 赋值(这是默认状态)不会改变 scope_test 对 spam 的绑定。 nonlocal 赋值会改变 scope_test 对 spam 的绑定,而 global 赋值会改变模块层级的绑定。
而且,global 赋值前没有 spam 的绑定。
三、帮助理解(重点):
这段代码演示了Python中变量作用域的概念,包括局部作用域、非局部作用域和全局作用域。
在这个例子中,spam变量在scope_test函数内部被定义,所以它的初始作用域是scope_test函数的局部作用域。
do_local函数试图修改spam,但是因为spam是在do_local函数内部被赋值的,所以这个赋值操作只会影响do_local函数的局部作用域,不会影响spam在scope_test函数中的值。
do_nonlocal函数使用了nonlocal关键字,这意味着它的赋值操作会影响到最近的外层作用域,也就是scope_test函数的局部作用域,所以这个赋值操作会修改scope_test函数中的spam。
do_global函数使用了global关键字,这意味着它的赋值操作会影响到全局作用域,所以这个赋值操作会创建一个全局变量spam。
最后,当我们在全局作用域中打印spam时,我们看到的是do_global函数赋予的值,因为这个值被赋予到了全局变量spam。
这个例子展示了Python中的作用域规则,以及nonlocal和global关键字如何改变变量的作用域。
四、总结
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会按照以下的顺序在不同的作用域中查找这个变量:
-
局部作用域(Local):首先,Python会在当前函数的局部作用域中查找变量。
-
封闭作用域(Enclosing):如果在局部作用域中找不到,Python会在任何封闭函数的作用域中查找,从内到外。
-
全局作用域(Global):如果在封闭作用域中也找不到,Python会在全局作用域中查找。
-
内建作用域(Built-in):如果在全局作用域中还是找不到,Python会在内建作用域中查找。
如果在所有的作用域中都找不到这个变量,Python会抛出一个NameError异常。
这就是Python中的LEGB规则,
即Local -> Enclosing -> Global -> Built-in。
这个规则定义了Python在查找变量时的优先级。
需要注意的是,如果我们在函数内部给一个变量赋值,而这个变量在全局作用域中也存在,那么这个赋值操作会创建一个新的局部变量,而不是修改全局变量。如果我们想在函数内部修改全局变量,我们需要使用global关键字。(上面的例子有说明)
本文详细解释了Python中的作用域概念,包括局部、全局、封闭和内建作用域,通过实例说明了变量在不同作用域下的行为,以及global和nonlocal关键字的作用。重点介绍了LEGB规则,即查找变量时的优先级顺序。
1101

被折叠的 条评论
为什么被折叠?



