Lambda function

This is not pertaining to any exercise in the course.
I’d appreciate if someone can help to explain this issue: Why the result is not [0, 2, 4, 6] ?
def multipliers():
return [lambda x : i * x for i in range(4)]

print([m(2) for m in multipliers()])

In python, there’s a concept called late binding closures. What this effectively means is that the values for your variables are looked up when the function has been defined. As the for loop inside your list comprehension is defining a function each time, the actual behaviour you want will not run until the last function definition i.e. when the for loop has been completed. So the behaviour after calling is as follows:

  1. Run through the for loop from 0 to 3
  2. Define your lambda function as x * 3, since this is the final value for i
  3. substitute x for 2 in all 4 function calls, resulting in [6, 6, 6, 6]

Honestly, what I would do instead would be to just use a regular function, like so:

def multipliers(x):
  return [x * i for i in range(4)]

# prints [0, 2, 4, 6]

If you are set on using a lambda function then there is a workaround. You can put the i into your lambda function, therefore the i is defined at each function call and thus the correct i is carried through, so instead use

def multipliers():
return [lambda x, i=i : i * x for i in range(4)]

print([m(2) for m in multipliers()])

This takes a little longer to run than the previous code as you define and call 4 functions, instead of just one. I would recommend in this scenario just using a regular function definition, however it is up to you depending on what you’re using it for i.e. lambda is fine here if it’s just for experimentation.


Thank you @adamgaffney96. Your explanation is awesome - Late binding closure!
Thanks for the solution.
Apparently, I also find another workaround using the yield keyword:

def multipliers():
    for i in range(4): yield lambda x: x * i
print([m(2) for m in multipliers()])
# [0, 2, 4, 6]