Creates a "key function" based on given keys.

    Resulting function will perform lookup using specified keys, in order,
    on the object passed to it as an argument.
    For example, ``key_func('a', 'b')(foo)`` is equivalent to ``foo['a']['b']``.

    :param keys: Lookup keys
    :param default: Optional keyword argument specifying default value
                    that will be returned when some lookup key is not present

    :return: Unary key function

def key_func(*keys, **kwargs):
    """Creates a "key function" based on given keys.

    Resulting function will perform lookup using specified keys, in order,
    on the object passed to it as an argument.
    For example, ``key_func('a', 'b')(foo)`` is equivalent to ``foo['a']['b']``.

    :param keys: Lookup keys
    :param default: Optional keyword argument specifying default value
                    that will be returned when some lookup key is not present

    :return: Unary key function
    """
    ensure_argcount(keys, min_=1)
    ensure_keyword_args(kwargs, optional=('default',))

    keys = list(map(ensure_string, keys))

    if 'default' in kwargs:
        default = kwargs['default']
        def getitems(obj):
            for key in keys:
                try:
                    obj = obj[key]
                except KeyError:
                    return default
            return obj
    else:
        if len(keys) == 1:
            getitems = operator.itemgetter(keys[0])
        else:
            def getitems(obj):
                for key in keys:
                    obj = obj[key]
                return obj

    return getitems