Weird lambda behavior

R

Rüdiger Ranft

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 )

def __callFn__( self, fnName, *args ):
'''Add the function call to the call list'''
self.calls.append( ( self.name, fnName, args ) )

class Testcase( unittest.TestCase ):
def testFoo( self ):
calls = []
wd = WidgetDummy( 'foo', calls )
wd.Append( 23 )
self.assertEqual( [ ( 'foo', 'Append', ( 23, {} ) ) ], calls )

unittest.main()
 
D

Diez B. Roggisch

Rüdiger Ranft said:
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.

Python's closures don't capture the values, but only the names they contain
when they are created. So whatever value is bound to that name as last is
used.

to overcome this, you need to create another closure or bind the value to a
name local to the created function via named arguments:
for f in [lambda i=i: i**2 for i in xrange(10)]:
.... f()
....
0
1
4
9
16
25
36
49
64
81


Diez
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,733
Latest member
LonaMonzon

Latest Threads

Top