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.

Author terry.reedy
Recipients Trundle, daniel.urban, docs@python, eric.araujo, jonathan.hartley, mjs0, rhettinger, terry.reedy
Date 2011-04-09.01:55:30
SpamBayes Score 3.773859e-11
Marked as misclassified No
Message-id <1302314131.5.0.681504806361.issue11796@psf.upfronthosting.co.za>
In-reply-to
Content
Thanks. I remember now: the initial iter_exp is evaluated immediately because it always *can* be, because it is only evaluated once and can only involve 'outside' names, whereas the result expression and any conditional expressions and further iteration expressions cannot be (evaluated immediately) because in general they usually involve the loop_var and are evaluated many times, each time with a different value of the loop_var (which are not available until the code is run).

The current 3.2 doc more or less says this already, though in fewer words.

To put it another way, the iter_exp either becomes or is treated like a parameter default value expression, so that

ge = (result_exp(loop_var) for loop_var in iter_exp)

is like

def __gf__(_it=iter_exp):
    for loop_var in _it:
        yield result_exp(loop_var)
ge = __gf__()
del __gf__

I wonder if something like this should be added to 5.2.8. Generator expressions, with that section moved up before the set/list/dict displays sections, and with the comprehension grammar included therein.

If one does *not* want the immediately evaluation of the iter_exp (which does not normally happen in generator functions) then, again, one should write a generator function. 

I guess the real lesson is that in 3.x, while comprehensions (including g.e.'s are very similar to nested loops and conditions or generator functions with the same, they are not identical in scoping behavior and need to be thought of as their own thing and not only as syntactic sugar. This is probably easier for people who start with 3.x ;-).

Along that line, here is another replacement for the not-working example 2:

class Foo:
    x = 3
    y = []
    for z in range(5):
        if z < x:
            y.append(z)

print(Foo.y)
# [0, 1, 2]
History
Date User Action Args
2011-04-09 01:55:31terry.reedysetrecipients: + terry.reedy, rhettinger, eric.araujo, Trundle, jonathan.hartley, daniel.urban, docs@python, mjs0
2011-04-09 01:55:31terry.reedysetmessageid: <1302314131.5.0.681504806361.issue11796@psf.upfronthosting.co.za>
2011-04-09 01:55:30terry.reedylinkissue11796 messages
2011-04-09 01:55:30terry.reedycreate