471,356 Members | 1,618 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

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

Autogenerate functions (array of lambdas)

What I want to do is build an array of lambda functions, like so:

a = [lambda: i for i in range(10)]

(This is just a demonstrative dummy array. I don't need better ways to
achieve the above functionality.)

print [f() for f in a]

results in: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
rather than the hoped for: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Clearly, lambda is returning the object i, which is left at the last
value of range(10). The following is my solution.

t = lambda i: lambda: i
a = [t(i) for i in range(10)]

or the somewhat more terse:

a = [(lambda i: lambda: i)(i) for i in range(10)]

This gives the behavior which, intuitively, I expected from the
original syntax. So my questions are:
1) Does this make sense as what should be done here? That is, would
this be the behavior you'd want more often than not? As I said,
intuitively, I would think the lambda would treat the iterator
variable as a constant in this context.
2) Is there a better or preferred method than the one I've found?

Thanks,
Chris

Sep 6 '07 #1
5 1562
Chris Johnson <ef******@gmail.comwrites:
a = [lambda: i for i in range(10)]
print [f() for f in a]
results in: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
rather than the hoped for: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
The usual idiom is

a = [lambda i=i: i for i in range(10)]

That way i is not a free variable in the lambda.
Sep 6 '07 #2
Chris Johnson schrieb:
What I want to do is build an array of lambda functions, like so:

a = [lambda: i for i in range(10)]

(This is just a demonstrative dummy array. I don't need better ways to
achieve the above functionality.)

print [f() for f in a]

results in: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
rather than the hoped for: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Clearly, lambda is returning the object i, which is left at the last
value of range(10). The following is my solution.

t = lambda i: lambda: i
a = [t(i) for i in range(10)]

or the somewhat more terse:

a = [(lambda i: lambda: i)(i) for i in range(10)]

This gives the behavior which, intuitively, I expected from the
original syntax. So my questions are:
1) Does this make sense as what should be done here? That is, would
this be the behavior you'd want more often than not? As I said,
intuitively, I would think the lambda would treat the iterator
variable as a constant in this context.
2) Is there a better or preferred method than the one I've found?
The problem you encountered relates to the fact that the lambdas close
around the names known when they were created - not the values bound to
them.

To overcome that, bind the value you pass to a new name, like this:

a = [lambda i=i: i for i in range(10)]

Diez
Sep 6 '07 #3
Chris Johnson <ef******@gmail.comwrote:
2) Is there a better or preferred method than the one I've found?
Use function default arguments to keep the current value of i at the point
where you define the function.

a = [(lambda n=i: n) for i in range(10)]

Sep 6 '07 #4
Chris Johnson <ef******@gmail.comwrites:
What I want to do is build an array of lambda functions, like so:

a = [lambda: i for i in range(10)]
Use a factory function for creating the lambdas. The explicit
function call will force a new variable binding to be created each
time, and the lambda will refer to that binding rather than to the
loop variable binding, which is reused for all loop iterations. For
example:

def makefn(i):
return lambda: i
>>a = [makefn(i) for i in xrange(10)]
[f() for f in a]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The alternative is to explicitly import the value into the lambda's
parameter list, as explained by others.
Sep 6 '07 #5
On Sep 6, 3:44 am, Paul Rubin <http://phr...@NOSPAM.invalidwrote:
Chris Johnson <effig...@gmail.comwrites:
a = [lambda: i for i in range(10)]
print [f() for f in a]
results in: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
rather than the hoped for: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

The usual idiom is

a = [lambda i=i: i for i in range(10)]

That way i is not a free variable in the lambda.
Thanks. I figured there had to be a better way than what I was doing.

Sep 6 '07 #6

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

8 posts views Thread by Christian Tismer | last post: by
76 posts views Thread by Nick Coghlan | last post: by
12 posts views Thread by Kay Schluehr | last post: by
1 post views Thread by Scott David Daniels | last post: by

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.