473,320 Members | 1,817 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

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 1945
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: 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...
1
isladogs
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...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

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.