lambda closure question

Kent Johnson kent37 at tds.net
Sat Feb 19 08:54:38 EST 2005


Ted Lilley wrote:
> What I want to do is pre-load functions with arguments by iterating
> through a list like so:
> 
> 
>>>>class myclass:
> 
> ...    pass
> 
>>>>def func(self, arg):
> 
> ...    print arg
> 
>>>>mylist = ["my", "sample", "list"]
>>>>for item in mylist:
> 
> ...    setattr(myclass, item, lamdba self: func(self, item))
> 
> This attaches a list of functions to the class, making them bound
> methods when called from a class instance.
> 
> 
>>>>obj = myclass()
>>>>obj.list()
> 
> list
> Unfortunately, it doesn't work.  It seems the closure keeps track of
> the variable fed to it dynamically - if the variable changes after the
> lambda is created, the lambda still references the _variable_ not the
> original _value_ and so gets the new value like so:
> 
> 
>>>>obj.sample()
> 
> list
> 
>>>>obj.my()
> 
> list

The closure isn't bound until the scope containing it is exited. A simple workaround is to bind item 
as a default argument to the lambda:
for item in mylist:
     setattr(myclass, item, lambda self, item=item: func(self, item))

You can also make a helper function that returns the closure, the closure will be bound each time 
the helper returns:

def make_f(item):
     def f(self): func(self, item)
     return f

mylist = ["my", "sample", "list"]
for item in mylist:
     setattr(myclass, item, make_f(item))

Kent



More information about the Python-list mailing list