Python作用域概述

238 阅读4分钟

1. 什么是作用域

作用域定义了在程序的某一部分可以访问的变量和对象的范围。Python通过作用域来解决命名冲突问题,并确保程序中不同区域的代码能够正确引用所需的变量。

Python有不同类型的作用域,主要体现在变量的查找路径上。Python的作用域遵循一个叫做LEGB规则的查找顺序:

  • L(Local) :局部作用域,即当前函数或方法内部的作用域。
  • E(Enclosing) :闭包作用域,指的是包含当前函数的外部函数作用域。
  • G(Global) :全局作用域,指的是当前模块的作用域。
  • B(Built-in) :内建作用域,指的是Python解释器内置的命名空间。

当你引用一个变量时,Python会从内到外按此顺序查找,直到找到该变量或引发NameError异常。

2. Python中的四种作用域

2.1 局部作用域(Local Scope)

局部作用域是指变量在函数内部的作用范围。当你在函数内部定义一个变量时,它只在该函数内部可见,外部代码无法访问。这个作用域的存在确保了不同函数中的同名变量互不干扰。

def my_function():
    x = 10  # 局部变量
    print(x)

my_function()
# print(x)  # 会抛出NameError,因为x在函数外部不可见

在上述代码中,变量x仅在my_function()函数内部可见。

2.2 闭包作用域(Enclosing Scope)

闭包作用域指的是包含当前函数的外部函数的作用域。如果一个函数被另一个函数包围,那么被包围的函数可以访问外部函数的变量。这种变量也称为自由变量。

def outer():
    x = 10  # 外部函数中的变量
    def inner():
        print(x)  # 内部函数可以访问外部函数的变量
    inner()

outer()

在这段代码中,inner()函数可以访问outer()函数中的x,这就是闭包作用域的特性。

2.3 全局作用域(Global Scope)

全局作用域是指在模块级别定义的变量或函数。全局变量可以在整个模块中访问,除非在局部作用域中使用global关键字进行声明,否则局部作用域不能修改全局变量。

x = 10  # 全局变量

def my_function():
    print(x)  # 可以访问全局变量

my_function()

在上面的代码中,x是一个全局变量,可以在my_function()函数内被访问和使用。

2.4 内建作用域(Built-in Scope)

内建作用域是Python解释器为每个程序运行时自动提供的命名空间。它包含了Python的内置函数、异常、对象类型等内容,如print(), len(), range()等。

print(len("Hello"))  # len 是内建函数

内建作用域是所有作用域中最外层的,任何时候你都可以访问内建命名空间中的对象。

3. LEGB查找规则

Python根据LEGB规则查找变量。当你在程序中引用一个变量时,Python将按照以下顺序查找:

  1. Local:首先查找局部作用域中的变量。
  2. Enclosing:如果局部作用域没有找到,查找封闭函数中的变量。
  3. Global:如果都没有找到,查找全局作用域中的变量。
  4. Built-in:如果在全局作用域中仍未找到,最后查找内建作用域。

示例:

x = 5  # 全局变量

def outer():
    x = 10  # 外部函数中的变量
    def inner():
        x = 15  # 局部变量
        print(x)  # 打印的是局部变量x

    inner()

outer()

在这个例子中,inner()函数打印的是局部变量x的值(15),而不是外部函数或全局作用域中的x。这说明Python遵循LEGB规则从局部作用域开始查找变量。

4. globalnonlocal关键字

Python提供了globalnonlocal关键字,用于修改变量的作用域。

  • global:用于声明一个全局变量,这样你可以在函数内部修改全局变量的值。

    x = 5
    
    def modify_global():
        global x
        x = 10
    
    modify_global()
    print(x)  # 输出 10
    
  • nonlocal:用于在嵌套函数中声明一个变量是来自于外部函数的作用域,从而修改外部函数中的变量。

    def outer():
        x = 5
        
        def inner():
            nonlocal x
            x = 10
            
        inner()
        print(x)  # 输出 10
    
    outer()