Lambda forms and scoping

R. David Murray rdmurray at bitdance.com
Fri Mar 20 08:28:08 EDT 2009


Benjamin Peterson <benjamin at 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




More information about the Python-list mailing list