[Chicago] April Talk Topic Python 3.2 Features

Walt Askew waltaskew at gmail.com
Tue Mar 13 14:27:23 CET 2012


On Tue, 2012-03-13 at 07:24 -0500, Brian Ray wrote:


> > 
> > nonlocal means that it is scoped outside of the current scope, but not
> > all the way up in global...
> > 
> > def bob(myvar):
> >  def subfunc():
> >    nonlocal myvar
> >    return myvar * 10
> >  return subfunc
> > 
> 
> So, technically, nonlocal is the previous frame? I can think of some cases I want to check this out to see what it does. For instance, if a class has self.foo and within a method could I just nonlocal foo?


No, definitely not the previous frame.  The scoping hasn't changed at
all by introducing nonlocal.  subfunc() can access myvar because the
variable was bound in the scope in which subfunc was created.  Python's
had closures like that for a while.

I think the best way to understand this is that the scoping doesn't
change at all when you introduce nonlocal.  It's just a way of
identifying a variable as already bound, which the grammar didn't
previously allow you to do.

nonlocal isn't actually needed for this example.  Works just fine
without it

def bob(myvar):
    def subfunc():
        return myvar * 10
    return subfunc

Try it -- it's fine in 2.X or whatever.  The scoping of variables
doesn't change with nonlocal -- you've always been able to make closures
like this.  nonlocal does allow you to make more useful closures,
though.  An example:

def make_counter(start):
    def counter():
        start = start + 1
        print(start)
    return counter

>>> c = make_counter(10)
>>> c()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in counter
UnboundLocalError: local variable 'start' referenced before assignment


So why doesn't this work?  This example a bit ambiguous grammar wise.
We can tell that the counter function is trying to update an already
bound variable start, but it's not made clear in the grammar that we're
trying to do that.  The expressions x = 1 doesn't tell you if you're
updating a previously bound variable x to 1 or creating a new variable x
which equals 1.

In javascript, you make this clear by adding 'var' when you first bind
variables and omitting it when you update previously bound variables.
In lisp, you have 'let' for binding and 'setq' or 'set!' for updating
bound variables.  In python, you've got '=' which is used for both.

The nonlocal keyword is how you say "I'm updating a previously bound
variable."

def make_counter(start):
    def counter():
        nonlocal start
        start = start + 1
        print(start)
    return counter

>>> c = make_counter(10)
>>> c()
11
>>> c()
12
>>> 



> _______________________
> Chicago mailing list
> Chicago at python.org
> http://mail.python.org/mailman/listinfo/chicago


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/chicago/attachments/20120313/b7447447/attachment.html>


More information about the Chicago mailing list