473,237 Members | 1,265 Online

# list of lambda

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'

my workaround is to define helper class with __call__ method:
class X:
def __init__(self,s): self.s=s
def __call__(self): return self.s.upper()
l=[X(x) for x in ['a','b','c']]

now it is correct, l[0]()=='A'

it is OK or it is bug?
can i do it correctly simplier than with helper X class?

thanks
Honza Prochazka
Nov 11 '05 #1
6 1940
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'

Fredrik Lundh provided the general solution, but in this specific case,
the simplest solution is:

l = [x.upper for x in ['a', 'b', 'c']]
Nov 22 '05 #2
jena <je**@vlakosim.com> writes:
l=[lambda:x.upper() for x in ['a','b','c']]
then l[0]() returns 'C', i think, it should be 'A'

Yeah, this is Python late binding, a standard thing to get confused
over. You want:

l = [lambda x=x: x.upper() for x in ['a', 'b', 'c']]
Nov 22 '05 #3

Leif K-Brooks wrote:
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'

Fredrik Lundh provided the general solution, but in this specific case,
the simplest solution is:

l = [x.upper for x in ['a', 'b', 'c']]

how about :

l = ['A','B','C']

Nov 22 '05 #4
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.

Nov 22 '05 #5
On 11 Nov 2005 18:28:22 -0800, Paul Rubin <http://ph****@NOSPAM.invalid> wrote:
jena <je**@vlakosim.com> writes:
l=[lambda:x.upper() for x in ['a','b','c']]
then l[0]() returns 'C', i think, it should be 'A'

Yeah, this is Python late binding, a standard thing to get confused
over. You want:

l = [lambda x=x: x.upper() for x in ['a', 'b', 'c']]

or if you want the upper() eagerly (and do it only once each,
in case of multiple lambda calls)

l = [lambda x=x.upper():x for x in ['a', 'b', 'c']]
l = [lambda x=x.upper():x for x in ['a', 'b', 'c']]
for lamb in l: print lamb.func_defaults[0],'=?=',lamb()

...
A =?= A
B =?= B
C =?= C

Regards,
Bengt Richter
Nov 22 '05 #6
On Sat, 12 Nov 2005 14:55:31 +1100, Steven D'Aprano <st***@REMOVETHIScyber.com.au> wrote:
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.

Yes, but it exposes bad (improvable;-) repr text IMO:
It's not just a method, it's a _bound_ method, but the repr text
doesn't say so (unless you read clues between the lines)
'a'.upper <built-in method upper of str object at 0x02EB03A0> 'a'.upper.__self__ 'a'
str.upper <method 'upper' of 'str' objects>

That's the unbound method. If we bind it to 'a' in the usual way
behind inst.method,
type('a') <type 'str'> type('a').__dict__ <dictproxy object at 0x02E81C44> type('a').__dict__['upper'] <method 'upper' of 'str' objects> type('a').__dict__['upper'].__get__('a', type('a')) <built-in method upper of str object at 0x02EB03A0>

Or str.upper.__get__('a', str) <built-in method upper of str object at 0x02EB03A0>

we get the bound method. So the clue is "... of str objects" vs ".. of str object at ..."
Maybe nicer would be
<bound built-in method upper of str object at 0x02EB03A0>

Same if it's inherited: class S(str): pass ... S('a').upper <built-in method upper of S object at 0x02F87A7C> S('a').upper() 'A'

But if we override, we get 'bound method ...'
class S(str): ... def upper(self): return 'S.upper => %r' % str.upper(self)
... S('a').upper <bound method S.upper of 'a'> S('a').upper()

"S.upper => 'A'"

A nit. I thought it clever to replace the lambda with the the bound method,
but while supplying a callable, it still postpones the upper execution, and
will repeat it for each call, whereas lambda x=x.upper():x does the work once
up front (in general not always possible, of course).

Regards,
Bengt Richter
Nov 22 '05 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

### Similar topics

 11 by: Nicolas Girard | last post by: Hi, Forgive me if the answer is trivial, but could you tell me how to achieve the following: {k1:,k2:v3,...} --> ,,,...] The subtle point (at least to me) is to "flatten" values that are... 23 by: Fuzzyman | last post by: Pythons internal 'pointers' system is certainly causing me a few headaches..... When I want to copy the contents of a variable I find it impossible to know whether I've copied the contents *or*... 42 by: Alan McIntyre | last post by: Hi all, I have a list of items that has contiguous repetitions of values, but the number and location of the repetitions is not important, so I just need to strip them out. For example, if my... 24 by: Mandus | last post by: Hi there, inspired by a recent thread where the end of reduce/map/lambda in Python was discussed, I looked over some of my maps, and tried to convert them to list-comprehensions. This one I... 3 by: Jef Driesen | last post by: The number of items in my std::list is changed after sorting (using std::list member function sort). I'm using MSVC6 and the actual (pseudo) code is posted below. The output from size() is... 5 by: Max Rybinsky | last post by: Hello! Please take a look at the example. >>> a = # Just a list of tuples >>> a Now i want to get a list of functions x*y/n, for each (x, y) in a: 11 by: Josiah Manson | last post by: In the following program I am trying to learn how to use functional programming aspects of python, but the following program will crash, claiming that the recursion depth is too great. I am... 2 by: james_027 | last post by: hi, are there available library or pythonic algorithm for sorting a list of list depending on the index of the list inside the list of my choice? d_list = , , , , 13 by: Joel Koltner | last post by: Is there an easy way to get a list comprehension to produce a flat list of, say, for each input argument? E.g., I'd like to do something like: for x in range(4) ] ....and receive 0 by: jianzs | last post by: Introduction Cloud-native applications are conventionally identified as those designed and nurtured on cloud infrastructure. Such applications, rooted in cloud technologies, skillfully benefit from... 0 by: abbasky | last post by: ### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method... 2 by: isladogs | last post by: The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE... 0 by: fareedcanada | last post by: Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like... 0 by: egorbl4 | last post by: Скачал я git, хотел начать настройку, а там вылезло вот это Что это? Что мне с этим делать? ... 0 by: MeoLessi9 | last post by: I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines".... 0 by: DolphinDB | last post by: The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take... 0 by: DolphinDB | last post by: Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million... 0 by: isladogs | last post by: The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.