[英]Semantics of tuple unpacking in python
Why does python only allow named arguments to follow a tuple unpacking expression in a function call? 为什么python只允许命名参数跟随函数调用中的元组解包表达式?
>>> def f(a,b,c):
... print a, b, c
...
>>> f(*(1,2),3)
File "<stdin>", line 1
SyntaxError: only named arguments may follow *expression
Is it simply an aesthetic choice, or are there cases where allowing this would lead to some ambiguities? 它只是一种美学选择,还是存在允许这会导致一些含糊不清的情况?
i am pretty sure that the reason people "naturally" don't like this is because it makes the meaning of later arguments ambiguous, depending on the length of the interpolated series: 我很确定人们“自然地”不喜欢这个的原因是因为它使得后面的参数的含义模糊不清,这取决于插值系列的长度:
def dangerbaby(a, b, *c):
hug(a)
kill(b)
>>> dangerbaby('puppy', 'bug')
killed bug
>>> cuddles = ['puppy']
>>> dangerbaby(*cuddles, 'bug')
killed bug
>>> cuddles.append('kitten')
>>> dangerbaby(*cuddles, 'bug')
killed kitten
you cannot tell from just looking at the last two calls to dangerbaby
which one works as expected and which one kills little kitten fluffykins. 你只能看看最近两次对
dangerbaby
调用,哪一个按预期工作,哪一个杀死小猫蓬松金属。
of course, some of this uncertainty is also present when interpolating at the end. 当然,在最后插值时也存在一些不确定性。 but the confusion is constrained to the interpolated sequence - it doesn't affect other arguments, like
bug
. 但混淆受限于插值序列 - 它不会影响其他参数,如
bug
。
[i made a quick search to see if i could find anything official. [我快速搜索,看看我是否能找到任何正式的东西。 it seems that the * prefix for varags was introduced in python 0.9.8 .
似乎varags的*前缀是在python 0.9.8中引入的 。 the previous syntax is discussed here and the rules for how it worked were rather complex.
这里讨论了以前的语法,它的工作原理相当复杂。 since the addition of extra arguments "had to" happen at the end when there was no * marker it seems like that simply carried over.
因为在没有*标记的情况下添加额外的参数“必须”发生在最后,似乎只是简单地延续了。 finally there's a mention here of a long discussion on argument lists that was not by email.]
最后在这里提到了一个关于参数列表的长时间讨论,而不是通过电子邮件。
I suspect that it's for consistency with the star notation in function definitions, which is after all the model for the star notation in function calls. 我怀疑这是为了与函数定义中的星号表示法保持一致,这是函数调用中星号表示法的所有模型。
In the following definition, the parameter *c
will slurp all subsequent non-keyword arguments, so obviously when f
is called, the only way to pass a value for d
will be as a keyword argument. 在下面的定义中,参数
*c
将会覆盖所有后续的非关键字参数,因此很明显,当调用f
时,传递d
值的唯一方法是作为关键字参数。
def f(a, b, *c, d=1):
print "slurped", len(c)
(Such "keyword-only parameters" are only supported in Python 3. In Python 2 there is no way to assign values after a starred argument, so the above is illegal.) (这种“唯一关键字参数”在Python 3只支持在Python 2 没有办法星号的参数后,分配值,所以上述是非法的。)
So, in a function definition the starred argument must follow all ordinary positional arguments. 因此,在函数定义中 ,加星标的参数必须遵循所有普通的位置参数。 What you observed is that the same rule has been extended to function calls.
您观察到的是,相同的规则已扩展到函数调用。 This way, the star syntax is consistent for function declarations and function calls.
这样,星形语法对于函数声明和函数调用是一致的。
Another parallelism is that you can only have one (single-)starred argument in a function call. 另一个并行性是在函数调用中只能有一个(单个)星号参数。 The following is illegal, though one could easily imagine it being allowed.
以下是非法的,但很容易想象它被允许。
f(*(1,2), *(3,4))
First of all, it is simple to provide a very similar interface yourself using a wrapper function: 首先,使用包装函数自己提供一个非常相似的界面很简单:
def applylast(func, arglist, *literalargs):
return func(*(literalargs + arglist))
applylast(f, (1, 2), 3) # equivalent to f(3, 1, 2)
Secondly, enhancing the interpreter to support your syntax natively might add overhead to the very performance-critical activity of function application. 其次,增强解释器以原生支持您的语法可能会增加功能应用程序的性能关键活动的开销。 Even if it only requires a few extra instructions in compiled code, due to the high usage of those routines, that might constitute an unacceptable performance penalty in exchange for a feature that is not called for all that often and easily accommodated in a user library.
即使它只需要编译代码中的一些额外指令,由于这些例程的高使用率,这可能构成不可接受的性能损失,以换取未被通用且容易地容纳在用户库中的所有特征调用的特征。
Some observations: 一些观察:
f(c=3, *(1, 2))
in your example still prints 1 2 3
). f(c=3, *(1, 2))
在您的示例中仍然打印1 2 3
)。 This makes sense as (i) most arguments in function calls are positional and (ii) the semantics of a programming language need to be unambiguous (ie, a choice needs to be made either way on the order in which to process positional and keyword arguments). f(*(1, 2), 3)
, should that be f(1, 2, 3)
or f(3, 1, 2)
and why would either choice make more sense than the other? f(*(1, 2), 3)
,那应该是f(1, 2, 3)
还是f(3, 1, 2)
,为什么这两种选择比另一种更有意义呢? def g(a, b, *c, d)
. def g(a, b, *c, d)
。 There's no way to provide a value for d
other than as a keyword argument (positional arguments would be 'grabbed' by c
). d
提供值(位置参数将由c
“抓取”)。 change the order: 改变顺序:
def f(c,a,b):
print(a,b,c)
f(3,*(1,2))
If you have a Python 3 keyword-only parameter, like 如果你有一个Python 3关键字参数,比如
def f(*a, b=1):
...
then you might expect something like f(*(1, 2), 3)
to set a
to (1 , 2)
and b
to 3
, but of course, even if the syntax you want were allowed, it would not, because keyword-only parameters must be keyword-only, like f(*(1, 2), b=3)
. 那么你可能期望像
f(*(1, 2), 3)
这样设置a
到(1 , 2)
和b
到3
,但是当然,即使你想要的语法被允许,它也不会,因为关键字-only参数必须是仅关键字,如f(*(1, 2), b=3)
。 If it were allowed, I suppose it would have to set a
to (1, 2, 3)
and leave b
as the default 1
. 如果允许,我想它会设置
a
到(1, 2, 3)
并留下b
作为默认1
。 So it's perhaps not syntactic ambiguity so much as ambiguity in what is expected, which is something Python greatly tries to avoid. 因此,它可能不是语法上的模糊性,而是预期的模糊性,这是Python极大地试图避免的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.