seeking deeper (language theory) reason behind Python design choice

Steven D'Aprano steve+comp.lang.python at pearwood.info
Fri May 11 01:17:59 EDT 2018


On Fri, 11 May 2018 03:29:57 +0300, Marko Rauhamaa wrote:

>> Now do you understand what I mean about putting the condition into the
>> loop header?
> 
> Thanks, but no thanks. The "while True" idiom beats that one hands down.

Why do you think it is better to lie to the reader and tell them they are 
entering an infinite loop, only to later on say "Ha ha, fooled you!"?

It doesn't matter whether it is one line later, or sixteen pages later. 
The initial "while True" suggests an infinite loop, because the loop 
condition is *always* True, so the loop never ends.

To answer your question from a later post:

    In what way does "while True" in the general case pretend
    to be an infinite loop?

It doesn't *pretend* to be an infinite loop. It *is* an infinite loop 
which breaks out early.

I realise that all infinite loops end up breaking out early, even if it's 
only when you power-cycle the device. But code ought to match intent, and 
"while condition which can never be false" shouts from the mountain tops 
that it is an infinite loop. The simpler the condition, the more loudly 
it shouts, and you can't get simpler than True.

(The one thing that beats "while True" as an indicator of an infinite 
loop is the old Hypertalk syntax "repeat forever".)

If we want to communicate the intent of our code, the while-condition 
ought to be in the loop header *if possible*. (I appreciate it isn't 
always possible.)

We wouldn't write this:

    # let's pretend we have GOTO
    if True:
        if not condition: GOTO 99
        block
    LABEL 99


and if we came across it in real life, we'd surely question the sanity of 
the developer who wrote it. Why should while loops be any different?

    while True:
        if not condition: break  # equivalent to GOTO 99
        block
    LABEL 99

I understand that *today*, using existing Python syntax, there is 
sometimes no avoiding that (except, possibly, with something worse). I 
get that. But if we had the choice to move the condition into the while 
condition, we ought to take it.


> As for the "is not None" test, I generally want to make it explicit
> because
> 
>  1. that's what I mean and
> 
>  2. there's a chance in some context of confusing None with other falsey
>     values.

Indeed #2 is correct, and of course *in general* we ought to be explicit 
when testing for None. But in the case of regexes, I doubt that testing 
for None is *actually* what you mean. It's merely what you *think* you 
mean *wink*

To be precise, the rule is that re.match() returns a true object (a 
MatchObject) if the search succeeded, and a false object (documented as 
None) if it fails. But we surely don't care that the failure case is 
*specifically* None. It should make no difference at all if re.match() 
returned False instead, or a falsey MatchObject with all fields left 
empty, since we never use it.

So we ought not care that it is specifically None.

Testing for None particularly makes sense if you need a sentinel and:

- you don't distinguish between truthy and falsey values at all;

- or you want to distinguish between truthy values, falsey values,
  and leave None to stand in for things which are neither ("maybe"?).

The re.match case doesn't meet either of those conditions.

Of course, none of this is to say that testing for None is "wrong". 
re.match is documented as returning None, and a backwards-incompatible 
change is exceedingly unlikely. So you're safe there. It's just 
unnecessary.



-- 
Steve




More information about the Python-list mailing list