Why results of map() and list comprehension are different?
closures, generator-expression, late-binding, list-comprehension, python
Solution
They are different, because the value of `i` in both the generator expression and the list comp are evaluated lazily, i.e. when the anonymous functions are invoked in `f`. By that time, `i` is bound to the last value if `t`, which is -1.
So basically, this is what the list comprehension does (likewise for the genexp):
x = []
i = 1 # 1. from t
x.append(lambda: i)
i = -1 # 2. from t
x.append(lambda: i)
Now the lambdas carry around a closure that references `i`, but `i` is bound to -1 in both cases, because that is the last value it was assigned to.
If you want to make sure that the lambda receives the current value of `i`, do
f(*[lambda u=i: u for i in t])
This way, you force the evaluation of `i` at the time the closure is created.
Edit: There is one difference between generator expressions and list comprehensions: the latter leak the loop variable into the surrounding scope.
Problem
The following test fails: ``` #!/usr/bin/env python def f(*args): """ >>> t = 1, -1 >>> f(*map(lambda i: lambda: i, t)) [1, -1] >>> f(*(lambda: i for i in t)) # -> [-1, -1] [1, -1] >>> f(*[lambda: i for i in t]) # -> [-1, -1] [1, -1] """ alist = [a() for a in args] print(alist) if __name__ == '__main__': import doctest; doctest.testmod() ``` In other words: ``` >>> t = 1, -1 >>> args = [] >>> for i in t: ... args.append(lambda: i) ... >>> map(lambda a: a(), args) [-1, -1] >>> args = [] >>> for i in t: ... args.append((lambda i: lambda: i)(i)) ... >>> map(lambda a: a(), args) [1, -1] >>> args = [] >>> for i in t: ... args.append(lambda i=i: i) ... >>> map(lambda a: a(), args) [1, -1] ```