Python变量查找遵循LEGB规则:Local→Enclosing→Global→Built-in;Local变量在函数内赋值即屏蔽同名全局变量,未赋值前引用报UnboundLocalError;Enclosing变量需nonlocal才能修改;Global变量需global声明才可修改;覆盖内置名应避免。

Python变量查找遵循LEGB规则:Local(局部)→ Enclosing(嵌套)→ Global(全局)→ Built-in(内置)。理解它,就能准确预判变量从哪来、为何报错、怎么改。
Local:函数内部定义的变量最优先
在函数体内用=赋值的变量默认为局部变量,哪怕同名全局变量存在,也会被屏蔽。
- 未赋值前就引用会报UnboundLocalError(不是NameError),因为Python已将该名标记为局部变量
- 想在函数内修改全局变量,必须显式声明global 变量名
- 想读取外层函数变量但不修改,可直接访问;若要修改,需用nonlocal
Enclosing:嵌套函数中“外层函数的局部”即闭包变量
当一个函数定义在另一个函数内部,外层函数的局部变量对内层函数来说就是Enclosing作用域。这类变量若被内层函数引用且未重新赋值,会自动形成闭包。
- 闭包变量生命周期延长——外层函数执行完,只要内层函数还存在,这些变量就保留在内存中
- 用nonlocal可让内层函数修改Enclosing变量;不加则只能读,不能写
- 常见误用:循环中创建多个闭包却共用同一个Enclosing变量,导致所有闭包行为一致(可用默认参数或functools.partial解决)
Global与Built-in:名字冲突时的后备路径
找不到Local和Enclosing变量时,Python依次查模块级(global)和内置命名空间(如len、print)。但要注意:
立即学习“Python免费学习笔记(深入)”;
- 在模块顶层赋值(如x = 10)即为global变量;函数内同名赋值默认是local,除非声明global
- 覆盖内置名(如list = [1,2])会导致后续无法使用原内置函数,应避免
- 可用dir(__builtins__)查看所有内置名,调试时globals()和locals()能快速定位当前作用域内容
实战判断技巧:三步定位变量来源
遇到NameError或值不对,按顺序问自己:
- 这个变量在当前函数里有没有赋过值?有 → 是Local,检查是否提前读取
- 没赋值但在外层函数里定义了?→ 看是否需要nonlocal,或确认是否意外覆盖
- 都没找到,查模块顶部有没有global定义?再查是不是拼错了内置名(比如把max写成maax)
不复杂但容易忽略










