Brett Cannon: Unravelling `elif`/`else` from `if` statements

image

While I won’t be attempting to unravel if statements entirely as part of my blog series on Python’s syntactic sugar, I will be attempting to partially unravel them by showing how you don’t need elif and else clauses.

Unravelling else

Let’s start with else . Semantically, else is run if the conditional guard on the if statement isn’t true. So we could view an else clause as saying that if the body of the if clause doesn’t run, then run the else clause. That means for the following example:

if a:
    b
else:
    c
Example of if/else

if b is not run then c should be run, and vice-versa. So maybe we can just make the else clause another if? By recording whether b executed, we can make executing c depend on whether b ran.

_b_ran = False
if a:
    _b_ran = True
    b
if not _b_ran:
    c
Unravelling else

By using a variable to record whether the if clause executed, else just becomes another if statement.

I’m not using assignment expressions for a reason

Now I will admit I was initially tempted to use assignment expressions to simply record the boolean value of the conditional guard and check if that happened to be true. But after poking at the C code I didn’t feel confident that it would never lead to unforeseen side-effects or incorrect semantic matching of what if checks against (i.e. I couldn’t guarantee that calling bool() on the value of the conditional guard wouldn’t trigger code that normally wouldn’t have been executed), so I’m going with the tried-and-true way of unique variables instead.

Unravelling elif

You can generalize our approach above while incorporating the conditional guard of an elif by checking if previous clauses executed and if the conditional guard is true. For example:

if a:
    b
elif c:
    d
Example using elif

becomes:

_b_ran = False
if a:
    _b_ran = True
    b
if not _b_ran and c:
    d
Unravelling the elif example

This generalizes such that each elif clause simply needs to make sure none of the previous clauses were executed. Taking a bigger, fuller example:

if a:
    b
elif c:
    d
elif e:
    f
else:
    g
Example with elif and else

This becomes:

_b_ran = _d_ran = _f_ran = False
if a:
    _b_ran = True
    b
if not _b_ran and c:
    _d_ran = True
if not (_b_ran or _d_ran) and e:
    _g_ran = True
if not (_b_ran or _d_ran or _f_ran):
    g
Unravelling of example with elif and else

And this pattern of checking if any of the preceding clauses ran simply continues to generalize for an arbitrary number of clauses!

Author: Shantun Parmar

Leave a Reply

Your email address will not be published.