Tom Plunket wrote in news:[EMAIL PROTECTED] in comp.lang.python:
> ...at least, I think that I'm having a problem understanding the way > closures work. > > I'm trying to define a function for an object which will take certain > objects from the parent scope at the time that function is defined. > For some reason, if I do this function definition in a loop, the > locals given by that function (is this a closure?) are changed each > iteration of the loop, whereas if the function definition is isn't > looped over, I get the behavior I desire. Can anyone provide any > insight for me? > Test 1 doesn't work the way I would expect: > Test 4 says, "Test 0" > Test 4 says, "Test 4" > > def CreateTests1(count): > tests = [] > for i in xrange(count): > name = 'Test %d' % i > t = Test(name) > tests.append(t) > > def ExCall(text): > print '%s says, "%s"' % (name, text) > > t.ExternalCall = ExCall > > return tests "name" in the above code is bound to a an entry in "CreateTests1"'s locals, and ExCall has a (hidden) reference to that locals, so by the time ExCall is finally called the value associated with "name" has been replaced by (count - 1). The solution (as always) is to add another level of indirection: def create_tests( count ): def make( arg ): def ExCall( text ): print arg, text return ExCall tests = [] for i in range( count ): name = i t = Test( name ) t.ExternalCall = make( name ) In the above, every call to make() creates a new frame (a new set of locals) and binds the value of the passed in "name" to the name "arg" in this new frame, it will be this value that is eventually printed. There is a trick with default arguments that lets you do what you want with a bit less faffing about: >>> r = [] >>> for i in range(10): def f( i = i ): print i r.append( f ) >>> for i in r: i() In this example the value of "i" is bound to the default argument for the function "f" every time the def f() statments are executed. Rob. -- http://www.victim-prime.dsl.pipex.com/ -- http://mail.python.org/mailman/listinfo/python-list