
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