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