Python’s Single Dispatch Method

org/pep-0443/

PEP 443 Single-dispatch generic functions | peps.python.org

Single Dispatch Generic Functions, or SDGF for short (because who has time to type out the whole thing?), are a new mechanism in Python’s standard library that allows you to write highly customized and specialized code without having to resort to ugly hacks like type inspection or monkeypatching.

Let me explain with an example: let’s say you have a function called `print_stuff` that takes any object as input, but depending on the type of the object, it should print different things. For instance, if the input is a string, it should just print the string; if the input is a list, it should iterate over each element and print them one by one; if the input is an integer, it should print “The number is X”, where X is the actual value of the integer.

Before SDGFs, you would have to write something like this:

# This function takes in an object as input and prints it based on its type
def print_stuff(obj):
    # Check if the input is a string
    if isinstance(obj, str):
        # If it is a string, simply print it
        print(obj)
    # Check if the input is a list
    elif isinstance(obj, list):
        # If it is a list, iterate over each element and print them one by one
        for item in obj:
            # Call the function recursively to handle nested lists
            print_stuff(item)
    # If the input is not a string or a list, it must be an integer
    else:
        # Print "The number is X", where X is the actual value of the integer
        print("The number is {}".format(obj))

But with SDGFs, you can write something much simpler and cleaner:

# Import the singledispatch function from the functools module
from functools import singledispatch

# Define a function named print_stuff and decorate it with the singledispatch decorator
@singledispatch
def print_stuff(obj):
    # Check if the input object is a string
    if isinstance(obj, str):
        # If it is a string, print it
        print(obj)
    # Check if the input object is a list
    elif isinstance(obj, list):
        # If it is a list, iterate through each item and call the print_stuff function recursively
        for item in obj:
            print_stuff(item) # recursive call!
    # If the input object is not a string or a list, raise a TypeError
    else:
        raise TypeError("Unsupported type")

# Register custom behavior for specific types
# Register a function to be called when the input object is an integer
print_stuff.register(int, lambda x: f"The number is {x}")

In this example, we’re using a lambda function to register a custom behavior for integers. This allows us to avoid writing an entire new function just for handling integer inputs. The `singledispatch` decorator automatically calls the registered function if it matches the input type. If no matching function is found, it raises a TypeError with an informative message.

This approach can significantly reduce code duplication and make your code more readable and maintainable. It also allows you to easily add new behavior for specific types without having to modify existing functions or monkeypatching the standard library.

SICORPS