This is the decorator for the generic function and it accepts
    only one argument *keyer*, it'll be called with the same arguments
    of the function call and it must return an hashable object
    (int, tuple, etc.).

    Rhe generic function has a *register* method used to decorate the
    function for some specific keys.
    *register* accepts one or more keys and returns the decorated
    function.

def dispatk(keyer):
    """This is the decorator for the generic function and it accepts
    only one argument *keyer*, it'll be called with the same arguments
    of the function call and it must return an hashable object
    (int, tuple, etc.).

    Rhe generic function has a *register* method used to decorate the
    function for some specific keys.
    *register* accepts one or more keys and returns the decorated
    function.
    """
    calls = {}

    def _dispatk(main):
        def register(*keys):
            def _register(spec):
                for key in keys:
                    if key in calls:
                        raise ValueError(
                            "function already registered for %r"
                            % (main.__name__, key))

                    calls[key] = spec

                return spec

            return _register

        @wraps(main)
        def run(*args, **kwargs):
            return calls.get(keyer(*args, **kwargs), main)(*args, **kwargs)

        run.register = register

        return run

    return _dispatk