<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sat, Nov 25, 2017 at 6:55 AM, Ivan Levkivskyi <span dir="ltr"><<a href="mailto:levkivskyi@gmail.com" target="_blank">levkivskyi@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-">On 25 November 2017 at 04:30, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-m_-321702978631925968gmail-">On Fri, Nov 24, 2017 at 4:22 PM, Guido van Rossum <span dir="ltr"><<a href="mailto:guido@python.org" target="_blank">guido@python.org</a>></span> wrote:<br></span><span class="gmail-m_-321702978631925968gmail-"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr">The more I hear about this topic, the more I think that `await`, `yield` and `yield from` should all be banned from occurring in all comprehensions and generator expressions. That's not much different from disallowing `return` or `break`.<span></span><br></div></blockquote></span></div><br clear="all"></div><div class="gmail_extra">From the responses it seems that  I tried to simplify things too far. Let's say that `await` in comprehensions is fine, as long as that comprehension is contained in an `async def`. While we *could* save `yield [from]` in comprehensions, I still see it as mostly a source of confusion, and the fact that the presence of `yield [from]` *implicitly* makes the surrounding `def` a generator makes things worse. It just requires too many mental contortions to figure out what it does.</div></div></blockquote><div><br></div></span><div>There were some arguments that `await` is like a function call, while `yield` is like `return`.</div><div>TBH, I don't really like these arguments since to me they are to vague. Continuing this logic one can say that</div><div>`return` is just a fancy function call (calling continuation with the result). To me there is one clear distinction:</div><div>`return` and `break` are statements, while `yield`, `yield from`, and `await` are expressions.</div></div></div></div></blockquote><div><br></div><div>Indeed. However, `yield from` as an expression is mostly a deprecated way to write `await`, and `yield` as an expression is mostly an alternative way of writing coroutines (it's the only way that exists in Python 2). Another big difference is that the use of `yield [from]` affects the surrounding function, making it a generator.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>Continuing the topic of the ban, what exactly should be banned? For example will this still be valid?<br></div><div><br></div><div>    def pack_two():</div><div>        return [(yield), (yield)]  # Just a list display<br></div></div></div></div></blockquote><div><br></div><div>It's not a comprehension so it's still valid. <br></div><div>  <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">I don't see how this is controversial. It is clear that `pack_two` is a generator.</div><div class="gmail_quote">If this is going to be prohibited, then one may be surprised by lack of</div><div class="gmail_quote">referential transparency, since this will be valid:</div><div class="gmail_quote"><br></div><div class="gmail_quote">    def pack_two():</div><div class="gmail_quote">        first = (yield)</div><div class="gmail_quote">        second = (yield)</div><div class="gmail_quote">        return [first, second]<br></div><div class="gmail_quote"><div><br></div><div>If the first example will be allowed, then one will be surprised why it can't be rewritten as</div><div><br></div><div><div>    def pack_two():</div>        return [(yield) for _ in range(2)]</div></div></div></div></blockquote><div><br></div><div>And yet Nick's example shows that that is not equivalent!</div><div><br></div><div>def example():<br>    comp1 = yield from [(yield x) for x in ('1st', '2nd')]<br>    comp2 = yield from [(yield x) for x in ('3rd', '4th')]<br>    return comp1, comp2<br></div><div><br></div><div>In this example each thing that looks syntactically like a list comprehension becomes actually a generator expression at at runtime! And so does your example, so instead of a list of two items, it returns a generator that will produce two values when iterated over.</div><div><br></div><div>That's not referential transparency to me, it feels more like a bug in the code generator.</div><div><br></div><div>I want to ban this because apparently nobody besides Nick knows about this behavior (I certainly didn't, and from the above it seems you don't either).<br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>I have found several other examples where it is not clear whether they should be prohibited with `yield` or not.</div></div></div></div></blockquote><div><br></div><div>Such as? <br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="gmail-"><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir="ltr"><div class="gmail_extra">I still propose to rule out all of the above from generator expressions, because those can escape from the surrounding scope.<br></div><span class="gmail-m_-321702978631925968gmail-"></span></div></blockquote><br></span></div>Here I agree. Also note that the above problem does not apply to generator expressions since (x, x) and (x for _ in range(2)) are</div><div class="gmail_extra">two very different expressions.<br></div></div></blockquote><div><br></div><div>PS. A more radical proposal (not for 3.7) would be to deprecate yield as an expression. It once was only a statement, but PEP 342 introduced yield as an expression in order to do coroutines. We now have `async def` and `await` as a superior coroutine mechanism. But we must continue to support yield expressions because there is a lot of Python 2/3 compatible code that depends on it. (E.g. Tornado.)<br></div></div><br>-- <br><div class="gmail_signature">--Guido van Rossum (<a href="http://python.org/~guido" target="_blank">python.org/~guido</a>)</div>
</div></div>