Weird lambda behavior (bad for)

namekuseijin namekuseijin.nospam at gmail.com
Sun Apr 26 03:33:34 CEST 2009


The real issue here has nothing to do with closures, lexical capture or 
anything like that.  It's a long known issue called side-effects.

Trying to program in a functional style in the presence of side-effects 
is bad.  *for* is the main perpetrator of side-effects here, because it 
updates its iterating variables rather than create a new lexical 
environment for them.

Say:
 >>> x
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
 >>> ps=[]
 >>> for x in range(3): ps.append( lambda y: x+y )
...
 >>> ps
[<function <lambda> at 0x8389a04>, <function <lambda> at 0x8389a74>, 
<function <lambda> at 0x8389c34>]
 >>> ps[0](1)
3
 >>> ps[1](1)
3
 >>> ps[2](1)
3

It also polutes the namespace by letting x live on:
 >>> x
2

Even list comprehensions still suffer from the updating:
 >>> xs=[lambda y:x+y for x in range(3)]
 >>> xs[0](1)
3
 >>> xs[1](1)
3
 >>> xs[2](1)
3

No such issue with map, which truly does it the proper functional way:
 >>> ys=map(lambda x: lambda y: x+y, range(3))
 >>> ys[0](1)
1
 >>> ys[1](1)
2
 >>> ys[2](1)
3

I don't like *for* at all.  It both makes it tough to get true closures 
and also unnecessarily pollutes the namespace with non-local variables.

So, beware of the lack of true lexical bindings associated with the evil 
imperative *for*! :)



More information about the Python-list mailing list