it looks strange

Peter Otten __peter__ at web.de
Tue Sep 27 04:32:31 EDT 2016


cpxuvs at gmail.com wrote:

>>>> li=[lambda :x for x in range(10)]
>>>> res=li[0]()
>>>> print res
> 9
> 
> why?

Look what happens if you look up x manually:

>>> li = [lambda :x for x in range(10)]
>>> x
9

So at this point x is 9 and a function written to return the value bound to 
the name x will return 9

>>> li[0]()
9

>>> x = 42
>>> li[0]()
42

This is called late binding and neither the lambda behaves like any other 
function

>>> def f(): return x
... 
>>> f()
42
>>> x = "whatever"
>>> f()
'whatever'

To get the desired results you can either use default values which are bound 
when the function is created

>>> li = [lambda x=x: x for x in range(9)]
>>> li[0]()
0
>>> li[5]()
5

or a closure:

>>> li = [(lambda x: lambda: x)(x) for x in range(9)]
>>> li[0]()
0
>>> li[5]()
5

This looks less messy when you use a function:

>>> def make_const_func(value):
...     return lambda: value
... 
>>> li = [make_const_func(x) for x in range(9)]
>>> li[7]()
7

In both cases the value is bound inside a function and not affected by the 
current binding of the global x. 

In Python 3 the situation is almost the same, except that the x from the 
list comprehension is no longer exposed to the enclosing namespace.





More information about the Python-list mailing list