python - What do (lambda) function closures capture? -
recently started playing around python , came around peculiar in way closures work. consider following code:
adders=[0,1,2,3] in [0,1,2,3]: adders[i]=lambda a: i+a print adders[1](3) it builds simple array of functions take single input , return input added number. functions constructed in for loop iterator i runs 0 3. each of these numbers lambda function created captures i , adds function's input. last line calls second lambda function 3 parameter. surprise output 6.
i expected 4. reasoning was: in python object , every variable essential pointer it. when creating lambda closures i, expected store pointer integer object pointed i. means when i assigned new integer object shouldn't effect created closures. sadly, inspecting adders array within debugger shows does. lambda functions refer last value of i, 3, results in adders[1](3) returning 6.
which make me wonder following:
- what closures capture exactly?
- what elegant way convince
lambdafunctions capture current value ofiin way not affected whenichanges value?
your second question has been answered, first:
what closure capture exactly?
scoping in python dynamic and lexical. closure remember name , scope of variable, not object it's pointing to. since functions in example created in same scope , use same variable name, refer same variable.
edit: regarding other question of how overcome this, there 2 ways come mind:
the concise, not strictly equivalent way one recommended adrien plisson. create lambda argument, , set argument's default value object want preserved.
a little more verbose less hacky create new scope each time create lambda:
>>> adders = [0,1,2,3] >>> in [0,1,2,3]: ... adders[i] = (lambda b: lambda a: b + a)(i) ... >>> adders[1](3) 4 >>> adders[2](3) 5the scope here created using new function (a lambda, brevity), binds argument, , passing value want bind argument. in real code, though, have ordinary function instead of lambda create new scope:
def createadder(x): return lambda y: y + x adders = [createadder(i) in range(4)]
Comments
Post a Comment