closures and dynamic binding

Aaron "Castironpi" Brady castironpi at gmail.com
Mon Sep 29 01:11:06 CEST 2008


On Sep 28, 4:47 pm, Terry Reedy <tjre... at udel.edu> wrote:
> Aaron "Castironpi" Brady wrote:
> > On Sep 28, 2:52 am, Steven D'Aprano <st... at REMOVE-THIS-
> >> 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.
>
> For this to work, the 'expansion' has to be mental and not actual.
> Which is to say, inner must be a text macro to be substituted back into
> outer.
>
> >> Then, later, when you call inner() it grabs the local scope and returns
> >> the number you expected.
>
> > I must have misunderstood.  Here's my run of your code:
>
> I cannot speak to what Steven meant, but
>
> >>>> inner = lambda: n
>
> when inner is actually compiled outside of outer, it is no longer a
> closure over outer's 'n' and 'n' will be looked for in globals instead.
>
> >>>> 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?
>
> That would be dynamic rather than lexical scoping.

I couldn't find how those apply on the wikipedia website.  It says:
"dynamic scoping can be dangerous and almost no modern languages use
it", but it sounded like that was what closures use.  Or maybe it was
what 'inner' in Steven's example would use.  I'm confused.

Actually, I'll pick this apart a little bit.  See above when I
suggested 'late' and 'early' functions which control (or simulate)
different bindings.  I get the idea that 'late' bound functions would
use a dangerous "dynamic scope", but I could be wrong; that's just my
impression.

> >> 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.

If you defined these as:

inner= late( lambda: n )
outer= lambda n: inner

You could get the right results.  It's not even clear you need
quotes.  Perhaps 'late' could carry the definition of 'n' with it when
it's returned from 'outer'.

In my proposal, it makes a copy of the "localest" namespace, at least
all the variables used below it, then returns its argument in an
original closure.



More information about the Python-list mailing list