Python 可变长度参数介绍(*args 和 **kwargs)
我们经常在开源的一些Python代码中看到 *args
和 **kwargs
这样函数参数定义, 到底他们是含义? 又如何使用呢?
在回答这个问题前,我们先来介绍下, Python 参数传递的方式.
函数定义中的 *args
和 **kwargs
在Python中,参数总是通过赋值传递的, 俗称值传递, 在默认情况下, 参数是通过其位置进行匹配的, 但是Python也是支持关键字的参数匹配形式的.
按位置进行匹配
这是Python的默认行为,通过其位置进行匹配, 从左到右,必须精确的传递和函数头部参数名一样多的参数。这种方式我们平常用的最多,比如:
def foo(a, b, c):
print(a, b, c)
foo(1, 2, 3)
按关键字进行匹配
按关键字进行参数匹配,在调用函数的时候,能够更加详尽的定义内容传递的位置。关键字参数允许通过变量名进行匹配,而不是通过位置。
def foo(a, b, c):
print(a, b, c)
foo(a=1, b=2, c=3)
从调用方式,我们可以看到, 以关键字参数使用时,参数从左至右的顺序已经不重要了.因为参数是通过变量名进行传递的,而不是通过其位置.
这种方式使用起来更直观,代码阅读更加清晰.
当然完全可以将基于位置和基于关键字的参数同时使用,这时,所有基于位置的参数从左至右的顺序匹配头部参数,接着按变量名进行关键字匹配.
def foo(a, b, c):
print(a, b, c)
foo(1, c=3, b=2)
参数默认值
上述提到了Python 参数的匹配模式, 我们继续介绍下, Python 默认参数. 默认参数允许函数定义可选参数.如果没有传入值的话,在函数运行前,可选参数赋予默认值.
def foo(a, b=2, c=3):
print(a, b, c)
foo(1)
foo(a=1)
foo(a=1,b=4,c=5)
foo(a=1, c=5)
因为参数 a
我们没有定义默认值,所以参数 a
我们必须赋值, 而我们不给 b
和 c
赋值,则默认将 2
赋给 b
, 3
赋给 c
.
而当我们三个参数同时赋值时,将不再使用默认值.
而关键字参数允许我们跳过有默认值的参数,比如 foo(a=1, c=5)
我们这里就跳过 b
的赋值, b
被赋予了默认值 2
.
好了到这里我们就可以介绍我们关注的 *
和 **
修饰的函数参数了.
*
和 **
表示任意数量的函数参数收集.
*args
*
是以元组的形式收集不匹配的位置参数, 当函数调用时, python将所有为匹配的位置相关的参数收集到一个元祖中, 并将这个元祖赋值给变量args.
def foo(a, *args):
print(args)
foo(1,2,3,4)
**kwargs
**
仅对关键字生效, **
将未匹配的关键字转换为字典,并赋值给kwargs.
def foo(a, **kwargs)
print(kwargs)
foo(a=1, b=2, c=3)
函数调用中的 *args
和 **kwargs
基本上, 我们就介绍清楚了, 函数定义过程的中 *
和 **
功能和区别. 相反, 如果我们在函数调用过程使用 *
和 **
意味着什么呢?
*args
我们在调用函数的过程中使用 *args
语法,在这种情况下, 它和函数定义的意义正好相反, 用于解包参数的元祖, 而不是在函数定义环节的创建元祖.
def foo(a, b, c, d):
print(a, b, c, d)
args = (1, 2, 3, 4)
foo(*args)
**kwargs
同样对于调用过程中的 **kwargs
, 会以键/值对的形式解包一个字典.
def foo(a, b, c, d):
print(a, b, c, d)
kwargs = {'a':1, 'b':2, 'c':3, 'd':4}
foo(**kwargs)
到这里, 我们就介绍完了, *args
和 **kwargs
的功能和使用场景.实际使用过程中,可能会碰到混合使用的情况, 尝试下去吧^_^
def foo(a, b, *args, **kwargs):
print(a, b, args, kwargs)
args=(2, 3)
kwargs = {'d':4}
foo(1, *args, **kwargs)