loop scope

Jacek Generowicz jacek.generowicz at cern.ch
Mon Mar 15 06:52:14 EST 2004


Jacek Generowicz <jacek.generowicz at cern.ch> writes:

> Imagine (for the sake of brevity of argument --- I wouldn't dream of
> suggesting such a "line-noise" syntax for Python) that you could use
> "x := 3" to mean "create a new local binding for x", while "x = 3"
> would mean "find the innermost x and rebind it", with function
> parameters, loop variables, list comprehension variables all behaving
> as if they were using ":=". Now you'll find that you gain a lot of
> flexibility to do what is appropriate with scopes of variables used in
> loops etc., and you have an opportunity to fix the immutability of
> closures ...
> 
> (Of course there are "issues" ... what happens, for
> example when you say
> 
>     def foo(a):
>         a := 3
>         a := 4
> 
> ... does that make three nested scopes for a?, is it an error?)

Hmm, this is starting to intrigue me.

What are the situations that need disambiguating?

What situations do (or might) create inner scopes?

"def" and "class" are currently the two ways of creating an inner
scope (have I overlooked any others?) ... and we are considering the
possibility of "for" doing the same (in two different flavours: loops
and comprehensions).

Current rules can be summarized as:

  In a scope creating block (def, class), assignment introduces a
  local binding, unless the name is declared global.

It looks like what's missing (because originally there were no other
scopes between local and global) is some way of declaring a name to
refer to an enclosing scope which may or may not be the global scope.

For example:

  >>> def make():
  ...     x = 0
  ...     def show(): print x
  ...     def inc(n): x = x+n
  ...     return show,inc
  ... 
  >>> show,inc = make()
  >>> show()
  0
  >>> inc(3)
  Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<stdin>", line 4, in inc
  UnboundLocalError: local variable 'x' referenced before assignment

The problem is that the "x =" inside "def inc():" tells the compiler
to treat "x" as local to the scope of "inc", and then the reference to
"x" or the RHS of the same line refers to an unbound variable ("x" in
the _local_ scope). "global" is there for exactly this sort of
situation, except that it originates from a time when there were no
nested scopes, so it offers no help if you want to refer to some scope
other than the global or local.

Imagine we have a "nested" keyword which is similar to "global", only
it ensures that the name is found in the nearest enclosing scope. Now
the above problem could be resolved by defining "inc" as follows.

    def make():
        x = 0
        ...
        def inc(n):
            nested x
            x = x+n
        ...

Works just like global would have done, only it is aware of the
other socpes between local and global.

> "Greg Ewing (using news.cis.dfn.de)" <wmwd2zz02 at sneakemail.com> writes:
> 
> > It wouldn't do to make the whole (non-comprehension)
> > for-loop a new scope, because that would make any
> > variables assigned within the loop body local as well.

Not if you have a "nested" keyword at your disposal.

What situations would this not cover ?



More information about the Python-list mailing list