Weird closure behavior in python

Solution 1:

As @thg435 points out, a lambda will not encapsulate the values at that moment, but rather the scope. There are too small ways you can address this:

lambda default argument "hack"

[ lambda v=i: v for i in [ 1, 2, 3 ] ]

Or use functools.partial

from functools import partial
[ partial(lambda v: v, i) for i in [ 1, 2, 3 ] ]

Essentially you have to move the scope to be local to the function you are creating. Generally I like using partial more often since you can pass it a callable, and any args and kargs to create a callable with a proper closure. Internally, it is wrapping your original callable so the scope is shifted for you.

Solution 2:

Closures don't refer to variables but rather to scopes. Since the last value of i in its scope is '3', all three closures return the same. To "lock" the current value of a variable, create a new scope just for it:

def get() : return [ (lambda x: lambda: x)(i) for i in [ 1, 2, 3 ] ]
for f in get() : print( f() )