for ...: # or while
if condition found:
# do _everything_ needed if it's found ...
break
else:
# do everything needed if it's not found
The proposal is to add a new, optional clause, to handle the “if it’s found” case in a clearer way:
for ...: # or while
if condition found:
break
if break:
# do everything needed if it's found ...
else:
# do everything needed if it's not found
Then:
The search loop body is solely devoted to searching - better separation of concerns.
The “found” and “not found” suites are at the same indentation level. Sometimes the “it’s found” condition is discovered in several layers of nested testing, pushing the important part “far off to the right”.
Mnemonic value for those who have a hard time remembering whether else: is entered if a break occurred, or didn’t occur.
if break: and else: are both optional. Nothing about the semantics of current code would change, and if break is currently a syntax error. Over time, I’d migrate much of my own code to use if break:.
Not a big deal, just a “nice to have”. I don’t intend to implement it, but suggest it would be a relatively easy addition for an aspiring core dev to tackle.
found = False
for ...: # or while
if condition found:
found = True
break
if found:
# do everything needed if it's found ...
else:
# do everything needed if it's not found
The proposal saves two lines and a name, at the cost of confusion when someone tries if break: independent of a loop construct.
Yes, that’s the kind of thing I sometimes resort to now. Code can, of course, be much more complex than my bare-bones skeleton, and it’s very easy to forget to add found = True before everybreak. I’m unsatisfied with that approach in real life.
Why would they? They don’t try to use a bare else: independent of a loop construct either. Or, if they do, they get a syntax error. Same thing here if they try to use if break: independent of a loop construct.
Usually you can move “do everything needed if it’s found” just before the break. The only exception if it contains break or continue for the outer loop, but this is not very common case.
With how much confusion else after loop causes, this will be even more obscure part of Python syntax.
This can be solved without any disruption by contributing a rule to popular linters (such as ruff) that mandates a “no break” comment every time a for/else construct is used:
else: # no break
I have seen this convention in the wild and it’s also recommended in several highly upvoted answers on SO.
Yes. That’s the pattern explicitly shown in my first skeleton. It conflates the search-loop logic with the “what to do if it’s found” logic, and can end up pushing the “what to do if it’s found” logic to deep indentation levels (in case of nested testing).
That I disagree with. We already have else:, and if break:: is very explicit about when its suite is entered. If there’s also an else: clause, it would be equally clear that its suite would be entered if notbreak. There’s nothing here that becomes more obscure.
if no break or if not break would be possible, but I would defer that until Tim’s proposal is implemented. if no except and if not except could also be added, if desired.
One inconvenience of this is that given current conditional statement, if break: looks like a start of a new statement.
Given it is a continuation of a previous one, elif might be a better choice.
for ...: # or while
if condition found:
break
elif break:
# do everything needed if it's found ...
else:
# do everything needed if it's not found
I wonder a) how often for ... else is found in the wild[1] and b) how many of those cases would actually migrate. Maybe you would, but not everyone would.
As @storchaka said, it seems like this would be a very obscure piece of syntax. Given how rarely most people would encounter it, I’m not sure there’s any spelling that will make it intuitive when it shows up.
which was the inspiration for this thread in the first place, but no one has done the research ↩︎
Yes, that’s unfortunate. I don’t have a perfect solution, though. I’m relying in the end on that if break: is such an unusual combination that it will stick in peoples’ brains. I don’t care nearly so much about how odd it looks at first glance as about how hard it is to forget after it’s learned. if break pretty much means what it appears to mean.
Possibly, although not to me yet. The advantage of if/else is that it faithfully reflects that exactly one of the branches will be taken. elif/else only reflects that at most one (If any) of the branches will be taken.
Could you explain to me why adding a condition to the else would make it execute here? elif condition is just an alias for else if condition (which is invalid in Python).
while True:
break
else:
print("no condition")
while True:
break
elif break:
print("condition")
If this assumption is broken, we’re making things even more confusing than they already are.