Help with lambda

L

lallous

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
 
A

Arnaud Delobelle

lallous said:
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

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
 
L

lallous

Yes it should be listed somewhere, now I get it. Thanks Arnaud.

--
Elias

lallous said:
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".

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
 
D

D'Arcy J.M. Cain

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

lallous

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

Jonathan Gardner

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

News123

Jonathan said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top