Python `inspect.Signature` 将所有定义的位置参数显示为 `ParameterKind.POSITIONAL_OR_KEYWORD`
Python `inspect.Signature` shows all defined positional arguments as `ParameterKind.POSITIONAL_OR_KEYWORD`
我的印象是您可以使用 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>)]
因此,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)
TL;DR
除非您使用以下语法将函数参数显式定义为 POSITIONAL_ONLY
或 KEYWORD_ONLY
,否则所有参数的默认行为都是 POSITIONAL_OR_KEYWORD
。 Python 3.8+ 的行为与 Python.
的早期版本之间存在差异
Python 3.8+
在 Python 3.8+ 中,参数是仅位置参数还是仅关键字参数可以分别使用 /
和 *
语法指定。例如:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or |
| keyword Keyword only
Positional only
/
之前的所有内容都只是位置; *
之后的所有内容都只是关键字。请注意顺序很重要——/
必须在 *
之前。此外,如果您没有通过语法明确指定位置或关键字,则所有参数都是位置或关键字 kind
。
这是由于 Python 3.8 中所做的更改所致。 /
语法的行为在 PEP 570 (following PEP 457 中指定)。在代码中:
>>> import inspect
# Positional or keyword (default behavior)
>>> def meow (a, b, c = 0, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>}
# Positional only, positional or keyword, keyword only
>>> def meow (a, /, b, c = 0, *, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_ONLY: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.KEYWORD_ONLY: 1>}
之前 Python 3.8
在 PEP 570 之前,/
语法不存在,但 *
语法存在(引入时无法找到确切的 PEP);在 3.7 中尝试 /
会引发语法错误:
#Python 3.7
>>> def meow (a, /, b, c = 0, *, d = 1):
File "<stdin>", line 1
def meow (a, /, b, c = 0, *, d = 1):
# If we just omit the `/` and keep the `*`, it works
>>> def meow (a, b, c = 0, *, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.KEYWORD_ONLY: 1>}
除了 PEP,我还发现 quick summary 有助于理解行为。
我的印象是您可以使用 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>)]
因此,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)
TL;DR
除非您使用以下语法将函数参数显式定义为 POSITIONAL_ONLY
或 KEYWORD_ONLY
,否则所有参数的默认行为都是 POSITIONAL_OR_KEYWORD
。 Python 3.8+ 的行为与 Python.
Python 3.8+
在 Python 3.8+ 中,参数是仅位置参数还是仅关键字参数可以分别使用 /
和 *
语法指定。例如:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or |
| keyword Keyword only
Positional only
/
之前的所有内容都只是位置; *
之后的所有内容都只是关键字。请注意顺序很重要——/
必须在 *
之前。此外,如果您没有通过语法明确指定位置或关键字,则所有参数都是位置或关键字 kind
。
这是由于 Python 3.8 中所做的更改所致。 /
语法的行为在 PEP 570 (following PEP 457 中指定)。在代码中:
>>> import inspect
# Positional or keyword (default behavior)
>>> def meow (a, b, c = 0, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>}
# Positional only, positional or keyword, keyword only
>>> def meow (a, /, b, c = 0, *, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_ONLY: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.KEYWORD_ONLY: 1>}
之前 Python 3.8
在 PEP 570 之前,/
语法不存在,但 *
语法存在(引入时无法找到确切的 PEP);在 3.7 中尝试 /
会引发语法错误:
#Python 3.7
>>> def meow (a, /, b, c = 0, *, d = 1):
File "<stdin>", line 1
def meow (a, /, b, c = 0, *, d = 1):
# If we just omit the `/` and keep the `*`, it works
>>> def meow (a, b, c = 0, *, d = 1):
... return (a * b + c) * d
>>> {p.name: p.kind for p in inspect.signature(meow).parameters.values()}
{'a': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'b': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'c': <_ParameterKind.POSITIONAL_OR_KEYWORD: 1>,
'd': <_ParameterKind.KEYWORD_ONLY: 1>}
除了 PEP,我还发现 quick summary 有助于理解行为。