functools
moduleThe 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.
singledispatchmethod
decoratorThe 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.
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)
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 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.
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")
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.