In Python, why do lambdas in list comprehensions overwrite themselves in retrospect?

Question:

Consider the following code:

def f (a):
    return 1
def g (a):
    return 2

[lambda a: i(a) for i in (f,g)][0](0)

The result is 2. Where it should clearly be 1! I would expect this code to execute as follows. Create a list. Copy the function f into the first index. Copy g into the second index. Fin.

Why does this execute the way it does?!

Asked By: user5339769

||

Answers:

The lambda didn’t overwrite itself, it is i that was overwritten. This is a common mistake regarding variable scopes. Try this:

[lambda a, i=i: i(a) for i in (f,g)][0](0)

(the difference is binding the value of i at the time the lambda is created)

See also:

Answered By: dsh

I’ll expand slightly on @dsh’s answer.

When the list comprehension expression

[lambda a: i(a) for i in (f,g)]

is evaluated, it creates two anonymous functions, each of which to the effect of

def _______(a):
    return i(a)

However, after the evaluation of the above list comprehension, the name i is bound to its last iteration value, which is the object bound to g, i.e. 2nd of your functions.

Now, after that, when one of the anonymous functions in the list gets called, it accesses the name i, which is in the module-global scope and bound to the same thing as g is.


Edit: oh, @dsh’s expanded it too.

Answered By: Cong Ma