Chris Rebert schrieb: > On Wed, Apr 22, 2009 at 4:50 AM, Rüdiger Ranft <_r...@web.de> wrote: >> Hi all, >> >> I want to generate some methods in a class using setattr and lambda. >> Within each generated function a name parameter to the function is >> replaced by a string constant, to keep trail which function was called. >> The problem I have is, that the substituted name parameter is not >> replaced by the correct name of the function, but by the last name the >> for loop has seen. >> >> import unittest >> >> class WidgetDummy: >> '''This class records all calls to methods to an outer list''' >> >> def __init__( self, name, calls ): >> '''name is the name of the object, which gets included into a >> call record. calls is the list where the calls are appended.''' >> self.name =ame >> self.calls =alls >> for fn in ( 'Clear', 'Append', 'foobar' ): >> func =ambda *y,**z: self.__callFn__( fn, y, z ) >> setattr( self, fn, func ) > > Common wart to run into as of late. fn (in the lambda) doesn't get > evaluated until the call-time of the lambda, by which point the loop > has finished and the loop variable has been changed to its final > value, which is used by the lambda.
Doh! I wasn't aware of the point when the lambda expression is evaluated. > Workaround: > #exact syntax may vary with your version of Python, but you should be > able to get the idea > func =ambda *y,**z, fn=fn: self.__callFn__( fn, y, z ) > > The default argument value gets evaluated at definition-time, thus > forcing the right value of fn within the function. Thank you, I replaced the direct assignment with a proxy function call, and now it works. def __init__( self, name, calls ): self.name = name self.calls = calls def forceEval(x): setattr( self, fn, lambda *y,**z: self.__callFn__(x, y, z) ) for fn in ( 'Clear', 'Append', 'foobar' ): forceEval(fn) -- GPG encrypted mails preferred. GPG verschlüsselte Mails bevorzugt. ---> http://chaosradio.ccc.de/media/ds/ds085.pdf Seite 20 <---- -- http://mail.python.org/mailman/listinfo/python-list