The functools module contains several higher-order functions and decorators. One of these is the singledispatch() decorator.

The singledispatch() function is used to provide a simple interface for generic functions that dispatch to functions implementations based on the type of a single argument. 

The function is capable of choosing the right implementation of a function to use, depending on the types of its arguments.

How it works

When a function is decorated with the singledispatch() function,  it can use the register() decorator method to add different implementations of the function for different types of arguments.

from functools import singledispatch

@singledispatch 
def add(a, b): 
     return a + b 

@add.register(int) 
def _(a, b): 
    return a + b 

@add.register(str) 
def _(a, b): 
     return f"{a},{b}"

print(add(20, 30))
print(add('Hello', 'World'))

If the type used has no implementation registered, the original implementation will be called normally.

Multiple type for same implementation

We can attach multiple types to same implementation by decorating the particular implementation with multiple types.

from functools import singledispatch

@singledispatch 
def add(a, b): 
     return a + b 

@add.register(int) 
@add.register(float)
def _(a, b): 
    return f"{a} + {b} = {a + b}" 

@add.register(str) 
def _(a, b): 
     return f"{a},{b}"

print(add(20, 30))
print(add(2.0, 3.5))
print(add('Hello', 'World'))

Get all the registered implementations

We can use the registry attribute to access the available implementations. The method returns a dictionary mapping the type to the reference of the function implementation for that particular type.

from functools import singledispatch

@singledispatch 
def add(a, b): 
     return a + b 

@add.register(int) 
@add.register(int)
def _(a, b): 
    return f"{a} + {b} = {a + b}" 

@add.register(str) 
def _(a, b): 
     return f"{a},{b}"

print(add.registry)