28

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?

user545424
  • 15,713
  • 11
  • 56
  • 70
  • 1
    You can add the last argument to the tuple before unpacking. – JBernardo May 23 '12 at 18:02
  • 2
    An interesting question. I seem to remember the rules changed around python 2.5 - you used to *have* to put the `*args` and `**kwargs` at the end but I can't find the changelog entry. – Nick Craig-Wood May 23 '12 at 18:12

6 Answers6

31

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

andrew cooke
  • 45,717
  • 10
  • 93
  • 143
6

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))
alexis
  • 48,685
  • 16
  • 101
  • 161
1

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.

wberry
  • 18,519
  • 8
  • 53
  • 85
1

Some observations:

  1. Python processes positional arguments before keyword arguments (f(c=3, *(1, 2)) in your example still prints 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 (i.e., a choice needs to be made either way on the order in which to process positional and keyword arguments).
  2. If we did have a positional argument to the right in a function call, it would be difficult to define what that means. If we call 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?
  3. For an official explanation, PEP 3102 provides a lot of insight on how function definitions work. The star (*) in a function definition indicates the end of position arguments (section Specification). To see why, consider: 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).
  4. It's important to realize what this means: as the star marks the end of positional arguments, that means all positional arguments must be in that position or to the left of it.
Simeon Visser
  • 118,920
  • 18
  • 185
  • 180
0

change the order:

def f(c,a,b):
    print(a,b,c)
f(3,*(1,2))
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • well it's a rule that the arguments should follow this order : `(args,name=args,*args,**args)` – Ashwini Chaudhary May 23 '12 at 18:05
  • 6
    Yes, but ***why*** is it a rule? – Ignacio Vazquez-Abrams May 23 '12 at 18:07
  • 6
    Because if you could do things in any order, then it would be hard to follow code as people write things any which way, and then you may as well not be using Python. In other words, because Guido says so, that's why :) – Karmel May 23 '12 at 18:35
  • @Karmel, I'm curious as to exactly why the function arguments must be in this order. I've read some of the PEP mailing list discussions and most of the decisions Guido makes are for very good, specific, and practical reasons, not simply "because he say so." – user545424 May 23 '12 at 22:37
  • @user545424 Actually some are "because he says so" like dictionary iteration. Iterating over a dictionary iterates over the keys, some people think it should be key,pair values but he said that iterating over just the keys was his gut instinct and usually he finds good reasons for his instincts later. This was from one of the Google IO talks, I forgot which one. – jamylak Jun 12 '12 at 10:16
0

If you have a Python 3 keyword-only parameter, like

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). If it were allowed, I suppose it would have to set a to (1, 2, 3) and leave b as the default 1. So it's perhaps not syntactic ambiguity so much as ambiguity in what is expected, which is something Python greatly tries to avoid.

asmeurer
  • 86,894
  • 26
  • 169
  • 240