multipliers
function which returns a list of functions (more exactly some anonymous functions aka lambdas) :
multipliers()
# the return of multipliers function
[<function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c048>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c0d0>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c158>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c1e0>]
[m(2) for m in multipliers()]
list comprehension in which you iterate and call each function from the list returned by multipliers
.
The catch is that python closures are late-binding , which means that the values of variables used in closures are looked up at the time the inner function it is called (lambda x : i * x for i in range(4)
)
That is why for your case the printed list is [6, 6, 6, 6]
because the functions from the list (returned by multipliers
) are actually looking something like this lambda x : 3 * x
and when you are iterating and calling each lambda in your list comprehension [m(2) for m in multipliers()]
you are actually calling more or less the same function
If you want to "fix" the behaviour of multipliers
function you can do something like this:
def fix_multipliers():
return [ lambda x, i=i: i*x for i in range(4)]
Afterwards you will see the "expected" behaviours:
print([m(2) for m in fix_multipliers()])
[0, 2, 4, 6]
PS : Closure is a function object that remembers values in enclosing scope even if they are not present in memory aka extend the scope of the inner function.