📄 一句话概括
变量不是全楼通用:函数里出生的局部变量出了门就消失,写在文件顶层的全局变量全楼可见——作用域就是一个变量的【有效半径】,半径越小越好管。
📝 本节和前面几节的关系
4-4~4-5 一直在函数里过日子,这一篇讲函数【围墙内外】的差别。回收 4-5 的【函数内换房号不影响外面】——那正是作用域隔离的日常表现。
一、两个世界:全局与局部
campus = "总部" # 全局变量:写在文件顶层,全楼可见
def show():
room = "301" # 局部变量:出生在函数内,出门即消失
print(campus, room) # 全局能读
show() # 总部 301
print(campus) # 总部
print(room) # NameError!room 已经不存在了
规则一句话:函数内出生的只在函数内有效;全局的谁都能读。 Python 查变量按【局部 → 全局 → 内置】逐层往外找(LEGB 的简化版),就近优先。
二、函数内能读全局,但赋值=造局部
这是作用域的头号陷阱:
count = 0
def bump():
print(count) # 能读:0
count = count + 1 # SyntaxError/UnboundLocalError!
# 赋值让 Python 把 count 判为局部,可它还没出生就要读自己
bump()
赋值语句让名字变成局部——count = count + 1 右边的 count 于是指向【还没出生的局部变量】。要真改全局必须声明 global count——但这是本节最后才推荐的招。局部优先:函数里有个 name = "x",全局的 name 就被遮住——函数内看到的一定是自己的。
三、为什么【少用全局变量】
全局变量像全楼公告栏:任何人都能改、改完所有人受影响——【谁改的】【什么时候改的】无从查起。真实理由三条:
- 改一处牵全身:函数 A 改了全局值,函数 B 悄悄跟着错——bug 隔空传播;
- 没法单测:函数行为依赖外部状态,调用两次结果都可能不同;
- 并发炸弹:多线程同时改一个全局值,数据说坏就坏(服务器课程的内容)。
正解=参数进、返回值出(4-4 的机器论):数据走【投料口】和【出料口】,不抄近道翻墙。
四、动手 Demo:遮蔽与改墙外
level = "全局"
def shadow():
level = "局部" # 遮蔽:函数内 level 是自己的
print("函数内:", level)
shadow()
print("函数外:", level) # 全局没被碰
counter = 0
def bump():
global counter # 声明后才能真改全局
counter += 1
bump(); bump()
print("counter =", counter) # 2
看到什么算成功:函数内: 局部、函数外: 全局、counter = 2。
读结果:第一对演示遮蔽——函数内的赋值造了一个同名局部,墙外的安然无恙;后面演示 global 声明——能改,但每写一处 global 都该问自己:这数据该不该当参数传?
五、30 秒实验
跑上面第一段【UnboundLocalError】版代码——报错信息写着 local variable referenced before assignment。30 秒记住:函数内的赋值=造局部,哪怕那行看起来像在改全局。
六、常见误区
- 【全局变量在任何地方都能直接改】——Python 里错。函数内直接赋值造的是局部;改全局必须 global 声明(读倒是随便读)。
- 【局部变量会用完内存所以要常驻】——错。局部变量随函数调用出生、返回即回收(3-16 调用栈弹栈),这恰恰是它省心之处;全局才是常驻内存的。
- 【用 global 很方便,多用无妨】——反了。global 是【这函数依赖并修改外部状态】的自首书;能用参数和返回值解决的,一律翻墙之外走正门。
自测三问(点开对答案)
1. **函数内 name = "x" 对全局的 name 有什么影响?** 答:没有影响——赋值造了同名的局部变量(遮蔽),全局的安然无恙。 2. **为什么函数内 count = count + 1 会报错(当 count 是全局时)?** 答:赋值让 Python 把 count 判定为局部,右边却在读这个【还没出生】的局部变量——UnboundLocalError。 3. **少用全局变量的三个理由?** 答:改一处牵全身(bug 隔空传播)、无法单测(行为依赖外部状态)、并发不安全——正解是参数进返回值出。- ☐ 下一节(4-7 递归、尾递归)
相关笔记
- 函数 —— 围墙是谁砌的
- C++ 6.4 · 变量作用域 —— C 家族的作用域规则
- 值传递与引用传递 —— 换房号不影响外面的作用域原理
- ⌨️ 编程原理 · 索引 —— 全课路线图