This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Allow `return yield from`
Type: enhancement Stage: resolved
Components: Parser Versions: Python 3.11
process
Status: closed Resolution: rejected
Dependencies: Superseder:
Assigned To: Nosy List: lys.nikolaou, pablogsal, pxeger, terry.reedy
Priority: normal Keywords:

Created on 2022-03-28 17:48 by pxeger, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (7)
msg416198 - (view) Author: Patrick Reader (pxeger) * Date: 2022-03-28 17:48
I would like to be able to use a `yield from` expression in a `return` statement without parentheses, as a small quality of life tweak, i.e.:

    return yield from gen

instead of

    return (yield from gen)

I think this makes sense, since `yield from` can be used on the right-hand-side of an assignment, which accepts any expression, and so should `return`.

Here is a medium-sized real-world example of where I'm using this, where it would be nice to allow `return yield from`: https://gist.github.com/pxeger/48f97484364bf0b43dee974a8f0f4265
msg416199 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-03-28 17:51
Please, submit an email to python-ideas or python-dev first as this need to be discussed in the mailing lists.
msg416205 - (view) Author: Patrick Reader (pxeger) * Date: 2022-03-28 19:45
Ok, will do, but what is the bar for a feature to need to go to the mailing lists first? I thought as this was a relatively minor one it wouldn't need to. Is it just because it's an actual syntax change?
msg416206 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-03-28 19:59
In general, anything changing the python syntax needs to be discussed in the mailing lists and it may likely need a PEP as well, even if is minor. This is because this has consequences rippling the whole ecosystem, from IDEs to other parsers and this need to be discussed, and communicated in a better forum than this.
msg416532 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2022-04-02 02:43
I think that this should be closed as rejected, and that Patrick should remove the 'return's that are in front of 'yield from ...'.  Then 'yield from x' will be a statement, not an expression, and the ()s will not be needed, as they are used to differentiate yield expressions from yield statements. Generator functions return generators, not return expressions.  The latter are only used for the StopIteration .value attribute, which I believe is always None for Patrick's code and in any case is never used.  So his code should run the same without these 'return's.

The exception for '= yield ...' is similar to '= a, ...' not needing ()s.  This is the only exception for yield expressions because this is normally the only place a yield expression should be used by itself instead of with other operators or functions, where ()s are needed.

The python-ideas thread archive is at
https://mail.python.org/archives/list/python-ideas@python.org/thread/L6XRQ5YWAE535JGZH2MF2TD32C65K5ZI/

Andrew Svetlov objected (-1) because to him ()s make the statement more readable.

Michael Smith got to the real problem, which is that one should not be using "return (yield from x)" unless one is accessing a possibly non-None value attribute of the implicitly raised StopIteration exception.

I oppose adding a second no-() exception for such rare (and somewhat confusing) expert uses. 

In a generator function, the return value is a generator based on the entire body of the function.  Any return statement value becomes the value attribute of the StopIteration raised when the generator is exhausted.  In other words, 'return x' in this context translates to "raise StopIteration(x)' (which is illegal to write directly). I am pretty sure that in your code, the value of 'yield from func' is always None.  In any case, StopIteration().value is never used.

To illustrate:

def g0():
    return (yield from ())  # Immediately raise StopIteration(None).

try: next(g0())
except StopIteration as e:
    print(e.value)

# Prints 'None'.
msg416537 - (view) Author: Patrick Reader (pxeger) * Date: 2022-04-02 06:15
As the one who wrote the code, I can guarantee you that the StopIteration value is not always None.

But I understand your point that for most other users it is always None, and therefore having special syntax might be misleading.
msg416572 - (view) Author: Pablo Galindo Salgado (pablogsal) * (Python committer) Date: 2022-04-02 17:46
I concur with Terry.
History
Date User Action Args
2022-04-11 14:59:57adminsetgithub: 91303
2022-04-02 17:46:47pablogsalsetstatus: open -> closed
resolution: rejected
messages: + msg416572

stage: resolved
2022-04-02 06:15:14pxegersetmessages: + msg416537
2022-04-02 02:43:26terry.reedysetnosy: + terry.reedy

messages: + msg416532
versions: + Python 3.11
2022-03-28 19:59:23pablogsalsetmessages: + msg416206
2022-03-28 19:45:44pxegersetmessages: + msg416205
2022-03-28 17:51:02pablogsalsetmessages: + msg416199
2022-03-28 17:48:12pxegercreate