变量作用域

在 Python 中有作用域的概念,但不是所有变量都是全局变量。Python 的作用域规则与其他语言有些不同,特别是关于块级作用域的处理。让我详细解释一下:

Python 的作用域层次(LEGB 规则)

  1. L - Local(局部作用域)

    • 在函数内部定义的变量
    • 只在函数内部可见
  2. E - Enclosing(闭包作用域)

    • 嵌套函数中的外层函数作用域
    • 适用于闭包情况
  3. G - Global(全局作用域)

    • 在模块级别(文件顶层)定义的变量
    • 整个文件可见
  4. B - Built-in(内置作用域)

    • Python 内置函数和变量(如 print, len

关键区别:没有块级作用域

Python 没有像 C/C++/Java 那样的块级作用域(block scope)。这意味着:

1
2
3
4
if True:
x = 10 # 这不是块级局部变量!

print(x) # 输出 10 - 完全合法

同样适用于:

1
2
3
4
5
6
7
for i in range(5):
pass
print(i) # 输出 4 - 仍然存在

with open('file.txt') as f:
data = f.read()
print(data) # 可以访问 - 如前例

与全局变量的区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 模块顶层 - 全局作用域
global_var = "我是全局的"

def my_function():
# 函数内部 - 局部作用域
local_var = "我是局部的"

if True:
# 不是新作用域!仍是函数局部作用域
inner_var = "我也是局部的"

print(local_var) # 正常
print(inner_var) # 正常

print(global_var) # 正常
# print(local_var) # 报错:未定义
# print(inner_var) # 报错:未定义

为什么人们会误解?

  1. 函数创建新作用域

    1
    2
    3
    def func():
    y = 20
    print(y) # 报错!y 只存在于函数作用域内
  2. 类创建新作用域

    1
    2
    3
    4
    class MyClass:
    z = 30
    print(MyClass.z) # 正确(通过类访问)
    # print(z) # 报错!z 不是全局变量
  3. 赋值会改变作用域

    1
    2
    3
    4
    x = 10
    def func():
    print(x) # 访问全局 x
    x = 20 # 这会将 x 变为局部变量!

作用域陷阱:globalnonlocal

1
2
3
4
5
6
7
8
9
10
11
12
count = 0

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

def outer():
counter = 0
def inner():
nonlocal counter # 声明使用闭包变量
counter += 1
return inner

总结表格

代码结构 是否创建新作用域 示例
模块(文件) ? 全局作用域 global_var = 1
函数定义 ? 局部作用域 def f(): local = 2
类定义 ? 类作用域 class C: cls_var = 3
if/for/while/with ? 不创建新作用域 if True: var = 4(仍在当前作用域)
列表推导式 ? Python 3+ 有独立作用域 [x for x in range(5)]x 未定义

所以回到你的原始问题:在 with 块中定义的变量能在外部使用,正是因为 Python 没有块级作用域,但不等于所有变量都是全局变量。变量的作用域取决于它被定义的位置(函数内、类内、模块内),而不是它所在的代码块类型。


变量作用域
https://mingzaitown.github.io/2025/10/29/python/Python基本语法/变量作用域/
作者
MingZai
发布于
2025年10月30日
许可协议