["python","closures","lazy-evaluation","late-binding","python-closures"]
How do lexical closures work?

While I was investigating a problem I had with lexical closures in Javascript code, I came along this problem in Python: flist = [] for i in xrange(3): def func(x): return x * i flist.append(func) for f in flist: print f(2) Note that this example mindfully avoids lambda. It prints "4 4 4", which is surprising. I'd expect "0 2 4". This equivalent Perl code does it right: my @flist = (); foreach my $i (0 .. 2) { push(@flist, sub {$i * $_[0]}); } foreach my $f (@flist) { print $f->(2), "\n"; } "0 2 4" is printed. Can you please explain the difference ? Update: The problem is not with i being global. This displays the same behavior: flist = [] def outer(): for i in xrange(3): def inner(x): return x * i flist.append(inner) outer() #~ print i # commented because it causes an error for f in flist: print f(2) As the commented line shows, i is unknown at that point. Still, it prints "4 4 4".
Python is actually behaving as defined. Three separate functions are created, but they each have the closure of the environment they're defined in - in this case, the global environment (or the outer function's environment if the loop is placed inside another function). This is exactly the problem, though - in this environment, i is modified, and the closures all refer to the same i. Here is the best solution I can come up with - create a function creater and invoke that instead. This will force different environments for each of the functions created, with a different i in each one. flist = [] for i in xrange(3): def funcC(j): def func(x): return x * j return func flist.append(funcC(i)) for f in flist: print f(2) This is what happens when you mix side effects and functional programming.