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.

ExampleEdit & Run
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'))
copy
Output:
50 Hello,World [Finished in 0.02064434252679348s]

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.

ExampleEdit & Run
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'))
copy
Output:
20 + 30 = 50 2.0 + 3.5 = 5.5 Hello,World [Finished in 0.02061796374619007s]

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.

ExampleEdit & Run
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)
copy
Output:
{<class 'object'>: <function add at 0x7f4b0af149a0>, <class 'int'>: <function _ at 0x7f4b0af8c4a0>, <class 'str'>: <function _ at 0x7f4b0af8c400>} [Finished in 0.020377867855131626s]