Python 中的作用域(Scope)是什么?
什么是作用域?
在 Python 中,作用域(Scope) 指的是:
变量在哪些地方可以使用,哪些地方不能使用。
你可以把作用域理解成变量的"活动范围"。
举个生活中的例子:
假设你在自己房间放了一本书。
- 你在房间里可以找到它。
- 客厅里找不到它。
- 如果把书放在客厅,那么家里所有人都能看到。
变量也是一样:
- 有些变量只能在函数里面使用。
- 有些变量整个程序都可以使用。
- Python 会按照一定顺序寻找变量。
Python 查找变量的规则 —— LEGB
Python 查找变量时,不是随便找,而是按照固定顺序:
| 顺序 | 名称 | 英文 | 作用范围 |
|---|---|---|---|
| ① | Local | 局部作用域 | 当前函数内部 |
| ② | Enclosing | 封闭作用域 | 外层函数 |
| ③ | Global | 全局作用域 | 当前 Python 文件 |
| ④ | Built-in | 内置作用域 | Python 自带内容 |
记住一句口诀:
L → E → G → B
Python 永远都是按照这个顺序寻找变量。
一、Local(局部作用域)
局部作用域就是:
函数里面定义的变量。
这种变量只能在函数里面使用。
例如:
def my_func():
my_var = 10
print(my_var)
my_func()
输出:
10
因为:
my_func()
│
├── my_var = 10
└── print(my_var)
变量只存在于这个函数里。
函数外面不能访问局部变量
例如:
def my_func():
my_var = 10
print(my_var)
运行结果:
NameError
为什么?
因为:
my_var
│
└── 只存在 my_func() 内
函数结束以后:
my_func()
结束
↓
my_var 消失
所以外面找不到。
小结
局部变量:
✅ 函数里面可以访问
❌ 函数外面不能访问
二、Enclosing(封闭作用域)
封闭作用域只会出现在:
函数里面还有函数(嵌套函数)
例如:
def outer():
msg = "Hello"
def inner():
print(msg)
inner()
outer()
输出:
Hello
结构如下:
outer()
│
├── msg
│
└── inner()
│
└── 可以访问 msg
因为:
inner 找不到自己的 msg
↓
去外层找
↓
找到 msg
↓
成功打印
外层不能访问内层变量
例如:
def outer():
def inner():
res = "Python"
print(res)
outer()
结果:
NameError
原因:
outer
│
├── inner
│ │
│ └── res
│
└── print(res)
res 在 inner 里面。
outer 无法访问。
规则:
外层可以被内层访问,
但内层变量不能反过来被外层访问。
修改封闭作用域变量 —— nonlocal
例如:
def outer():
count = 0
def inner():
nonlocal count
count = 1
inner()
print(count)
outer()
输出:
1
为什么?
默认情况下:
count = 1
Python 会认为:
这是 inner 自己的新变量。
加上:
nonlocal count
表示:
我要修改外层那个 count。
nonlocal 的作用
作用:
修改上一层函数中的变量。
记住:
Local
↓
Enclosing(nonlocal 修改这里)
↓
Global
三、Global(全局作用域)
全局变量就是:
在所有函数外面定义的变量。
例如:
score = 100
def show():
print(score)
show()
输出:
100
结构:
Global
score =100
↓
所有函数都能看到
函数可以读取全局变量
例如:
name = "Tom"
def hello():
print(name)
hello()
输出:
Tom
因为:
函数里面没有 name。
Python:
Local 没有
↓
Enclosing 没有
↓
Global 找到了。
修改全局变量 —— global
例如:
count = 10
def change():
global count
count = 20
change()
print(count)
输出:
20
如果没有:
global count
Python 会认为:
count =20
只是创建了一个新的局部变量。
不会修改全局变量。
global 还能创建新的全局变量
例如:
def create():
global age
age = 18
create()
print(age)
输出:
18
函数结束以后:
age 依然存在。
global 和 nonlocal 的区别
| 关键字 | 修改谁? |
|---|---|
| global | 全局变量 |
| nonlocal | 外层函数变量 |
例如:
Global
│
├── outer()
│ │
│ ├── x
│ │
│ └── inner()
global
↓
修改 Global
----------------
nonlocal
↓
修改 outer() 的 x
四、Built-in(内置作用域)
最后一层就是:
Python 自带的名字。
例如:
print()
len()
type()
str()
int()
float()
range()
这些都是 Python 已经写好的。
例如:
print(type(3))
输出:
<class 'int'>
这里:
type
↓
Python 内置函数
我们不用自己写。
Python 查找变量全过程
来看一个例子:
name = "Global"
def outer():
name = "Outer"
def inner():
name = "Inner"
print(name)
inner()
outer()
输出:
Inner
查找过程:
print(name)
↓
Local
找到 "Inner"
↓
停止寻找
不会继续找。
如果改成:
name = "Global"
def outer():
name = "Outer"
def inner():
print(name)
inner()
outer()
输出:
Outer
查找过程:
Local
没有
↓
Enclosing
找到
↓
停止
如果继续:
name = "Global"
def outer():
def inner():
print(name)
inner()
outer()
输出:
Global
查找:
Local
↓
Enclosing
↓
Global
找到
最后:
print(len("Hello"))
查找:
Local
↓
Enclosing
↓
Global
↓
Built-in
找到 len()
LEGB 查找流程图
开始查找变量
│
▼
Local(当前函数)
│
│ 找到?
├──────► 是:停止
│
▼ 否
Enclosing(外层函数)
│
│ 找到?
├──────► 是:停止
│
▼ 否
Global(当前文件)
│
│ 找到?
├──────► 是:停止
│
▼ 否
Built-in(Python内置)
│
│ 找到?
├──────► 是:停止
│
▼ 否
NameError
常见错误
① 在函数外访问局部变量
def test():
x = 10
print(x)
结果:
NameError
② 忘记 global
count = 1
def test():
count = 2
test()
print(count)
输出:
1
这里只创建了新的局部变量。
③ 忘记 nonlocal
def outer():
x = 10
def inner():
x = 20
inner()
print(x)
outer()
输出:
10
因为:
inner 创建的是自己的 x。
没有修改外层。
本章总结
| 概念 | 作用 |
|---|---|
| Local | 当前函数内部变量 |
| Enclosing | 外层函数变量 |
| Global | 全局变量,整个文件都能访问 |
| Built-in | Python 自带函数、关键字等 |
| global | 修改或创建全局变量 |
| nonlocal | 修改外层函数变量 |
| LEGB | Python 查找变量的固定顺序 |
| NameError | 找不到变量时出现的错误 |
记住一句话:Python 查找变量永远遵循 LEGB:Local → Enclosing → Global → Built-in。