← 返回首页

Python 中变量的作用域?

在 Python 中,变量的作用域决定了程序在哪些代码块中可以访问或修改该变量。Python 的作用域规则通常被称为 LEGB 规则,它定义了变量查找的优先级顺序:

1. LEGB 规则详解

  • L (Local) 局部作用域: 当前函数内部。函数调用时创建,函数返回时销毁。局部变量仅在函数内部有效。
  • E (Enclosing) 嵌套作用域(闭包): 外层嵌套函数的作用域。它既不是全局的,也不是最内层的局部作用域。内部函数可以读取外层函数的变量,但如果要修改,需要使用 nonlocal 关键字。
  • G (Global) 全局作用域: 当前 Python 模块(文件)的顶层作用域。在函数外部定义的变量属于全局作用域。在函数内部如果要修改全局变量,必须使用 global 关键字。
  • B (Built-in) 内置作用域: Python 解释器内置的作用域,包含了所有的内置关键字和函数(如 len(), print(), int 等)。它的优先级最低,只有在前面三个作用域都找不到变量时才会查找这里。

2. 变量的“读”与“写”行为差异

Python 对变量的读取和赋值有不同的处理逻辑:

  • 读取变量时:解释器会严格按照 L -> E -> G -> B 的顺序向外层逐级查找,找到即停止。
  • 赋值/修改变量时:解释器默认认为你在当前作用域(通常是 Local)创建或修改一个新的局部变量。如果你想修改外层作用域的变量,必须显式声明。

3. 核心关键字:global 与 nonlocal

  • global:用于在函数内部声明某个变量指向全局作用域中的变量。

    count = 10
    def update():
        global count  # 声明要修改全局变量
        count = 20
    update()
    print(count)  # 输出 20
    
  • nonlocal:用于在嵌套函数中声明某个变量指向外层(Enclosing)作用域的变量。

    def outer():
        num = 10
        def inner():
            nonlocal num  # 声明要修改外层函数的变量
            num = 20
        inner()
        print(num)  # 输出 20
    outer()
    

4. 常见陷阱:UnboundLocalError

如果在函数内部对一个变量进行赋值,但没有声明 global 或 nonlocal,Python 会将其视为局部变量。如果在这个赋值语句之前尝试读取该变量,就会报错:

x = 10
def test():
    print(x)  # 报错:UnboundLocalError: local variable 'x' referenced before assignment
    x = 20    # 因为这一行,Python 在编译时就把 x 当成了局部变量
test()

总结:理解 Python 作用域的关键在于掌握 LEGB 查找顺序,以及在需要跨作用域修改变量时,正确使用 global 和 nonlocal 关键字。