Brett Cannon: Unravelling `elif`/`else` from `if` statements
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
10.7k
By Amol Rathi
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!