0

Can someone explain me the following:

This works as I expect:

>>> [(x, [x for i in xrange(2)]) for x in xrange(3)]
[(0, [0, 0]), (1, [1, 1]), (2, [2, 2])]

Using a generator x is evaluated as 2

>>> [(x, list(x for i in xrange(2))) for x in xrange(3)]
[(0, [2, 2]), (1, [2, 2]), (2, [2, 2])]

This seems because x within the generator expression is taken from the global scope

>>> x = -1
>>> [(x, list(x for i in xrange(2))) for x in xrange(3)]
[(0, [-1, -1]), (1, [-1, -1]), (2, [-1, -1])]
>>> del x
>>> [(x, list(x for i in xrange(2))) for x in xrange(3)]
Traceback (most recent call last):
  File "C:\Program Files (x86)\JetBrains\PyCharm Community Edition 4.0.4\helpers\pydev\pydevd_exec.py", line 3, in Exec
exec exp in global_vars, local_vars
  File "<input>", line 1, in <module>
  File "<input>", line 1, in <genexpr>
NameError: global name 'x' is not defined

Why is that?

Wouter
  • 523
  • 4
  • 8
  • I can't reproduce this, actually. Not in Python 2.4 through to 2.7, and given your `xrange()` use it cannot be Python 3. Are you using Python 2.6 still perhaps? – Martijn Pieters Jun 09 '15 at 11:41
  • Even in Python 3 with `xrange` replaced by `range` I cannot reproduce the results. List comprehension and generator expression namespaces act like those in a function, but `x` *is* available to the generator expression from the parent list comprehension. – Martijn Pieters Jun 09 '15 at 11:43
  • Python 2.7 does use a `LOAD_GLOBAL` for the `x` so if this is *inside a class body* you'd have a point and we can reproduce this. In which case this is a duplicate question. In Python 3 the `x` in the generator expression is loaded as a closure. – Martijn Pieters Jun 09 '15 at 11:46
  • The results I posted I found while debugging, not in a class body but in a while loop, could that be the cause? Indeed in a plain python console the results are as I expect. Still I don't understand why `x` in the nested generator is not taken from the parent list comprehension. Why does it matter if this code is inside a class body or not? – Wouter Jun 09 '15 at 12:13
  • Because that changes the scoping rules, and in Python 2 that matters as a list comprehension is run in the class scope, not in a separate scope as in Python 3. – Martijn Pieters Jun 09 '15 at 12:18
  • 1
    I've duped you to a post that explains in detail what happens with list comprehensions and generators in class scopes. The behaviour you've observed can certainly be reproduced in that context. If you can reproduce it in a different context, feel free to update your question, but make sure we can reproduce the issue with just the code provided. – Martijn Pieters Jun 09 '15 at 14:01

0 Answers0