Question about lambda and variable bindings

Duncan Booth duncan.booth at invalid.invalid
Sun Mar 2 12:10:16 CET 2008


Michael Torrie <torriem at 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.



More information about the Python-list mailing list