List comprehension + lambdas - strange behaviour

Terry Reedy tjreedy at udel.edu
Fri May 7 16:54:21 EDT 2010


On 5/7/2010 8:31 AM, Neil Cerutti wrote:
> On 2010-05-07, Terry Reedy<tjreedy at udel.edu>  wrote:
>> On 5/6/2010 3:34 PM, Artur Siekielski wrote:
>>> Hello.
>>> I found this strange behaviour of lambdas, closures and list
>>> comprehensions:
>>>
>>>>>> funs = [lambda: x for x in range(5)]
>>>>>> [f() for f in funs]
>>> [4, 4, 4, 4, 4]
>>
>> You succumbed to lambda hypnosis, a common malady ;-). The
>> above will not work in 3.x, which does not leak comprehension
>> iteration variables.
>
> It functions the same in 3.1.
>
> Python 3.1.1 (r311:74483, Aug 17 2009, 17:02:12) [MSC v.1500 32 bit (Intel)] on
> win32
> Type "help", "copyright", "credits" or "license" for more information.
>>>> funs = [lambda: x for x in range(5)]
>>>> [f() for f in funs]
> [4, 4, 4, 4, 4]

Ok.

 >>> x
Traceback (most recent call last):
   File "<pyshell#1>", line 1, in <module>
     x
NameError: name 'x' is not defined
#only in 3.x

But because the list comp is implemented in 3.x as an anonymous 
function, which is then called and discarded (an implementation that I 
believe is not guaranteed by the language ref), the lambda expression 
defines a nested function which captures the (final) value of x.

 >>> funs[0].__closure__[0].cell_contents
4

So it works (runs without exception), but somewhat accidentally and for 
a different reason than in 2.x, where 'x' is 4 at the global level.

Terry Jan Reedy








More information about the Python-list mailing list