原文链接

目录

  1. 位置参数与关键字参数

  2. 收集参数(args与*kwargs参数)

  3. 分配参数


1. 位置参数与关键字参数

参数的概念都是与函数息息相关的。其中def语句中,位于函数名后面的变量通常称为 形参 ,而调用函数时提供的值称为 实参
。一般情况下不对此进行严格区分。

在了解收集参数前(args与*kwargs参数)要知道位置参数与关键字参数的含义。位置参数就是根据位置,进行实参到形参的值传递匹配。如下:

  1. def hello(greeting, name):
  2. print('{},{}!'.format(greeting, name))
  3. >>>hello('Hello', 'World')
  4. Hello,world!

有时候,参数的排列顺序可能很难记住,尤其是参数很多的时候,为了简化调用工作,可指定参数的 名称 ,即将参数赋予关键字。如下:

  1. def hello(greeting, name):
  2. print('{},{}!'.format(greeting, name))
  3. >>>hello(greeting='Hello', name='World')
  4. Hello,world!
  5. >>>hello(name='World', greeting='Hello')
  6. Hello,world!

此时,参数的顺序无关紧要。像这样使用名称指定的参数称为关键字参数,主要有点是有助于澄清各个参数的作用。及时输入参数多些,每个参数的作用也很明确。另外,参数顺序错了也没关系。然而,关键字参数最大的优点在于,可以指定默认值。

  1. def hello(greeting='Hello', name='World'):
  2. print('{},{}!'.format(greeting, name))

像这样给参数指定默认值后,调用函数是可以不提供它!可以根据需求,一个参数值都不提供、提供部分参数值或者提供全部参数值。

2. 收集参数(args与*kwargs参数)

温馨提示argsarguments 的缩写,参数的意思; kwargskeywords
arguments
的缩写,关键字参数的意思。】

有时候,用户需要提供任意数量的参数。实际上,实现起来并不困难,仅需要像这样定义函数:

  1. def print_params(*arg):
  2. print(arg)

这里好像只指定了一个参数,但它的前面有一个星号。可以尝试调用一下,一探究竟。

  1. >>>print_params('Testing')
  2. ('Testing',)
  3. >>>print_params(1, 2, 3)
  4. (1, 2, 3)

不难发现,打印的是一个 元组
。也就是说,前面有星号的参数将被放在元组中,也就是将这些值收集起来。带星号的参数可以放在多个形参的后面(此时它收集其他形参没有收集的值),也可以放在前面或者中间,不过此时会麻烦点,如下:

  1. def in_the_middle(x, *y, z):
  2. print(x, y, z)
  3. >>>in_the_middle(1, 2, 3, 4, 5, 6, z=7)
  4. 1 (2, 3, 4, 5, 6) 7

可见,如果带星号形参放在前面或者中间,则它后面的参数则需要使用名称指定,类似关键字参数。

另外,单星号参数(*arg)是不会收集关键字参数的,要收集关键字参数,就要使用两个星号。

  1. def print_params_2(**kwargs):
  2. print(kwargs)
  3. >>>print_params_2(x=1, y=2, z=3)
  4. {'z':3, 'x:1, 'y':2}

可见,这样得到的是一个 字典 而不是元组。 讲这些参数形式结合:

  1. def print_params_3(x, y, z=3, *args, **kwargs):
  2. print(x, y, z)
  3. print(args)
  4. print(kwargs)
  5. >>>print_params_3(1, 2, 3, 4, 5, 6, 7, foo=1, bar=2)
  6. 1 2 3
  7. (5, 6, 7)
  8. {'foo':1, 'bar':2}
  9. >>>priint_param_3(1, 2)
  10. 1 2 3
  11. ()
  12. {}

3. 分配参数

前面介绍了如何将参数收集到元组或者字典中,但使用同样的两个运算符(和*)也可以执行相反的操作,即将参数分配传递给形参,恰好与收集实参传递的参数的操作相反。如下:

  1. def add(x, y):
  2. return x+y
  3. #同时假设存在一个元组,包含两个要加的数
  4. params = (1, 2)
  5. >>>add(*params)
  6. 3

这与前面执行的操作差不多是相反的:不是收集参数,而是 分配
参数。这是通过在调用函数(而不是定义函数)时实现的。这猴子那个做法也可以用于参数列表的一部分,条件是这部分位于参数列表末尾。通过使用**可将字典中的值分配给关键字参数。如下:

  1. def hello(greeting='Hello', name='World'):
  2. print('{},{}!'.format(greeting, name))
  3. params = {'name':'Song', 'greeting':'Well met'}
  4. >>>hello(**params)
  5. Well met,Song!

最后,给一个忠告,虽然星号和双星号*,既可以使用在定义函数又可以使用在调用函数时,但非常不建议同时使用。如果同时使用,将值传递元组或者字典。因此还不如不用它们,不用还能省去些许麻烦。

这篇文字,写给对python函数不熟悉的同学,也写给记性不好的自己。