7. *args和**kwargs

7.1. *args

*args 用来将 不定数量 的参数打包成 tuple 给函数体使用。

例一:

1def foo(x, *args):
2  print "x:", x
3  for k in range(len(args)):
4    print "args[{}]:".format(k), args[k]
 1>>> foo(1, 100, '200k', 300)
 2x: 1
 3args[0]: 100
 4args[1]: 200k
 5args[2]: 300
 6
 7>>> args = [1,2,'abc']
 8>>> foo('A', *args)
 9x: A
10args[0]: 1
11args[1]: 2
12args[2]: abc
13
14>>> foo('A', args) ## 注:此时把args当做一个参数,参数类型为列表
15x: A
16args[0]: [1, 2, 'abc']

例二:

1def foo(x, var1, var2, var3):
2  print "x:", x
3  print "var1:", var1
4  print "var2:", var2
5  print "var3:", var3
 1>>> args = [1,2,'A'] # list
 2>>> foo(1, args)
 3TypeError: foo() takes exactly 4 arguments (2 given)
 4>>> foo(1, *args)
 5x: 1
 6var1: 1
 7var2: 2
 8var3: A
 9
10>>> args = (1,2,'A') # tuple
11>>> foo(1, args)
12TypeError: foo() takes exactly 4 arguments (2 given)
13>>> foo(1, *args)
14x: 1
15var1: 1
16var2: 2
17var3: A

7.2. **kwargs

**kwargs 打包 不定数量 的键值对参数成 dict 给函数体使用。

例一:

1def foo(**kwargs):
2  for key, val in kwargs.items():
3    print "{} : {}".format(key, val)
1>>> foo(var1=1, var2='a', var3=[1,2,3])
2var1 : 1
3var3 : [1, 2, 3]
4var2 : a

例二:

1def foo(x, var1=2, var2='a'):
2  print "x:", x
3  print "var1:", var1
4  print "var2:", var2
 1>>> dict_input = {"var1": 10, "var2": "A"}
 2>>> foo(1, dict_input)
 3x: 1
 4var1: {'var1': 10, 'var2': 'A'}
 5var2: a
 6
 7>>> foo(1, **dict_input)
 8x: 1
 9var1: 10
10var2: A

7.3. arg,*args,**kwargs

位置参数、*args、**kwargs三者的顺序必须是(arg,*args,**kwargs)。

1def foo(arg, *args, **kwargs):
2  print "arg:", arg
3  print "args:", args
4  print "kwargs:", kwargs
1>>> foo(1, 2, 3, 4, x=1, y='b')
2arg: 1
3args: (2, 3, 4)
4kwargs: {'y': 'b', 'x': 1}
5
6>>> foo(1, x=1, y='b', 2, 3, 4)
7SyntaxError: non-keyword arg after keyword arg

位置参数、默认参数、**kwargs三者的顺序必须是(位置参数,默认参数,**kwargs)。

1def foo(x, y=1, **kwargs): ## 不能出现 (x=1,y,**kwargs)
2  print "x:", x
3  print "y:", y
4  print "kwargs:", kwargs
1>>> foo(4, var1=1, var2='b')
2x: 4
3y: 1
4kwargs: {'var1': 1, 'var2': 'b'}

7.4. 仅限位置参数

在函数定义中, / 表示在它之前的形参是仅限位置形参(Positional-Only Argument),仅限位置形参没有外部可用的名称。 在调用接受仅限位置形参的函数时,参数只会基于它们的位置被映射到形参。 在 / 之后的参数可以是位置参数,也可以是键值对参数。

 1>>> def foo(a, /, b):
 2...     print(a, b)
 3...
 4>>> foo(1, 3)
 51 3
 6>>> foo(1, b=3)
 71 3
 8>>> foo(a=1, b=3)
 9Traceback (most recent call last):
10  File "<stdin>", line 1, in <module>
11TypeError: foo() got some positional-only arguments passed as keyword arguments: 'a'
12
13>>> def foo(a, b):
14...     print(a, b)
15...
16>>> foo(1, 2)
171 2
18>>> foo(a=1, b=2)
191 2

7.5. 命名关键字参数

Python3 的命名关键字参数(Keyword-Only Argument),以独立的 * 为标记,强制用户在调用函数的时候必须写出 * 之后的参数名。

 1>>> def foo(a, *, b=0, c):
 2...     print(a, b, c)
 3...
 4>>> foo(1,2,3)
 5Traceback (most recent call last):
 6  File "<stdin>", line 1, in <module>
 7TypeError: foo() takes 1 positional argument but 3 were given
 8>>> foo(1,c=2,b=3)
 91 3 2
10>>> foo(1, c=2)
111 0 2
12>>> foo(1, b=2)
13Traceback (most recent call last):
14  File "<stdin>", line 1, in <module>
15TypeError: foo() missing 1 required keyword-only argument: 'c'

7.6. 默认参数与可变类型

默认参数是在函数定义的时候就被计算的,默认参数值存储在函数的 __defaults__ 属性中,每次调用函数都是从这个属性中读取默认参数值。

当默认参数值是可变类型的时候,这个默认值可能会因为函数调用而改变。

 1>>> def foo(n, l=[]):
 2...     l.append(n)
 3...     return l
 4...
 5>>> foo.__defaults__
 6([],)
 7>>> foo(1)
 8[1]
 9>>> foo(2)
10[1, 2]
11>>> foo.__defaults__
12([1, 2],)

为了避免这种预期之外的结果,可以使用 None 作为默认参数值,在函数体中增加一个判断。

 1>>> def bar(n, l=None):
 2...     if l is None: l = []
 3...     l.append(n)
 4...     return l
 5...
 6>>> bar.__defaults__
 7(None,)
 8>>> bar(1)
 9[1]
10>>> bar(2)
11[2]
12>>> bar.__defaults__
13(None,)

7.7. 参考资料

  1. 大话Python中*args和**kargs的使用

  1. python函数——形参中的:*args和**kwargs

  1. 函数的参数