Python变量作用域全解析:从局部到全局,彻底掌握LEGB规则

📅 2026/6/30 3:05:39
Python变量作用域全解析:从局部到全局,彻底掌握LEGB规则
Python 变量作用域详解Python 3.x变量作用域是指变量可被访问的代码范围。与 Java 等语言不同Python 的变量作用域规则更灵活尤其在全局变量和局部变量的区分上有特殊机制。本文将详细解析 Python 中变量的作用域类型、访问规则及修改全局变量的方法。作用域的基本类型Python 中变量的作用域分为以下四种按访问优先级从高到低排列局部作用域Local在函数内部定义的变量仅在函数内有效。嵌套作用域Enclosing在嵌套函数外层的函数中定义的变量适用于闭包场景。全局作用域Global在模块.py 文件顶层定义的变量整个模块内可访问。内置作用域Built-inPython 内置的变量或函数如print、len。查找顺序L → E → G → B由内向外局部变量Local在函数内部定义的变量默认为局部变量仅在函数执行期间存在函数外部无法访问。示例局部变量的特性# 全局变量 xx50deffunction_local(x_param):# 函数内部的 x 是局部变量参数也是局部变量print(f函数内初始 x参数{x_param})x_local2# 局部变量print(f函数内修改后局部 x{x_local})# 调用函数function_local(x)# 函数外部无法访问局部变量print(f函数外全局 x{x})# 输出50不受函数内局部变量影响# print(x_local) # 报错NameError: name x_local is not defined输出结果函数内初始 x参数50 函数内修改后局部 x2 函数外全局 x50结论函数参数如x_param也是局部变量。函数内部定义的变量如x_local仅在函数内有效。局部变量与全局变量同名时函数内优先使用局部变量。全局变量Global在模块顶层定义的变量为全局变量可在模块内的任何函数外访问。若要在函数内修改全局变量需用global关键字声明。访问全局变量无需声明函数内可直接访问全局变量无需global声明# 全局变量greetingHellodefprint_greeting():# 直接访问全局变量print(greeting)print_greeting()# 输出Hello修改全局变量需用global声明若在函数内直接修改全局变量Python 会将其视为局部变量创建新的局部变量而非修改全局变量。如需修改必须用global声明# 全局变量count0defincrement():# 声明使用全局变量 count而非创建局部变量globalcount count1# 修改全局变量print(f函数内 count{count})increment()# 输出函数内 count1print(f函数外 count{count})# 输出函数外 count1全局变量已被修改如果不声明globalcount0defincrement_error():count1# 报错UnboundLocalErrorPython 认为 count 是局部变量但未初始化increment_error()global关键字的作用告诉 Python“该变量是全局变量不要创建局部变量”。global声明必须放在变量使用之前。nameAlicedefchange_name():globalname# 声明在使用前nameBob# 修改全局变量change_name()print(name)# 输出Bob嵌套作用域Enclosing当函数嵌套时内层函数可访问外层函数的变量非全局这种作用域称为嵌套作用域。若要修改外层函数的变量需用nonlocal关键字Python 3 新增。示例嵌套函数与nonlocaldefouter():# 外层函数的变量嵌套作用域messageHello from outerdefinner():# 声明使用外层函数的 message非局部非全局nonlocalmessage messageHello from inner# 修改外层变量print(f内层函数{message})inner()print(f外层函数{message})# 输出修改后的值outer()输出结果内层函数Hello from inner 外层函数Hello from inner说明若不用nonlocal内层函数的message会被视为局部变量。nonlocal仅用于嵌套作用域不可用于全局变量。闭包Closure当内层函数返回并被外部使用时外层函数的变量会被“记住”这就是闭包。defmake_multiplier(n):创建一个乘以 n 的函数defmultiplier(x):returnx*n# n 来自外层函数returnmultiplier# 创建两个不同的闭包doublemake_multiplier(2)triplemake_multiplier(3)print(double(5))# 10print(triple(5))# 15print(triple(10))# 30# 查看闭包捕获的变量print(double.__closure__[0].cell_contents)# 2内置作用域Built-inPython 内置的名称Python 预定义了一些内置函数和异常它们位于builtins模块中。# 常用内置函数print(len([1,2,3]))# 3print(max(10,20,30))# 30print(type(42))# class int# 查看所有内置名称# import builtins# print(dir(builtins))内置作用域被遮蔽的问题如果不小心定义了与内置函数同名的变量会“遮蔽”内置函数。# ⚠️ 严重问题遮蔽了内置的 len 函数len100# 创建了全局变量 lendefget_length(items):returnlen(items)# ❌ TypeError: int object is not callable# 恢复删除自己定义的 lendellenprint(len([1,2,3]))# 3恢复最佳实践避免使用内置名称作为变量名如len、list、dict、str、type等作用域查找规则LEGB 原则当访问一个变量时Python 按以下顺序查找LLocal当前函数内部的局部变量。EEnclosing外层函数的变量嵌套作用域。GGlobal模块顶层的全局变量。BBuilt-inPython 内置的变量或函数。若找不到变量会抛出NameError。示例LEGB 原则演示# 全局变量Gxglobaldefouter():# 嵌套作用域变量Exouterdefinner():# 局部变量Lxinnerprint(x)# 优先使用局部变量L→ 输出innerinner()print(x)# 外层变量E→ 输出outerouter()print(x)# 全局变量G→ 输出global# 访问内置函数Bprint(len([1,2,3]))# 调用内置的 len 函数 → 输出3常见问题与最佳实践避免滥用全局变量全局变量会增加函数间的耦合降低代码可读性。优先通过函数参数传递数据而非依赖全局变量。区分global和nonlocalglobal用于修改全局变量模块顶层。nonlocal用于修改嵌套作用域的变量外层函数。局部变量遮蔽Shadowing若局部变量与全局变量同名局部变量会 “遮蔽” 全局变量函数内优先使用局部。x100defshadow():x200# 局部变量遮蔽全局 xprint(x)# 输出200shadow()print(x)# 输出100全局 x 未变