调用函数时使用:*、**
test(*args)中 * 的作用:其实就是把序列 args 中的每个元素,当作位置参数传进去。比如上面这个代码,如果 args 等于 (1,2,3) ,那么这个代码就等价于 test(1, 2, 3) 。
test(**kwargs)中** 的作用:则是把字典 kwargs 变成关键字参数传递。比如上面这个代码,如果 kwargs 等于 {'a':1,'b':2,'c':3} ,那这个代码就等价于 test(a=1,b=2,c=3) 。
定义函数参数时使用* 、**
def test(*args):
这里 *args 表示把传进来的位置参数都装在元组 args 里面。比如说上面这个函数,调用 test(1, 2, 3) 的话, args 的值就是 (1, 2, 3) 。
def test(**kwargs):
类似的, ** 就是针对关键字参数和字典的了,调用 test(a=1,b=2,c=3) 的话, kwargs 的值就是 {'a':1,'b':2,'c':3} 了。
"普通的参数定义和传递方式和 * 们都可以和平共处,不过显然 * 必须放在所有位置参数的最后,而 ** 则必须放在所有关键字参数的最后,否则就要产生歧义了。"
上面用引号括起来的话是摘抄作者的原文,但是我做了下实验,发现在调用时,*不一定要在位置参数后面,它可以在任意位置,只要传递参数不冲突,但是**的位置则有一定要求了,因为它必须按照关键字参数的要求传递,但是关键字参数和**的位置是可以随意的.
1 def fun(a,b,c,d,e,f,g,h,i,j):
2 print(a,b,c,d,e,f,g,h,i,j)
3 return
4 L = [8,8,8,8,8]
5 fun(1,2,3,*L,4,5) # 1 2 3 8 8 8 8 8 4 5
6 fun(1,2,3,*L,i=4,j=5) # 1 2 3 8 8 8 8 8 4 5
7 fun(1,2,3,i=4,j=5,*L) # 1 2 3 8 8 8 8 8 4 5
8 fun(*L,1,2,3,i=4,j=5) # 8 8 8 8 8 1 2 3 4 5
9
10 D = {'d':1,'f':2,'e':3}
11 fun(8,8,8,**D,g=10,h=10,j=10,i=10) # 8 8 8 1 3 2 10 10 10 10
12 fun(8,8,8,g=10,h=10,j=10,i=10,**D) # 8 8 8 1 3 2 10 10 10 10
在定义函数时:
函数定义时的各类参数顺序分析
如果不考虑*参数,则参数列表只能是:(p1,p2,d1=0,d2=0,**k),其中p,d代表非默认位置参数和默认位置参数.
考虑加上参数,则有以下几种可能
(,p1,p2,d1=0,d2=0,**k),此时四个位置参数p1,p2,d1,d2必须都作为位置参数传入,当然d1,d2可以不传
(p1,*l,p2,d1=0,d2=0,**k),此时p2,d1,d2必须用位置实参传递
(p1,p2,*l,d1=0,d2=0,**k),此时d1,d2需用位置实参传递
(p1,p2,d1=0,*l,d2=0,**k),此时d2需要用位置实参传递
(p1,p2,d1=0,d2=0,*l,**k),此时位置参数按顺序给p1,p2,d1,d2,有剩余的则给l
1 def f(*l,p1,p2,d1=0,d2=0,**k):
2 print(l,p1,p2,d1,d2,k)
3
4 f(1,2,3,p1=4,p2=5,d1=6,d2=7,kk=100) # (1, 2, 3) 4 5 6 7 {'kk': 100}
5
6 def f(p1,*l,p2,d1=0,d2=0,**k):
7 print(p1,l,p2,d1,d2,k)
8 f(1,2,3,p2=4,d1=5,d2=6,kk=100) # 1 (2, 3) 4 5 6 {'kk': 100}
9
10 def f(p1,p2,*l,d1=0,d2=0,**k):
11 print(p1,p2,l,d1,d2,k)
12 f(1,2,3,4,d1=5,d2=6,kk=100) # 1 2 (3, 4) 5 6 {'kk': 100}
13
14 def f(p1,p2,d1=0,*l,d2=0,**k):
15 print(p1,p2,d1,l,d2,k)
16 f(1,2,3,4,5,d2=6,kk=100) # 1 2 3 (4, 5) 6 {'kk': 100}
17 f(1,d1=2,p2=3,d2=6,kk=100) # 1 3 2 () 6 {'kk': 100}
18
19 def f(p1,p2,d1=0,d2=0,*l,**k):
20 print(p1,p2,d1,d2,l,k)
21 f(1,2,3,4,kk=100) # 1 2 3 4 () {'kk': 100}
22 f(1,2,3,4,5,kk=100) # 1 2 3 4 (5,) {'kk': 100}
以上实例说明,*参数后的所有位置参数(默认和非默认)必须一关键字实参形式传递,实际上解释器也把它们定义为keyword-only参数了.
实际使用中,很少会搞这么复杂,如果硬是要所有四种参数都有,则(p,*l,d=0,**k)和(p,d=0,l,**k)这两种是最清晰的,并且这两种中第一种可能更好用,因为可以同时利用好和默认参数的特性,第二种则不能同时有两种特性.
python中的*args和**kw
学习python装饰器decorator的时候遇到*args和**kw两种函数值传递。
在python中定义函数,可以使用一般参数、默认参数、非关键字参数和关键字参数。
一般参数和默认参数在前面的学习中我们都遇到过了,而*args和**kw分别属于非关键字参数和关键字参数,后两者也都是可变参数。
非关键字参数的特征是一个星号*加上参数名,比如*number,定义后,number可以接收任意数量的参数,并将它们储存在一个tuple中。
关键字参数的特征是两个星号**加上参数名,比如**kw, 定义后,kw将接收到的任意数量参数存到一个dict中。关键字参数是在传递构成中不必按照顺序传递(因为dict内的key-value是没有顺序的),但必须要提供”传递参数名=传递参数值”形式的参数。
如:
def try_it(*args, **kw):
print 'args:',args
print 'kw:',kw
try_it(1,2,3,4, a=1,b=2,c=3)
try_it('a', 1, None, a=1, b='2', c=3)
运行结果:
args: (1, 2, 3, 4)
kw: {'a': 1, 'c': 3, 'b': 2}
args: ('a', 1, None)
kw: {'a': 1,'b': '2','c': 3, }
python中的一般参数、默认参数、非关键字参数和关键字参数可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:一般参数、默认参数、可变参数和关键字参数,先后顺序不能颠倒。即:
def func(a, b, c=0, *args, **kw):
pass