[Python-Dev] 2.5 and beyond

Giovanni Bajo rasky at develer.com
Sat Jul 1 21:24:04 CEST 2006


Andrew Koenig wrote:

> Suppose I write
>
> x = []
> for i in range(10):
> x.append(lambda:i)
> print [f() for f in x]
>
> This example will print [9, 9, 9, 9, 9, 9, 9, 9, 9, 9], which I think
> is wildly unintuitive.

That is my point: to me, it's counter-intuitive just like the infamous
"except NameError, TypeError". I believe that names in
lambdas/nested-functions referring to local names in the outer scope should
really be bound at function definition time (much like default arguments
are).

> What surprises me even more is that if I try to define such a variable
> explicitly, it still doesn't work:
>
> x = []
> for i in range(10):
> j = i
> x.append(lambda:j)
> print [f() for f in x]
>
> This example still prints [9, 9, 9, 9, 9, 9, 9, 9, 9, 9].  If I
> understand the reason correctly, it is because even though j is
> defined only in the body of the loop, loop bodies are not scopes, so
> the variable's definition is hoisted out into the surrounding
> function scope.

Yes. And by itself, I like this fact because it's very handy in many cases.
And it's also handy that the iteration variable of the for loop is
accessible after the for loop is terminated (in fact, this specific
behaviour is already listed among the wont-change for Py3k).

> On the other hand, I think that
> the subtle pitfalls that come from allowing "for" variables to leak
> into the surrounding scopes are much harder to deal with and
> understand than would be the consequences of restricting their scopes
> as outlined above.

As I said, to me there's nothing wrong with the way Python variables leak
out of the suites; or, in other words, with the fact that Python has only
two namespaces, the function-local and the global namespace. What I don't
like is that the lookup of lambda's names are fully deferred at execution
time. This behaviour is already not fully followed for local variables in
functions, since:

>>> y = 0
>>> def foo():
...     print y
...     y = 2
...
>>> foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 2, in foo
UnboundLocalError: local variable 'y' referenced before assignment

which means that Python users *already* know that a variable is not really
looked up only at run-time, but there's "something" going on even at
function definition time. I don't see anything wrong if lambdas (or nested
scopes) did the same for names provably coming from the outer scope.
-- 
Giovanni Bajo



More information about the Python-Dev mailing list