在 Python 中,作用域决定了变量的“可见范围”和生命周期。Python 遵循一套非常经典的变量查找规则,也就是常说的**LEGB 规则**。
当 Python 遇到一个变量名时,它会按照L → E → G → B的顺序,从内到外依次查找。只要在其中某一层找到了,就会立刻停止查找。
我们可以把这四个层级想象成一个公司的权限管理:
L (Local) 局部作用域:相当于你个人的办公桌抽屉,里面的东西只有你自己能用。
E (Enclosing) 嵌套作用域:相当于你所在的项目组办公室,组里的文件组员都能看,但别的组(外层函数外部)看不到。
G (Global) 全局作用域:相当于公司的公共公告栏,全公司(整个代码文件/模块)的人都能看到。
B (Built-in) 内置作用域:相当于国家法律法规,在任何公司、任何地方都默认生效。
L - Local(局部作用域)
这是最内层的作用域。在函数(或 lambda 表达式)内部定义的变量,就属于局部作用域。它们只能在当前函数内部被访问,函数一旦执行完毕,这些变量就会被销毁。
def my_func(): local_var = "我是局部变量" #L print(local_var)my_func() # 输出: 我是局部变量# print(local_var) # 报错!出了这个函数,没人认识它
E - Enclosing(嵌套/闭包作用域)
这种情况出现在嵌套函数中。如果在一个函数(外层函数)内部又定义了另一个函数(内层函数),那么外层函数的局部变量,对于内层函数来说,就是 Enclosing 作用域。
def outer(): enclosing_var = "我是嵌套变量" # E def inner(): print(enclosing_var) # 内层函数可以直接读取外层函数的变量 inner()outer() # 输出: 我是嵌套变量
G - Global(全局作用域)
在 Python 脚本文件的最外层(也就是任何函数、类之外)定义的变量,属于全局作用域。它们在整个模块(文件)内都可以被访问。
global_var = "我是全局变量" # Gdef my_func(): print(global_var) # 函数内部可以直接读取全局变量my_func() # 输出: 我是全局变量print(global_var) # 输出: 我是全局变量
B - Built-in(内置作用域)
这是最外层的作用域,由 Python 解释器预先定义好。比如我们常用的print、len、int、list等内置函数和异常,它们在任何地方都能直接使用。
# len 就是内置作用域的变量print(len([1, 2, 3])) # 输出: 3
关键字:global
如果你在函数内部直接对一个全局变量进行赋值(比如count = 10),Python 会默认你是在创建一个新的局部变量,而不是修改外面的全局变量。
count = 0def add(): # 这里如果不加 global,Python 会认为你要创建局部变量 count # 但由于下面做了 += 操作,会引发 UnboundLocalError 报错 global count count += 1add()print(count) # 输出: 1 (成功修改了全局变量)
关键字: nonlocal
同理,如果在内层函数中想修改外层函数(Enclosing)的变量,必须使用nonlocal关键字声明。
def outer(): num = 10 def inner(): nonlocal num # 声明我要修改的是外层的 num,而不是新建局部变量 num = 20 inner() print(num) # 输出: 20outer()
总结
理解了这套规则,你就能轻松应对 Python 中绝大多数的变量作用域问题了。