Python检查模块:仅限关键字参数

14
在Python中,“keyword only args”这个短语有点模棱两可 - 通常我认为它指的是传递给 **kwarg 参数的args。但是,inspect模块似乎区分**kwarg和称为“仅限关键字参数”的内容。
文档中可以看到:
inspect.getfullargspec(func)
获取Python函数参数的名称和默认值。返回一个namedtuple:
FullArgSpec(args,varargs,varkw,defaults,kwonlyargs,kwonlydefaults,annotations)
args是参数名称列表。 varargs和varkw是 * ** 参数的名称或None。defaults是最后n个参数的默认值的n元组,如果没有默认参数,则为None。kwonlyargs是关键字仅参数名称的列表。kwonlydefaults是将名称从kwonlyargs映射到默认值的字典。annotations是将参数名称映射到注释的字典。

因此,inspect模块有一个称为kwonlyargskwonlydefaults的东西。在实际函数签名中,这意味着什么?如果您有一个接受**kwarg参数的函数签名,您无法真正知道关键字参数的名称,直到运行时,因为调用者基本上可以传递任意字典。那么,在函数签名的上下文中,kwonlyargs有什么含义-这是inspect.getfullargspec提供的内容。

1个回答

18

TL;DR: 关键字参数和普通关键字参数不同。


关键字参数是在函数调用时在*args之后和**kwargs之前的参数。例如,考虑这个通用函数的头部:

def func(arg, *args, kwonly, **kwargs):

在上面的代码中,kwonly 接受一个关键字参数。这意味着在给它赋值时必须提供参数的名称。换句话说,你必须明确地编写:
func(..., kwonly=value, ...)

不仅传递值:

func(..., value, ...)

为了更好地解释,考虑上述函数的示例调用:
func(1, 2, kwonly=3, kw=4)

当Python解释这个调用时,它将会:
  • Assign arg to 1 because its position in the function signature matches the position of 1 in the call.

  • Place 2 in *args because *args collects any extra positional arguments and 2 is extra.

  • Assign kwonly to 3 because we have (as is necessary) explicitly told it to. Note that if we had done this instead:

    func(1, 2, 3, kw=4)
    

    3 would also be placed in *args and a TypeError would be raised for not supplying an argument to kwonly (since we did not give it a default value in this case).

  • Place kw=4 in **kwargs because it is an extra keyword argument, which are collected by **kwargs.

以下是我之前所述的演示内容:
>>> def func(arg, *args, kwonly, **kwargs):
...     print('arg:', arg)
...     print('args:', args)
...     print('kwonly:', kwonly)
...     print('kwargs:', kwargs)
...
>>> func(1, 2, kwonly=3, kw=4)
arg: 1
args: (2,)
kwonly: 3
kwargs: {'kw': 4}
>>>
>>> func(1, 2, 3, kw=4)  # Should have written: 'kwonly=3'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() missing 1 required keyword-only argument: 'kwonly'
>>>

基本上,你可以将关键字参数看作必须提供参数名称才能为其赋值的关键字参数。与普通关键字参数不同,位置值是不够的。
>>> def func(kw=None):
...     print('kw:', kw)
...
>>> func(kw=1)
kw: 1
>>> func(1)  # Do not need the name in this case.
kw: 1
>>>
>>> def func(*, kwonly=None):
...     print('kwonly:', kwonly)
...
>>> func(kwonly=1)
kwonly: 1
>>> func(1)  # Always need the name with keyword-only arguments.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: func() takes 0 positional arguments but 1 was given
>>>

最后,我知道有些人会问“为什么需要关键字只限参数?”答案很简单,它们在某些情况下使事情更易读(特别是对于采用可变数量参数的函数)。

举个例子,考虑内置的max函数及其关键字-only key参数。哪种方式更易读?像这样做:

max(lambda x: -x, arg1, arg2, arg3)

让人们记住max函数的第一个参数始终是键函数,可以这样做:

max(arg1, arg2, arg3, key=lambda x: -x)

并向所有人明确表明lambda x: -x是您的关键函数。此外,将key设置为关键字参数可以使您在不需要该参数的情况下简单地省略关键函数:
max(arg1, arg2, arg3)

不要做:

max(None, arg1, arg2, arg3)

如需更多信息,请查看以下来源:


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接