lambda in list comprehension acting funny
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Fri Jul 13 02:36:45 EDT 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