[Python-ideas] for/else syntax

Antti Rasinen ars at iki.fi
Fri Oct 2 08:05:00 CEST 2009


On 2009-10-02, at 06:07, Steven D'Aprano wrote:

> On Thu, 1 Oct 2009 09:00:21 pm Antti Rasinen wrote:
>
>> To add further insult to the naming injury, the else branch suffers
>> from the fact that 99.9% of the time, the for-loop contains an if:
>
> Really? You've done a statistically significant survey of code in the
> wild and come to a figure accurate to one part in a thousand? Not just
> plucked a number straight out of thin air?
>
> In my code, the figure is more like 20-40%. Choosing one  
> representative
> module at random, only one in three for-loops include an if inside the
> loop. And when I use for...else, it's closer to 10%.

Oh silly me. I used some sloppy language there. I did not mean that  
all for-loops have ifs inside them. What does your last statistic  
mean? Do you have if statements in only 10% of your for..else loops or  
in 10% of your all for-loops (including for...else)? If you mean the  
first case, then please ignore the rest of this message and post an  
example :-)

What I meant that most *for...else* structures have an if inside. The  
99.9% number is, as you say, plucked from thin air -- but I think it  
is very close to the truth. There are simpler alternatives to  
for..else if the loop does not contain an if. Consider the following  
structure:

   for x in xs:
       # body
   else:
       # else-branch

If you don't have a break in the body of the for-loop, then you don't  
need the else: at all. You can write the above segment as:

   for x in xs:
       # body
   # else-branch

If, on the other hand, you do have a break in the body, then either it  
is conditional or it is not. If there is no break, then you are either  
only processing the first element in the iterable or skipping directly  
to the else branch. In this case it would be natural to use plain if:

   if xs:
       # body with xs[0]
   # else-branch

Iterators complicate the matter, but even in that case then I'd rather  
use a peeking wrapper around xs.

It seems to me that the only sensible use case for for..else is when  
there is an conditional break inside the loop. I'll appreciate any  
counter examples, of course.

Nick Coghlan's had a lovely example about search loops earlier in the  
thread. It also highlights one of the reasons why I think the  
for..else construct is so rare. Consider his example:

  for obj in iterable:
    if found_it(obj):
      # Found what we were looking for!
      break
  else:
    # It wasn't there :(

There are several ways of writing this without for..else. If the  
context for the loop is correct, you might just use return True (or  
obj) during the loop. No need for an else-branch there.

Or you might use any:

   if not any(found_it(obj) for obj in iterable):
       # It wasn't there :(

It seems to me that there often are "more intuitive" ways of writing a  
for..else-loop. And accordingly, the construct is rare. I'll resort to  
some newspeak here and define "intuitive" as either "conveys the  
intent of the programmer better" or as "feels like the more obvious  
way to do it". Pick either.

--Antti

-- 
[ ars at iki.fi <*> Antti Rasinen ]

This drone-vessel speaks with the voice and authority of the Ur-Quan.




More information about the Python-ideas mailing list