变量的作用域
困难1变量的作用域:理解代码中的“领地”规则
想象一下你在学校里:每个班级都有自己的黑板,老师在黑板上写的“明天春游”只有这个班的学生能看到;而学校大门口的告示板上写的通知,全校师生都能看。变量的作用域就是这个道理——每个变量都有自己能“生效”的区域,在这个区域里它能被访问,跨出这个区域就看不到它了。
为什么要关心作用域?因为程序里变量很多,如果所有变量都能在任何地方修改,那代码就会乱成一锅粥,就像全校所有班级都写在同一块黑板上的话,你根本分不清哪个通知是哪个班的。作用域帮我们管理变量的“归属权”,避免命名冲突,让代码更有条理。
一、局部变量(班级黑板)
在函数内部定义的变量,叫做局部变量。它只属于这个函数,函数外面无法访问它。
def show():
message = "函数内部的秘密" # 局部变量
print(message)
show() # 输出:函数内部的秘密
print(message) # 报错!name 'message' is not defined
为什么函数外不能访问?
因为局部变量在函数调用时才被创建,函数执行完毕后就自动销毁了。就像班级黑板上的内容,老师一擦掉,别人就看不到了。
生活中的例子:你每天有妈妈给的零花钱(比如5元),这个钱只能你自己花,你不能直接拿姐姐的零花钱。每个函数就像一个人,它有自己的局部零花钱。
二、全局变量(学校告示板)
在所有函数外面、在代码顶层定义的变量,叫做全局变量。它就像学校告示板上的内容,所有人都能看到。
1. 在函数内可以读取全局变量
函数内部可以读取(使用)全局变量的值,不需要特殊声明。
school_name = "阳光小学" # 全局变量
def show_school():
print("我所在的学校是:", school_name)
show_school() # 输出:我所在的学校是:阳光小学
2. 在函数内不能直接修改全局变量
如果尝试在函数内给一个全局变量赋值(用 =),Python 会认为你在创建一个新的局部变量,它和外面的全局变量名字相同但彼此无关。
count = 0 # 全局变量:记录全班人数
def add_one():
count = 10 # 这其实定义了一个新的局部变量,不会影响全局变量
print("函数内count:", count)
add_one() # 输出:函数内count: 10
print("函数外count:", count) # 输出:函数外count: 0 (全局变量没变)
生活中的例子:学校告示板上写着“今天大扫除”,你看到后自己嘀咕了一句“改成明天吧”,但告示板上的字并没有改变——你只是在自己心里改了。只有你拿着粉笔去告示板上改写,才是真的修改。
三、如何真正修改全局变量:global声明
如果确实需要在函数内部修改全局变量,必须用 global 关键字声明这个变量是全局的。
count = 0 # 全局变量
def add_one():
global count # 声明count是全局变量
count = count + 1 # 现在修改的是全局变量
add_one()
print(count) # 输出:1 (成功修改)
重要提醒:global 声明一般只在需要修改全局变量时才用。能不用就尽量不用,因为滥用全局变量会让代码难以理解和调试。就像学校告示板,不是每个人都能上去改,只有校长或值日生才有权力。
四、新手最容易犯的错误
-
忘记
global关键字
以为函数内修改了全局变量,实际却创建了局部变量,导致程序逻辑错误。比如上面的count例子,如果不加global,外面count还是0。 -
在函数内部意外重名
函数内定义了一个与全局变量同名的变量,本意是想用全局变量,结果却变成了局部变量,覆盖了全局变量的访问能力。score = 90 # 全局变量:考试分数 def change(): score = 100 # 想修改全局分数,但实际创建了局部变量 print("函数内分数:", score) change() # 输出:函数内分数: 100 print("函数外分数:", score) # 输出:函数外分数: 90 (没改成功) -
在函数内使用全局变量名但未赋值
如果函数内只读取全局变量,不会产生问题;但如果既读取又赋值,Python 就会困惑——它会认为这个变量是局部的,但在赋值前你又读取了它,导致“变量未定义”错误。x = 10 def test(): print(x) # 这里想读取全局x x = 20 # 但又写了一个局部x,导致冲突 # 运行会报错:UnboundLocalError: local variable 'x' referenced before assignment解决方法:要么全用全局(加
global),要么不要这样混用。
五、作用域查找规则(LEGB)
Python 在访问一个变量时,按照以下顺序依次查找:
- Local(本地) → 当前函数内部定义的变量
- Enclosing(嵌套) → 外层函数(如果有嵌套函数)中定义的变量
- Global(全局) → 整个程序顶层定义的变量
- Built-in(内置) → Python 自带的函数和常量(比如
print、len、True)
简单记住:先找自己,再找外层,再找全局,最后找内置。一旦找到就停止查找。
举个例子(如果你还没学嵌套函数,可以跳过):
x = "全局x" # 全局
def outer():
x = "外层x" # 嵌套作用域
def inner():
x = "内层x" # 局部
print(x)
inner()
outer() # 输出:内层x
如果 inner 函数里没有定义 x,就会去外层找,再找不到就去全局,最后去内置。
六、完整可运行示例:统计考试平均分
下面是一个综合例子,用全局变量记录总人数和总分,局部变量处理每一轮的输入,用函数来更新成绩。
total_students = 0 # 全局变量:学生总人数
total_score = 0 # 全局变量:总分数
def add_score(score): # 参数score是局部变量
global total_students, total_score # 声明要修改全局变量
total_students = total_students + 1 # 人数加1
total_score = total_score + score # 总分加上新分数
print("已录入分数:", score, ",当前总人数:", total_students)
# 主程序
print("请输入3个同学的考试成绩(按回车分隔):")
for i in range(3):
s = int(input()) # 局部变量 s,存放本次输入
add_score(s) # 调用函数
average = total_score / total_students # 计算平均分(全局变量)
print("班级平均分:", average)
运行示例(假设输入 85, 92, 78):
请输入3个同学的考试成绩(按回车分隔):
85
92
78
已录入分数: 85 ,当前总人数: 1
已录入分数: 92 ,当前总人数: 2
已录入分数: 78 ,当前总人数: 3
班级平均分: 85.0
这个例子中,全局变量 total_students 和 total_score 记录整个班级的数据,函数 add_score 负责更新它们,而主程序中的 s 只是局部变量,函数执行完就消失了。
七、相关指引
掌握了变量的作用域,你就理解了函数内部和外部如何安全地交换数据。接下来可以学习:
- 函数的参数与返回值——这是让函数和外界交流更灵活的方式(通常比全局变量更推荐)。
- 递归函数——递归中的每一层调用都有自己的局部变量,理解作用域能帮你写出正确的递归。
- 模块与命名空间——当程序变大,分成多个文件时,每个文件有自己的全局作用域,用
import来访问。 nonlocal关键字——用于嵌套函数中修改外层函数的局部变量。
记住:变量作用域就像学校的领地划分——班级内的事自己管,学校的事大家管,不要随便越界,但需要时可以通过规则(global)来协调。 这样你的代码就会井井有条。
例题精讲
在Python中,以下关于变量作用域的说法,错误的是?
执行以下代码后,输出的结果是? x = 10 def change(): x = 5 change() print(x)
在Python中,函数内部可以任意读取函数外部定义的全局变量的值,但无法直接修改全局变量的值(除非使用global关键字)。
以下代码使用嵌套函数,函数outer中定义了变量x,函数inner中试图修改外层的x。请填写正确的内容,使得最终输出为10。
def outer():
x = 5
def inner():
___ # 此处填写声明语句
x = 10
inner()
print(x)
outer()以下代码中,函数func试图修改全局变量a,但未使用关键字,请填写正确的声明语句使得最终输出为20。
a = 10
def func():
___ # 此处填写声明语句
a = 20
func()
print(a)