[Python-ideas] Tweaking closures and lexical scoping to include the function being defined

Ron Adam ron3200 at gmail.com
Fri Sep 30 05:35:26 CEST 2011


On Thu, 2011-09-29 at 21:32 -0400, Nick Coghlan wrote:
> On Thu, Sep 29, 2011 at 9:07 PM, Ron Adam <ron3200 at gmail.com> wrote:
> > On Thu, 2011-09-29 at 13:01 -0700, Guido van Rossum wrote:
> >> On Thu, Sep 29, 2011 at 12:03 PM, Eric Snow <ericsnowcurrently at gmail.com> wrote:
> >> > The alternative is to leave nonlocal as just a simple statement, but
> >> > change its behavior when the name is not found inside a containing
> >> > function scope.  Currently that is a syntax error.
> >>
> >> For a reason. It would be too easy for a typo to produce the wrong
> >> interpretation.
> >
> > But this is exactly how it works now!  The behavior of nonlocal doesn't
> > need to be changed.  It already behaves that way with closures. :-)
> 
> That isn't what Guido and Eric are talking about here. They're talking
> about this syntax error:
> 
> >>> def f():
> ...     nonlocal x
> ...
> SyntaxError: no binding for nonlocal 'x' found
> 
> We had the opportunity in PEP 3104 to make 'nonlocal x' a synonym for
> 'global x' and chose not to do so. After deliberately passing up that
> more obvious interpretation, we aren't likely to now decide to use it
> to denote function state variables.

Ah, ok,  There are so many suggestions it's hard to keep up.

I think, all that is needed is a way to rebind a function inside a
decorator.  If we can do that, then everything will pretty much just
work.  And nonlocal should do the right thing as it is.

Could a method be added to the Function class, that will copy a function
and capture the current scope and any additional cells?

class function(object)
 |  function(code, globals[, name[, argdefs[, closure]]])
 |  
 |  Create a function object from a code object and a dictionary.
 |  The optional name string overrides the name from the code object.
 |  The optional argdefs tuple specifies the default argument values.
 |  The optional closure tuple supplies the bindings for free variables.

Looking at this, it may already be able to do that.  But it could be
easier.


How about if we add the ability for it to copy a function, so that we
can do...

   func = type(func)(func)                     # get a copy

   func = type(func)(func, closure={'x':0})    # with closures


Then we can do...

   def set_closure(**kwds):   
       def wrapper(f):
           f = type(f)(f, closure=kwds)
           return f
       return wrapper

   @set_closure(x=0)
   def adder(y):
       nonlocal x
       x += y
       return x
   

That looks fine to me.     



   def set_this(f):
       kwds = {'__this__':f}
       f = type(f)(f, closure={'__this__':f)
       return f

This decorator won't work as the function '__this__' points to is the
old function, the new one hasn't been created yet. Hmmm.

Cheers,
   Ron









   














More information about the Python-ideas mailing list