lambda in list comprehension acting funny

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri Jul 13 08:36:45 CEST 2012


On Thu, 12 Jul 2012 21:33:40 -0700, rusi wrote:

> On Jul 11, 11:41 am, Daniel Fetchinson <fetchin... at googlemail.com>
> wrote:
>> funcs = [ lambda x: x**i for i in range( 5 ) ] print funcs[0]( 2 )
>> print funcs[1]( 2 )
>> print funcs[2]( 2 )
>>
>> This gives me
>>
>> 16
>> 16
>> 16
>>
>> When I was excepting
>>
>> 1
>> 2
>> 4
>>
>> Does anyone know why?
>>
>> Cheers,
>> Daniel
> 
> Your expectations are reasonable.

You forget to finish that sentence.

"Your expectations are reasonable, for languages that don't have 
variables which can actually vary."

*wink*

For purely functional languages like Haskell, the behaviour you show 
below makes sense. Since Haskell doesn't allow variables to change their 
value, once a closure sees i=1 (say), then it must *always* see i=1.

But that's not the case in Python, where the Haskell behaviour would be 
unfortunate. Imagine if you did this:

VERBOSE = True

def function(arg):
    if VERBOSE:
        print("calling function with arg %r" % arg)
    process(arg)

You would expect the function to honour changes to the variable VERBOSE, 
would you not? Using Python's scoping rules for closures, it does. Using 
Haskell's rules, it wouldn't.

> Heres the equivalent in Haskell from which python has taken
> comprehensions.
> ---------------------------------
> GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
> 
> Prelude> let funcs = [ (\ x -> x ^ i)| i <- [0..4]] 
> Prelude> (funcs !! 0)(2)
> 1
> Prelude> (funcs !! 1)(2)
> 2
> Prelude> (funcs !! 2)(2)
> 4
> Prelude>



-- 
Steven



More information about the Python-list mailing list