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

Greg Ewing greg.ewing at canterbury.ac.nz
Sat Oct 4 02:12:04 CEST 2008


Andrew Clover wrote:

> Why only the loop variable? What about:
> 
>     >>> for i in range(3):
>     ...     j= str(i)
>     ...     funs.append(lambda: j)

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)

The 'let' statement would do the same thing for its
variable as the for-loop, but in a one-off fashion.

> It seems an odd sort of scope that lets rebindings inside it fall 
> through outwards.

I think this is an unavoidable consequence of not having
variable declarations. Otherwise it would be impossible for
an assignment inside a for-loop to perform an ordinary
rebinding of some local variable outside it.

> Some of those languages can bind the variable value early, so if 
> you were to write the equivalent of:
> 
>     >>> i= 3
>     >>> f= lambda: i
>     >>> i= 4

Can you give me an example of an imperative language that
behaves that way? I don't think I've ever seen one.

(Note that the above would be illegal in any functional
(i.e. side-effect-free) language, since the syntax doesn't
allow you to express rebinding an existing variable.)

> There are other languages with lexical scope and late value binding, 
> such as JavaScript; their for loops behave the same as Python.

Yes, and I would say that their for-loops are broken
(or perhaps I should say suboptimally designed) in
the same way.

>     >>> i= 0
>     >>> geti= lambda: i
> 
>     >>> for i in [1]:
>     ...     print i is geti()
>     True
> 
>     >>> for i in [1]:
>     ...     dummy= lambda: i
>     ...     print i is geti()
>     False

Hm, there's something I left out of the specification.
My intention was that the current value of the loop
variable should *also* be seen from outside the loop
while the loop is executing, so both of the above
would print True. The implementation I suggested using
cells has this property.

> How about explicitly requesting to 
> be given a new scope each time around the loop? 
> 
>     >>> for local i in range(3):
>     ...     funs.append(lambda: i)

That's a possibility, too. I actually proposed something
like it once before, using 'new':

   for new i in range(3):
     ...

However, it's quite an unexpected thing to have to do,
so it would do nothing to reduce the frequency of questions
on c.l.py about why people's lambdas are broken. It would
provide a slightly more elegant answer to give them, though.

One advantage would be that it could be extended to
be usable on any assignment, not just for loops, so
there wouldn't be a need for a separate 'let' statement.

There would be some details to sort out, e.g. if you're
unpacking into multiple variables, do you use just one
'new' for them all, or do you have to put 'new' in
front of each one? I.e.

   for new a, b, c in stuff:
     ...

or

   for new a, new b, new c in stuff:
     ...

-- 
Greg



More information about the Python-ideas mailing list