Python lambdas and scope

Given this piece of code:

funcs = [] for x in range(3): funcs.append(lambda: x) print [f() for f in funcs] 

I expect it to print [0, 1, 2] , but instead print [2, 2, 2] . Is there something fundamental that I skipped about about how lambdas work with scope?

+7
python lambda
source share
3 answers

This is a frequently asked question in Python. Basically, the scope is such that when f() called, it will use the current value of x , and not the value of x during lambda formation. There is a standard workaround:

 funcs = [] for x in range(10): funcs.append(lambda x=x: x) print [f() for f in funcs] 

Using lambda x = x retrieves and stores the current value of x .

+8
source share

x is tied to the modular level x (which remains from the for loop).

A bit clearer:

 funcs = [] for x in range(10): funcs.append(lambda: x) x = 'Foo' print [f() for f in funcs] # Prints ['Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo'] 
+5
source share

You know the answer: yes .;) Accept comfort, however, since this is a very common discovery for novice pythonists. When you define a function or lambda that references variables that are not "created" inside that function, it creates a closure on the variables. The effect is that you get the value of the variable when you call the function, and not during the definition. (You were expecting the latter.)

There are several ways to handle this. Firstly, these are optional variables:

 funcs = [] for x in range(10): funcs.append(lambda x=x: x) print [f() for f in funcs] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 

The second way is a bit more formal:

 from functools import partial funcs = [] for x in range(10): funcs.append(partial(lambda x: x, x)) print [f() for f in funcs] # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
+4
source share

All Articles