Autogenerate functions (array of lambdas)

Diez B. Roggisch deets at nospam.web.de
Thu Sep 6 04:46:15 EDT 2007


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



More information about the Python-list mailing list