classification
Title: Disallow iterable argument unpacking after a keyword argument?
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.9
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: brandtbucher, gvanrossum, josh.r, rhettinger
Priority: normal Keywords:

Created on 2019-10-23 00:20 by brandtbucher, last changed 2019-10-29 17:28 by gvanrossum. This issue is now closed.

Messages (6)
msg355195 - (view) Author: Brandt Bucher (brandtbucher) * (Python committer) Date: 2019-10-23 00:20
Calls of the form f(name=value, *args) are currently legal syntax. The resulting argument binding is awkward, and almost never does what you want/expect it to:

>>> def f(x, y, z):
...     print(x, y, z)
... 

>>> f(x=0, *(1, 2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for argument 'x'

>>> f(y=0, *(1, 2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for argument 'y'

>>> f(z=0, *(1, 2))
1 2 0

I'm not sure if this is intentional, or an oversight. Every other way of passing positional arguments after keyword arguments results in an error:

f(kwarg=kwarg, arg)  # SyntaxError: positional argument follows keyword argument
f(**kwargs, arg)     # SyntaxError: positional argument follows keyword argument unpacking
f(**kwargs, *args)   # SyntaxError: iterable argument unpacking follows keyword argument unpacking

I think this case should raise a "SyntaxError: iterable argument unpacking follows keyword argument".

I'd like to work on this if we believe it should be changed.
msg355251 - (view) Author: Josh Rosenberg (josh.r) * (Python triager) Date: 2019-10-23 19:02
I'd be +1 on this, but I'm worried about existing code relying on the functional use case from your example.

If we are going to discourage it, I think we either have to:

1. Have DeprecationWarning that turns into a SyntaxError, or
2. Never truly remove it, but make it a SyntaxWarning immediately and leave it that way indefinitely
msg355267 - (view) Author: Brandt Bucher (brandtbucher) * (Python committer) Date: 2019-10-23 21:20
I've found one occurrence of this in the CPython codebase, in test_ast.py. Basically it makes sure that the following expression parses and compiles correctly:

f(1,2,c=3,*d,**e)

I doubt that this is to protect against regressions in this specific syntax. More likely it's just trying to create as many of the different argument passing AST nodes as possible in one call (it's the only test for function calls with arguments). It can probably be slightly refactored:

f(1,2,*c,d=3,**e)
msg355658 - (view) Author: Brandt Bucher (brandtbucher) * (Python committer) Date: 2019-10-29 15:48
I’ve thought about it and I’m +1 on DeprecationWarning in 3.9 and SyntaxError in 3.10.

Removing any type of legal function call is tricky, but this is such obscure, sneaky syntax that it’s likely an accident/bug if it does pop up (that’s how I discovered it). And every instance can be trivially refactored.
msg355660 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-10-29 16:16
Changes to the grammar of the language need to be discussed on python-dev (especially ones that can break existing code and ones that change syntax that has worked for many years).  Arguably, this is something that should just go into a lint tool.
msg355663 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-10-29 17:28
Well, as you point out, f(z=0, *(1, 2)) is legal, and the parser doesn't know what the names of the keyword arguments are. SO this cannot be changed.
History
Date User Action Args
2019-10-29 17:28:43gvanrossumsetstatus: open -> closed
resolution: not a bug
messages: + msg355663

stage: resolved
2019-10-29 16:16:20rhettingersetnosy: + rhettinger, gvanrossum
messages: + msg355660
2019-10-29 15:48:29brandtbuchersetmessages: + msg355658
title: Allow iterable argument unpacking after a keyword argument? -> Disallow iterable argument unpacking after a keyword argument?
2019-10-23 21:20:14brandtbuchersetmessages: + msg355267
2019-10-23 19:02:41josh.rsetnosy: + josh.r
messages: + msg355251
2019-10-23 00:20:42brandtbuchercreate