day10 课程(函数变量 & 函数返回值 & 函数参数 & 拆包 & 引用)
课程:https://www.bilibili.com/video/BV1o4411M71o?spm_id_from=333.788.videopod.episodes&p=183
10.1 函数二学习目标简介
10.1 目标
变量作用域
多函数程序执行流程
函数的返回值
函数的参数
拆包和交换两个变量的值
引用
可变和不可变类型
10.2 局部变量
变量作用域指的是变量生效的范围,主要分为两类:局部变量 和 全局变量
所谓局部变量是定义在函数体内部的变量,即只在函数体内部生效
def testA(): # 定义函数 a = 100 # 定义局部变量,只在函数内部生效 print(a) # 函数体内部访问, 能访问到 a 变量 testA() # 函数调用 返回 100 # print(a) # 打印局部变量, 报错: NameError: name 'a' is not defined ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\01.局部变量.py 100 Process finished with exit code 0
变量a 是定义在 testA 函数内部的变量,在函数外部访问则立即报错
局部变量的作用:在函数体内部,临时保存数据,即当函数调用完成后,则销毁局部变量
10.3 访问全局变量
所谓全局变量,指的是在函数体内、外都能生效的变量
思考:如果有一个数据,在函数A 和函数B 中都要使用,该怎么办?
答:将这个数据存储在一个全局变量里
# 定义全局变量a a = 100 def testA(): # 函数testA() 内生效 print(a) def testB(): # 函数testB() 内生效 print(a) print(a) # 外面生效 100 testA() # 100 testB() # 100 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\02.访问全局变量.py 100 100 100 Process finished with exit code 0
10.4 修改全局变量
思考:testB 函数需求修改变量 a 的值为 200,如何修改程序?
# 定义全局变量 a = 100 def testA(): a = 200 # 局部变量 print(a) def testB(): print(a) print(a) # 全局变量 a = 100 testA() # 函数内有局部变量 a = 200 testB() # 函数内无局部变量a, 使用全局变量a a = 100 print(a) # 上面 testA 使用的局部变量, 未对全局变量产生影响 a = 100 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\03.修改全局变量.py 100 200 100 100 Process finished with exit code 0
思考:在 testA 函数内部的 a = 200 中的 变量a 是在修改 全局变量a 吗?
答:不是,观察上诉代码发现,第二个 print(a) 得到 a 的数据是 100,仍然是定义全局变量a 时候的值,而没有返回 testB 函数内部的 200
综上:testB 函数内部的 a=200 是定义了一个局部变量
思考:如何在函数体内部修改全局变量?global
# 定义全局变量 a = 100 print(a) # 全局变量 a = 100 def testA(): global a # global 声明全局变量 a = 200 # 经过 global 声明后,变成了全局变量,重新对 a 赋值 a = 200 print(a) def testB(): print(a) testA() # 函数内变量 a = 200 testB() # 函数内无局部变量,使用经过修改后的全局变量a a = 200 print(a) # 使用全局变量, 全局变量更改 a = 200 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\03.修改全局变量.py 100 200 200 200 Process finished with exit code 0
总结: 1.如果在函数里直接把变量 a=200 赋值,不是对 a 全局变量的修改,而是相当于在函数内部声明了一个新的局部变量
2.函数体内部修改全局变量,先 global 声明 a 为全局变量,然后再变量重新赋值
10.5 多函数执行流程
一般在实际开发过程中,一个程序往往由多个函数(后面知识中会讲解类)组成,并且多个函数共享某些数据,如下所示:
glo_num = 0 # 定义全局变量 def test1(): global glo_num glo_num = 100 # 修改全局变量 def test2(): print(glo_num) print(glo_num) # 修改的函数未执行,使用原全局变量 0 test2() # 第一次打印,使用原全局变量 0 test1() # 函数内部 定义修改全局变量, 只要调用修改全局变量的函数, 全局变量就发生修改 test2() # 第二次打印,使用经过修改的全局变量 100 print(glo_num) # 修改的函数已经执行,使用经过修改的全局变量 100 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\04.多函数执行流程.py 0 0 100 100 Process finished with exit code 0
10.6 返回值作为参数传递
def testA(): # 函数中定义返回值 50 return 50 def testB(num): # 定义形参, 打印传入的实参 print(num) result = testA() # 保存函数 testA 的返回值 testB(result) # 将函数返回值所在变量作为参数传递到 testB 函数 50 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\05.返回值作为参数传递.py 50 Process finished with exit code 0
10.7 函数的返回值
思考:如果一个函数中有两个 return ,程序如何执行?
答:只执行了第一个 return,原因是 return 可以退出当前函数,导致 return 下方的代码不执行
def return_num(): return 1 # 函数调用后, 执行, 函数执行至此结束 return 2 # 函数调用后, 上面遇到 return 已经结束, 所以下面此行代码不执行 result = return_num() print(result) # 只返回 1 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\06.函数的返回值.py 1 Process finished with exit code 0
思考:如果一个函数要有多个返回值,该如何书写代码?
def return_num(): # return 1, 2 # 同一行, 返回多个值时,使用逗号分割 返回 (1, 2) 一个元祖, 默认返回元祖 # return (10, 20) # 返回 (10, 20), 默认也是返回一个元祖 # return [100, 200] # 返回 [100, 200], 可以返回列表 # return {"name":"Python",'age':18} # 返回 {'name': 'Python', 'age': 18}, 可以返回字典 return (10, 20), [100, 200], {"name":"Python",'age':18} # 返回元组, 将多种类型封装成 元组 result = return_num() print(result) # 返回 (1, 2) 一个元祖 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\06.函数的返回值.py ((10, 20), [100, 200], {'name': 'Python', 'age': 18}) Process finished with exit code 0
注意:1. return a, b 写法,返回多个数据的时候,默认是元祖类型
2.return 后面可以接列表、元组或字典,用以返回多个值
10.8 函数参数之位置参数
位置参数:调用函数时根据函数定义的参数位置来传递参数
def user_info(name, age, gender): # 定义了三个形参 print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}") user_info("Tom", 20, "男") # 按照传参位置, 正确输出打印内容 # user_info("Tom", 20, ) # 实参传参个数不为3个时, 报错漏参:TypeError: user_info() missing 1 required positional argument: 'gender' user_info(20, "男", "Tom") # 传参顺序要和定义必须一致, 否则导致数据无意义 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\07.函数参数之位置参数.py 您的名字是Tom, 年龄是20, 性别是男 您的名字是20, 年龄是男, 性别是Tom Process finished with exit code 0
注意:传递和定义参数的顺序及个数必须一致
10.9 关键字参数
函数调用,通过“键=值”形式加以指定,可以让函数更加清晰、容易使用,同时也清除了参数的顺序需求
def user_info(name, age, gender): # 定义了三个形参 print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}") user_info("Tom",20, "男") # 上一节的位置传参,但是 传参位置更改会使数据混乱,变得无意义 user_info(name="Rose", age=18, gender="女") # 关键字传参, 以键值形式传参 user_info(age=16, gender="女", name="Lily") # 关键字传参, 即使位置错乱, 数据不会乱 user_info("Python", age=22, gender="男") # 既有位置参数又有关键字参数, 位置参数必须在前, 关键字参数可以无序 # user_info(age="22","Loli", gender="男") # 违反位置参数在前, 报错: SyntaxError: positional argument follows keyword argument ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\08.关键字参数.py 您的名字是Tom, 年龄是20, 性别是男 您的名字是Rose, 年龄是18, 性别是女 您的名字是Lily, 年龄是16, 性别是女 您的名字是Python, 年龄是22, 性别是男 Process finished with exit code 0
注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数的前面,但关键字参数之间不存在先后顺序
10.10 缺省参数
缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值(注意:所有位置参数必须出现在默认参数前, 包括函数定义和调用)
def user_info(name, age, gender='男'): # 定义了三个形参, 设置 gender 参数为默认值 print(f"您的名字是{name}, 年龄是{age}, 性别是{gender}") user_info("Tom", 20) # gender未传值, 使用默认值 男 user_info("Rose", 18, "女") # gender传值了, 使用传入的值 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\09.缺省参数.py 您的名字是Tom, 年龄是20, 性别是男 您的名字是Rose, 年龄是18, 性别是女 Process finished with exit code 0
注意:函数调用时,如果为缺省参数传值则修改默认参数值,否则使用这个默认值
10.11 不定长参数之包裹位置参数
不定长参数也叫可变参数,用于被调用时不确定传参个数(不传参也可以)的场景,此时,可用包裹(packing)位置参数或包裹关键字参数,来进行参数传递,会显得非常方便
def user_info(*args): # *args 可传入多个参数 print(args) user_info("Tom") # 传入一个参数 返回 ('Tom',) 元组 user_info("Tom", 18) # 传入两个参数 返回 ('Tom', 18) 元组 user_info("Tom", 18, "男") # 传入三个参数 返回 ('Tom', 18, '男') 元组 user_info() # 传入空, 返回 () 元组 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\10.不定长参数之包裹位置参数.py ('Tom',) ('Tom', 18) ('Tom', 18, '男') () Process finished with exit code 0
注意:传进的所有参数都会被 args 变量所收集,它会根据传进参数的位置合并为一个元祖(tuple), args 是元祖类型,这就是包裹位置传递
10.12 不定长参数之包裹关键字参数
def user_info(**kwargs): # **kwargs 可传入多个参数, 格式须是 键值对形式 print(kwargs) user_info(name="Tom", age=18) # 传入两个键值对参数 返回 {'name': 'Tom', 'age': 18} 字典 user_info(name="Tom", age=18, gender="男") # 传入三个参数 返回 {'name': 'Tom', 'age': 18, 'gender': '男'} 字典 user_info() # 传入空, 返回 {} 字典 # user_info("Tom", age=18, gender="男") # 当传入中有非键值对形式 报错:TypeError: user_info() takes 0 positional arguments but 1 was given ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\11.不定长参数之包裹关键字参数.py {'name': 'Tom', 'age': 18} {'name': 'Tom', 'age': 18, 'gender': '男'} {} Process finished with exit code 0
注意:传进的所有参数都会被 kwargs 变量所收集,它会根据传进参数的位置合并为一个字典 {dict}, kwargs 是字典类型,这就是包裹关键字传递
综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程
10.13 元组拆包
def return_num(): return 100, 200 # 调用函数会返回元祖数据 (100, 200) num1, num2 = return_num() # 调用函数,函数的两个返回值对两个变量赋值 print(num1) print(num2) ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\12.元组拆包.py 100 200 Process finished with exit code 0
10.14 字典拆包
def user_info(): return {"name":"Tom", "age":18} num1, num2 = user_info() # 对字典进行拆包, 取出来的是字典的key print(num1) # name print(num2) # age result = user_info() print(result[num1]) # 用 key = name 取 value Tom print(result[num2]) # 用 key = age 取 value 18 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\13.字典拆.py name age Tom 18 Process finished with exit code 0
10.15 交换变量的值之方法一
需求:有变量 a = 10 和 b = 20,交换两个变量的值
# 借助第三变量存储数据 a = 10 b = 20 c = 0 # 定义了第三变量, 先赋值为 0 c = a # 让 a 先赋值给 c c = 10 a = b # 再让 b 赋值给 a, a 等于 b 的值 a = 20 b = c # 最后 c 赋值给 b, b 等于 c 的值 b = c = 10 print(a) # 20 print(b) # 10 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\14.交换变量的值之方法一.py 20 10 10 Process finished with exit code 0
10.16 交换变量的值之方法二
a = 10 b = 20 a, b = b, a # 先执行右边, 所以 b 和 a 是上面的赋值 即: a, b = 20, 10 进行赋值 print(a) print(b) ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\15.交换变量的值之方法二.py 20 10 Process finished with exit code 0
10.17 了解引用之不可变类型
结论:在 python 中,值是靠引用来传递的
可以用 id() 来判断两个变量是否为同一个值的引用,可以将 id值 理解为 变量值 在内存的地址标识
a = 1 b = a print(a) # 1 print(b) # 1 print(id(a)) # 检查两个值在内存的地址相同 140723787756456 相同 print(id(b)) # 检查两个值在内存的地址相同 140723787756456 相同 a = 2 # 修改了 a 的数据, 内存开辟了一个新的空间 2, 所以 a 内存地址发生变化 print(a) # 2 print(b) # 1 print(id(a)) # 检查两个值在内存的地址 140723787756488 不相同 print(id(b)) # 检查两个值在内存的地址 140723787756456 不相同 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\16.了解引用之不可变类型.py 1 1 140723787756456 140723787756456 2 1 140723787756488 140723787756456 Process finished with exit code 0

