[Python-Dev] closure semantics

Jeremy Hylton jeremy at alum.mit.edu
Tue Oct 21 23:00:43 EDT 2003


On Tue, 2003-10-21 at 18:51, Guido van Rossum wrote:
> [Samuele]
> > this is a bit OT and too late, but given that our closed over
> > variables are read-only, I'm wondering whether, having a 2nd chance,
> > using cells and following mutations in the enclosing scopes is
> > really worth it, we kind of mimic Scheme and relatives but there
> > outer scope variables are also rebindable. Maybe copying semantics
> > not using cells for our closures would not be too insane, and people
> > would not be burnt by trying things like this:
> > 
> > for msg in msgs:
> >    def onClick(e):
> >      print msg
> >    panel.append(Button(msg,onClick=onClick))
> > 
> > which obviously doesn't do what one could expect today. OTOH as for
> > general mutability, using a mutable object (list,...) would allow
> > for mutability when one really need it (rarely).

I think copying semantics would be too surprising.

> It was done this way because not everybody agreed that closed-over
> variables should be read-only, and the current semantics allow us to
> make them writable (as in Scheme, I suppose?) if we can agree on a
> syntax to declare an "intermediate scope" global.
> 
> Maybe "global x in f" would work?

Woo hoo.  I'm happy to hear you've had a change of heart on this topic.
I think a simple, declarative statement would be clearer than assigning
to an attribute of a special object.

If a special object, like __global__, existed, could you create an
alias, like:

    surprise = __global__
    surprise.x = 1
    print __global__.x

?

It would apparently also allow you to use a local and global variable
with the same name in the same scope.  That's odd, although I suppose it
would be clear from context whether the local or global was intended.

> def outer():
>     x = 1
>     def intermediate():
>         x = 2
>         def inner():
>             global x in outer
>             x = 42
>         inner()
>         print x      # prints 2
>     intermediate()
>     print x          # prints 42

I would prefer to see a separate statement similar to global that meant
"look for the nearest enclosing binding."  Rather than specifying that
you want to use x from outer, you could only say you don't want x to be
local.  That means you'd always get intermediate.

I think this choice is more modular.  If you can re-bind a non-local
variable, then the name of the function where it is initially bound
isn't that interesting.  It would be safe, for example, to move it to
another place in the function hierarchy without affecting the semantics
of the program -- except that in the case of "global x in outer" you'd
have to change all the referring global statements.  Or would the
semantics be to create a binding for x in outer, even if it didn't
already exist?

Jeremy





More information about the Python-Dev mailing list