查看全课大纲(第 28 / 51 节)
- 1.Python 是什么?为什么值得学?
- 2.如何为 Python 编程准备一个“全家桶”环境?
- 3.Python 有哪几种执行方法?
- 4.行与缩进到底有什么用?
- 5.注释有什么用,怎么写?
- 6.变量:如何给数据起个好名字?
- 7.运算符的优先级和常见坑点是什么?
- 8.Python 中,数字和布尔值究竟有哪几种?
- 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
- 10.如何将程序的结果展示给用户或保存下来?
- 11.CSV 文件怎么读怎么写才方便?
- 12.列表是什么,如何创建和访问它?
- 13.列表的修改操作,有哪些方法?
- 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
- 15.判断语句:如何让程序根据条件做不同的事?
- 16.for 循环如何遍历序列中的元素?
- 17.while 循环什么时候才会停?
- 18.while 循环的结束条件,你写对了吗?
- 19.循环中途想提前结束,怎么办?
- 20.`break` 和 `continue` 到底有什么区别?
- 21.列表推导式如何让代码更简洁高效?
- 22.字符串怎么定义、拼接和操作?
- 23.元组:为什么定义单个元素时要加逗号?
- 24.集合(set)怎么用?如何快速去重和做集合运算?
- 25.字典是什么,为什么比列表更方便?
- 26.字典的增删改查与遍历,如何避免 KeyError?
- 27.函数里的变量,为什么有的能用有的不能用?
- 28.在函数内部修改全局变量,为什么有时不生效?
- 29.函数里能修改全局变量吗?返回值怎么用?
- 30.匿名函数:如何用 lambda 快速定义简单函数?
- 31.面向对象编程是什么,为什么需要它?
- 32.类中的方法和属性到底怎么定义和使用?
- 33.如何控制对对象内部属性和方法的访问?
- 34.异常发生时,程序会怎样继续执行?
- 35.如何组织代码:包和模块
- 36.`if __name__ == '__main__'` 到底有什么用?
- 37.如何用 IDE 的 Debug 功能排查程序错误?
- 38.Matplotlib 绘图的第一步该做什么?
- 39.Figure 是什么,如何设置图形尺寸?
- 40.如何自定义 Matplotlib 的坐标轴?
- 41.如何为图表添加图例,让不同曲线一目了然?
- 42.饼图怎么画才能直观展示数据占比?
- 43.如何用 Matplotlib 绘制散点图?
- 44.柱状图怎么画?
- 45.如何使用 Matplotlib 绘制等高线图?
- 46.如何在 Matplotlib 中绘制子图?
- 47.zip 函数如何把多个列表“打包”在一起?
- 48.如何给可迭代对象加上索引?
- 49.random 模块如何生成随机数?
- 50.math 模块怎么用?
- 51.Counter 如何快速统计元素出现次数?
在函数内部修改全局变量,为什么有时不生效?
约 3 分钟
小象实战讲义 · Python 编程从入门到实践
在上一节我们学习了函数的基本定义和调用,知道了函数内部可以定义自己的局部变量。但当我们希望在函数内部去修改一个在函数外部定义的全局变量时,可能会遇到一个常见问题:看似修改了,但函数执行完后,全局变量的值并没有改变。本节将通过一个具体的练习,讲解函数内修改全局变量的正确方法,以及 global 关键字的作用。这是理解 Python 变量作用域的关键一步,为后续学习更复杂的函数交互打下基础。
💡 核心导读
- 问题重现:在函数内部直接对全局变量名赋值,为什么不会改变全局变量的值?
- 原因剖析:Python 会默认在函数内部创建一个同名的局部变量,而非修改外部的全局变量。
- 解决方案:使用
global关键字声明变量,明确告知 Python 要操作的是全局变量。 - 访问与修改的区别:仅读取全局变量的值无需声明
global,只有修改时才需要。
一个令人困惑的示例
我们先来看一段代码,它试图在函数内部修改一个全局变量 age。
age = 20 # 定义一个全局变量 age
def update_age():
age = 25 # 试图在函数内部修改 age
print("函数内部 age 的值: {}".format(age))
update_age() # 调用函数
print("函数外部 age 的值: {}".format(age))函数内部 age 的值: 25
函数外部 age 的值: 20执行结果令人困惑:函数内部的 print 显示 age 变成了 25,但函数执行完毕后,外部的 age 依然是 20。这说明函数内部的赋值操作 age = 25 并没有成功修改全局变量 age。
为什么修改不生效?
在 Python 中,当你在函数内部对一个变量进行赋值操作(如 变量名 = 值)时,Python 会默认这个变量是函数的局部变量。即使外部存在同名的全局变量,Python 也会在函数内部创建一个新的局部变量,而不是去修改外部的那个。
所以,在上面的例子中:
- 全局作用域有一个变量
age = 20。 - 进入
update_age函数后,执行age = 25,Python 认为你要创建一个新的局部变量age,并将其赋值为 25。 - 函数内部的
print打印的是这个局部变量age的值(25)。 - 函数调用结束,局部变量
age被销毁。 - 外部的
print打印的是全局变量age,它从未被修改过,所以仍然是 20。
如何正确修改全局变量?
如果我们的本意就是要修改那个全局变量 age,就需要使用 global 关键字来明确声明。
global 关键字的作用是:告诉 Python 解释器,后面跟着的变量名指向的是全局作用域中的变量,而不是在函数内部新建局部变量。
修改后的代码如下:
age = 20 # 全局变量 age
def update_age_correctly():
global age # 声明 age 是全局变量
age = 25 # 现在这个赋值操作是针对全局变量 age 的
print("函数内部 age 的值: {}".format(age))
update_age_correctly() # 调用函数
print("函数外部 age 的值: {}".format(age))
# 只是读取全局变量,不需要 global 声明
def print_age():
print("在函数中读取全局 age 的值: {}".format(age))
print_age()函数内部 age 的值: 25
函数外部 age 的值: 25
在函数中读取全局 age 的值: 25这次,函数内外的 age 都变成了 25。global age 这行代码是关键,它建立了函数内部标识符 age 与外部全局变量 age 的链接。
读取与修改的区别
一个重要的细节是:如果只是读取(访问)全局变量的值,而不修改它,则不需要使用 global 关键字。
在上面的 print_age 函数中,我们只是在函数内部打印 age,并没有对它赋值,所以 Python 知道这里的 age 指的就是全局变量,不需要任何声明。而 update_age_correctly 中执行了 age = 25(赋值操作),要作用于全局变量,就必须先用 global age 声明。需要 global 的场景只有一个:在函数内部修改全局变量。
📝 动手练一练
- 下面这段代码想让
add_score函数把全局变量score改成 90,请先判断最后的print(score)会输出什么,再运行验证,并说明如何修改才能真的改掉全局变量。
score = 60
def add_score():
score = 90
add_score()
print(score)👉 点击查看参考答案
运行结果:
60原因:函数内部执行 score = 90 时,Python 在 add_score 中创建了一个新的局部变量 score,全局的 score 始终是 60。
正确写法:在赋值之前用 global 声明。
score = 60
def add_score():
global score
score = 90
add_score()
print(score)90常见错误
| 错误写法 | 现象或报错 | 原因 | 正确写法 |
|---|---|---|---|
| 在函数内直接赋值修改全局变量 | 函数内值改变,函数外值不变 | Python 默认创建了同名的局部变量,未修改全局变量 | 在函数内使用 global 关键字声明变量后再赋值 |
在 global 声明前使用变量 | SyntaxError: name 'x' is used prior to global declaration | global 语句必须出现在对该变量的任何使用之前 | 将 global 语句放在函数开头,先声明后使用 |
小结
- 在函数内部,如果对一个变量进行赋值操作(
=),Python 默认会创建一个新的局部变量。 - 若要修改函数外定义的全局变量,必须在函数内部使用
global关键字进行声明。 global语句只需要在需要修改全局变量的函数中使用,仅读取全局变量值时不需要。global声明应置于函数顶部,先声明后使用,避免语法错误。- 理解这一机制有助于避免因变量作用域混淆导致的程序逻辑错误。
📋 行动清单
- 将本节第一个示例代码中的
age = 25前面加上global age,运行并观察内外age值的变化。 - 编写一个函数
reset_age(),在不使用global的情况下把age赋值为 20,观察函数外的age是否改变;再加上global重试一次。 - 思考:如果一个函数既需要读取也需要修改某个全局变量,
global声明应该放在哪里?
—— 小象教研组