lambda functions within list comprehensions

Alex Martelli aleaxit at yahoo.com
Sat Oct 29 23:41:00 CEST 2005


Max Rybinsky <sunspire at gmail.com> 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



More information about the Python-list mailing list