@functools.singledispatch in Python

In Python, functools.singledispatch acts as a decorator within the functools module, transforming a function into a generic function. This allows the function to have multiple implementations for the same operation across different types, with the selection of the implementation determined during a call through the dispatch algorithm.\

Single dispatch:

The single dispatch, is a form of generic function dispatch, selects the implementation based on the type of a single argument. Essentially, this decorator introduces function overloading in Python.

To achieve function overloading, you can utilize the register() attribute of the generic function. This attribute, also functioning as a decorator, takes a single parameter specifying the type of data the function will handle.

Syntax

The signature for the singledispatch decorator is as shown below.

@singledispatch

Python @singledispatch Examples:

Example 1:

In this scenario, we are accepting parameters such as a string, an int, and a list. Depending on the type of the parameter, the function will either concatenate or add the values accordingly.

from functools import singledispatch

#Using decorator  
@singledispatch
def adding(s):
    print("Welcome ",s)

#Using register method to overload function  
@adding.register(int)
def _1(s):
    print("Computing ",s," + ",s," = ", s+s)
  
@adding.register(list)
def _2(s):
    sum=0
    for i in range(0,len(s)+1):
        sum=sum+i
    print("Sum of all values in the list is ",sum)
  
adding('Python Programming')
adding(50)
adding([1,2,3,4,5])

Output

Welcome  Python Programming
Computing  50  +  50  =  100
Sum of all values in the list is  15

Example 2:

In this situation, we are calculating the multiplication of various primitive data types. However, attempting to access the product function with a string argument will result in a “Not Implemented” response.

from functools import singledispatch
# Function computing multiplication   
@singledispatch
def product(num1,num2):
    if(type(num1)==type("") or type(num2)==type("")):
        return NotImplemented
    else:
        return num1*num2

#Computing the product of numbers in the list 
print("Multiplying 5 * 5 =",product(5,5))
print("Multiplying 5.5 * 5 =",product(5.5,5))
print("Multiplying 1.25 * 2.5 =",product(1.25,2.5))
print("Multiplying 5 * A =",product(5,'A'))

Output

Multiplying 5 * 5 = 25
Multiplying 5.5 * 5 = 27.5
Multiplying 1.25 * 2.5 = 3.125
Multiplying 5 * A = NotImplemented

Example 3:

In this instance, we are negating the values of different types such as int and boolean. However, if the argument is of string or char type, the function will return “Not Implemented.”

from functools import singledispatch
# Function returning negative value of parameter
@singledispatch
def neg(a):
    return NotImplemented

@neg.register(int)
def _1(a):
    return -a

@neg.register(bool)
def _2(a):
    return not a

print("Negative value of 5 is ",neg(5))
print("Negative value of True is ",neg(True))
print("Negative value of A is ",neg('A'))

Output

Negative value of 5 is  -5
Negative value of True is  False
Negative value of A is  NotImplemented

Conclusion:

Therefore, the combination of this decorator and the register() method provides a powerful means to implement function overloading in Python.

References:

Happy Learning 🙂