On 03/03/2017 04:36 AM, Nick Coghlan wrote:
On 2 March 2017 at 21:06, Wolfgang Maier
<wolfgang.ma...@biologie.uni-freiburg.de
<mailto:wolfgang.ma...@biologie.uni-freiburg.de>> wrote:

    - overall I looked at 114 code blocks that contain one or more breaks


Thanks for doing that research :)


    Of the remaining 19 non-trivial cases

    - 9 are variations of your classical search idiom above, i.e.,
    there's an else clause there and nothing more is needed

    - 6 are variations of your "nested side-effects" form presented
    above with debatable (see above) benefit from except break

    - 2 do not use an else clause currently, but have multiple breaks
    that do partly redundant things that could be combined in a single
    except break clause


Those 8 cases could also be reviewed to see whether a flag variable
might be clearer than relying on nested side effects or code repetition.


[...]


This is a case where a flag variable may be easier to read than loop
state manipulations:

    may_have_common_prefix = True
    while may_have_common_prefix:
        prefix = None
        for item in items:
            if not item:
                may_have_common_prefix = False
                break
            if prefix is None:
                prefix = item[0]
            elif item[0] != prefix:
                may_have_common_prefix = False
                break
        else:
            # all subitems start with a common "prefix".
            # move it out of the branch
            for item in items:
                del item[0]
            subpatternappend(prefix)

Although the whole thing could likely be cleaned up even more via
itertools.zip_longest:

    for first_uncommon_idx, aligned_entries in
enumerate(itertools.zip_longest(*items)):
        if not all_true_and_same(aligned_entries):
            break
    else:
        # Everything was common, so clear all entries
        first_uncommon_idx = None
    for item in items:
        del item[:first_uncommon_idx]

(Batching the deletes like that may even be slightly faster than
deleting common entries one at a time)

Given the following helper function:

    def all_true_and_same(entries):
        itr = iter(entries)
        try:
            first_entry = next(itr)
        except StopIteration:
            return False
        if not first_entry:
            return False
        for entry in itr:
            if not entry or entry != first_entry:
                return False
        return True

    - finally, 1 is a complicated break dance to achieve sth that
    clearly would have been easier with except break; from typing.py:


[...]


I think is another case that is asking for the inner loop to be factored
out to a named function, not for reasons of re-use, but for reasons of
making the code more readable and self-documenting :)


It's true that using a flag or factoring out redundant code is always a possibility. Having the except clause would clearly not let people do anything they couldn't have done before. On the other hand, the same is true for the else clause - it's only advantage here is that it's existing already - because a single flag could always distinguish between a break having occurred or not:

brk = False
for item in iterable:
    if some_condition:
        brk = True
        break
if brk:
    do_stuff_upon_breaking_out()
else:
    do_alternative_stuff()

is a general pattern that would always work without except *and* else.

However, the fact that else exists generates a regrettable asymmetry in that there is direct language support for detecting one outcome, but not the other.

Stressing the analogy to try/except/else one more time, it's as if "else" wasn't available for try blocks. You could always use a flag to substitute for it:

dealt_with_exception = False
try:
    do_stuff()
except:
    deal_with_exception()
    dealt_with_exception = True
if dealt_with_exception:
    do_stuff_you_would_do_in_an_else_block()

So IMO the real difference here is that the except clause after for would require adding it to the language, while the else clauses are there already. With that we're back at the high bar for adding new syntax :( A somewhat similar case that comes to mind here is PEP 315 -- Enhanced While Loop, which got rejected for two reasons, the first one being pretty much the same as the argument here, i.e., that instead of the proposed do .. while it's always possible to factor out or duplicate a line of code. However, the second reason was that it required the new "do" keyword, something not necessary for the current suggestion.
_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to