Duncan Booth
3/2/2008 11:10:00 AM
Michael Torrie <torriem@gmail.com> wrote:
> poof65 wrote:
>> An idea, i don't know if it will work in your case.
>>
>> for x in xrange(10):
>> funcs.append(lambda p,z=x: testfunc(z+2,p))
>
> Good idea. I will try it. I also figured out a way to architecture my
> program differently to avoid this problem. But this idiom might be
> handy in certain situations. Suppose you need to provide a callback
> function with a fixed signature to some library routine. But you want
> to add extra contextual data to your callback. This just might be the
> ticket.
There are three obvious ways to solve your problem:
1) Using a default argument as above is the original and used to be the
only way to do it.
2) Using a factory function to generate the function:
def gencaller(fn, x):
def caller(p):
return fn(x+2, p)
return caller
for x in xrange(10):
funcs.append(gencaller(testfunc, x))
3) Using functools.partial:
from functools import partial
for x in xrange(10):
funcs.append(partial(testfunc, x+2))
or even: funcs = [partial(testfunc, x+2) for x in range(10)]
A lot depends on what your real code actually wants to pass as the
parameters. If they are some complicated expression you cannot evaluate
until it is called then use a factory function, if it is something simple
as in your example then partial is easily the cleanest.