Overloading Functions with Python Singledispatch

Photo by Maddi Bazzocco on Unsplash

Sometimes, you may need to implement a slight different variation of one function call depends on the type of the passed in parameter. Well you could have a long and tedious switch or if..else... statement together with isinstance or type . But there is a helper function to solve your parametric polymorphism problem.

In programming languages and type theory, parametric polymorphism is a way to make a language more expressive, while still maintaining full static type-safety. Using parametric polymorphism, a function or a data type can be written generically so that it can handle values identically without depending on their type. Such functions and data types are called generic functions and generic datatypes respectively and form the basis of generic programming.

For example, a function append that joins two lists can be constructed so that it does not care about the type of elements: it can append lists of integers, lists of real numbers, lists of strings, and so on. Let the type variable a denote the type of elements in the lists. Then append can be typed

forall a. [a] × [a] -> [a]

Following Christopher Strachey, parametric polymorphism may be contrasted with ad hoc polymorphism, in which a single polymorphic function can have a number of distinct and potentially heterogeneous implementations depending on the type of argument(s) to which it is applied. Thus, ad hoc polymorphism can generally only support a limited number of such distinct types, since a separate implementation has to be provided for each type.

— wiki

Starting Python 3.4. , there is a decorator in functools called singledispatch been added. In Python 3.8, there is another decorator called singledispatchmethod.been added.

Essentially, what these decorators do is to help overload a function which is essentially a function with different implementations. Calling an overloaded function will invoke one implementation of the many, which is a generic function, based on some prior conditions.

A generic function is composed of multiple functions implementing the same operation for different types. Which implementation should be used during a call is determined by the dispatch algorithm. When the implementation is chosen based on the type of a single argument, this is known as single dispatch.


Still too abstract? Let’s look at an example.

You can also overload it with the customised function.

Since the singledispatch can only dispatch based on the first argument passed, this becomes a problem with class method, as the default first self argument will take the spot. In this case, we can use the functools.singledispatchmethod, which transform a method into a single-dispatch generic function.

To define a generic method, decorate it with the @singledispatchmethod decorator. Note that the dispatch happens on the type of the first non-self or non-cls argument, create your function accordingly:

To check which implementation will the generic function choose for a given type, use the dispatch() attribute:

To access all registered implementations, use the read-only registry attribute:

That’s so much of it!

Happy Reading!

Hi :)