Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #54477 > unrolled thread

lambda - strange behavior

Started byKasper Guldmann <gmane@kalleguld.dk>
First post2013-09-20 15:21 +0000
Last post2013-09-20 19:30 +0300
Articles 4 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  lambda - strange behavior Kasper Guldmann <gmane@kalleguld.dk> - 2013-09-20 15:21 +0000
    Re: lambda - strange behavior Rotwang <sg552@hotmail.co.uk> - 2013-09-20 16:52 +0100
    Re: lambda - strange behavior rusi <rustompmody@gmail.com> - 2013-09-20 09:25 -0700
    Re: lambda - strange behavior Jussi Piitulainen <jpiitula@ling.helsinki.fi> - 2013-09-20 19:30 +0300

#54477 — lambda - strange behavior

FromKasper Guldmann <gmane@kalleguld.dk>
Date2013-09-20 15:21 +0000
Subjectlambda - strange behavior
Message-ID<mailman.185.1379690708.18130.python-list@python.org>
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 )

[toc] | [next] | [standalone]


#54483

FromRotwang <sg552@hotmail.co.uk>
Date2013-09-20 16:52 +0100
Message-ID<l1hqv8$8k9$1@dont-email.me>
In reply to#54477
On 20/09/2013 16:21, Kasper Guldmann wrote:
> 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))

[toc] | [prev] | [next] | [standalone]


#54489

Fromrusi <rustompmody@gmail.com>
Date2013-09-20 09:25 -0700
Message-ID<57ea049c-8b78-43ff-a14c-b9b4b3e5e2a4@googlegroups.com>
In reply to#54477
On Friday, September 20, 2013 8:51:20 PM UTC+5:30, Kasper Guldmann wrote:
> 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> 

[toc] | [prev] | [next] | [standalone]


#54491

FromJussi Piitulainen <jpiitula@ling.helsinki.fi>
Date2013-09-20 19:30 +0300
Message-ID<qot7gebcv76.fsf@ruuvi.it.helsinki.fi>
In reply to#54477
Kasper Guldmann writes:

> 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.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web