深入解析Python变量作用域与LEGB查找规则

Dylan
Dylan
发布时间:2026-10-14| 5人浏览过
原创

本文深入解析Python变量作用域机制,详细阐述LEGB(Local, Enclosing, Global, Built-in)查找规则。通过代码示例说明局部、嵌套、全局及内置作用域的区别,重点讲解Global与Nonlocal关键字在修改外部变量时的具体用法及常见报错原因,帮助开发者避免NameError并优化代码结构。

Python变量作用域的基本特点

特点

Python采用静态作用域机制,这意味着变量名的有效访问范围由其在源代码中的定义位置决定。需要注意的是,并非所有代码块都会创建新的作用域;只有当变量定义在模块(Module)、类(Class)或函数(def)内部时,才会形成特定的作用域边界。

1. 函数内部的变量,函数外部不能访问


def func():
  variable = 100 
  print(variable) 
print(variable) # name 'variable' is not defined

2. 函数上层的变量(标量)只能读取,不能再次定义或初始化


def counter1():
  n = 0
  def compute():
    n = n + 1 # n为标量(数值,字符串,浮点数),Python程序会因为“如果内部函数有引用外部函数的同名变量或者全局变量,并且对这个变量有修改.那么python会认为它是一个局部变量,又因为函数中没有n的定义和赋值,所以报错
    # y = n + 1 # 更改为y就没事
    # return y
    return n
  return compute

variable = 300
def test_scopt():
  print(variable) # 此时调用局部变量variable并有没绑定到一个内存对象(没有定义和初始化,即没有赋值)。本质上还是遵循的LEGB法则
  variable = 200 #因为这里,前面调用过一次,所以variable就变为了局部变量
  # print(variable) # 写在下面就没问题,因为variable是新的局部变量,而不是重新被定义,却没有绑定
test_scopt()

Python模块代码在执行前不经过预编译,但模块内的函数体在运行前会进行预编译。因此,无论变量绑定发生在作用域的哪个位置,编译器都能识别其存在。尽管Python属于静态作用域语言,但变量名的解析是动态进行的,作用域相关的问题通常在程序运行时才会暴露。

3. list、dict等复合变量内部的值都可以引用并更改


def counter():
  n = [0]
  def compute():
    n[0] += 1 # 更改的是n里面的第一个值,不是更改n
    return n[0]
  return compute

func = counter()
func() # 1
func() # 2
func() # 3

4. 使用global声明全局变量。若需在局部作用域中修改全局变量,必须先在局部作用域内通过global关键字声明该变量。


def counter1():
  n = 0
  def compute():
    global n # 如果在局部要对全局变量修改,需要在局部也要先声明该全局变量,但此处也会报错,因为没有全局变量n
    n += 1
    return n
  return compute


# right
def counter1():
  global n
  n = 0
  def compute():
    global n
    n += 1
    return n
  return compute

5. nonlocal关键字用于在函数或其他嵌套作用域中引用并修改外层(非全局)变量。


def make_counter():
  count = 0
  def counter():
    nonlocal count # 使用外层非全局变量
    count += 1
    return count
  return counter

Python中的四种作用域类型

作用域的类型

在Python中,使用变量前无需显式声明,但在使用前必须将其绑定到具体的内存对象(即完成定义或赋值)。这种绑定操作会在当前作用域引入新变量,并屏蔽外层作用域中同名的变量。

L (Local) 局部作用域

局部变量是指在def关键字定义的函数块内部定义的变量。每次调用函数时,都会创建一个新的局部作用域。Python支持递归,即函数调用自身,每次递归调用都会生成一个新的局部命名空间。除非特别声明为全局变量,否则函数内的变量默认均为局部变量。若需在函数内部定义全局变量,可使用global关键字。局部作用域类似于栈结构,具有临时性,仅当创建该作用域的函数处于活动状态时才存在。因此,建议尽量减少全局变量的使用,因为它们在整个模块运行期间占用内存空间。 注意:若需在函数内部对全局变量赋值,必须通过global语句声明该变量为全局变量。

E (Enclosing) 嵌套作用域

E作用域同样包含在def关键字定义的函数中。E与L是相对概念,对于更上层的函数而言,E也是L。与L的区别在于,对于某个函数,L是定义在该函数内部的局部作用域,而E是定义在该函数上一层父级函数的局部作用域。E作用域主要是为了实现Python的闭包功能而设计的。

G (Global) 全局作用域

全局作用域指在模块层次中定义的变量,每个模块本身就是一个全局作用域。也就是说,在模块文件顶层声明的变量具有全局作用域。从外部视角看,模块的全局变量表现为该模块对象的属性。 注意:全局作用域的范围仅限于单个模块文件内。

B (Built-in) 内置作用域

内置作用域包含系统固定模块中定义的变量,例如预定义在builtins模块内的变量。

LEGB变量查找法则与示例

作用域链:变量名解析LEGB法则

变量名搜索的优先级顺序为:局部作用域 > 嵌套作用域 > 全局作用域 > 内置作用域。 LEGB法则规定:当在函数中使用未确定的变量名时,Python会按优先级依次搜索这四个作用域,以确定变量名的含义。首先搜索局部作用域(L),接着是上一层嵌套结构中def或lambda函数的嵌套作用域(E),然后是全局作用域(G),最后是内置作用域(B)。遵循此查找原则,一旦在第一个匹配的作用域中找到变量即停止搜索。若未找到任何匹配项,则触发NameError错误。

example 1


name = "lzl"

def f1():
  print(name)

def f2():
  name = "eric"
  f1()
  
f2() # 在函数未执行之前,作用域链就已经形成了,此时f1()的上一级应该name = 'lzl'

example 2


def scope_test():
  def do_local():
    spam = "local spam" # 此函数定义了另外的一个spam字符串变量,并且生命周期只在此函数内。此处的spam和外层的spam是两个变量,如果写出spam = spam + “local spam” 会报错
  def do_nonlocal():
    nonlocal spam  # 使用外层的spam变量 test spam
    spam = "nonlocal spam"
  def do_global():
    global spam
    spam = "global spam"
  spam = "test spam"
  do_local()
  print("After local assignmanent:", spam) # test spam
  do_nonlocal()
  print("After nonlocal assignment:",spam) # nonlocal spam
  do_global()
  print("After global assignment:",spam) # nonlocal spam ???? 先找是本地变量,找到的本地变量已经在do_nonlocal()里面改变了所以输出的是nonlocal spam

scope_test()
print("In global scope:",spam) # global spam

以上就是深入了解Python变量作用域的详细内容,更多关于Python变量作用域的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。