fun with lambdas

Mike Meyer mwm at mired.org
Fri Oct 21 00:16:05 EDT 2005


Robert Kern <robert.kern at gmail.com> writes:
> Juan Pablo Romero wrote:
>> Hello!
>> 
>> given the definition
>> 
>> def f(a,b): return a+b
>> 
>> With this code:
>> 
>> fs = [ lambda x: f(x,o) for o in [0,1,2]]
>> 
>> or this
>> 
>> fs = []
>> for o in [0,1,2]:
>>     fs.append( lambda x: f(x,o) )
>> 
>> I'd expect that fs contains partial evaluated functions, i.e.
>> 
>> fs[0](0) == 0
>> fs[1](0) == 1
>> fs[2](0) == 2
>> 
>> But this is not the case :(
>> 
>> What is happening here?
>
> Namespaces. The functions are looking up o at runtime. In both cases, o
> is bound to the last object in [0,1,2] once the iteration is finished.
>
> Try this (although I'm sure there are better ways):
>
> In [4]: fs = [lambda x, o=o: f(x, o) for o in [0,1,2]]
>
> In [5]: fs[0](0)
> Out[5]: 0
>
> In [6]: fs[0](1)
> Out[6]: 1
>
> In [7]: fs[0](2)
> Out[7]: 2

Right explanation. Right solution. Wrong examples. He wanted to see:

>>> fs[0](0)
0
>>> fs[1](0)
1
>>> fs[2](0)
2
>>> 

List comprehensions were purposely designed to mimic for loops, which
(unlike other languages) don't create a new variable for each pass
through the loop. ((They also "leak" the variable to the surrounding
namespace.) So you need to capture the current value of the loop index
somewhere. An alternative (and maybe slightly cleaner) method is:

>>> def makef(a):
...  return lambda b: a + b
... 
>>> fs = [makef(o) for o in [0, 1, 2]]
>>> fs[0](0)
0
>>> fs[1](0)
1
>>> fs[2](0)
2
>>> 

Generator comprehensions have the same issue:

>>> fs = list(lambda x: f(o, x) for o in [0, 1, 2])
>>> fs[0](0)
2
>>> fs[1](0)
2
>>> fs[2](0)
2
>>> 

          <mike
-- 
Mike Meyer <mwm at mired.org>			http://www.mired.org/home/mwm/
Independent WWW/Perforce/FreeBSD/Unix consultant, email for more information.



More information about the Python-list mailing list