Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Semantics of tuple unpacking in python

Why does python only allow named arguments to follow a tuple unpacking expression in a function call?

>>> 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?

like image 900
user545424 Avatar asked May 23 '12 17:05

user545424


People also ask

What is tuple unpacking in Python?

Python offers a very powerful tuple assignment tool that maps right hand side arguments into left hand side arguments. THis act of mapping together is known as unpacking of a tuple of values into a norml variable. WHereas in packing, we put values into a regular tuple by means of regular assignment.

Is unpacking possible in a tuple?

Unpacking a Tuple Note: The number of variables must match the number of values in the tuple, if not, you must use an asterisk to collect the remaining values as a list.

What do you mean by packing and unpacking a tuple give example?

Tuple packing refers to assigning multiple values into a tuple. Tuple unpacking refers to assigning a tuple into multiple variables. You have already used tuple packing because it is as simple as: >>> django_movie = ("Tarantino", 2012, 8.4, "Waltz & DiCaprio")

Does tuple unpacking work with lists?

In Python, unpacking is not limited to tuples only. You can unpack a list or a string with the same syntax. Unpacking is more commonly known as multiple assignment, as it reminds of assigning multiple variables on the same line.


2 Answers

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.

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.

[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. 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.]

like image 180
andrew cooke Avatar answered Oct 18 '22 18:10

andrew cooke


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.

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.)

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)) 
like image 38
alexis Avatar answered Oct 18 '22 19:10

alexis