volperossa
volperossa

Reputation: 1431

python: about lambda and closure

I understand that:

a=[lambda :k for k in [1,2,3]]
[e() for e in a]

returns [3, 3, 3] because it takes the value of k at runtime, and the last value of k is 3. However, I don't understand why, if I do:

k=50
[e() for e in a]

I still get [3, 3, 3]. Why this? I updated the value of k with 50, why do(es) the e() function(s) still read the old k value?

Upvotes: 0

Views: 77

Answers (1)

habrewning
habrewning

Reputation: 1069

Although you just said it is clear, that

a=[lambda :k for k in [1,2,3]]
[e() for e in a]

returns [3,3,3], this needs a few words. And for sure this is not clear for everybody. The first list comprehensions creates three functions. They all take no arguments and they all return the variable k. Inside the list comprehension k is not a number. K is a variable. And your three functions return that variable. So you have three identical functions. Normally the k variable would be lost. It scopes only withing the list comprehension. You cannot access it any more outside the list comprehension. But in your special case k still lives. It is still captured in the three functions, because these return it. This is what is called a closure (of k). And as k was for iterating through the list [1,2,3] at the end it still is 3. So all three functions return 3. But that is not so obvious. Python could also set it back to zero again or a random number. There is no such statement that k remains at the last value. So even if your code returns [3, 3, 3], that is not obvious and that is not guaranteed.

As said k is not accessible any more outside the list comprehension. It is in the scope of the list comprehension only. Only with the three a-functions you have ever access to that k. And on the other hand, you cannot tell the a-funcions to use another k. The k from the list comprehension is in their closure. The k=50 has a completely different scope.

If you want the other k in the a-functions, you must define them this way:

a=[lambda k : k_compr for k_kompr in [1,2,3]]
[e() for e in a]

and pass the k to them. But I think you question is just informatory. Nobody would ever use such a list comrehension.

Upvotes: 1

Related Questions