Recently I started playing around with Python and I came around something peculiar in the way closures work. Consider the following code:
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
It builds a simple array of functions that take a single input and return that input added by a number. The functions are constructed in for
loop where the iterator i
runs from 0
to 3
. For each of these numbers a lambda
function is created which captures i
and adds it to the function's input. The last line calls the second lambda
function with 3
as a parameter. To my surprise the output was 6
.
I expected a 4
. My reasoning was: in Python everything is an object and thus every variable is essential a pointer to it. When creating the lambda
closures for i
, I expected it to store a pointer to the integer object currently pointed to by i
. That means that when i
assigned a new integer object it shouldn't effect the previously created closures. Sadly, inspecting the adders
array within a debugger shows that it does. All lambda
functions refer to the last value of i
, 3
, which results in adders[1](3)
returning 6
.
Which make me wonder about the following:
- What do the closures capture exactly?
- What is the most elegant way to convince the
lambda
functions to capture the current value of i
in a way that will not be affected when i
changes its value?
Question&Answers:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…