[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Loop with else clause

Wow, you dug deep.

My example was the reverse of the "toy example"'s you mention as I find
that often code becomes much clearer if you order it such that
specific cases, sanity checking and exceptions go first, and then the
default case at the end.

So my general suggestion would be to handle your empty list/no valid
candidates cases first,
and then do the for loop at the end.

If you style this with if/elif/else, or put return statements in
certain places, I have no opinion about and will depend on the specific


Adriaan Renting.

>>> On 7-2-2019 at 9:42, DL Neil <PythonList at DancesWithMice.info>
> Further to our discussion of how to improve a code review's discovery
> the mistaken handling of a for...else... construct:-
> Yesterday was a national holiday, but today gave some opportunity to

> research. Way back in 2009 there was spirited discussion over on the

> Python Ideas list (warning, even the mailing list's index covers 
> multiple screen-lengths):
> - this confusion is not new by any measure, herewith a list of
> occasions "fists were raised concerning for..else."
> - an excellent summary of the 2009 debate which offers no less than
> ways to 'improve' for... else...
> - (as mentioned earlier) the BDFL weighed-in a couple of times. His 
> regret is: "That's a flaw, and I don't quite know what to do about
> It's about 20 years too late to remove or rename it. But we probably

> should not do more of these. That's a lesson."
> (OK, so make that thirty years - older than the coder who the 
> code-review noticed falling into this coding 'gotcha'!)
> - herewith a (rather complicated) suggestion, and critique
> - one rather hopeful option (actual words to be used
> 	for i in SEQ:
> 	  A
> 	except:
> 	  B
> 	else:
> 	  C
> appears here:
> Somewhat related, PEP 548 proposed an "More Flexible Loop Control".
> was addressing the confusion caused by break within a loop. It was
> Each of the above addresses issues 'within', that is to say
> during iteration - whether the entire loop or iteration cut-short by
> break (and thus the idea that "else" might be re-worded to indicate 
> 'after a break').
> However, as mentioned by one contributor, the specific use-case our
> faced was an issue that arises prior to the loop.
> that according to Python's logic, prevents even a single iteration of

> that loop. Thus, any 'solution' would reside outside of for and while

> statements because they only consider if a loop should continue or 
> terminate - not handling the question of whether it should start at
> PEP 315 is the only discussion (I've found) which looks 'outside' or

> 'before' the loop itself. It proposed an "Enhanced While Loop", 
> attempting to separate 'setup' or loop control from loop content. It
> rejected.
> So, reading-around brought nothing much useful. Back to the
> Thank you to the several folk who responded with ideas to
>      if list:
>          process_list() #the heading and for-loop, as above
>      else:
>          print( "Sorry...
> NB this is a constructed 'toy example' attempting to be the shortest

> illustration of use-cases and invented purely to communicate the need

> and structure. It was expected to be interpreted as
> (you'd not use/allow "process_list" as the name of a function, would
> (With apologies as necessary) one of the dangers of 'toy examples' is

> the reader taking them at face value, instead of as (over-)simplified

> illustrations. In 'real life' the loop code and the no-loop exception

> are both considerably longer than a single line. Accordingly, using a

> function would be a good way to summarise and self-document the 
> activity, ie the if statement's two code-blocks would make the whole

> statement very/too-long (readability)!
> The "if list:" expression is overly-simplistic. The recommendation of

> "if len(list):" is absolutely sound, for reasons of polymorphism.
> In-lieu of a Python construct, there are definitely situations when
> of a sentinel makes better sense. However, given their risk, in many

> ways Python tries to avoid using such, eg consuming iterators until a

> StopIteration exception is returned. (includes files, is subsumed by

> ContextManagers...), thus "pythonic". That said, the classic use of 
> for... else... is in searching for a particular element within an 
> iterable which has all the hallmarks of a "sentinel".
> Today, kicking ideas around, I coded three other possible 'solutions'

> for the review team's discussions:
> One of these involves coding three functions: the decision (yielding
> boolean), the expected-case, and the unusual-case. The satisfaction
> this was readability factors with a simple if statement..
> Somewhat more complex, and I feel a bit OTT, was to sub-class list()
> write a method which would indicate an empty list, plus include much
> both the expected-case and the empty-list methods therein. Somehow 
> "class ListShouldNotBeEmpty" doesn't seem a catchy (if descriptive) 
> title - however, it works! The decision 'function' could also/then be

> made @property and (perhaps) thus contribute to readability.
> Lastly, I 'remembered' conditional expressions. Thus, furthering the

> idea of two/three functions:
>      process_list() if list_has_contents() \
> 			else process_empty_list()
> Report card:
> Functional = yes.
> Pythonic = yes.
> Readable = much debated/relates to the expertise of the coder/reader
> Your thoughts?