[Python-Dev] accumulator display syntax

Tim Peters tim.one at comcast.net
Tue Oct 21 21:06:31 EDT 2003


[Samuele Pedroni]
> so this, if I understand:
>
> def h():
>    y = 0
>    l = [1,2]
>    it = (x+y for x in l)
>    y = 1
>    for v in it:
>      print v
>
> will print 1,2 and not 2,3

That is what I had in mind, and that if the first assignment to "y" were
commented out, the assignment to "it" would raise UnboundLocalError.

> unlike:
>
> def h():
>    y = 0
>    l = [1,2]
>    def gen(S):
>      for x in S:
>        yield x+y
>    it = gen(l)
>    y = 1
>    for v in it:
>      print v

Yes, but like it if you replaced the "def gen" and the line following it
with:

    def gen(y=y, l=l):
        for x in l:
            yield x+y
    it = gen()

This is worth some thought.  My intuition is that we *don't* want "a
closure" here.  If generator expressions were reiterable, then (probably
obnoxiously) clever code could make some of use of tricking them into using
different inherited bindings on different (re)iterations.  But they're
one-shot things, and divorcing the values actually used from the values in
force at the definition site sounds like nothing but trouble to me
(error-prone and surprising).  They look like expressions, after all, and
after

    x = 5
    y = x**2
    x = 10
    print y

it would be very surprising to see 100 get printed.  In the rare cases
that's desirable, creating an explicit closure is clear(er):

    x = 5
    y = lambda: x**2
    x = 10
    print y()

I expect creating a closure instead would bite hard especially when building
a list of generator expressions (one of the cases where delaying generation
of the results is easily plausible) in a loop.  The loop index variable will
probably play some role (directly or indirectly) in the intended operation
of each generator expression constructed, and then you severely want *not*
for each generator expression to see "the last" value of the index vrlbl.

For concreteness, test_generators.Queens.__init__ creates a list of rowgen()
generators, and rowgen uses the default-arg trick to give each generator a
different value for rowuses; it would be an algorithmic disaster if they all
used the same value.

Generator expressions are too limited to do what rowgen() does (it needs to
create and undo side effects as backtracking proceeds), so it's not
perfectly relevant as-is.  I *suspect* that if people work at writing
concrete use cases, though, a similar thing will hold.

BTW, Icon can give no guidance here:  in that language, the generation of a
generator's result sequence is inextricably bound to the lexical occurrence
of the generator.  The question arises in Python because definition site and
generation can be divorced.




More information about the Python-Dev mailing list