Scope Variable With A Loop
Solution 1:
To clarify a bit more on the subject, the reference to i
does not change within the lambda - you see that each iteration of i
generates a new object:
def makeActions():
acts=[]
for i in range(5):
print('i:', i, 'object id:', id(i))
acts.append(lambda: id(i))
print('final i:', i, 'object id:', id(i))
return acts
acts=makeActions()
print([fn() for fn in acts])
Returns
i: 0 object id: 140418781832928
i: 1 object id: 140418781832960
i: 2 object id: 140418781832992
i: 3 object id: 140418781833024
i: 4 object id: 140418781833056
final i: 4 object id: 140418781833056
[140418781833056, 140418781833056, 140418781833056, 140418781833056, 140418781833056]
The reference from i
always points to its last assigned object, thus the id of i
will not change after its last alteration.
If you want to keep the value at the time of the lambda creation, you need to "trap" the value of the reference at the desired place and time, for instance you could delegate the lambda creation to a function:
def delegated(d):
return lambda: id(d)
def makeDelegatedActions():
acts=[]
for i in range(5):
print('i:', i, 'object id:', id(i))
acts.append(delegated(i))
print('final i:', i, 'object id:', id(i))
return acts
acts=makeDelegatedActions()
print([fn() for fn in acts])
Which returns
i: 0 object id: 140418781832928
i: 1 object id: 140418781832960
i: 2 object id: 140418781832992
i: 3 object id: 140418781833024
i: 4 object id: 140418781833056
final i: 4 object id: 140418781833056
[140418781832928, 140418781832960, 140418781832992, 140418781833024, 140418781833056]
Solution 2:
Each lambda will just know to fetch i
from its enclosing scope, which is the makeActions
call. They don't actually do so until they're called themselves. i
is the same name within the same scope, it just happens to take different values during the loop, and will simply hold the last value after the loop finishes. So the lambdas just ended up creating 5 identical functions.
A variation that can work:
def expgen(n):
def myexp(x):
return n**x
return myexp
acts = [expgen(i) for i in range(5)]
In this case, the scope that n
is fetched from is that of expgen
, which had distinct calls in the list comprehension, and each function will work independently.
Post a Comment for "Scope Variable With A Loop"