简体   繁体   English

解包参数:只有命名参数可以跟*表达式

[英]Unpacking arguments: only named arguments may follow *expression

The following works beautifully in Python: 以下在Python中运行得非常好:

def f(x,y,z): return [x,y,z]

a=[1,2]

f(3,*a)

The elements of a get unpacked as if you had called it like f(3,1,2) and it returns [3,1,2] . 的元素a得到解压缩,如果你有一个像把它称为f(3,1,2)并返回[3,1,2] Wonderful! 精彩!

But I can't unpack the elements of a into the first two arguments: 但是我无法将a的元素解压缩到两个参数中:

f(*a,3)

Instead of calling that like f(1,2,3) , I get "SyntaxError: only named arguments may follow *expression". 我没有像f(1,2,3)那样调用它,而是“SyntaxError:只有命名参数才能跟*表达式”。

I'm just wondering why it has to be that way and if there's any clever trick I might not be aware of for unpacking arrays into arbitrary parts of argument lists without resorting to temporary variables. 我只是想知道为什么它必须是这样的,如果有任何聪明的技巧我可能不会意识到将数组解压缩到参数列表的任意部分而不诉诸临时变量。

As Raymond Hettinger's answer points out, this may change has changed in Python 3 and here is a related proposal , which has been accepted. 正如Raymond Hettinger的回答所指出的,这可能会在Python 3中发生变化, 这是一个相关的提案 ,已被接受。 Especially related to the current question, here's one of the possible changes to that proposal that was discussed: 特别是与当前问题有关,这是对该提案的可能变更之一:

Only allow a starred expression as the last item in the exprlist. 仅允许星号表达式作为exprlist中的最后一项。 This would simplify the unpacking code a bit and allow for the starred expression to be assigned an iterator. 这将简化解包代码并允许为星号表达式分配迭代器。 This behavior was rejected because it would be too surprising. 这种行为被拒绝了,因为它太令人惊讶了。

So there are implementation reasons for the restriction with unpacking function arguments but it is indeed a little surprising! 所以有解包函数参数限制的实现原因,但确实有点令人惊讶!

In the meantime, here's the workaround I was looking for, kind of obvious in retrospect: 与此同时,这是我正在寻找的解决方法,回顾过去有点明显:

f(*(a+[3]))

Thanks to the PEP 448 - Additional Unpacking Generalizations , 感谢PEP 448 - 附加拆包概括

f(*a, 3)

is now accepted syntax starting from Python 3.5 . 现在从Python 3.5开始接受的语法 Likewise you can use the double-star ** for keyword argument unpacking anywhere and either one can be used multiple times. 同样,您可以在任何地方使用双星**关键字参数解压缩,并且可以多次使用其中一个。

It doesn't have to be that way. 并不一定是这样的。 It was just rule that Guido found to be sensible. Guido认为合情合理。

In Python 3, the rules for unpacking have been liberalized somewhat: 在Python 3中,解包的规则已经有所自由:

>>> a, *b, c = range(10)
>>> a
0
>>> b
[1, 2, 3, 4, 5, 6, 7, 8]
>>> c
9

Depending on whether Guido feels it would improve the language, that liberalization could also be extended to function arguments. 根据Guido是否认为它会改善语言,自由化也可以扩展到功能论点。

See the discussion on extended iterable unpacking for some thoughts on why Python 3 changed the rules. 有关Python 3更改规则的原因的一些想法,请参阅有关扩展可迭代解包的讨论。

f is expecting 3 arguments ( x , y , z , in that order). f期望3个参数( xyz ,按此顺序)。

Suppose L = [1,2] . 假设L = [1,2] When you call f(3, *L) , what python does behind the scenes, is to call f(3, 1, 2) , without really knowing the length of L . 当你调用f(3, *L) ,python在幕后做的是调用f(3, 1, 2) ,而不知道L的长度。

So what happens if L was instead [1,2,3] ? 那么如果L代替[1,2,3]会发生什么?

Then, when you call f(3, *L) , you'll end up calling f(3,1,2,3) , which will be an error because f is expecting exactly 3 arguments and you gave it 4. 然后,当你调用f(3, *L) ,你最终会调用f(3,1,2,3) ,这将是一个错误,因为f期待正好3个参数,你给它4。

Now, suppose L=[1,2]1. Look at what happens when you call 现在,假设L=[1,2]1. Look at what happens when you call L=[1,2]1. Look at what happens when you call f`: L=[1,2]1. Look at what happens when you call f` L=[1,2]1. Look at what happens when you call

>>> f(3,*L) # works fine
>>> f(*L) # will give you an error when f(1,2) is called; insufficient arguments

Now, you implicitly know when you call f(*L, 3) that 3 will be assigned to z , but python doesn't know that. 现在,你隐含地知道你何时调用f(*L, 3)将3分配给z ,但是python不知道。 It only knows that the last j many elements of the input to f will be defined by the contents of L . 它只知道f的输入的最后j元素将由L的内容定义。 But since it doesn't know the value of len(L) , it can't make assumptions about whether f(*L,3) would have the correct number of arguments. 但由于它不知道len(L)的值,因此无法假设f(*L,3)是否具有正确数量的参数。

This however, is not the case with f(3,*L) . 然而,这不是f(3,*L) In this case, python knows that all the arguments EXCEPT the first one will be defined by the contents of L . 在这种情况下,python知道除了第一个参数之外的所有参数都将由L的内容定义。

But if you have named arguments f(x=1, y=2, z=3) , then the arguments being assigned to by name will be bound first. 但是如果你有参数f(x=1, y=2, z=3) ,则首先绑定按名称分配的参数。 Only then are the positional arguments bound. 只有这样才能限制位置参数。 So you do f(*L, z=3) . 所以你做f(*L, z=3) In that case, z is bound to 3 first, and then, the other values get bound. 在这种情况下, z首先绑定到3 ,然后绑定其他值。

Now interestingly, if you did f(*L, y=3) , that would give you an error for trying to assign to y twice (once with the keyword, once again with the positional) 现在有趣的是,如果你做f(*L, y=3) ,这会给你一个错误,试图分配给y两次(一次用关键字,再一次用位置)

Hope this helps 希望这可以帮助

Nice. 尼斯。 This also works for tuples. 这也适用于元组。 Don't forget the comma: 不要忘记逗号:

a = (1,2)
f(*(a+(3,)))

如果你使用f(*a, 3) ,你可以使用f(*a, z=3) ,它不知道如何解压缩参数,因为你提供了2个参数而2是第二个参数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM