[Python-ideas] For-loop variable scope: simultaneous possession and ingestion of cake

Bruce Leban bruce at leapyear.org
Sat Oct 4 03:53:17 CEST 2008


On Fri, Oct 3, 2008 at 6:00 PM, Dillon Collins <dillonco at comcast.net> wrote:

> On Friday 03 October 2008, Greg Ewing wrote:
> > My next step would be to propose a 'let' statement
> > for dealing with things like that:
> >
> >    for i in range(3):
> >      let j = str(i):
> >        funs.append(lambda: j)
> >
>
> Well now, that seems more than a little ridiculous.  If we're going to be
> creating a keyword that rescopes variables, why not just use that instead
> of
> messing with the for loop.


I don't see how this is messing with the for loop at all.


> Seems like that would be a generally more useful
> solution anyway.
>
> Perhaps instead:
>
> for i in range(10):
>     j = str(i)
>    scope i, j:
>        funs.append(lambda: (j,i))
>

The difference between my or Greg's proposal is that the scope of the
variable is the inner block while your proposal the variable has two scopes.
That is, to annotate the code:

  for i in range(10):  # creates a new variable i in function scope (if it
didn't already exist)
    local k:  # creates a new scope for k
      k = i**2  # creates a new variable k (every time we execute this
block)
      a.append(lambda: k)  # closure references the variable in the
enclosing scope (as it normally does)
  print(k)  # error -- there is no k in this scope

  for i in range(10):  # creates a new variable i in function scope (if it
didn't already exist)
    k = i**2  # creates a new variable k in function scope (if it didn't
already exist)
    scope k:  # creates new variables k and copies the values from the outer
scope
      a.append(lambda: k)  # closure references the variable in the
enclosing scope (as it normally does)
  print(k)  # prints 81, the last k from the loop

I don't care for the fact that there are really two k variables here (or
more properly N+1). Also, the implicit copying sort of obscures some
details. The fact that my alternative requires explicit setting of the value
of the scoped variable is a good thing.

For example, consider this:

  a = [0,1,2]
  for i in range(3):
    scope a:
      a.append(i)
      ... lambda: ... a ...

Yes, a is in a different scope, but references the same list so the scope is
useless. At least in my or Greg's version, since you have to assign to the
local variable, there's a clear place where you can see the copying is
missing.

  a = [0,1,2]
  for i in range(3):
    local b:
      b = a  # easy to see that this should be b = copy.copy(a)
      b.append(i)
      ... lambda: ... b ...

I've used my suggested syntax because I like it a bit better although the
above would also apply to Greg's suggestion. Comparing our suggestions, I
think local a,b: is a bit more clear than let a = value, b = value: and mine
does not force you to initialize the variables. They could be combined:

  'local' var [ '=' expr ] ( ',' var [ '=' expr ] )* ':'

with the ',' in the local statement taking priority over ',' in the
expressions just as it does for function calls.

--- Bruce
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20081003/2a796afb/attachment.html>


More information about the Python-ideas mailing list