3

Take this code snippet for example:

a = []
for x in range(2):
    a.append(lambda: print(x))
print(a[0](), a[1]())

The output is:

1 1

But I expected it to be

0 1

How do I fix this?

Avi Shah
  • 109
  • 6
  • try putting `del x` in between the `for loop` and the last `print statement`. When you are executing lambda it is looking for variable x, which has the latest value as 1. – Epsi95 Feb 04 '21 at 05:39

3 Answers3

3

Use default arguments:

a = []
for x in range(2):
    a.append(lambda x = x: print(x))
print(a[0](), a[1]())

This works because the default value is evaluated when the function is created. Otherwise all lambda functions will point to the last value of x, which was 1.

sarartur
  • 1,178
  • 1
  • 4
  • 13
  • 1
    Can you add an explanation of why this works? It will be useful. Abdul has added an explanation why OP's code won't work but It will be useful I think for explaining this. – Rahul Feb 04 '21 at 05:48
  • @Rahul posted the explanation. Also see Abdul Niyas P M's answer. – sarartur Feb 04 '21 at 05:54
  • It's basically creating a parameter x and assigning a default value to it, so the equivalent to >>>lambda x = x: print(x) is >>>def someThing(x=x): print(x) – Avi Shah Feb 04 '21 at 05:54
  • Thanks @sarartur. I guess Avi Shah already knew the answer. Thanks for sharing. – Rahul Feb 04 '21 at 05:57
1

@sarartur already provided the solution. Here is little more explanation for this behavior.

This is called Late Binding Closures. Quoting from the blog,

Python’s closures are late binding. This means that the values of variables used in closures are looked up at the time the inner function is called.

So here whenever any of the returned functions are called, the value of i is looked up in the surrounding scope at call time. By then, the loop has completed and i is left with its final value of 1.

Abdul Niyas P M
  • 18,035
  • 2
  • 25
  • 46
0

This is happening because your lambda expressions are printing x, but x is being updated by your for loop, so by the time your lambda expressions are invoked, x has finished with a value of 1 because that's the last value in range(2).

>>> for num in range(10):
...     pass
...
>>> num
9
ddejohn
  • 8,775
  • 3
  • 17
  • 30