I just read about Python 3.4’s release notes. I found a nice little gem.
I didn’t know what “Single Dispatch Functions” were all about. Sounded very abstract. But it’s actually pretty cool, and covered in PEP 443.
What’s going on here is that Python has added support for another kind of polymorphism known as “single dispatch”. This allows you to write a function with several implementations, each associated with one or more types of input arguments. The “dispatcher” (called
singledispatch and implemented as a Python function decorator) figures out which implementation to choose based on the type of the argument. It also maintains a registry of types to function implementations.
Also, the other interesting thing about this change is that the library is already on Bitbucket and PyPI and has been tested to work as a backport with Python 2.6+. So you can start using this today, even if you’re not on 3.x!
Someone on Hacker News asked,
Huh? But that’s not single dispatch? Single dispatch is deciding what function to call based on the type of your object, not on the type of arguments. That’s called double dispatch.
Single dispatch is pretty standard polymorphism, C++ can do that.
That’s a bit of a semantic argument. Python already has “object-oriented single dispatch” — aka traditional object-oriented polymorphism.
What this module adds is “functional single dispatch”.
So, whereas before you’d always be forced to implement some type-varying function using two classes
HandleB, each with an implementation for
class HandleA: def handle(self): pass class HandleB: def handle(self): pass def main(obj): # obj could be instance of HandleA or HandleB obj.handle()
In this case, “dynamic dispatch” is done by
obj.handle(), which will pick a different implementation depending on the type of
With this PEP/stdlib addition, you can now write two functions,
handle_B, which take an argument,
obj, and are dynamically dispatched using the generic function
from functools import singledispatch @singledispatch def handle(obj): pass @handle.register(A) def handle_A(obj): pass @handle.register(B) def handle_B(obj): pass def main(obj): # obj could be instance of A or B handle(obj)
And in this case, “dynamic dispatch” is done by
handle(obj), or really, by the dispatcher decorator. It chooses
handle_B based on the type of the
The reason this is a nice addition is because it makes Python eminently “multi-paradigm” — you can choose object-oriented or functional styles depending on your taste and the applicability to the task at hand, instead of being forced into one programming style or the other.