示例:
def foo(a, b=2, *args, **kwargs): pass
为什么这不会导致SyntaxError? * args不会捕获其他非关键字参数,因为在关键字参数之后传递它们是非法的。
对于python3.x,* args,** kwargs在这种情况下的正确用法如下所示:
def foo(a, *args, b=2, **kwargs): pass
感谢您对这种奇怪行为的任何见识。
编辑:
感谢Jab向我指出PEP 3102,它简要地解释了此行为。看看吧!
还要感谢jsbueno的出色解释,由于其详尽性,我将其更新为最佳答案。
答案 0 :(得分:3)
由于多种原因,它已在3.X中实现。我可以询问的最佳方法是
PEP 3102
还请查看Python 3.0.1文档中的New Syntax部分。
TLDR:
命名参数出现在 参数列表中的* args必须在调用中使用关键字语法指定。您也可以在参数列表中使用裸露的*表示 您不接受变长参数列表,但是您确实有 仅关键字的参数。
答案 1 :(得分:1)
给出:
def foo(a, b=2, *args, **kwargs): pass
b
不是仅用于关键字的参数-它只是一个参数,其参数可以是位置或名称,但具有默认值。无法将任何值传递给args
并忽略您建议的签名中传递b
或不按顺序传递b
的情况。
该签名是有意义的,并且非常明确-您可以从0到n个位置参数传递,但是如果您传递2个或更多,则第二个参数将分配给“ b”,并结束故事。
如果您传递0个位置参数,您仍然可以将值分配给“ a”或“ b”作为命名参数,但是尝试尝试类似以下操作:foo(0, 1, 2, a=3, b=4)
将失败,因为尝试将多个值传递给两个参数。
位置:
def foo(a, *args, b=2, **kwargs): pass
这也是一个明确的情况:第一个位置参数转到“ a”,其他位置参数转到“ args”,并且您只能将值作为命名参数传递给“ b”。
Python 3.8随附的签名定义中新的/
语法为此提供了更大的灵活性,允许人们要求将“ a”和“ b”作为仅位置参数传递。同样,没有歧义:
def foo(a, b=2, /, *args, **kwargs): pass
对此新语法感到奇怪:允许将命名参数传递给“ a”和“ b”,但是命名参数将作为“ kwargs”中的键/值对出现-而局部变量“ a”和“ b”将被分配唯一的位置参数:
def foo(a, b=2, /, *args, **kwargs):
print(a, b, args, kwargs)
...
In [9]: foo(1, 2, a=3, b=4)
1 2 () {'a': 3, 'b': 4}
使用传统语法时,您会询问-def foo(a, b=2, *args, **kwargs):
-如果尝试过,则会出现TypeError:
In [11]: foo(1,2, a=3, b=4)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-11-d002c7717dba> in <module>
----> 1 foo(1,2, a=3, b=4)
TypeError: foo() got multiple values for argument 'a'