The case against Python
Or, how to implement a switch statement in Python. Because why not.
Using closures and the decorator syntax, we can make something that looks reasonably close to a simple switch statement in Python. The idea is this: we’ll design a simple factory function to generate both a case
function that can be used as a decorator to register cases in our switch and a run
function to run our switch statement.
def switch(expr):
cases = []
def case(e):
def wrapper(f):
cases.append(e, f)
return wrapper
def run():
v = expr()
for e, body in cases:
if e == v:
body()
break
return case, run
We require that the parameter to switch
be a callable so that we can delay evaluating the expression to switch on until the moment the switch is run. In fact, we might even want to have the generated run
take the expression to switch on as a parameter, so that we can reuse the same switch many times on different values.
Let’s see our switch statement in action.
if __name__ == '__main__':
x = input()
case, run = switch(lambda: x)
@case(5)
def _():
print 'kindergarden!'
@case(18)
def _():
print 'university!'
run()
- If the user inputs
5
, then we printkindergarden!
- If the user inputs
18
, then we printuniversity!
- If the user inputs anything else, then nothing happens.
This trick of using decorators for side effects rather than to perform a transformation of a function is extremely useful. It’s how the Flask framework registers handlers on routes, for example.
There are some simple improvements that can be made to this.
- We can implement a default case by returning a third function called
default
. - We can allow passing unary functions to the
case
function to switch on the result of a function. Then@case(5)
becomes equivalent to@case(lambda x: x == 5)
.