Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > lambda functions within list comprehensions

Reply
Thread Tools

lambda functions within list comprehensions

 
 
Max Rybinsky
Guest
Posts: n/a
 
      10-29-2005
Hello!

Please take a look at the example.

>>> a = [(x, y) for x, y in map(None, range(10), range(10))] # Just a list of tuples
>>> a

[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6), (7, 7), (8,
, (9, 9)]

Now i want to get a list of functions x*y/n, for each (x, y) in a:

>>> funcs = [lambda n: x * y / n for x, y in a]


It looks consistent!

>>> funcs

[<function <lambda> at 0x010F3DF0>, <function <lambda> at 0x010F7CF0>,
<function <lambda> at 0x010F7730>, <function <lambda> at 0x010FD270>,
<function <lambda> at 0x010FD0B0>, <function <lambda> at 0x010FD5B0>,
<function <lambda> at 0x010FD570>, <function <lambda> at 0x010FD630>,
<function <lambda> at 0x01100270>, <function <lambda> at 0x011002B0>]

....and functions are likely to be different.

>>> funcs[0](1)

81

But they aren't!

>>> for func in funcs:

.... print func(1)
....
81
81
81
81
81
81
81
81
81
81

It seems, all functions have x and y set to 9.
What's wrong with it? Is it a bug?

On the other hand, this problem has a solution:

>>> def buldFunc(x, y):

.... return lambda n: x * y / n
....
>>> funcs = [buldFunc(x, y) for x, y in a]


.... and it does work!

But why not to save several lines of code?

Thanks in advance.

 
Reply With Quote
 
 
 
 
Alex Martelli
Guest
Posts: n/a
 
      10-29-2005
Max Rybinsky <(E-Mail Removed)> wrote:
...
> >>> funcs = [lambda n: x * y / n for x, y in a]

...
> It seems, all functions have x and y set to 9.
> What's wrong with it? Is it a bug?


It's known as *late binding*: names x and y are looked up when the
lambda's body is executing, and at that time they're both set to the
value 9. You appear to have expected *early binding*, with the names
being somehow looked up at the time the lambda keyword executed, but
that's just not Python semantics (and would interfere with many other
cases where late binding is exactly what one wants).

You've already indicated what's probably the best solution -- a factory
function instead of the lambda. There are other ways to request early
binding, and since you appear to value compactness over clarity the most
compact way is probably:

funcs = [lambda n, x=x, y=y: x*y/n for x, y in a]

it's not perfect, because the resulting functions can take up to 3
arguments, so that if you called funcs[1](2,3) you'd get an unwanted
result rather than a TypeError exception. If you're keen on getting the
exception in such cases, you can use a lambda factory in the same role
as the much clearer and more readable factory function you had (which I
keep thinking is the _sensible_ solution)...:

funcs = [ (lambda x,y: lambda n: x*y/n)(x,y) for x,y in a ]


Alex
 
Reply With Quote
 
 
 
 
Max Rybinsky
Guest
Posts: n/a
 
      10-29-2005
Thank you for explanation, Alex.
It appears that almost every beginner to Python gets in trouble with
this ...feature.

 
Reply With Quote
 
Alex Martelli
Guest
Posts: n/a
 
      10-29-2005
Max Rybinsky <(E-Mail Removed)> wrote:

> Thank you for explanation, Alex.
> It appears that almost every beginner to Python gets in trouble with
> this ...feature.


Almost every beginner to Python gets in trouble by expecting "do what
I'm thinking of RIGHT NOW"-binding, which no language offers: in other
words, such beginners sometimes expect late binding where Python binds
early, and, vice versa, they at other times expect early binding where
Python binds late. Not ALWAYS, mind you -- what they expect depends on
what would appear to them to be most convenient for their immediate
needs on each separate occasion. Some other languages try to follow
beginners and offer "do what I mean" semantics -- when using such
languages, one ends up in a battle of wit against the compiler's guesses
about one's intentions. Python instead offers extremely simple rules,
such as: any name is looked up each and every time it's evaluated (and
at no other times); evaluation of function headers happens completely at
the time the 'def' or 'lambda' evaluates, while evaluation of function
bodies happens completely at the time the function is _called_. By
learning and applying such simple rules there can be no surprise about
what is evaluated (and, in particular, looked up) when. E.g., consider
the difference between the following two functions:

def early(x=whatever()):
...

def late():
x=whatever()
...

In 'early', the call to whatever() is part of the function's header, and
therefore happens at the time the 'def' statement executes -- and thus
name 'whatever' means whatever it means at THAT time (if at that time
it's not bound to anything, the 'def' statement fails with an
exception).

In 'late', the call to whatever() is part of the function's body, and
therefore happens each time the function is called -- and thus name
'whatever' means whatever it means at THAT time (if at that time it's
not bound to anything, the call fails with an exception).


Alex
 
Reply With Quote
 
Max Rybinsky
Guest
Posts: n/a
 
      10-30-2005
OK.
The thing i've got is an obscure semantic bug, occured because of my
unawareness of the following Python "features":
1. (In major)
http://mail.python.org/pipermail/pyt...er/056508.html
2. "late" bindings of the function's body

Got to know!

Thanks for your attention.

 
Reply With Quote
 
Max Rybinsky
Guest
Posts: n/a
 
      10-30-2005
Valid link in my previews message is

http://mail.python.org/pipermail/pyt...er/056669.html

Sorry.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Type of lambda function returning a lambda function... Haochen Xie C++ 4 03-17-2013 11:23 PM
lambda vs non-lambda proc Steve Dogers Ruby 1 03-30-2009 10:11 PM
list(...) and list comprehensions (WAS: Arithmetic sequences in Python) Steven Bethard Python 7 01-20-2006 04:13 PM
Re: Lambda as declarative idiom (was RE: what is lambda used for inreal code?) Roman Suzi Python 13 01-07-2005 09:33 PM
Can I simulate list comprehensions? seguso C++ 9 12-22-2004 11:51 PM



Advertisments