1.引言
函数有时不知道用户想传入多少个参数,而print()是支持参数可多可少的函数
>>> print("小甲鱼")
小甲鱼
>>> print("小甲鱼","爱","编程") #打印三个参数
小甲鱼 爱 编程
2.收集参数将参数打包为元祖
收集参数:形参的名字前面加上一个星号就行了。
( * args) 称之为Non-keyword Variable Arguments 无关键字参数,一个*为参数收集器,类型为元祖类型
举例如下:
>>> def myfunc(*args): #用*args表示收集参数
print("有{}个参数。".format(len(args))) #字符串的format方法
print("第2个参数是:{}".format(args[1]))
>>> myfunc("小甲鱼","中国")
有2个参数。
第2个参数是:中国
>>>
>>> myfunc(1,2,3,4,5)
有5个参数。
第2个参数是:2
>>>
打印形参,收集参数打印出来是元祖,而元祖具有打包和解包的能力
>>> def myfunc(*args):
print(args)
>>> myfunc(1,2,3,4,5)
(1, 2, 3, 4, 5) #元祖
>>>
函数可以同时返回多个值(前几节讲过)
>>> def myfunc():
return 1,2,3
>>> myfunc()
(1, 2, 3) #返回值以元祖形式打印
>>> x,y,z=myfunc() #对拿到的返回值解包
>>> x
1
>>> y
2
>>> z
3
>>>
收集参数*args后面还有其他参数,就应该使用使用关键字参数来指定后面的参数
>>> def myfunc(*args):
print(type(args))
>>> myfunc(1,2,3,4,5) #收集参数*args类型为元祖
>>>
>>> def myfunc(*args,a,b):
print(args,a,b)
>>> myfunc(1,2,3,4,5) #报错,4,5应使用关键字参数
Traceback (most recent call last):
File "", line 1, in
myfunc(1,2,3,4,5)
TypeError: myfunc() missing 2 required keyword-only arguments: 'a' and 'b'
>>>
>>> myfunc(1,2,3,a=4,b=5) #正确写法,关键字参数a=4,b=5
(1, 2, 3) 4 5
只能使用关键字参数不能使用位置参数(上一讲讲过函数的几种参数 位置参数、关键字参数、默认参数等)
>>> def abc(a,*,b,c): # *后只能用关键字参数
print(a,b,c)
>>> abc(1,2,3) #需要1个位置参数,b,c也就是2和3需要使用关键字参数。
Traceback (most recent call last):
File "", line 1, in
abc(1,2,3)
TypeError: abc() takes 1 positional argument but 3 were given
>>>
>>> abc(1,b=2,c=3) #正确写法
1 2 3
3.收集参数将参数打包为字典
(* args)称之为Non-keyword Variable Arguments 无关键字参数,一个星号*为参数收集器,类型为元祖类型
(**kwarge) 称之为keyword Variable Arguments,有关键字参数,两个星号 ** 为字典形式的收集参数
举例如下:
字典是以键值对出现的,如a=1,等号左边是键,右边是值。
>>> def myfunc(**kwargs):
print(kwargs)
>>> myfunc(a=1,b=2,c=3) #关键字参数
{'a': 1, 'b': 2, 'c': 3}
>>>
>>> def myfunc(a,*b,**c): #两种收集参数方法混合使用,
print(a,b,c)
>>> myfunc(1,2,3,4,x=5,y=6) #1为位置参数,2,3,4为元祖,5,6为字典
1 (2, 3, 4) {'x': 5, 'y': 6}
字符串的format方法同时使用一个星号和两个星号作为收集参数的情况
>>> help(str.format)
Help on method_descriptor:
format(...)
S.format(*args, **kwargs) -> str
Return a formatted version of S, using substitutions from args and kwargs.
The substitutions are identified by braces ('{' and '}').
>>>
4.解包参数
一个星号和两个星号在函数上也有使用,在形参上使用我们称为参数的打包,在实参上使用则起到了相反的结果。
一个星号* 实际参数将元祖解包:
>>> args=(1,2,3,4)
>>> def myfunc(a,b,c,d):
print(a,b,c,d)
>>> myfunc(args) #报错,需要4个参数但只传入一个参数
Traceback (most recent call last):
File "", line 1, in
myfunc(args)
TypeError: myfunc() missing 3 required positional arguments: 'b', 'c', and 'd'
>>>
>>> myfunc(*args) #对参数的解包,args不在是一个元祖,它被解包成1,2,3,4传递到a,b,c,d四个形参里面
1 2 3 4
两个星号**实际参数将字典解包成关键字参数
>>> kwargs={'a':1,'b':2,'c':3,'d':4}
>>> myfunc(**kwargs) #字典解包
1 2 3 4
>>>
课后题:
2. 请问下面代码会打印什么呢?
>>> def func(a, b=4, c=5):
... print(a, b, c)
...
>>> func(1, 2)
>>> # 请问这里会打印什么内容?
答:
>>> func(1, 2)
1 2 5
解析:1 和 2 作为位置参数传递给了形参 a 和 b,并且 c 在调用中被忽略了,从而使用默认值 5。
3. 请问下面代码会打印什么呢?
>>> def func(x, *y, z=3):
... print(x, y, z)
...
>>> func(1, 1, 2, 3, 5)
>>> # 请问这里会打印什么内容?
答:
>>> func(1, 1, 2, 3, 5)
1 (1, 2, 3, 5) 3
解析:由于形参 y 是定义为收集参数,所以除了第一个实参 1 给到 x;其它的实参(1、2、3、5)都给到了 y;z 就只能使用默认值 3,如果想要给 z 赋值,需要使用关键字参数才行。
4.请问下面代码会打印什么呢?
>>> def func(x, *y, **z):
... print(x, y, z)
...
>>> func(1, 2, 3, 4, y=5)
>>> # 请问这里会打印什么内容?
答:
>>> func(1, 2, 3, 4, y=5)
1 (2, 3, 4) {'y': 5}
解析:实参 1 传给第一个位置参数 x;接着的 2,3,4 传给元组收集参数 y;最后一个 y=5 传给字典收集参数 z。
5.请问下面代码会打印什么呢?
>>> def func(x, *y, **z):
... print(x, y, z)
...
>>> func(1, 2, x=3, y=4, z=5)
>>> # 请问这里会打印什么内容?
答:会报错。
>>> func(1, 2, x=3, y=4, z=5)
Traceback (most recent call last):
File "", line 1, in
func(1, 2, x=3, y=4, z=5)
TypeError: func() got multiple values for argument 'x'
解析:虽然说映射形式的多个参数会被字典形的收集参数统一收集,但这里由于 x 是第一个形参的名字,从而产生冲突(Python 搞不懂 x=3 的含义是要通过关键字参数赋值,还是被收集参数 z 获取……所以注意代码一定不要有二义性,否则都会出错。
6.请问下面代码会打印什么呢?
>>> def func(x, y, z=3):
... print(x, y, z)
...
>>> func((1, 2), *(3, 4))
>>> # 请问这里会打印什么内容?
答:
>>> func((1, 2), *(3, 4))
(1, 2) 3 4
解析:第一个实参 (1, 2) 是以元组的形式传递,所以作为整个传递给形参 x;第二个参数 * (3, 4) 虽说也是元组,但作为实参前面带个星号(*),表示解包操作,会将 3 和 4 拆开后再分别传递给形参 y 和 z。
题目来自小甲鱼函数(III)