closures and dynamic binding

Aaron "Castironpi" Brady castironpi at gmail.com
Sun Sep 28 14:46:06 EDT 2008


On Sep 28, 2:52 am, Steven D'Aprano <st... at REMOVE-THIS-
cybersource.com.au> wrote:
> On Sat, 27 Sep 2008 21:43:15 -0700, Aaron \"Castironpi\" Brady wrote:
> > Hello all,
>
> > To me, this is a somewhat unintuitive behavior.  I want to discuss the
> > parts of it I don't understand.
>
> >>>> f= [ None ]* 10
> >>>> for n in range( 10 ):
> > ...     f[ n ]= lambda: n
> > ...
> >>>> f[0]()
> > 9
> >>>> f[1]()
> > 9
>
> > I guess I can accept this part so far, though it took a little getting
> > used to.  I'm writing some code and found the following workaround, but
> > I don't think it should give different results.  Maybe I'm not
> > understanding some of the details of closures.
>
> >>>> f= [ None ]* 10
> >>>> for n in range( 10 ):
> > ...     f[ n ]= (lambda n: ( lambda: n ) )( n )
> > ...
> >>>> f[0]()
> > 0
> >>>> f[1]()
> > 1
>
> > Which is of course the desired effect.  Why doesn't the second one just
> > look up what 'n' is when I call f[0], and return 9?
>
> That's an awfully complicated solution. A much easier way to get the
> result you are after is to give each function its own local copy of n:
>
> f[n] = lambda n=n: n
>
> As for why the complicated version works, it may be clearer if you expand
> it from a one-liner:
>
> # expand: f[ n ]= (lambda n: ( lambda: n ) )( n )
>
> inner = lambda: n
> outer = lambda n: inner
> f[n] = outer(n)
>
> outer(0) => inner with a local scope of n=0
> outer(1) => inner with a local scope of n=1 etc.
>
> Then, later, when you call inner() it grabs the local scope and returns
> the number you expected.
>
> --
> Steven

Steven,

I must have misunderstood.  Here's my run of your code:

>>> inner = lambda: n
>>> outer = lambda n: inner
>>> outer(0)
<function <lambda> at 0x00A01170>
>>> a=outer(0)
>>> b=outer(1)
>>> a()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
NameError: global name 'n' is not defined

Why doesn't 'inner' know it's been used in two different scopes, and
look up 'n' based on the one it's in?



More information about the Python-list mailing list