Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help with lambda

2 views
Skip to first unread message

lallous

unread,
Feb 18, 2010, 7:28:00 AM2/18/10
to
Hello,

I am still fairly new to Python. Can someone explain to me why there
is a difference in f and g:

def make_power(n):
return lambda x: x ** n

# Create a set of exponential functions
f = [lambda x: x ** n for n in xrange(2, 5)]
g = [make_power(n) for n in xrange(2, 5)]

print f[0](3), f[1](3)
print g[0](3), g[1](3)


I expect to have "f" act same like "g".

Thanks

Arnaud Delobelle

unread,
Feb 18, 2010, 7:47:31 AM2/18/10
to
lallous <elias.ba...@gmail.com> writes:

It's a FAQ! Except I don't think it's in the official Python FAQ, but
it ought to be.

The reason (very quickly) is that each time you call make_power() you
create a new name 'n' which is bound to a different value each time,
whereas in f:



[lambda x: x ** n for n in xrange(2, 5)]

The 'n' is the same name for each of the lambda functions and so is
bound to the same value, which by the end of the loop is 4. So each of
the lambdas in the list f is the same as:

lambdsa x; x**4

after the end of the list comprehension.

The usual fix for this is to change f to:

f = [lambda x, n=n: x ** n for n in xrange(2, 5)]

I'll let you think why this works.

HTH

--
Arnaud

lallous

unread,
Feb 18, 2010, 7:52:02 AM2/18/10
to
Yes it should be listed somewhere, now I get it. Thanks Arnaud.

--
Elias

On Feb 18, 1:47 pm, Arnaud Delobelle <arno...@googlemail.com> wrote:

D'Arcy J.M. Cain

unread,
Feb 18, 2010, 7:56:03 AM2/18/10
to lallous, pytho...@python.org
On Thu, 18 Feb 2010 04:28:00 -0800 (PST)
lallous <elias.ba...@gmail.com> wrote:
> def make_power(n):
> return lambda x: x ** n

Hint: type(make_power(2))

Did you expect that to return "int"?

> # Create a set of exponential functions
> f = [lambda x: x ** n for n in xrange(2, 5)]
> g = [make_power(n) for n in xrange(2, 5)]

The result of make_power(n) is a function that raises it's argument to
the power of n. I don't know what you are trying to do. Maybe this?

g = [make_power(n)(2) for n in xrange(2, 5)]
or
g = [make_power(2)(n) for n in xrange(2, 5)]

--
D'Arcy J.M. Cain <da...@druid.net> | Democracy is three wolves
http://www.druid.net/darcy/ | and a sheep voting on
+1 416 425 1212 (DoD#0082) (eNTP) | what's for dinner.

lallous

unread,
Feb 18, 2010, 8:08:03 AM2/18/10
to
On Feb 18, 1:56 pm, "D'Arcy J.M. Cain" <da...@druid.net> wrote:
> On Thu, 18 Feb 2010 04:28:00 -0800 (PST)
>
> lallous <elias.bachaal...@gmail.com> wrote:
> > def make_power(n):
> >     return lambda x: x ** n
>
> Hint: type(make_power(2))
>
> Did you expect that to return "int"?
>

No, I expect to see a specialized function.

> > # Create a set of exponential functions
> > f = [lambda x: x ** n for n in xrange(2, 5)]
> > g = [make_power(n) for n in xrange(2, 5)]
>
> The result of make_power(n) is a function that raises it's argument to
> the power of n.  I don't know what you are trying to do.  Maybe this?
>
> g = [make_power(n)(2) for n in xrange(2, 5)]
> or
> g = [make_power(2)(n) for n in xrange(2, 5)]
>


What I am trying to do is generate different functions.

If you're curious, I was playing with ctypes and wanted to see how it
handles C<->Python callbacks:

CB_T = WINFUNCTYPE(c_int, c_int)
many_cb_t = CFUNCTYPE(c_int, c_int, CB_T)
many_cb = many_cb_t(addressof(c_void_p.in_dll(dll, "many_cb")))
#ANY_SIMPLER

def make_power(n):
return lambda x: x ** n

cbs = [CB_T(make_power(n)) for n in xrange(0, 1000)]
cbs.append(None)

many_cb(3, *cbs)

And the C code in a shared lib:

int many_cb(int value, ...)
{
va_list va;
va = va_start(va, value);
cb_t cb;
int s = 0;
while ( (cb = va_arg(va, cb_t)) != NULL)
{
printf("calling %p", cb);
int r = cb(value);
s += r;
printf(", r=%d\n", r);
}
va_end(va);
return s;
}

Speaking of that, anyone has an idea how to make simpler the line with
#ANY_SIMPLER?

I try: many_cb = CB_T.in_dll(dll, "many_cb") <- but that seems to work
with data items only.

Jonathan Gardner

unread,
Feb 18, 2010, 5:26:33 PM2/18/10
to
On Feb 18, 4:28 am, lallous <elias.bachaal...@gmail.com> wrote:
>
> f = [lambda x: x ** n for n in xrange(2, 5)]

This is (pretty much) what the above code does.

>>> f = []
>>> n = 2
>>> f.append(lambda x: x**n)
>>> n = 3
>>> f.append(lambda x: x**n)
>>> n = 4
>>> f.append(lambda x: x**n)
>>> n = 5
>>> f.append(lambda x: x**n)

Now, when you call f[0], you are calling "lambda x: x**n". What is
"n"?

You need some way of creating a new namespace and a new variable
pointing to what "n" was for that iteration. Python doesn't create a
namespace for every iteration like some languages may. You have to be
more explicit about that. After all, what would you expect the
following code to do?

>>> n = 5
>>> f = [lambda x: x**n for i in range(2,5)]
>>> n = 2
>>> f[0][5]

Or, just call a function that will have a new namespace *for every
call* and generate a function within each execution of that function
(like make_power does).

News123

unread,
Feb 24, 2010, 4:21:59 PM2/24/10
to
Jonathan Gardner wrote:
> On Feb 18, 4:28 am, lallous <elias.bachaal...@gmail.com> wrote:
>> f = [lambda x: x ** n for n in xrange(2, 5)]
>
> This is (pretty much) what the above code does.
>
>>>> f = []
>>>> n = 2
>>>> f.append(lambda x: x**n)
>>>> n = 3
>>>> f.append(lambda x: x**n)
>>>> n = 4
>>>> f.append(lambda x: x**n)
>>>> n = 5
>>>> f.append(lambda x: x**n)
>
> Now, when you call f[0], you are calling "lambda x: x**n". What is
> "n"?
>


If you use a newer version of python (>= 2.5), then you might want to
look at functools.partial.


> def pow(a,n):
> return a ** n
>
> f = [functools.partial(pow,n=n) for n in xrange(2, 5)]
>


Not sure, whether there's any (dis)advantage over
> f = [lambda x,n=n: x ** n for n in xrange(2, 5)]
or
> f = [lambda x,n=n: pow(x,n) for n in xrange(2, 5)]


bye

N

0 new messages