①:在内存中开辟一块地址 存储数字类型的 1
②:a 变量在内存地址中指向 1 的内存地址 即 a = 1 过程
③:b 变量在内存地址中指向 a,而 a 指向 1 的内存地址 即 b = a 过程
④:在内存中开辟一块地址 存储数字类型的 2,a 变量在内存地址中指向 2 的内存地址 即 a = 2 过程,b 仍指向1 的内存地址
10.18 了解引用之可变类型
aa = [10, 20] # 定义列表 bb = aa print(aa) # [10, 20] print(bb) # [10, 20] print(id(aa)) # 检查两个值在内存的地址相同 2188572075840 相同 print(id(bb)) # 检查两个值在内存的地址相同 2188572075840 相同 aa.append(30) # 对列表中追加数据 print(aa) # [10, 20, 30] print(bb) # [10, 20, 30] print(id(aa)) # 检查两个值在内存的地址 2188572075840 仍旧相同 print(id(bb)) # 检查两个值在内存的地址 2188572075840 仍旧相同 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\17.了解引用之可变类型.py [10, 20] [10, 20] 2188572075840 2188572075840 [10, 20, 30] [10, 20, 30] 2188572075840 2188572075840 Process finished with exit code 0

①:在内存中开辟一块地址 存储列表类型的 [10, 20]
②:aa 变量在内存地址中指向 [10, 20] 的内存地址 即 aa = [10, 20] 过程
③:bb 变量在内存地址中指向 aa,而 aa 指向 [10, 20] 的内存地址 即 bb = aa 过程
④:在内存中直接修改 [10, 20] 为 [10, 20, 30],内存地址没有发生变化,仍是原内存地址
10.19 引用当做实参传入
def test1(a): print(a) print(id(a)) a += a # a = a + a 加自己本身, 再重新赋值给 a print(a) print(id(a)) b = 100 # int 计算前后 id 值不同 test1(b) # 调用函数, 其中的两个内存地址不同, 100 的地址 140723792150536、200 的地址 140723792153736 c = [11, 22] # 列表 计算前后 id 值相同 test1(c) # 调用函数, 其中的两个内存地址相同, [11, 22] 的地址 2008917452608、[11, 22, 11, 22] 的地址 2008917452608 ------------------------------------------------ 执行后 C:\Users\马俊南\AppData\Local\Microsoft\WindowsApps\python3.13.exe D:\Pycharm\code\day10\18.引用当做实参传入.py 100 140723792150536 200 140723792153736 [11, 22] 2008917452608 [11, 22, 11, 22] 2008917452608 Process finished with exit code 0
10.20 可变和不可变类型
所谓可变类型与不可变类型是指:数据能够直接进行修改,如果能直接修改那么就是可变类型,否则是不可变类型
可变类型:
1.列表
2.字典
3.集合
不可变类型:
1.整型
2.浮点型
3.字符串
4.元组
5.布尔型
10.21 函数二总结
变量作用域
全局:函数体内外都能生效
局部:当前函数体内部生效
函数多返回值写法
return 表达式1, 表达式2, ...
函数的参数
位置参数
形参和实参的个数和书写顺序必须一致
关键字参数
写法:key = value
特点:形参和实参的书写顺序可以不一致,关键字参数必须书写在位置参数的后面
缺省参数
缺省参数就是默认参数
写法:key = value
不定长位置参数
*args 收集所有位置参数,返回一个元祖
不定长关键字参数
**kwargs 收集所有关键字参数,返回一个字典
引用:Python 中,数据的传递都是通过引用
———————————————————————————————————————————————————————————————————————————
无敌小马爱学习
浙公网安备 33010602011771号