classification
Title: return of non-parenthesized star-unpacking expression a SyntaxError
Type: enhancement Stage: resolved
Components: Interpreter Core Versions: Python 3.9
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: benjamin.peterson, gvanrossum, mark.dickinson, serhiy.storchaka
Priority: normal Keywords: patch

Created on 2018-08-26 14:25 by mark.dickinson, last changed 2019-10-18 05:01 by gvanrossum. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 8941 closed mark.dickinson, 2018-08-26 16:01
PR 8942 closed mark.dickinson, 2018-08-26 16:16
Messages (10)
msg324118 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2018-08-26 14:25
[From https://stackoverflow.com/q/52026406/270986]

The following is valid, and works as expected:

>>> def f():
...     x = *(1, 2), 3
...     return x
... 
>>> f()
(1, 2, 3)

But the tuple expression can't be used directly in a "return" statement:

>>> def f():
...     return *(1, 2), 3
  File "<stdin>", line 2
    return *(1, 2), 3
           ^
SyntaxError: invalid syntax

It's trivial to work around, by adding an extra pair of parentheses around the return target, but it seems a surprising inconsistency. Would it make sense to allow this? In terms of the grammar,

    return_stmt: 'return' [testlist]

would be replaced with:

    return_stmt: 'return' [testlist_star_expr]

There may be other places in the grammar where "testlist" could reasonably be replaced with "testlist_star_expr", for example:

    for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
msg324232 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-08-28 09:54
Other examples:

    eval('*(1, 2), 3')

    a = []; a += *(1, 2), 3

    for i in *(1, 2), 3: pass

    def g(): yield *(1, 2), 3
msg324254 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2018-08-28 14:28
Thanks, Serhiy. I'm happy to extend my PR to cover those cases, if there's general agreement that it's worth doing so. (*I* personally think this is worth doing, since it smooths some currently rough edges and removes a few surprises, but I'm not comfortable with pushing this forward just on that single data point.)
msg324258 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-08-28 15:25
I think all of these are good.

Perhaps with a small change the for-loop example can allow an elegant way of iterating over multiple iterables. It would need a special case so that `for x in *a, *b:` doesn't first construct a tuple of all elements in a and b. Thoughts?
msg324263 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-08-28 16:42
> It would need a special case so that `for x in *a, *b:` doesn't first construct a tuple of all elements in a and b. Thoughts?

It may be surprising that `for x in *a, *b:` behave differently from `for x in (*a, *b):`.

It is idiomatic to create a list of keys and iterate it if you want to modify the dict during iterating:

    for key in list(d):
        # modify d

This can be written in a form

    for key in [*d]:
        # modify d

or

    for key in (*d,):
        # modify d

(although the latter variant is slightly slower).
msg324266 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-08-28 17:18
That's fair. Maybe we shouldn't support `for x in *a, *b:` at all then, until we've got a BDFL decision? (Because once you support it one way you can't easily change the semantics without breaking backwards compatibility.)
msg324267 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-08-28 17:33
I understand why non-parenthesized tuples are supported in assignments, in return statements and yield expressions and in for loops, but I'm surprised that they are supported in augmented assignments: `a += 1, 2, 3`.
msg324269 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2018-08-28 17:59
> I'm surprised that they are supported in augmented assignments: `a += 1, 2, 3`.

I guess at the time it was felt that it was better to support it everywhere it *could* be supported -- and if a is a list it even makes some amount of sense. In any case it's too late to change. :-)
msg354861 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-10-18 04:59
Why is this still open? That feature appears already implemented.
msg354862 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2019-10-18 05:01
See:

commit fd97d1f1af910a6222ea12aec42c456b64f9aee4
Author: David Cuthbert <dacut@kanga.org>
Date:   Fri Sep 21 18:31:15 2018

    bpo-32117: Allow tuple unpacking in return and yield statements (gh-4509)
    
    Iterable unpacking is now allowed without parentheses in yield and return
    statements, e.g. ``yield 1, 2, 3, *rest``. Thanks to David Cuthbert for the
    change and jChapman for added tests.
History
Date User Action Args
2019-10-18 05:01:08gvanrossumsetstatus: open -> closed
resolution: out of date
messages: + msg354862

stage: patch review -> resolved
2019-10-18 04:59:30gvanrossumsetmessages: + msg354861
2019-10-18 01:26:29cheryl.sabellasetversions: + Python 3.9, - Python 3.8
2018-08-28 17:59:34gvanrossumsetmessages: + msg324269
2018-08-28 17:33:09serhiy.storchakasetmessages: + msg324267
2018-08-28 17:18:20gvanrossumsetmessages: + msg324266
2018-08-28 16:42:08serhiy.storchakasetmessages: + msg324263
2018-08-28 15:25:17gvanrossumsetmessages: + msg324258
2018-08-28 14:28:17mark.dickinsonsetmessages: + msg324254
2018-08-28 09:54:28serhiy.storchakasetnosy: + serhiy.storchaka, gvanrossum, benjamin.peterson
messages: + msg324232
2018-08-26 16:16:41mark.dickinsonsetpull_requests: + pull_request8415
2018-08-26 16:01:53mark.dickinsonsetkeywords: + patch
stage: patch review
pull_requests: + pull_request8414
2018-08-26 14:25:50mark.dickinsoncreate