lambda - strange behavior

K

Kasper Guldmann

I was playing around with lambda functions, but I cannot seem to fully grasp
them. I was running the script below in Python 2.7.5, and it doesn't do what
I want it to. Are lambda functions really supposed to work that way. How do
I make it work as I intend?

f = []
for n in range(5):
f.append( lambda x: x*n )

assert( f[4](2) == 8 )
assert( f[3](3) == 9 )
assert( f[2](2) == 4 )
assert( f[1](8) == 8 )
assert( f[0](2) == 0 )
 
R

Rotwang

I was playing around with lambda functions, but I cannot seem to fully grasp
them. I was running the script below in Python 2.7.5, and it doesn't do what
I want it to. Are lambda functions really supposed to work that way. How do
I make it work as I intend?

f = []
for n in range(5):
f.append( lambda x: x*n )

assert( f[4](2) == 8 )
assert( f[3](3) == 9 )
assert( f[2](2) == 4 )
assert( f[1](8) == 8 )
assert( f[0](2) == 0 )

This is a common gotcha. In the function "lambda x: x*n" n is a global
variable, which means that when the function is called it searches
globals() for the current value of n, which is 4 (since that was its
value when the for loop ended). There are several ways to define
functions that depend on the values bound to names at creation time,
like you're trying to do. One is to use the fact that default function
arguments are evaluated when the function is created. So this will work:

f = []
for n in range(5):
f.append(lambda x, n = n: x*n)


Another is to use the fact that arguments passed in function calls are
evaluated when the function is called. That means that you can define a
function which takes a parameter as an argument and returns a function
which depends on that parameter to get the desired behaviour, like this:

f = []
for n in range(5):
f.append((lambda n: lambda x: x*n)(n))
 
R

rusi

I was playing around with lambda functions, but I cannot seem to fully grasp
them. I was running the script below in Python 2.7.5, and it doesn't do what
I want it to. Are lambda functions really supposed to work that way. How do
I make it work as I intend?

f = []
for n in range(5):
f.append( lambda x: x*n )

assert( f[4](2) == 8 )
assert( f[3](3) == 9 )
assert( f[2](2) == 4 )
assert( f[1](8) == 8 )
assert( f[0](2) == 0 )

You are not wrong in being surprised. Here's the python rewritten in a more functional style

And then the same in haskell.

$ python3
Python 3.3.2+ (default, Jun 13 2013, 13:47:13)
[GCC 4.8.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
fl= [lambda x: x + n for n in range(5)]
[f(1) for f in fl] [5, 5, 5, 5, 5]

-------haskell-----
$ ghci
GHCi, version 7.4.1: http://www.haskell.org/ghc/ :? for help

Prelude> let fl = [\x-> x+n | n <- [0..4]]
Prelude> [f 1 | f <- fl]
[1,2,3,4,5]
Prelude>
 
J

Jussi Piitulainen

Kasper said:
I was playing around with lambda functions, but I cannot seem to
fully grasp them. I was running the script below in Python 2.7.5,
and it doesn't do what I want it to. Are lambda functions really
supposed to work that way. How do I make it work as I intend?

f = []
for n in range(5):
f.append( lambda x: x*n )

assert( f[4](2) == 8 )
assert( f[3](3) == 9 )
assert( f[2](2) == 4 )
assert( f[1](8) == 8 )
assert( f[0](2) == 0 )

It's not the lambda, it's the for. All five functions share the one n,
whose value the for changes in each iteration so that the last value
remains in force after the loop.

There's a trick: f.append( lambda x, n=n: x*n ). Now the lambda gets
to remember the value of the n of the for as the default value of its
own local n.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,967
Messages
2,570,148
Members
46,694
Latest member
LetaCadwal

Latest Threads

Top