Python 函数的位置参数(positional argument)和关键字参数(keyword argument)

在 Python 里,函数的参数默认是 positional-or-keyword,就是说即可以是位置参数,也可以是关键字参数。文档里是这样描述的:

positional-or-keyword: specifies an argument that can be passed either positionally or as a keyword argument. This is the default kind of parameter ..

比如:

>>> def f(a, b, c):
...     print('a={}, b={}, c={}'.format(a, b, c))
...
>>> f(1, 2, 3)
a=1, b=2, c=3
>>> f(a=1, c=3, b=2)
a=1, b=2, c=3
>>> f(1, c=3, b=2)
a=1, b=2, c=3

函数调用的时候,可以按位置参数直接调用,比如 f(1, 2, 3),也可以按(部分或者全部的)关键字参数调用,比如 f(1, c=3, b=2),这里顺序都可以随意指定,因为在理解上不存在歧义。

在其他语言里,参数类型和位置是需要明确的,至于参数名字,其实并不重要。但在 Python 里,既然可以是关键字参数,那参数名字就是属于函数定义的一部分。如果更改了函数参数的名字,那么已经实现的调用了这个函数的代码里,凡是用到关键字参数来调用的地方,都要相应地修改。

在 Python 3.8 里引入了这样的语法:

def f(a, b, /, c, d, *, e, f):
    print(a, b, c, d, e, f)

在这个函数里 :

  • 参数 a、b 是位置参数(positional-only);
  • 参数 c、d 可以是位置参数,也可以是关键字参数;
  • 参数 e、f 只能是关键字参数(keyword-only);

有了这样的语法后,函数在使用时会比较直接,跟其他语言里一致,比如文档里举的一个例子:

def divmod(a, b, /):
    "Emulate the built in divmod() function"
    return (a // b, a % b)

这里 a、b 只能按位置参数来使用,而不能用作关键字参数。那这种位置参数,参数名字就不再是函数的一部分了,以后即使参数名字修改了,已有代码也不用跟着调整,从而避免了关键字参数引入的问题。

再比如:

>>> help(len)
Help on built-in function len in module builtins:

len(obj, /)
    Return the number of items in a container.
>>>
>>> len(obj=range(10))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: len() takes no keyword arguments
>>>
>>> len(range(10))
10
>>>

这里也一样,obj 不能作为关键字参数来用。

参考资料

Read More: