<div class="gmail_quote">On Fri, Nov 16, 2012 at 10:46 AM, Nick Coghlan <span dir="ltr"><<a href="mailto:ncoghlan@gmail.com" target="_blank">ncoghlan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="gmail_quote">However, I realised there's a more serious problem with your idea: the outermost clause in a list comprehension or generator expression is evaluated immediately and passed as an argument to the inner scope that implements the loop, so you have an unresolved sequencing problem between the evaluation of that argument and the evaluation of the context manager. If you want the context manager inside the generator, you *can't* reference the name bound in the as clause in the outermost iterable.<br>
</div></blockquote><div><br>(Andrew's reply here dropped the list from the cc, but I figure my subsequent clarification is worth sharing more widely) <br></div><br></div>When you write a genexp like this:<br><br>    gen = (x for x in get_seq())<br>
<br>The expansion is *NOT* this:<br><br>    def _g():<br>        for x in get_seq():<br>            yield x<br><br>    gen = _g()<br><br>Instead, it is actually:<br>
<br>    def _g(iterable):<br>        for x in iterable:<br>            yield x<br><br>    gen = _g(get_seq())<br><br>That
 is, the outermost iterable is evaluated in the *current* scope, not 
inside the generator. Thus, the entire proposal is rendered incoherent, 
as there is no way for the context manager expression to be executed 
both *before* the outermost iterable expression and *inside* the 
generator function, since the generator doesn't get called until *after*
 the outermost iterable expression has already been evaluated. (And, to 
stave of the obvious question, no this order of evaluation is *not* 
negotiable, as changing it would be a huge backwards compatibility 
breach, as well as leading to a lot more obscure errors with generator 
expressions)<br>
<br>The reason PEP 403 is potentially relevant is because it
 lets you write a one-shot generator function using the long form and 
still make it clear that it *is* a one shot operation that creates the 
generator-iterator directly, without exposing the generator function 
itself:<br>
<br>    @in gen = g()<br>    def g():<br>        for x in get_seq():<br>            yield x<br><br>Or, going back to the use case in the original post:<br><br>    @in upperlines = f()<br>
    def f():<br>
        with open('foo', 'r') as file:<br>
            for line in file:<br>
                yield line.upper()<div class="yj6qo ajU"><div id=":no" class="ajR" tabindex="0"><img class="ajT" src="https://mail.google.com/mail/images/cleardot.gif"></div></div><br>
<br>Cheers,<br>Nick.<br clear="all"><br>-- <br>Nick Coghlan   |   <a href="mailto:ncoghlan@gmail.com">ncoghlan@gmail.com</a>   |   Brisbane, Australia<br>