[Python-Dev] Possible resolution of generator expression variable capture dilemma

Phillip J. Eby pje at telecommunity.com
Wed Mar 24 12:46:10 EST 2004


At 08:24 AM 3/24/04 -0800, Guido van Rossum wrote:
>Phillip shows some examples involving inner functions defined inside
>the for loop.  But in current Python these examples work just as well
>if the function is defined *outside* the loop (as long as no default
>argument values are needed):
>
> > for x in 1,2,3:
> >      def y():
> >          print z
> >      z = x * 2
> >      y()
>
>is the same as
>
>   def y():
>       print z
>   for x in 1, 2, 3:
>       z = x*2
>       y()
>
>That would change under Phillip's proposal.

Hm.  I was viewing it a bit differently.  In effect, I was treating the 
loop as a new "nested scope", so a function defined within a loop would 
have different variable capture than one defined outside a loop.


>There are similar examples that would break under Greg's original
>proposal: just use the loop variable in the function, e.g.:

Right, I mentioned at the end that the issue with my proposal was also 
applicable to Greg's.


>All this is just more reason to put this one off until 3.0.

I agree, and withdraw my support for early binding in generator 
expressions, despite Tim's example.  Instead, we should have a consistent 
failure under "practicality beats purity".  That is, a straightforward 
translation of:

     pipe = source
     for p in predicates:
         # add a filter over the current pipe, and call that the new pipe
         pipe = e for e in pipe if p(e)

to:

     pipe = source
     for p in predicates:
         def __():
             for e in pipe:
                if p(e):
                    yield e
         # add a filter over the current pipe, and call that the new pipe
         pipe = __()

produces exactly the same broken behavior in today's Python.  The solution, 
of course is:

     def ifilter(pred,pipe):
         for e in pipe:
             if pred(e):
                 yield e

     pipe = source
     for p in predicates:
         # add a filter over the current pipe, and call that the new pipe
         pipe = ifilter(p,pipe)





More information about the Python-Dev mailing list