How can I dispatch Python 2 functions based on the data type passed to the function?

2.4k Views Asked by At

I would like to dispatch Python functions dependent (e.g. using a dict approach) on the data type of the argument passed to the "dispatching" function (e.g. using isinstance()). Are there implementation alternatives? What's the easiest approach?

2

There are 2 best solutions below

0
On BEST ANSWER

As of Python 3.4, the Python standard library includes support for @singledispatch() generic functions.

This lets you register multiple functions to handle different types, and it'll handle dispatch based on type, including subclass testing and caching. The method is described in PEP 443 - Single-dispatch generic functions.

There is a backport available on PyPI that supports Python 2.6 and up, written by the PEP author.

Note that Python 2.7 will soon be hitting a final end-of-life date, where it'll no longer receive bug fixes and security updates; you really need to plan for upgrading to Python 3 sooner rather than later. When you do, you'll note that the Python 3.7 version supports using type hinting to document what type each function accepts.

For example, a series of functions to remove None and False values from a nested dictionary-and-list data structure (a typical JSON data structure), can be defined as:

from functools import singledispatch

@singledispatch
def remove_null_false(ob):
    return ob

@remove_null_false.register
def _process_list(ob: list):
    return [remove_null_false(v) for v in ob]

@remove_null_false.register
def _process_list(ob: dict):
    return {k: remove_null_false(v) for k, v in ob.items()
            if v is not None and v is not True and v is not False}

In Python versions < 3.7 you'd have to move the type to the @remove_null_false.register(...) decorator factory notation.

2
On

Please have a look at the below example.

def get_int_square(a):
    """
    Returns square of integer parameter
    """
    return a ** 2

def get_float_cube(a):
    """
    Returns cube of float parameter
    """
    return a ** 3

def sum_of_items(l):
    """
    Returns sum of all the items in list
    """
    return sum(l)

def get_squared_items(t):
    return tuple(item ** 2 for item in t)

def dispatching(a):
    """
    Calls the corresponding functions based on match found in the dictionary
    """
    functions = {
        'int': get_int_square,
        'float': get_float_cube,
        'list': sum_of_items,
        'tuple': get_squared_items
    }

    data_type = str(type(a)).split("'")[1]
    result = functions[data_type](a)
    return result

if __name__ == "__main__":
    print(dispatching(12))  # 144
    print(dispatching(1.2)) # 1.7279999999999998
    print(dispatching((4, 7, 9, 3, 1, 5, 8))) # (16, 49, 81, 9, 1, 25, 64)
    print(dispatching([56, 4, 50, 26, 24]))   # 160