[Python-Dev] PEP 443 - Single-dispatch generic functions

Ethan Furman ethan at stoneleaf.us
Thu May 23 19:44:13 CEST 2013


> User API
> ========
>
> To define a generic function, decorate it with the ``@singledispatch``
> decorator. Note that the dispatch happens on the type of the first
> argument, create your function accordingly:
>
> .. code-block:: pycon
>
>    >>> from functools import singledispatch
>    >>> @singledispatch
>    ... def fun(arg, verbose=False):
>    ...     if verbose:
>    ...         print("Let me just say,", end=" ")
>    ...     print(arg)
>
> To add overloaded implementations to the function, use the
> ``register()`` attribute of the generic function. It takes a type
> parameter:
>
> .. code-block:: pycon
>
>    >>> @fun.register(int)
>    ... def _(arg, verbose=False):
>    ...     if verbose:
>    ...         print("Strength in numbers, eh?", end=" ")
>    ...     print(arg)
>    ...
>    >>> @fun.register(list)
>    ... def _(arg, verbose=False):
>    ...     if verbose:
>    ...         print("Enumerate this:")
>    ...     for i, elem in enumerate(arg):
>    ...         print(i, elem)
>
> To enable registering lambdas and pre-existing functions, the
> ``register()`` attribute can be used in a functional form:
>
> .. code-block:: pycon
>
>    >>> def nothing(arg, verbose=False):
>    ...     print("Nothing.")
>    ...
>    >>> fun.register(type(None), nothing)
>

So to have a generic `mapping` function that worked on dicts, namedtuples, user-defined record types, etc., would look 
something like:

--> from functools import singledispatch

--> @singledispatch
--> def mapping(d):
...     new_d = {}
...     new_d.update(d)
...     return new_d
...

--> @mapping.register(tuple)
... def _(t):
...     names = getattr(t, '_fields', ['f%d' % n for n in range(len(t))])
...     values = list(t)
...     return dict(zip(names, values))
...

--> @mapping.register(user_class):
... def _(uc):
...     blah blah
...     return dict(more blah)
...

Very cool.  I'm looking forward to it!

Oh, the tuple example above is intended primarily for named tuples, but since there is no common base class besides 
tuple I had to also handle the case where a plain tuple is passed in, and personally I'd rather have generic field names 
than raise an exception.

--
~Ethan~


More information about the Python-Dev mailing list