Weird lambda behavior

Chris Rebert clp2 at rebertia.com
Wed Apr 22 13:59:14 CEST 2009


On Wed, Apr 22, 2009 at 4:50 AM, Rüdiger Ranft <_rdi_ at 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 = name
>        self.calls = calls
>        for fn in ( 'Clear', 'Append', 'foobar' ):
>            func = lambda *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.

Workaround:
#exact syntax may vary with your version of Python, but you should be
able to get the idea
func = lambda *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.

Cheers,
Chris
-- 
I have a blog:
http://blog.rebertia.com



More information about the Python-list mailing list