Python `inspect.Signature` 将所有定义的位置参数显示为 `ParameterKind.POSITIONAL_OR_KEYWORD`

lur*_*her 4 reflection inspect python-3.x

我的印象是,您可以使用该inspect.Signature函数来检索和区分位置参数和关键字参数。然而,情况似乎并非如此:

def foo(a,b,c, t=3, q=5):
    print(a,b,c,t,q)

[(u, u.kind) for u in i.signature(foo).parameters.values()]

[(<Parameter "a">, <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>),
 (<Parameter "b">, <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>),
 (<Parameter "c">, <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>),
 (<Parameter "t=3">, <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>),
 (<Parameter "q=5">, <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>)]

Run Code Online (Sandbox Code Playgroud)

因此,事实上,该kind属性似乎对于区分位置参数和关键字参数毫无用处

所以这里的问题是:

我如何区分参数a,b,c和参数t,q,以便如果我要调用 foo:

  #build args from signature with args = [a,b,c]
  #build kwargs from signature with kwargs = {'t': t,'q': q}
  foo(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

Gre*_*ick 5

长话短说

\n

除非您将函数参数显式定义为 isPOSITIONAL_ONLYKEYWORD_ONLY使用以下语法,否则所有参数的默认行为均为POSITIONAL_OR_KEYWORD。Python 3.8+ 和以前版本的 Python 的行为之间存在差异。

\n

Python 3.8+

\n

/在 Python 3.8+ 中,可以分别使用和语法指定参数是仅位置参数还是仅关键字参数*。举个例子:

\n
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):\n      -----------    ----------     ----------\n      |              |              |\n      |              Positional or  |\n      |              keyword        Keyword only\n      Positional only\n
Run Code Online (Sandbox Code Playgroud)\n

之前的一切都/只是位置;之后的所有内容都*只是关键字。请注意,顺序问题 \xe2\x80\x93/必须位于 之前*。另外,如果您没有显式指定POSITIONAL_ONLYKEYWORD_ONLY使用此语法,则所有参数都默认POSITIONAL_OR_KEYWORD为该kind属性的值。

\n

这是由于 Python 3.8 中所做的更改所致。语法的行为在PEP 570/中指定(遵循PEP 457)。在代码中:

\n
>>> import inspect\n\n# Positional or keyword (default behavior)\n>>> def meow (a, b, c = 0, d = 1):\n...    return (a * b + c) * d\n\n>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}\n{\'a\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'b\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'c\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'d\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>}\n\n# Positional only, positional or keyword, keyword only\n>>> def meow (a, /, b, c = 0, *, d = 1):\n...    return (a * b + c) * d\n\n>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}\n{\'a\': <_ParameterKind.POSITIONAL_ONLY: 1>, \n \'b\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'c\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'d\': <_ParameterKind.KEYWORD_ONLY: 1>}\n
Run Code Online (Sandbox Code Playgroud)\n

Python 3.8 之前

\n

在 PEP 570 之前,该/语法不存在,但该*语法确实存在(引入时尚未能找到确切的 PEP);尝试/3.7 中的 会引发语法错误:

\n
# Python 3.7 - we get an error if use the `/` syntax\n>>> def meow (a, /, b, c = 0, *, d = 1):\n  File "<stdin>", line 1\n    def meow (a, /, b, c = 0, *, d = 1):\n\n# If we omit the `/` but keep the `*`, it works\n>>> def meow (a, b, c = 0, *, d = 1):\n...    return (a * b + c) * d\n\n>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}\n{\'a\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'b\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'c\': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>, \n \'d\': <_ParameterKind.KEYWORD_ONLY: 1>}\n
Run Code Online (Sandbox Code Playgroud)\n

除了 PEP 之外,我还发现这个快速总结有助于理解行为。

\n