Autogenerate functions (array of lambdas)
dstanek at dstanek.com
Thu Sep 6 11:00:12 CEST 2007
On 9/6/07, Chris Johnson <effigies at gmail.com> wrote:
> 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?
A more explicit example of your solution would be:
>>> def gen(i):
... return lambda: i # bind to the i passed in
>>> l = [gen(i) for i in range(10)]
>>> [f() for f in l]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Your initial lambda: i creates a function that binds to i in the current
scope. When you wrapped that in another lambda you were creating a new scope
with a new value of i and returning a function bound to that value for i.
Take a look at closures:
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Python-list