unintuitive for-loop behavior

Gregory Ewing greg.ewing at canterbury.ac.nz
Sat Oct 1 20:44:49 EDT 2016


Steve D'Aprano wrote:
> When you say:
> 
>     x = 0
>     x = 1
> 
> inside a function, and the interpreter does the name binding twice, there's
> no way of telling whether it writes to the same cell each time or not.

Yes, there is:

...  x = 0
...  f1 = lambda: x
...  x = 1
...  f2 = lambda: x
...  print(f1(), f2())
...
 >>> f()
1 1

This indicates that both assignments updated the same slot.
Otherwise the result would have been "0 1".

It's not currently possible to observe the other behaviour in
Python, because the only way to create new bindings for local
names is to enter a function. The change to for-loop semantics
I'm talking about would introduce another way.

> Certainly when you call a function, the local bindings need to be created.
> Obviously they didn't exist prior to calling the function! I didn't think
> that was the difference you were referring to, and I fail to see how it
> could be relevant to the question of for-loop behaviour.

My proposed change is (mostly) equivalent to turning the
loop body into a thunk and passing the loop variable in as
a parameter.

This is the way for-loops or their equivalent are actually
implemented in Scheme, Ruby, Smalltalk and many other similar
languages, which is why they don't have the same "gotcha".
(Incidentally, this is why some people describe Python's
behaviour here as "broken". They ask -- it works perfectly
well in these other languages, why is Python different?)

The trick with cells is a way to get the same effect in
CPython, without the overhead of an actual function call
on each iteration (and avoiding some of the other problems
that using a thunk would entail).

The cell trick isn't strictly necessary, though -- other
Python implementations could use a thunk if they had to.

-- 
Greg



More information about the Python-list mailing list