
Andrew Barnert via Python-ideas writes:
powers = [lambda x: x**i for i in range(10)]
This gives you ten functions that all return x**9, which is probably not what you wanted.
The reason this is a problem is that Python uses "late binding", which in this context means that each of those functions is a closure that captures the variable i in a way that looks up the value of i at call time. All ten functions capture the same variable, and when you later call them, that variable's value is 9.
But this explanation going to confuse people who understand the concept of variable in Python to mean names that are bound and re-bound to objects. The comprehension's binding of i disappears before any element of powers can be called. So from their point of view, either that expression is an error, or powers[i] closes over a new binding of the name "i", specific to "the lambda's scope" (see below), to the current value of i in the comprehension. Of course the same phenomenon is observable with other scopes. In particular global scope behaves this way, as importing this file i = 0 def f(x): return x + i i = 1 and calling f(0) will demonstrate. But changing the value of a global, used the way i is here, within a library module is a rather unusual thing to do; I doubt people will observe it. Also, once again the semantics of lambda (specifically, that unlike def it doesn't create a scope) seem to be a source of confusion more than anything else. Maybe it's possible to exhibit the same issue with def, but the def equivalent to the above lambda >>> def make_increment(i): ... def _(x): ... return x + i ... return _ ... >>> funcs = [make_increment(j) for j in range(3)] >>> [f(0) for f in funcs] [0, 1, 2] closes over i in the expected way. (Of course in practicality, it's way more verbose, and in purity, it's not truly equivalent since there's at least one extra nesting of scope involved.) While >>> def make_increment(): ... def _(x): ... return x + i ... return _ ... >>> funcs = [make_increment() for i in range(3)] >>> [f(0) for f in funcs] Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 1, in <listcomp> File "<stdin>", line 3, in _ NameError: name 'i' is not defined >>> i = 6 >>> [f(0) for f in funcs] [6, 6, 6] doesn't make closures at all, but rather retains the global binding.