Why lambda function to get the list of values i = 4 .During the call lambda, enclosing scope does not exist. The function f has finished work and returned control (the variable i does not exist).
def f():
L = []
for i in range(5):
L.append(lambda x: i ** x)
return L
L = f()
L[0]
def f1(N):
def f2(X):
return X**N
return f2
f=f1(2)
f (3)
9
g = f1(3)
g(3)
27
f(3)
9
Python uses closures to capture references to the original variable. The lambda
objects retain a reference to the i
name, through which the value can be accessed. This means that the i
variable continues to live on after f
completes.
You can introspect this closure in the .__closure__
tuple on the lambda objects; functions have the same attribute:
>>> L[0].__closure__
(<cell at 0x1077f8b78: int object at 0x107465880>,)
>>> L[0].__closure__[0]
<cell at 0x1077f8b78: int object at 0x107465880>
>>> L[0].__closure__[0].cell_contents
4
This is also why all lambdas in your list L
refer to the value 4
, and not to the numbers 0 through to 4. They all refer to the same closure:
>>> L[0].__closure__[0] is L[1].__closure__[0]
True
The closure refers to the variable, not to the value of that variable at the time the closure was defined. At the end of the loop i
was last set to 4
, so when looking up i
in the lambda closure 4
will be found, for all lambdas in your list.
If you want your lambdas to refer to the value of i
during the loop, capture it in a keyword argument:
def f():
L = []
for i in range(5):
L.append(lambda x, i=i: i ** x)
return L
Now i
is a local variable to the lambda, not a closure.
Alternatively, create an entirely new scope from which to draw the closure:
def create_lambda(i):
return lambda x: i ** x
def f():
return [create_lambda(i) for i in range(5)]
Now create_lambda()
is a new scope with it's own local i
for the lambda closure to refer to. The lambdas then each have their own closures:
>>> L[0].__closure__[0] is L[1].__closure__[0]
False
Closures refer to a variable in a specific namespace; each time you call a function a new local namespace is created, so each closure refers to i
in create_lambda
in a separate namespace from other calls to create_lambda
.