9

I was slightly surprised by this example given by Eli Bendersky (http://eli.thegreenplace.net/2015/the-scope-of-index-variables-in-pythons-for-loops/)

>>> def foo(): ... lst = [] ... for i in range(4): ... lst.append(lambda: i) ... print([f() for f in lst]) ... >>> foo() [3, 3, 3, 3] 

But when I thought about it, it made some sense — the lambda is capturing a reference to i rather than i's value.

So a way to get around this is the following:

>>> def foo(): ... lst = [] ... for i in range(4): ... lst.append((lambda a: lambda: a)(i)) ... print([f() for f in lst]) ... >>> foo() [0, 1, 2, 3] 

It appears that the reason that this works is that when i is provided to the outer lambda, the outer lambda creates a scope and dereferences i, setting a to i. Then, the inner lambda, which is returned, holds a reference to a.

Is this a correct explanation?

1

3 Answers 3

15

Default param is an another way to catch a value:

lst.append(lambda i=i: i) 
Sign up to request clarification or add additional context in comments.

Comments

3

It appears that the reason that this works is that when i is provided to the outer lambda, the outer lambda creates a scope and dereferences i, setting a to i. Then, the inner lambda, which is returned, holds a reference to a.

Is this a correct explanation?

I don't like it. Python does not pass by reference:

def func(x): x = 10 num = 3 func(num) print num #=>3 

As a result, the terms reference and dereference are not in the python lexicon. Or, you could say that python always dereferences a function argument before assigning it to a parameter variable--so your explanation doesn't really explain anything.

The reason the example works is because of the rule:

A function's local variables are destroyed after it finishes executing.

A function's local variables include its parameter variables. Every time the outer lambda executes, a new 'a' variable is created. As a result, each inner lambda closes over a different 'a' variable.

You did allude to that state of affairs:

the outer lambda creates a scope

...

the lambda is capturing a reference to i rather than i's value.

Or, as I like to phrase it.

A closure closes over variables--not values.

That is the way closures work in most languages(an exception being perl, where closures close over values).

Comments

0

Yes, it looks correct. If you are familiar with javascript and know closures, you will notice how similar they are.

If not - there is a nice explanation on SO regarding JS closures and the concept is absolutely the same (as well as the explanation and even wrong and correct usage).

1 Comment

Yep! I am familiar with the concept of the closure!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.