I recently read Functional Programming in Python which mentions a library which adds multiple dispatch to Python. One of my biggest hobbies is creating things from scratch, as it really helps me get a better understanding of how they work, so I thought I’d see if I couldn’t figure out how to do it myself.
Here’s what I whipped up. I’ll add a disclaimer that in this form, it
doesn’t work well for methods or class methods, as they both take a
special argument in the first position (namely self
or
cls
), and it doesn’t accept keyword arguments. At some
stage I’ll try to make it a bit more rigorous.
class Dispatch: _existing = {} def __init__(self, *types): self.types = types def __call__(self, fn): name = fn.__qualname__ if name not in self._existing: table = {} def dispatcher(*args): types = tuple(map(type, args)) try: overload = table[types] except KeyError: try: overload = table[(True,)] except KeyError: raise NotImplemented from None return overload(*args) self._existing[name] = (table, dispatcher) (table, dispatcher) = self._existing[name] table[self.types] = fn return dispatcher
Once you tuck this away in a library somewhere where you don’t have to look at it, you can use it to write some pretty elegant code. See the following implementation of the flatten function.
@Dispatch(list) def flatten(elems): return reduce(add, map(flatten, elems), []) @Dispatch(True) def flatten(elem): return [elem]