On Sat, 12 Nov 2005 14:55:31 +1100, Steven D'Aprano <[EMAIL PROTECTED]> 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 -- http://mail.python.org/mailman/listinfo/python-list