4、不定长参数
不定长参数也叫可变参数。用于不确定调用的时候会传递多少个参数(不传参也可以)的场景。此时,可用包裹位置参数,或者包裹关键字参数,来进行参数传递,会显得非常方便。
(1)包裹位置传递
"""
1.在定义函数时,可以在形参前边加上一个*,这样这个形参将会获取到所有的实参,
它将会将所有的实参保存到一个元组中
2.*args说明:*一定要写,args表示形参,可以自定义名称。
但在实际工作中,一般默认使用*args做为不定长包裹位置传递参数的表示,不做修改。
"""
def user_info(*args):
print(args)
# ('TOM',)
user_info('TOM')
# ('TOM', 18)
user_info('TOM', 18)
# ()
user_info()
注意:传进的所有参数都会被args变量收集,它会根据传进的所有的位置实参,合并为一个元组(tuple),args是元组类型,这就是包裹位置传递。(这个过程也叫装包或者组包)
小应用
# 定义一个函数,可以求任意个数字的和
def sum(*nums):
# 定义一个变量,来保存结果
result = 0
# 遍历元组,并将元组中的数进行累加
for n in nums:
result += n
print(result)
sum(123, 456, 789, 10, 20, 30, 40)
注意事项
# 注意事项1
# 带星号的形参只能有一个
# 带星号的参数,可以和其他参数配合使用
# 第一个参数给a,第二个参数给b,剩下的都保存到c的元组中
def fn2(a, b, *c):
print('a =', a)
print('b =', b)
print('c =', c)
fn2(1, 2, 3, 4, 5)
"""
输出结果:
a = 1
b = 2
c = (3, 4, 5)
"""
# 注意事项2
# 可变参数不是必须写在最后,但是注意,
# 带*的参数后的所有参数,必须以关键字参数的形式传递
# 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
def fn2(a, *b, c):
print('a =', a)
print('b =', b)
print('c =', c)
# TypeError: fn2() missing 1 required keyword-only argument: 'c'
# fn2(1, 2, 3, 4, 5) # 报错
fn2(1, 2, 3, 4, c=5)
"""
输出结果:
a = 1
b = (2, 3, 4)
c = 5
"""
# 注意事项3
# 所有的位置参数都给a,b和c必须使用关键字参数,
# 且必须写在最后。
def fn2(*a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
fn2(1, 2, 3, b=4, c=5)
"""
输出结果:
a = (1, 2, 3)
b = 4
c = 5
"""
# 注意事项4
# 如果在形参的开头直接写一个*,
# 则要求我们的所有的参数必须以关键字参数的形式传递。
def fn2(*, a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
fn2(a=3, b=4, c=5)
"""
输出结果:
a = 3
b = 4
c = 5
"""
# 注意事项5
# *形参只能接收位置参数,而不能接收关键字参数
def fn3(*a):
print('a =', a)
# TypeError: fn3() got an unexpected keyword argument 'a'
fn3(a=3, b=4, c=5)
(2)包裹关键字传递
"""
**kwargs说明:**一定要写,args表示形参,可以自定义名称。
但在实际工作中,一般默认使用**kwargs做为不定长包裹关键字传递参数的表示,不做修改。
"""
# 收集所有关键字参数,它会将这些参数统一保存到一个字典中返回。
# 字典的key就是参数的名字,字典的value就是参数的值
def user_info(**kwargs):
print(kwargs)
# {'name': 'TOM', 'age': 18, 'id': 110}
# 关键字不能加引号,应为关键字对应的是形参。
user_info(name='TOM', age=18, id=110)
# 包裹关键字传递只能有一个,并且必须写在所有参数的最后
# 实参可以不按顺序传递
def fn3(b, c, **a):
print('a =', a, type(a))
print('b =', b)
print('c =', c)
fn3(e=10, b=1, d=2, c=3, f=20)
"""
输出结果:
a = {'e': 10, 'd': 2, 'f': 20} <class 'dict'>
b = 1
c = 3
"""
综上:无论是包裹位置传递还是包裹关键字传递,都是一个组包的过程(组包简单的说,就是收集分散的参数,返回一个整体数据)。关于组包对应就是拆包,在文档3中(四)元组中有介绍,可以对应的总结。
5、拓展,参数解包
关于组包对应就是拆包,在文档3中(四)元组中有介绍,可以对应的总结。
通过包裹位置传递来(*)对一个元组进行解包操作
# 参数的解包(拆包)
def fn4(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
# 创建一个元组
t = (10, 20, 30)
# 我们直接传递t,会报错
# TypeError: fn4() missing 2 required positional arguments: 'b' and 'c'
# fn4(t)
# 而以前我们是这样拆包的
# fn4(t[0], t[1], t[2])
"""
输出结果:
a = 10
b = 20
c = 30
"""
# *号拆包
# 传递实参时,也可以在序列类型的参数前添加星号,
# #这样他会自动将序列中的元素依次作为参数传递。
# 这里要求序列中元素的个数必须和形参的个数的一致
fn4(*t)
"""
输出结果:
a = 10
b = 20
c = 30
"""
通过包裹关键字传递(**)来对一个字典进行解包操作
# 参数的解包(拆包)
def fn4(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)
# 创建一个字典
d = {'a': 100, 'b': 200, 'c': 300}
# 通过 **来对一个字典进行解包操作
# 字典中的key要和函数的形参一一对应。
fn4(**d)
"""
输出结果:
a = 100
b = 200
c = 300
"""