How do lexical closures work?
closures, late-binding, lazy-evaluation, python, python-closures
Solution
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.
Problem
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".