list of lambda

Steven D'Aprano steve at REMOVETHIScyber.com.au
Fri Nov 11 22:55:31 EST 2005


On Sat, 12 Nov 2005 00:17:59 +0100, jena wrote:

> hello,
> when i create list of lambdas:
> l=[lambda:x.upper() for x in ['a','b','c']]
> then l[0]() returns 'C', i think, it should be 'A'

What is wrong with just doing this?

L = [x.upper() for x in ['a', 'b', 'c']]



py> L = [lambda: x.upper() for x in ['a', 'b', 'c']]
py> L
[<function <lambda> at 0xf6ff9844>, <function <lambda> at 0xf6ff987c>, <function <lambda> at 0xf6ff98b4>]

Why do you want a list of functions?

>>> L[0]()
'C'
>>> L[1]()
'C'
>>> L[2]()
'C'

What you have discovered is a bug in your code, caused by some accidental
behaviour of Python which will be removed in a new version soon:

py> [x.upper() for x in "abc"]
['A', 'B', 'C']
py> x
'c'

You can see that the temporary variable x used by the list comprehension
is exposed. It shouldn't be, and soon won't be -- it will be an error to
refer to the list comp variable outside the list comp.

Now watch this:

py> x = "it is was a mistake to expose list comprehension variables"
py> L[0]()
'IT IS WAS A MISTAKE TO EXPOSE LIST COMPREHENSION VARIABLES'
py> L[1]()
'IT IS WAS A MISTAKE TO EXPOSE LIST COMPREHENSION VARIABLES'

Do you see what is going on now?


Assuming you actually do need a list of *functions*, rather than just
the results of those functions, this would be the way to do it:

lambda x: x.upper()

is an anonymous function which takes input x and returns x converted to
upper case.

lambda x: x.upper  # note the brackets are gone

is an anonymous function which takes input x and returns a function
(technically, a method) which will return x converted to upper case when
called.

So the list comprehension you want is:


# note all the brackets
py> L = [(lambda x: x.upper)(x) for x in ['a', 'b', 'c']]
py> L
[<built-in method upper of str object at 0xf706a040>, <built-in method upper of str object at 0xf706a0e0>, <built-in method upper of str object at 0xf706ca00>]
py> L[0](); L[1](); L[2]() 
'A'
'B'
'C'

But now that gives us a clue that using lambda just adds too much
complication! What we want is the string methods, and we don't need lambda
to get them. So we can make it much simpler:

py> L = [x.upper for x in ['a', 'b', 'c']]
py> L
[<built-in method upper of str object at 0xf706a040>, <built-in method upper of str object at 0xf706a0e0>, <built-in method upper of str object at 0xf706ca00>]
py> L[0](); L[1](); L[2]()
'A'
'B'
'C'

Hope this helps.


-- 
Steven.




More information about the Python-list mailing list