1

Very simple code:

for f in [lambda x: x*i for i in [1, 2, 3]]:
    print(f(1))

returns:

3
3
3

But I would expect to get 1, 2, 3.

I think I know the reason why this happens (lazy evaluation, and the value of i is evaluated only at the end, when the for loop has ended and i=3), but my question is: is there a way to avoid this "misbehavior" while keeping the list-comprehension syntax?

I tried to use copy.deepcopy() on i:

for f in [lambda x: x*deepcopy(i) for i in [1, 2, 3]]:
    print(f(1))

but the result is the same.

  • `i` is a *closure variable*, taken from the parent namespace, *when you call the function*. By the time you call the function (after creating the list) the value of `i` has moved on to `3`. Don't leave it a closure, use a keyword argument: `lambda x, i=i: x * i`. Now you captured the value of `i` as it was bound when the lambda is created. – Martijn Pieters Oct 28 '19 at 16:15
  • Thank you very much Martijin, I realized this possible way out. I was wondering if there is a way to declare the list of lambda functions upfront, to avoid the need of "carrying" the `i` value. It seems that it is not possible then. It would have been more comfortable. – Francesco Calcavecchia Oct 28 '19 at 16:28
  • This isn't due to *lazy evaluation*, rather, this is due to the *late-binding* of *lexically scoped* closures. – juanpa.arrivillaga Oct 28 '19 at 18:16

0 Answers0