Trusted answers to developer questions

What is the singledispatchmethod() decorator in Python?

Get Started With Data Science

Learn the fundamentals of Data Science with this free course. Future-proof your career by adding Data Science skills to your toolkit — or prepare to land a job in AI, Machine Learning, or Data Analysis.

The functools module

The functools module in Python allows us to create higher-order functions that interact with other functions. The higher-order functions either return other functions or operate on them to broaden the functions’ scope without modifying or explicitly defining them.

The singledispatchmethod decorator

The singledispatchmethod decorator is used for method classes overloading. The functionality is similar to the singledispatch decorator. However, the dispatch is based on the type of the first non-self or non-cls argument. This allows for the overloading of both the method and the class method.

Example

from functools import singledispatchmethod
class Sum:
@singledispatchmethod
def sumMethod(self, arg1, arg2):
print("Default implementation with arg1 = %s and arg2 = %s" % (arg1, arg2))
@sumMethod.register
def _(self, arg1: int, arg2: int):
print("Sum with arg1 as integer. %s + %s = %s" % (arg1, arg2, arg1 + arg2))
@sumMethod.register
def _(self, arg1: float, arg2: float):
print("Sum with arg1 as float. %s + %s = %s" % (arg1, arg2, arg1 + arg2))
s = Sum()
s.sumMethod(2, 3)
s.sumMethod(2.1, 3.4)
s.sumMethod("hi", 3.4)

Explanation

  • Line 1: The singledispatchmethod decorator is imported from the functools module.

  • Line 3: The Sum class is defined.

  • Lines 6-7: A function named sumMethod is defined in the Sum class. It accepts two arguments, arg1 and arg2. The sumMethod function is decorated with the singledispatchmethod decorator. This is the default implementation of the sumMethod function.

  • Lines 10-11: We register the first implementation of the sumMethod function for which arg1 should be of the integer type. Here, arg1 is annotated with int as its type.

  • Lines 14-15: We register the second implementation of the sumMethod function for which arg1 should be of the float type. Here, arg1 is annotated with float as its type.

  • Lines 18-21: We invoke sumMethod with different types of values for arg1.

  • Line 21: The default implementation of sumMethod will be executed since there is no implementation of sumMethod for the string type.

from functools import singledispatchmethod
class Sum:
@singledispatchmethod
def sumMethod(self, arg1, arg2):
print("Default implementation with arg1 = %s and arg2 = %s" % (arg1, arg2))
@sumMethod.register(int)
def _(self, arg1, arg2):
print("Sum with arg1 as integer. %s + %s = %s" % (arg1, arg2, arg1 + arg2))
@sumMethod.register(float)
def _(self, arg1, arg2):
print("Sum with arg1 as float. %s + %s = %s" % (arg1, arg2, arg1 + arg2))
s = Sum()
s.sumMethod(2, 3)
s.sumMethod(2.1, 3.4)
s.sumMethod("hi", 3.4)

The code above shows how to achieve the same functionality without using annotations. The expected type of arg1 is passed to the register attribute.

Overloading class methods

The @singledispatchmethod decorator supports nesting with other decorators such as @classmethod, @staticmethod, and so on. To allow for dispatcher.register, singledispatchmethod must be the outermost decorator.

Let’s take a look at an example:

from functools import singledispatchmethod
class Educative:
@singledispatchmethod
@classmethod
def newPrint(cls, arg):
print("Default implementation. arg - %s" % (arg, ))
@newPrint.register(int)
@classmethod
def _(cls, arg):
print("Integer implementation. arg - %s" % (arg, ))
@newPrint.register(bool)
@classmethod
def _(cls, arg):
print("Boolean implementation. arg - %s" % (arg, ))
Educative.newPrint(4)
Educative.newPrint(True)
Educative.newPrint("hi")

Explanation

In the code above, we define a class called Educative. Here, the newPrint class method is overloaded using the @singledispatchmethod. We then decorate the newPrint method with the @singledispatchmethod decorator as the outermost decorator.

RELATED TAGS

python
Did you find this helpful?