我们在使用调用 python API 的时候,经常能够看见在参数列表的最后有两个“奇怪”的参数*args, **kwargs。首先要明白,其实并不是必须写成*args**kwargs。只有变量前面的***才是必须的。这两个参数的用法就是 python 中的不定长参数[当然了,大多数语言都支持不定长参数]。

不定长参数有广泛的使用场景,比如,要求定义函数,求任意数字的和。如果只是定义固定的参数列表,那么永远也无法达成目标[比如下面的代码,就无法处理三个及更多的数的和]。

def sum(a, b):
    print(a + b)

要实现这个函数,需要使用不定长参数。在定义函数列表时,在形参前面加上一个*,则这个形参将会获得所有的实参[比如下面的代码]。

def sum(*args):
    print("args = ",args,type(a))

sum(1,2,3)
# printout: args = (1, 2, 3) <class 'tuple'>

从打印结果能看出来,不定长参数能接受所有的位置参数,因为其本质就是将所有的位置参数打包成一个 tuple

使用*args有些注意事项:

  1. 一个函数的形参列表中最多只能有一个*args
  2. *args和其他参数配合并且没有写到最后时,*args会接收所有的位置参数,直到一个关键字参数为止。
  3. fn(*,a,b,c)是要求该函数的所有形参,必须使用关键字方式传递。

说完了*args可以接受所有的位置参数,那么关键字参数呢,这就是**kwwags的作用。

def fn(**kwargs):
    print('a =',a,type(a))

fn(a=1,b=2,c=3)
# printout: a={'a':1, 'b':2, 'c'=:3} <class 'dict'>

这里的**kwargs就是将所有的位置参数和关键字参数打包成一个dict,然后可以像访问 dict 一样访问这些参数。

那么这两种参数同时使用的目的就很清楚了,也就是我们在各种 API 中常见到的(..., *args, **kwargs),这么做的目的就是同时接受不定长的位置参数和关键字参数,比如下面的代码。

def fn(*args, **kwargs):
    print('args=', args)
    print('kwargs=', kwargs)

fn(1,2,3,4,A='a',B='b',C='c',D='d')
# printout:
# args= (1, 2, 3, 4)
# kwargs= {'A': 'a', 'B': 'b', 'C': 'c', 'D': 'd'}