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
--
Arnaud
--
Elias
On Feb 18, 1:47 pm, Arnaud Delobelle <arno...@googlemail.com> wrote:
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.
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.
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).
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