Benjamin Peterson <benja...@python.org> wrote: > Márcio Faustino <m.faustino <at> gmail.com> writes: > > > > Executing the example below doesn't produce the expected behavior, but > > using the commented code does. Is this normal, or is it a problem with > > Python? I've tested it with version 2.6.1 on Windows XP. > > > > Thanks, > > > > -- > > > > from abc import * > > from types import * > > import re > > > > class Base (ObjectType): > > __metaclass__ = ABCMeta > > > > def __init__(self): > > for option in self.get_options().keys(): > > method = 'get_%s_option' % re.sub(' ', '_', option.lower > > ()) > > setattr(self.__class__, method, lambda self: > > self.get_option(option)) > > This is because the closure over option is changed when it is reassigned in > the > for loop. For example: > > >>> def f(): > ... return [lambda: num for num in xrange(2)] > ... > >>> f() > [<function <lambda> at 0x83f30>, <function <lambda> at 0x83e70>] > >>> f()[0] > <function <lambda> at 0x83ef0> > >>> g = f() > >>> g[0]() > 1 > >>> g[1]() > 1
Here's the way I find it useful to think about this: When your lambda is created in your for loop inside your __init__ method, it acquires a pointer to __init__'s local namespace. (That's how I understand what "closure" means in this case, though I imagine "closure" probably means something slightly different in computer-science-ese :) So, when any of those lambdas is executed, they all have a pointer to the exact same namespace, that of __init__. And when they are called, __init__'s namespace is in whatever state it was left in when __init__ ended. In this case, that means that 'option' is pointing to the value it had at the _end_ of the for loop. Hope this helps. I find that thinking in terms of namespaces helps me understand how Python works better than any other mental model I've come across. -- R. David Murray http://www.bitdance.com -- http://mail.python.org/mailman/listinfo/python-list