[Python-ideas] for/else statements considered harmful

Ethan Furman ethan at stoneleaf.us
Thu Jun 7 15:52:49 CEST 2012


Nick Coghlan wrote:
> On Thu, Jun 7, 2012 at 11:06 PM, Alice Bevan–McGregor
> <alice at gothcandy.com> wrote:
>> On 2012-06-07 00:53:22 +0000, Nick Coghlan said:
>>>    for x in range(20):
>>>        if x > 10:
>>>            break
>>>    except break:
>>>        # Bailed out early
>>>    else:
>>>        # Reached the end of the loop
>>
>> Seems a not insignifigant number of readers got fixated on the alternate
>> keyword for the current behaviour of else (finally in my example) and
>> ignored or misinterpreted the -really important part- of being able to
>> detect if the loop was skipped (no iterations performed; else in my
>> example).
>>
>> Being able to have a block executed if the loop is never entered is vitally
>> important so you can avoid expensive or potentially impossible length checks
>> on the iterator before the loop.  Take this example:
>>
>>   sock = lsock.accept()
>>   for chunk in iter(partial(sock.recv, 4096), ''):
>>       pass # do something with the chunk
>>   else:
>>       pass # no data recieved before client hangup!
>>
>> Using a temporary varable to simulate this is… unfortunate.
>>
>>   sock = lsock.accept()
>>   has_data = False
>>   for chunk in iter(partial(sock.recv, 4096), ''):
>>       has_data = True
>>       pass # do something with the chunk
>>
>>   if not has_data:
>>       pass # no data recieved before client hangup!
>>
>> empty woud be a good keyword to preserve the existing meaning of else, but
>> I'm pretty sure that's a fairly common variable name.  :/
> 
> Yeah, it's usually fairly important on here to separate out "this is
> the problem I see" from "this is a proposed solution". Getting
> agreement on the former is usually easier than the latter, since there
> are so many additional constraints that come into play when it comes
> to considering solutions. And if we can't even reach agreement that a
> problem needs to be solved, then talking about solution details isn't
> especially productive (although it can be fun to speculate about the
> possibilities anyway).
> 
> FWIW, I usually solve this particular problem with for loops by using
> the iteration variable itself to hold a sentinel value:
> 
>    sock = lsock.accept()
>    chunk = None
>    for chunk in iter(partial(sock.recv, 4096), ''):
>        pass # do something with the chunk
> 
>    if chunk is None:
>        pass # no data recieved before client hangup!
> 
> If "None" is a possible value in the iterable, then I'll use a
> dedicated sentinel value instead:
> 
>     var = sentinel = object()
>     for var in iterable:
>         ...
>     if var is sentinel:
>         ...
> 
> I've never found either of those constructs ugly enough to
> particularly want dedicated syntax to replace it, and the availability
> of this approach is what makes it especially difficult to push for
> dedicated syntactic support (since all that can really be saved is the
> assignment that sets up the sentinel value).

This seems like a good work-around (meaning: I'll definitely use it, 
thanks!), but it does not address the confusion issues.

I think the main problem with the current while/else, for/else is 
two-fold: 1) we have two failure states (empty from the start, and 
desired result not met), and 2) even though the else is more similar to 
the else in try/except/else, it is formatted *just like* the if/else.

Perhaps the solution is to enhance for and while with except?

    sock = lsock.accept()
    for chunk in iter(partial(sock.recv, 4096), ''):
        pass # do something with the chunk
    except:
        pass # no data recieved before client hangup!
    else:
        pass # wrap-up processing on chunks

~Ethan~



More information about the Python-ideas mailing list