"Gabriel Genellina" <gagsl-...@yahoo.com.ar> wrote: Of course this is clearly stated in the Language Reference "Variables used in the generator expression are evaluated lazily in a separate scope when the next() method is called for the generator object (in the same fashion as for normal generators). However, the in expression of the leftmost for clause is immediately evaluated in the current scope..." -- but this behaviour is still surprising and not obvious to me. ("not obvious" means that things could have been different, choosing this was a design decision).
I am not so sure that it could have been done differently - I see it something like this: (going back to almost your original example, and reversing the position of globals and locals to make it shorter) >>> def foo(things): for thing in things: yield thing() #it is obvious this is in the local scope of foo >>> boo = foo([locals,globals]) >>> boo.next() {'thing': <built-in function locals>, 'things': [<built-in function locals>, <built-in function globals>]} >>> and so it is, when you feed it the locals function Your other example would have been something like this: >>> def bar(things): for thing in things: yield thing # this just returns it unchanged >>> baz = bar([locals(),globals()]) # here we are still in the outer scope >>> baz.next() {'bar': <function bar at 0x011BB5B0>, '__builtins__': <module '__builtin__' (built-in)>, 'baz': <generator object at 0x011D1CD8>, '__file__': 'E:\\Python24\\Lib\\idlelib\\idle.pyw', 'idlelib': <module 'idlelib' from 'E:\PYTHON24\lib\idlelib\__init__.pyc'>, 'boo': <generator object at 0x011D14B8>, '__name__': '__main__', 'foo': <function foo at 0x011BDFB0>, '__doc__': None} >>> and we get the top level locals back, as expected. Now I don't think that you could really do it differently - the right hand side of the generator expression is exactly like my passed argument "things", in all cases as far as I can see, and this means that the right hand side is evaluated when it is "passed", and the left hand side is whatever is done in the "for thing in things:" loop. All the generator expression does is that it saves you the trouble of defining the function - it kind of does it for you, and calls it, and returns the generator object, and throws the function away, all in one hit. (this is not necessarily the real mechanism, but the effect is exactly as if it were) I can't think of a way to do it differently - you have to make the "things" you want to iterate over, before you can do the iteration, and this is the cause of the timing difference and the outer level evaluation of the "passed" argument, and the different scope comes from the scope of the "ghost" function. Or is this view too simple? - Hendrik -- http://mail.python.org/mailman/listinfo/python-list