Weird lambda behavior (bad for)
namekuseijin
namekuseijin.nospam at gmail.com
Sat Apr 25 21:33:34 EDT 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