Functional dynamic dispatch with Python’s new singledispatch decorator in functools

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.

This is not technically “multimethods” — which can also be implemented as a decorator, as GvR did in 2005 — but it’s related. See the Wikipedia article on Dynamic Dispatch for more information.

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 HandleA and HandleB, each with an implementation for handle:

    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 obj.

With this PEP/stdlib addition, you can now write two functions, handle_A and handle_B, which take an argument, obj, and are dynamically dispatched using the generic function handle.

    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_A or handle_B based on the type of the obj argument

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.

2 thoughts on “Functional dynamic dispatch with Python’s new singledispatch decorator in functools”

  1. Your small example comparing the object-oriented way to the “dynamic dispatch” mechanism of doing the same thing really distills the core of what this is about. Not only that but it is also very nice reference material related to software design. Should be added in the official documentation.

Leave a Reply