查看全课大纲(第 27 / 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 如何快速统计元素出现次数?
函数里的变量,为什么有的能用有的不能用?
约 21 分钟
小象实战讲义 · Python 编程从入门到实践
函数是 Python 中组织代码、实现复用的核心工具。在学完列表、元组、集合、字典这些数据结构之后,本节我们将系统地学习如何定义和使用函数,并理解函数内外变量的作用范围。学完本节,你将能清晰地分辨函数参数的类型,并避免因变量作用域不清而导致的常见错误。
💡 核心导读
- 函数定义与调用:掌握
def关键字定义函数,以及通过函数名加括号进行调用的基本形式。 - 形参与实参:理解定义函数时的形式参数(形参)和调用函数时传入的实际参数(实参)的区别。
- 参数的高级用法:学习缺省参数和命名参数,让函数调用更灵活。
- 变量作用域:分清局部变量和全局变量,知道它们各自在哪里有效,以及修改全局变量时需要
global声明。
函数的基本形式
函数是对一段特定功能的代码封装。定义后,通过一个名字即可反复调用这段代码,无需重复编写。
定义语法:
def 函数名(参数):
函数体代码
return 返回值 # 可选def是定义函数的关键字。函数名遵循变量命名规则。参数是可选的,写在括号内,多个参数用逗号分隔。- 函数体是一个缩进的代码块,与
if、for的代码块格式要求一致。 return语句用于把结果返回给调用者;return也可以没有,这种函数称为无返回值函数。
调用方式:函数名(参数)
下面是本节的第一组示例:先定义一个打印固定用户信息的无参函数,再定义一个带参函数,对比“写死信息”和“由调用者传入信息”两种做法。
# 定义无参函数
def print_user_info():
print("name: zhangsan")
print("age: 10")
print("gender: male")
# 调用函数
print_user_info()
# 定义带参函数:name, age, gender 是形参
def print_user_info2(name, age, gender):
print("name: {}".format(name))
print("age: {}".format(age))
print("gender: {}".format(gender))
# 调用函数,把变量作为实参传入
name = "悟空"
age = 100
gender = "female"
print_user_info2(name, age, gender)
# 实参也可以直接写字面值
print_user_info2("悟空", 100, "male")name: zhangsan
age: 10
gender: male
name: 悟空
age: 100
gender: female
name: 悟空
age: 100
gender: male函数的参数:形参与实参
为了让函数处理不同的数据,我们需要给它传递参数。
- 形参 (Formal Parameter):定义函数时设置的参数,是形式上的变量名。
- 实参 (Actual Parameter):调用函数时传入的参数,是实际的值。
调用时,实参按顺序依次传递给形参;实参不仅可以是变量,也可以是直接写在调用处的字面值。
让函数调用更灵活:缺省参数与命名参数
缺省参数
在定义函数时,可以为某些参数指定一个默认值,这样的参数称为缺省参数。调用时,如果未提供该参数的值,则使用默认值。
定义规则:缺省参数必须放在参数列表的最后。
命名参数
调用函数时,可以通过指定参数名来传递值,这称为命名参数。使用命名参数时,可以不按形参定义的顺序传参;参数名必须与定义时的形参名称相同。
def x_y_sum(x, y=20): # y 是缺省参数,默认值为 20
return x + y
print(x_y_sum(10)) # 只传 x,y 使用缺省值 20
print(x_y_sum(10, 30)) # 传入 30 替换缺省值
def x_y_sum2(x=10, y=20):
return x + y
print(x_y_sum2(y=30, x=15)) # 按参数名传,顺序可以与定义时不同
print(x_y_sum2(x=20)) # 只传 x,y 使用默认值
print(x_y_sum2()) # 都使用默认值
print(x_y_sum2(30)) # 只传第一个位置参数,y 仍用默认值30
40
45
40
30
50错误示例:将缺省参数放在非缺省参数前面会导致语法错误。
def wrong_sum(y=20, x): # 错误!缺省参数 y 不能放在非缺省参数 x 前面
return x + y原因:如果只传一个参数 wrong_sum(10),Python 无法确定这个 10 是给 y 还是给 x。
函数中的变量:局部与全局
局部变量
在函数内部定义的变量称为局部变量。
- 作用范围:仅在定义它的函数内部有效。
- 独立性:不同函数内的局部变量即使同名,也互不影响。
- 外部不可见:在函数外部或其他函数内部无法直接访问。
def func_a():
x = 1 # func_a 的局部变量 x
print("func_a 中的 x: {}".format(x))
def func_b():
x = 2 # func_b 的局部变量 x,与 func_a 的 x 无关
print("func_b 中的 x: {}".format(x))
func_a()
func_b()
# 常见误区:跨函数访问局部变量
def set_name():
my_name = "张三" # 局部变量
def get_name():
print(my_name) # 错误!此处无法访问 set_name 中的 my_name
set_name()
# get_name() # 取消注释会报 NameError: name 'my_name' is not defined
# 正确做法:通过 return 将局部变量的值传递出来
def set_name2():
name = "张三"
return name # 返回局部变量的值
def print_name(n):
print(n)
retrieved_name = set_name2() # 用外部变量接收返回值
print_name(retrieved_name) # 将返回值作为参数传入func_a 中的 x: 1
func_b 中的 x: 2
张三全局变量
在函数外部定义的变量称为全局变量。
- 作用范围:从定义开始,到整个文件结束,在函数内部也可以访问(读取)。
- 修改限制:在函数内部修改全局变量的值,需要使用
global关键字声明。
name = "张三" # 全局变量
def get_name():
print(name) # 在函数内部可以读取全局变量
get_name()
print(name) # 在函数外部也可以读取张三
张三修改全局变量:在函数内部修改全局变量的值,必须先用 global 关键字声明;具体现象和写法放到后面的练习讲解里完整展开。
命名建议:为了清晰区分,全局变量命名常以 g_ 开头(如 g_name),但这只是约定,并非语法要求;决定一个变量是不是全局变量的是它声明的位置,而不是名字。
📝 动手练一练
- 编写一个函数
greet(name, greeting="Hello"),它接受一个名字和一个可选的问候语(默认为 “Hello”),并打印问候语和名字。尝试用不同的方式调用它:只传名字、同时传名字和自定义问候语、使用命名参数颠倒顺序传入。
👉 点击查看参考答案
思路:定义一个带有缺省参数 greeting 的函数。调用时演示使用默认值、覆盖默认值以及使用命名参数。
def greet(name, greeting="Hello"):
print("{}, {}!".format(greeting, name))
# 只传名字,使用默认问候语
greet("Alice")
# 同时传名字和自定义问候语
greet("Bob", "Good morning")
# 使用命名参数,颠倒顺序
greet(greeting="Hi", name="Charlie")Hello, Alice!
Good morning, Bob!
Hi, Charlie!常见错误
| 错误写法 | 现象或报错 | 原因 | 正确写法 |
|---|---|---|---|
def func(a=1, b): | SyntaxError: parameter without a default follows parameter with a default | 缺省参数 a=1 放在了非缺省参数 b 的前面。 | def func(b, a=1): |
在函数内直接 全局变量 = 新值 | 函数外该全局变量的值未被修改。 | 未使用 global 声明,这行代码实际创建了一个同名的局部变量。 | 在函数内使用 global 全局变量名 声明后再赋值。 |
| 在函数 A 中定义变量,在函数 B 中直接使用 | NameError: name 'xxx' is not defined | 局部变量的作用域仅限于其所在的函数内部。 | 通过函数 A 的返回值将值传递给函数 B 的参数。 |
| 调用函数时,实参顺序与形参定义不匹配且未使用命名参数 | 程序可能不报错,但逻辑错误,得到意外结果。 | 实参会按位置顺序传递给形参。 | 仔细核对顺序,或使用命名参数明确指定。 |
小结
- 函数用
def定义,通过函数名加括号调用。 - 定义时的参数叫形参,调用时传入的值叫实参。
- 缺省参数让调用更简洁,但必须定义在参数列表末尾。
- 命名参数允许在调用时不按形参顺序传参。
- 局部变量在函数内定义,仅函数内有效;全局变量在函数外定义,整个文件有效。
- 在函数内修改全局变量,必须先用
global关键字声明。
📋 行动清单
- 将“动手练一练”中的代码自己敲一遍,并尝试修改参数,观察输出变化。
- 创建一个全局变量
g_count = 0,写一个函数increment(),在函数内用global声明并修改g_count,调用几次后打印其值,验证修改是否生效。 - 故意写一个错误的函数定义(如缺省参数在前),运行它,看看 Python 会报什么错。
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。
- 下载第3章代码包:函数(含1 个 Notebook)ZIP · 3KB