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

image

①:在内存中开辟一块地址 存储数字类型的 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

image

①:在内存中开辟一块地址 存储列表类型的 [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 中,数据的传递都是通过引用

———————————————————————————————————————————————————————————————————————————

                                                                                                                         无敌小马爱学习

posted on 2025-09-24 22:20  马俊南  阅读(8)  评论(0)    收藏  举报