变量的作用域决定了哪些代码块可以使用这个该变量名称。

四层变量作用域

Python变量一共有4个层次的作用域:





  • 1) L(local)局部作用域,只在本代码块内有效

Ø 典型的,函数体的变量都是局部变量

  • 2) E(Enclosing)闭包作用域。

Ø 这是一种特殊的作用域,往往存在于嵌套函数的场景。

Ø 在外层函数内的一个局部变量,相对于内层函数来说,就是一个闭包变量。

Ø (这种场景较少使用,函数内再嵌套一个函数,谁会发神经这样写呢?)

  • 3) G(Global)全局作用域,模块内或导入该模块的程序都可以访问

Ø 典型的,就是在函数体外的该模块内的变量就是全局变量。

  • 4) B(Built-in)内置作用域,任何程序皆可直接访问

Ø 即Python内置函数所在模块的范围,不需要明确导入。

Ø 典型的系统属性如__name__, __sepc__等就是内置变量。


变量的四层作用域


作用域使用规则

不同作用域的变量,在使用时应该遵循如下规则:

1) 本层作用域可直接读取或修改本层定义的所有变量。

2) 下层作用域可读取上层变量,但不能修改(赋值)上层变量。实际上,在下层作用域内赋值,相当于在下层重新定义了一个名称相同的新的变量,从而覆盖了上层变量的作用域。

3) 在下一层作用域内,可以重新定义一个与上层变量名相同的变量名,且互不影响。

4) 当在不同层次有相同变量名时,在使用变量时,变量的查找顺序是由本层向高层查找。完整的顺序是:L->E->G->B,即在局部找不到,就会去局部外的局部去找,再找不到就去全局找,最后在内置模块中去找。如果都找不到,才会抛出NameError异常。



跨域修改变量

正常情况下,不能跨作用域(跨层)修改变量。其根因是,Python中变量定义语句和赋值语句是合一的,这使得变量修改有可能变成变量定义,进而使得不同作用域下的变量产生混乱。

在某些场景下,如果要跨作用域修改上层的变量,该怎么办?此时,需要使用特殊的关键字来进行变量声明(Python好奇怪,变量不需要声明即可赋值,这种情况下,却是需要声明的)。

1) 如果要修改全局变量,需要使用global关键字声明

2) 如果要修改闭包变量,需要使用nonlocal关键字声明

3) 跨域变量在声明后,才能够被修改