lambda in list comprehension acting funny
Steven D'Aprano
steve+comp.lang.python at pearwood.info
Wed Jul 11 19:47:34 EDT 2012
On Wed, 11 Jul 2012 11:38:18 -0700, woooee wrote:
> You should not be using lambda in this case
> .for x in [2, 3]:
> . funcs = [x**ctr for ctr in range( 5 )]
> . for p in range(5):
> . print x, funcs[p]
> . print
If you change the requirements, it's always easy to solve problems. But
it is the wrong problem that you have solved.
The problem we have been asked to solve is to create a sequence of
function objects, so that they can be called later, when needed, *not* to
pre-calculate the results.
In this case, the most obvious solution is to store a local variable in
each function object with the value you want.
funcs = [(lambda x, i=i: x**i) for i in range(5)]
creates a list of five functions:
lambda x, i=0: x**i
lambda x, i=1: x**i
lambda x, i=2: x**i
and so on.
In this case, each function has two local variables, x and i, with i
having a default value. The function parameter i is bound to the value of
i when the function was created.
Because parameter defaults are calculated once, when the function is
created, this causes the value of i to stick to the newly created
function, and we get the result we need.
What happens if you don't use a parameter with a default value?
funcs = [(lambda x: x**i) for i in range(5)]
In this case, each function body contains one local variable, x, and one
non-local or global variable, i.
Because i is a non-local, the function doesn't store a value for it.
Instead, the function stores a lump of data pointing to just enough of
the environment to fetch the current value of the non-local i when
needed. Since all five functions are in the same environment, they all
see the same value of i when you call them, regardless of what the value
of i was when they were created.
This is little different from doing this:
i = 1
def f1(x): return x**i
i = 2
def f2(x): return x**i
i = 3
def f3(x): return x**i
Is there any surprise that all three functions return the same value?
They all point to the same global variable i. I'm not sure what it is
about lambda that fools people into thinking that it is different (I've
even been fooled myself!) but it is not.
--
Steven
More information about the Python-list
mailing list