I was expecting Python's lambda
to keep reference to value of local variables. So when I wrote:
>>> ls = [
... lambda: x*x
... for x in range(3)
... ]
>>> [f() for f in ls]
[4, 4, 4]
I expected the result to be: [0,1,4]
where each lambda would remember a different value of x
used to create it. But as you can see above, the result is [4,4,4]
as if they all have been eval against the last value of x
. This is unintuitive as x
does not even exists in the context the lambda
s are evaluated in.
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
Just to make sure, I create a local scope to change value of x
after the last lambda
creation to see if the evaluation use the last value of x
and it sure did.
>>> def get_ms():
... ms = []
... for x in range(3):
... ms.append(lambda: x*x)
... print([f() for f in ms])
... x = 3
... return ms
...
>>> ms = get_ms()
[4, 4, 4]
>>> [f() for f in ms]
[9, 9, 9]
NOTE: It appears inner function also works the same way.
First question: Is my above analysis of the situation correct? (Lambda remember references to local variable used to create it rather than value of the variable, and this variable somehow persist outside its scope)
Second question: What is behaviour supposed to be used for? Or is just an undefined part of specification?
The easiest way I can think of to get the behaviour I originally wanted is:
>>> import functools
>>> def square(x):
... return x*x
...
>>> ls_ = [
... functools.partial(square, x)
... for x in range(3)
... ]
>>> [f() for f in ls_]
[0, 1, 4]
Final question: Is there a better way than using functools.partial
as seen above?