Python

Python中的 *args 和 **kwargs

2020-08-05  本文已影响0人  西北小生_

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 相当于“*”作用在一个列表或元组前,可以去除其两边的括号。
如何区分什么时候是打包,什么时候是拆包呢?

如果一个变量首次出现,在其前面加了*或 **, 就表示是打包操作,符号*仅仅表示其后面的变量是一个列表或元组变量,可以装任意多个元素值。**表示其后面的变量是一个字典变量,可以装任意多个键值对。
如果已知一个变量是一个列表,元组或字典,在其前面加上*或 **就表示拆包操作,相当于将其两边的括号去掉。

同理,**是对字典的打包和拆包。

上一篇下一篇

猜你喜欢

热点阅读