Code talks more:
from pprint import pprint
li = []
for i in range(5):
li.append(lambda : pprint(i))
for k in li:
k()
yield:
4 4 4 4 4
why not
0 1 2 3 4
??
Thanks.
P.S. If I write the complete decorator, it works as expected:
from pprint import pprint
li = []
#for i in range(5):
#li.append(lambda : pprint(i))
def closure(i):
def _func():
pprint(i)
return _func
for i in range(5):
li.append(closure(i))
for k in li:
k()
you need to do:
lambda i=i: pprint(i)
instead to capture the current value of i
It does properly reference i
, only the thing is, that by the time your list gets populated, i
would have the value assigned form the last item in the sequence when the iteration ended, so that's why your seeing 4
all over.
If you don't want to use a default argument -- which could introduce bugs if accidentally called with an argument -- you can use a nested lambda:
from pprint import pprint
li = []
for i in range(5):
li.append((lambda x: lambda: pprint(x))(i))
for k in li:
k()
This is an anonymous version of your closure
function.
The lambda functions create closures over the i
variable. After the first for
loop is finished, i
has value 4
.
Then the second for
loop starts and all the lambda functions are executed. Each of them then prints the current value of i
, which is 4
.
The answer: Because the code inside the lambda is using your global variable i
.
Your second variant will do the same as the first one with lambda if you remove the parameter i
:
def closure():
Instead of
def closure(i):
I.e. the code inside the function will use the global variable i
.
精彩评论