Python 中的 4 种作用域

Python 的作用域遵循 LEGB 规则 ,即:L → E → G → B(由内向外查找)。

一、四种作用域

作用域 英文 说明 示例
Local 局部作用域 函数内部定义的变量 def func(): x = 1
Enclosing 闭包/嵌套作用域 外层嵌套函数的变量 嵌套函数中访问外层函数的变量
Global 全局作用域 模块顶层定义的变量 脚本中 x = 1
Built-in 内置作用域 Python 内置的名称 print()、len()、range()

二、详细说明

1. Local(局部作用域)

函数内部定义的变量,只能在函数内部访问。

复制代码
def my_func():
    x = 10  # 局部变量
    print(x)  #  可以访问

my_func()
# print(x)  #  NameError: name 'x' is not defined

特点:

  • 函数调用时创建,函数返回时销毁

  • 不同函数的局部变量互不干扰

    def func_a():
    x = 10
    return x

    def func_b():
    x = 20 # 与 func_a 的 x 不同,互不影响
    return x

    print(func_a()) # 10
    print(func_b()) # 20

2. Enclosing(闭包/嵌套作用域)

在嵌套函数中,内层函数可以访问外层函数的变量。

复制代码
def outer():
    x = 10  # enclosing 变量
    
    def inner():
        print(x)  #  可以访问外层变量
    
    inner()

outer()  # 10
修改 enclosing 变量
复制代码
def outer():
    x = 10
    
    def inner():
        nonlocal x  # 声明要修改外层变量
        x = 20
    
    inner()
    print(x)  # 20

outer()

3. Global(全局作用域)

在模块顶层定义的变量,可以在整个模块中访问。

复制代码
x = 10  # 全局变量

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

my_func()  # 10
修改全局变量
复制代码
x = 10

def my_func():
    global x  # 声明要修改全局变量
    x = 20

my_func()
print(x)  # 20
模块级别的全局变量
复制代码
# file: config.py
MAX_SIZE = 100
DATABASE_URL = "sqlite:///db.sqlite"

# file: main.py
import config
print(config.MAX_SIZE)  # 100

4. Built-in(内置作用域)

Python 预定义的名称,在任何地方都可以直接使用。

复制代码
# 内置函数
print("Hello")
len([1, 2, 3])
range(5)

# 内置异常
ValueError
TypeError

# 内置常量
True
False
None
查看所有内置名称
复制代码
print(dir(__builtins__))
# ['ArithmeticError', 'AssertionError', 'BaseException', ...]

三、作用域规则

1. 变量查找顺序(LEGB)

复制代码
x = "global"  # Global

def outer():
    x = "enclosing"  # Enclosing
    
    def inner():
        x = "local"  # Local
        print(x)     # 输出: local(先找到 Local)
    
    inner()

outer()  # local

2. 逐级查找过程

复制代码
x = "global"

def outer():
    x = "enclosing"
    
    def inner():
        # 1. 先查 Local → 没有 x
        # 2. 再查 Enclosing → 有 x = "enclosing"
        # 3. 不会继续往上查
        print(x)  # 输出: enclosing
    
    inner()

outer()

3. 不同作用域同名变量的遮蔽

复制代码
x = "global"      # Global

def outer():
    x = "enclosing"   # Enclosing(遮蔽 Global)
    
    def inner():
        x = "local"   # Local(遮蔽 Enclosing)
        print(x)
    
    inner()
    print(x)  # enclosing

outer()
print(x)  # global

四、作用域相关关键字

1. global 关键字

用于在函数内部修改全局变量。

复制代码
count = 0

def increment():
    global count  # 声明 count 是全局变量
    count += 1

increment()
print(count)  # 1

2. nonlocal 关键字

用于在嵌套函数中修改外层函数的变量。

复制代码
def outer():
    x = 10
    
    def inner():
        nonlocal x  # 声明 x 是外层变量
        x = 20
    
    inner()
    print(x)  # 20

outer()

3. 常见错误:忘记声明

复制代码
x = 10

def func():
    # 错误!这会在局部作用域创建新变量,不会修改全局变量
    x = 20  # 这是局部变量,不是修改全局

func()
print(x)  # 10(全局变量未被修改)

x = 10

def func():
    global x  # 正确
    x = 20

func()
print(x)  # 20

五、作用域与数据类型

1. 可变对象的修改不需要 global

复制代码
my_list = [1, 2, 3]

def append_item():
    # 修改列表内容,不需要 global
    my_list.append(4)

append_item()
print(my_list)  # [1, 2, 3, 4]

# 但如果要重新赋值,就需要 global
def reassign():
    global my_list
    my_list = [5, 6, 7]  # 重新赋值

2. 不可变对象必须用 global

复制代码
count = 0

def increment():
    global count
    count += 1  # 整数是不可变对象,需要重新赋值

六、注意事项

1. 条件语句不创建作用域

复制代码
if True:
    x = 10  # 即使缩进,x 还是在全局作用域

print(x)  # 10(不是错误!)

for i in range(5):
    pass

print(i)  # 4(循环变量会泄露到外层)

七、对比表

作用域 位置 访问方式 修改关键字
Local 函数内部 直接访问 -
Enclosing 外层嵌套函数 直接访问(读) nonlocal(写)
Global 模块顶层 直接访问(读) global(写)
Built-in Python 内置 直接访问 不能修改

查找顺序:

LEGB:Local → Enclosing → Global → Built-in

修改规则:

读变量,按 LEGB 找;写变量,默认只在 Local 改。

想改外层用 nonlocal,想改全局用 global。

核心点:

  1. Python 使用 静态作用域(词法作用域)

  2. 变量赋值默认在当前作用域创建/修改

  3. 访问变量按 LEGB 顺序查找

  4. global 和 nonlocal 用于修改外层变量

  5. 循环、条件语句不创建新作用域

相关推荐
I Am a robert girl2 小时前
稀有事件估计的迭代去对齐:从源码视角拆解重要性采样新范式
开发语言·python·机器学习·重要性采样·蒙特卡洛方法·稀有事件估计
天若有情6732 小时前
开源|Comfort Lang v1.0.1,一款主打清爽交互的新型命令式编程语言
python·开源·交互·编程语言·项目分享·repl·comfort lang
打工仔折腾 AI2 小时前
System Prompt 替代 Few-shot:用规则约束大模型输出的省钱实践
java·人工智能·python·spring·langchain·prompt·ai agent 实战
打工仔折腾 AI2 小时前
从零写一个CAD 05:以鼠标为中心的滚轮缩放,招法能复用但顺序不能反
开发语言·后端·python·性能优化·计算机外设·swift·ai agent 实战
for_ever_love__3 小时前
控制流——if、for、while 与可迭代对象
python·大模型开发·循环·控制流
for_ever_love__3 小时前
PyTorch 张量与 autograd——自动求导怎么工作
pytorch·python·深度学习·自动求导
小小张说故事3 小时前
Python 里 `is` 和 `==` 到底差在哪?5 个让你怀疑人生的案例 + 对照表
python
XLYcmy4 小时前
PDF 论文处理器 — 改进方向与建议文档
python·pdf·llm·agent·dify·rag·harness
青柠之夏cc4 小时前
前端拖拽功能原生实现,不引入拖拽库完成业务
开发语言·前端·python
曾晓森4 小时前
OpenAI 兼容 API 接入山猫云:先核对分组和价格,再发最小请求
网络·python