变量的作用域决定了哪些代码块可以使用这个该变量名称。
四层变量作用域
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) 跨域变量在声明后,才能够被修改