查看全课大纲(第 28 / 51 节)
  1. 1.Python 是什么?为什么值得学?
  2. 2.如何为 Python 编程准备一个“全家桶”环境?
  3. 3.Python 有哪几种执行方法?
  4. 4.行与缩进到底有什么用?
  5. 5.注释有什么用,怎么写?
  6. 6.变量:如何给数据起个好名字?
  7. 7.运算符的优先级和常见坑点是什么?
  8. 8.Python 中,数字和布尔值究竟有哪几种?
  9. 9.输入函数 `input()` 和文件读取 `open()` 怎么用?
  10. 10.如何将程序的结果展示给用户或保存下来?
  11. 11.CSV 文件怎么读怎么写才方便?
  12. 12.列表是什么,如何创建和访问它?
  13. 13.列表的修改操作,有哪些方法?
  14. 14.列表切片为什么能取到部分元素?排序和查找又该怎么用?
  15. 15.判断语句:如何让程序根据条件做不同的事?
  16. 16.for 循环如何遍历序列中的元素?
  17. 17.while 循环什么时候才会停?
  18. 18.while 循环的结束条件,你写对了吗?
  19. 19.循环中途想提前结束,怎么办?
  20. 20.`break` 和 `continue` 到底有什么区别?
  21. 21.列表推导式如何让代码更简洁高效?
  22. 22.字符串怎么定义、拼接和操作?
  23. 23.元组:为什么定义单个元素时要加逗号?
  24. 24.集合(set)怎么用?如何快速去重和做集合运算?
  25. 25.字典是什么,为什么比列表更方便?
  26. 26.字典的增删改查与遍历,如何避免 KeyError?
  27. 27.函数里的变量,为什么有的能用有的不能用?
  28. 28.在函数内部修改全局变量,为什么有时不生效?
  29. 29.函数里能修改全局变量吗?返回值怎么用?
  30. 30.匿名函数:如何用 lambda 快速定义简单函数?
  31. 31.面向对象编程是什么,为什么需要它?
  32. 32.类中的方法和属性到底怎么定义和使用?
  33. 33.如何控制对对象内部属性和方法的访问?
  34. 34.异常发生时,程序会怎样继续执行?
  35. 35.如何组织代码:包和模块
  36. 36.`if __name__ == '__main__'` 到底有什么用?
  37. 37.如何用 IDE 的 Debug 功能排查程序错误?
  38. 38.Matplotlib 绘图的第一步该做什么?
  39. 39.Figure 是什么,如何设置图形尺寸?
  40. 40.如何自定义 Matplotlib 的坐标轴?
  41. 41.如何为图表添加图例,让不同曲线一目了然?
  42. 42.饼图怎么画才能直观展示数据占比?
  43. 43.如何用 Matplotlib 绘制散点图?
  44. 44.柱状图怎么画?
  45. 45.如何使用 Matplotlib 绘制等高线图?
  46. 46.如何在 Matplotlib 中绘制子图?
  47. 47.zip 函数如何把多个列表“打包”在一起?
  48. 48.如何给可迭代对象加上索引?
  49. 49.random 模块如何生成随机数?
  50. 50.math 模块怎么用?
  51. 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 也会在函数内部创建一个新的局部变量,而不是去修改外部的那个。

所以,在上面的例子中:

  1. 全局作用域有一个变量 age = 20。
  2. 进入 update_age 函数后,执行 age = 25,Python 认为你要创建一个新的局部变量 age,并将其赋值为 25。
  3. 函数内部的 print 打印的是这个局部变量 age 的值(25)。
  4. 函数调用结束,局部变量 age 被销毁。
  5. 外部的 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 的场景只有一个:在函数内部修改全局变量。

📝 动手练一练

  1. 下面这段代码想让 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 declarationglobal 语句必须出现在对该变量的任何使用之前将 global 语句放在函数开头,先声明后使用

小结

  1. 在函数内部,如果对一个变量进行赋值操作(=),Python 默认会创建一个新的局部变量。
  2. 若要修改函数外定义的全局变量,必须在函数内部使用 global 关键字进行声明。
  3. global 语句只需要在需要修改全局变量的函数中使用,仅读取全局变量值时不需要。
  4. global 声明应置于函数顶部,先声明后使用,避免语法错误。
  5. 理解这一机制有助于避免因变量作用域混淆导致的程序逻辑错误。

📋 行动清单

  • 将本节第一个示例代码中的 age = 25 前面加上 global age,运行并观察内外 age 值的变化。
  • 编写一个函数 reset_age(),在不使用 global 的情况下把 age 赋值为 20,观察函数外的 age 是否改变;再加上 global 重试一次。
  • 思考:如果一个函数既需要读取也需要修改某个全局变量,global 声明应该放在哪里?

—— 小象教研组