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

Greg Ewing greg.ewing at canterbury.ac.nz
Sat Oct 4 03:48:48 CEST 2008


Terry Reedy wrote:

> If one understands that 'lambda: i' is essentially 'def f(): return i' 
> and that code bodies are only executed when called, the behavior is 
> obvious.

It's not just about lack of understanding -- even when
you fully understand what's going on, you have to do
something about it, and the available solutions are,
to me, less than satisfying.

Yes, that's an opinion. Most things in programming
language design are. I'm discussing this to find
whether anyone shares my opinion.

> Here are 5 more alternatives that have the same effect: 

All of which are even worse, to my eyes.

>> For one thing, it's still abusing default arguments,
> 
> Use is a fact, abuse is an opinion.

The reason I call it "abuse" is that the intended use
of default argument values is as just that, a default
to use if no other value is passed in. In this case
there's no intention of passing a value in, so you're
using the feature for something other than its intended
purpose.

What's more, if a value does happen to get passed in,
it *breaks* what you're trying to do. So it only works
in favourable circumstances, and isn't a general solution.

>> as if the function needs to take a variable number of
>> arguments.

Usually it doesn't, but it could, if the API you're
passing the function to requires it to.

> A respondant on c.l.p pointed out that Python works the same as C and 
> Common Lisp.

Yes, but... in Lisp or its derivatives, you *don't*
normally write the equivalent of a for-loop by
rebinding an existing control variable. You use a
mapping function of some sort, in which the whole
loop body is a lambda, and therefore receives a
new binding for each loop value.

This is the natural way to code in such languages.
Most of the time you create new bindings rather
than change existing ones, and this interacts
well with nested functions.

Python's assignment rules and lack of variable
declarations, on the other hand, interact rather
badly with nested functions. The most natural
way of writing code often ends up rebinding
where a new binding would be more appropriate.

I'm suggesting a change to the for-loop because
it's a place where, if it matters at all, a new
binding is almost certainly what you want.

To address the rest of the cases, there would be
a 'let' statement or some such to introduce new
bindings.

> As I understand this, you are proposing that
> 
> for i in it:
>   body
> 
> be rewritten as
> 
> def _(i):
>   body
> for i in it:
>   _(i)

Only conceptually. It would be unacceptably inefficient
to actually implement it that way in current CPython.

This translation isn't quite equivalent, because if
the body assigns to i, in your version the change won't
be seen from outside the loop during that iteration.
In my version, it will.

> I believe this sort of automagic would make Python even harder to learn 
> and understand.  One should be able to learn and use loops and simple 
> functions before learning about nested functions and closures.

Since loops without any nested functions would be
completely unaffected, either conceptually or
implementation-wise, I don't see how this would
interfere with learning about loops before closures.

-- 
Greg



More information about the Python-ideas mailing list