Python3 命名空间与作用域

名字(变量名)与对象的对应关系存放在"命名空间"里:函数内、模块内、内置各有各的 空间。Python 按 LEGB 规则逐层查找名字,理解它才能读懂变量遮蔽与 global/nonlocal。

什么是命名空间

命名空间是"名字 → 对象"的映射表,主要分三类:

  • 局部命名空间:函数/类内部定义的名字。
  • 全局命名空间:模块顶层定义的名字。
  • 内置命名空间:print、len 等内置函数所在的空间。

LEGB 查找顺序

引用名字时按 局部(Local) → 外层(Enclosing) → 全局(Global) → 内置(Built-in) 顺序查找:

x = 10                      # 全局命名空间

def show():
    x = 99                  # 局部命名空间
    print(x)                # 输出:99(局部优先)

show()
print(x)                    # 输出:10(全局未被修改)

局部变量遮蔽全局

函数内赋值只会创建新的局部变量,不会改动同名全局变量:

count = 0

def add_one():
    count = 1               # 新的局部变量,遮蔽全局
    return count

print(add_one())            # 输出:1
print(count)                # 输出:0(全局没变)

global:修改全局变量

想在函数内修改全局变量,必须先声明 global:

count = 0

def add_one():
    global count            # 声明操作的是全局 count
    count += 1

add_one()
add_one()
print(count)                # 输出:2

nonlocal:修改外层函数变量

内层函数要修改外层函数的局部变量,用 nonlocal:

def outer():
    num = 0

    def inner():
        nonlocal num        # 指向 outer 里的 num
        num += 1
        return num

    return inner            # 返回内层函数(闭包)

f = outer()
print(f())                  # 输出:1
print(f())                  # 输出:2

各作用域综合示例

x = "global"                # 全局

def outer():
    x = "enclosing"         # 外层(Enclosing)

    def inner():
        x = "local"         # 局部(Local)
        print(x)            # 输出:local

    inner()
    print(x)                # 输出:enclosing

outer()
print(x)                    # 输出:global

小结:名字查找遵循 LEGB(局部→外层→全局→内置);只读外层名字不必声明,要修改 全局变量用 global,修改嵌套外层变量用 nonlocal。

笔记加载中…