En Thu, 29 Jan 2009 05:14:41 -0200, Hendrik van Rooyen
<m...@microcorp.co.za> escribió:
"Gabriel Genellina" <gagsl-...@yahoo.com.ar> wrote:
En Wed, 28 Jan 2009 16:00:43 -0200, Scott David Daniels
(I *think* this has to do with free variables in the "right side" (after
the "in" keyword) of a generator expression; they appear to be evaluated
when the expression is *defined*, not when is is *used*. By contrast,
free
variables in the "left side" appear to be evaluated when the expression
is
used.)
Yikes! this is, IMO, far too complicated a way of looking at it.
Sure? "Make everything as simple as possible, but not simpler." (att. A.
Einstein). I cannot find a simpler way to explain it that is still true...
I think that if you rewrite the "comprehensions" as loops,
you will see what is happening. - in the one case, the locals()
returned is from the outer scope, while in the other the
locals function is called from inside the loop - a different scope,
because there must be *somewhere* where the state is kept to yield
the next value.
But a loop doesn't define a new scope (only "def" and "class" used to
define one; now generator expressions do too). The new scope is not the
issue, but the fact that the right and left parts of a gen.expr. are
evaluated at different times. This wasn't obvious to me -- and still
isn't. If you rewrite the generator expression as a generator function you
don't get the same behaviour:
print "genexpr"
A = [1,2,3]
B = 1
g = (x+B for x in A)
A = [4,5,6]
B = 10
print list(g)
# output: [11,12,13]
# A is evaluated at the time g is *defined*
# B is evaluated at the time g is *iterated*
print "genfunc"
A = [1,2,3]
B = 1
def f():
for x in A:
yield x+B
A = [4,5,6]
B = 10
g = f()
A = [7,8,9]
B = 100
print list(g)
# output: [107,108,109]
# A and B are evaluated at the time g is *iterated*
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).
As far as I can tell, this is the only case in Python where parts of the
same expression are evaluated in different contexts at different times.
I find it very confusing because locals is always the same
function - but what it returns varies depending on where you
call it from. So if you want to pass it around, it's no good
passing the function - you have to pass the returned result,
*called from the scope of interest*. Subtle stuff.
Yep, the fact that locals() returns a different thing depending on
when/where you call it, was the initial clue to this issue.
--
Gabriel Genellina
--
http://mail.python.org/mailman/listinfo/python-list