1.args 和 kwargs的含义
*args 和 **kwargs经常出现在函数定义中,如:
def fun(*args, **kwargs):
pass
其中args是参数的英文arguments的缩写,在这里表示位置参数(position arguments)。
kwargs是英文keyword arguments的缩写,即关键字参数。
2.什么是位置参数和关键字参数?
# 函数定义
def fun(a, b, c=0, d=1):
pass
# 函数使用
# (1)位置参数
fun(1, 2, 3, 4)
# (2)关键字参数
fun(b=2, c=3, a=1, d=4)
# (3)位置参数和关键字参数混合
fun(1, 2, d=5)
在使用函数时,我们需要进行参数传递,这时有三种情况:
(1)按参数定义时的位置顺序依次进行传递,如 fun(1,2,3,4),此时a=1, b=2, c=3, d=4。
(2)按参数名(关键字)对其赋值进行参数传递,如 fun(a=1,d=4,c=3,b=2).
(3)位置和关键字混合传递,如 fun(1,2,d=4),这里的1,2就是位置参数,d=4就是关键字参数。
3.*args 和 **kwargs:
函数中同时出现*args 和 *kwargs时,args 位置必须在 **kwargs前面,这是Python语法规定的位置参数必须在关键字参数前面。
# 定义函数
In [24]: def fun(*args, **kwargs):
...: print('args:', args)
...: print('kwargs:', kwargs)
...:
# 使用函数
In [25]: fun(1,2,3,d=4,e=5)
args: (1, 2, 3)
kwargs: {'d': 4, 'e': 5}
从上例中可以看出:*args将会接收函数传入的位置参数,并将其装进一个元组里面赋值给变量args, **kwargs将会接收函数传入的关键字参数,并将其装进一个字典里赋值给变量kwargs。
4.这里的*和**是什么操作?
先上结论:
在声明时,*是对元组或列表的打包操作,将传入的一个或多个值打包成一个元组或列表,并赋值给符号*后面的变量。
在使用时,*是对元组或列表的拆包操作,将符号*后面的元组或列表拆分成多个元素。
同样的,**是对字典的相应打包和拆包操作。
如下例:
打包:
In [28]: (a,b,*c)=1,2,3,4,5,6
In [29]: print(a,b,c)
1 2 [3, 4, 5, 6]
在上例中,第一句表示将括号右边的第一个数赋值给变量a, 第二个数赋值给变量b,后面无论有多少个数,都赋值给变量c。这里的a,b,c均是首次在程序中出现,表示变量的声明和初始化。而变量c前面加了一个*号表示c是一个列表或元组,这样就可以装下多个值。
在第二行我们输出3个变量a,b,c,可以看出,变量c确实是个列表,它将第三个数及其后面的所有值都打包成一个列表,赋值给了c.
拆包:
In [35]: def fun(a,b,c,d):
...: print(a,b,c,d)
...:
In [36]: inp = [1,2,3,4]
In [37]: fun(inp)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-37-e8e9c29393b7> in <module>
----> 1 fun(inp)
TypeError: fun() missing 3 required positional arguments: 'b', 'c', and 'd'
In [38]: fun(*inp)
1 2 3 4
上例中我们定义的函数fun需要4个参数,inp是一个包含4个元素的列表,如果直接将这个列表传递给函数fun ,会出现报错。但是如果在其前面加上一个*号就不报错了,这是为什么呢?
这里的“*”是拆包操作,它作用在一个列表或元组变量前面,表示将其拆分成一个个元素。 即*[1,2,3,4] = 1,2,3,4 相当于“*”作用在一个列表或元组前,可以去除其两边的括号。
如何区分什么时候是打包,什么时候是拆包呢?
如果一个变量首次出现,在其前面加了*或 **, 就表示是打包操作,符号*仅仅表示其后面的变量是一个列表或元组变量,可以装任意多个元素值。**表示其后面的变量是一个字典变量,可以装任意多个键值对。
如果已知一个变量是一个列表,元组或字典,在其前面加上*或 **就表示拆包操作,相当于将其两边的括号去掉。
同理,**是对字典的打包和拆包。
网友评论