# Autogenerate functions (array of lambdas) - Python

This is a discussion on Autogenerate functions (array of lambdas) - Python ; 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 ...

1. ## 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

2. ## Re: Autogenerate functions (array of lambdas)

Chris Johnson <effigies> writes:
> 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.

3. ## Re: Autogenerate functions (array of lambdas)

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

4. ## Re: Autogenerate functions (array of lambdas)

Chris Johnson <effigies> wrote:

> 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)]

5. ## Re: Autogenerate functions (array of lambdas)

Chris Johnson <effigies> writes:

> 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.

6. ## Re: Autogenerate functions (array of lambdas)

On Sep 6, 3:44 am, Paul Rubin <http://phr...@NOSPAM.invalid> wrote:
> Chris Johnson <effig...> writes:
> > 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.