What is the singledispatchmethod() decorator in Python?
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 singledispatchmethodclass Sum:@singledispatchmethoddef sumMethod(self, arg1, arg2):print("Default implementation with arg1 = %s and arg2 = %s" % (arg1, arg2))@sumMethod.registerdef _(self, arg1: int, arg2: int):print("Sum with arg1 as integer. %s + %s = %s" % (arg1, arg2, arg1 + arg2))@sumMethod.registerdef _(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
singledispatchmethoddecorator is imported from thefunctoolsmodule. -
Line 3: The
Sumclass is defined. -
Lines 6-7: A function named
sumMethodis defined in theSumclass. It accepts two arguments,arg1andarg2. ThesumMethodfunction is decorated with thesingledispatchmethoddecorator. This is the default implementation of thesumMethodfunction. -
Lines 10-11: We register the first implementation of the
sumMethodfunction for whicharg1should be of the integer type. Here,arg1is annotated withintas its type. -
Lines 14-15: We register the second implementation of the
sumMethodfunction for whicharg1should be of thefloattype. Here,arg1is annotated withfloatas its type. -
Lines 18-21: We invoke
sumMethodwith different types of values forarg1. -
Line 21: The default implementation of
sumMethodwill be executed since there is no implementation ofsumMethodfor thestringtype.
from functools import singledispatchmethodclass Sum:@singledispatchmethoddef 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 singledispatchmethodclass Educative:@singledispatchmethod@classmethoddef newPrint(cls, arg):print("Default implementation. arg - %s" % (arg, ))@newPrint.register(int)@classmethoddef _(cls, arg):print("Integer implementation. arg - %s" % (arg, ))@newPrint.register(bool)@classmethoddef _(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.