def keyed_helper(helper):
    @wraps(helper)
    def wrapper(instance=None, key=None, attr=None, *args, **kwargs):
        if set((instance, key, attr)) == {None}:
            raise ValueError("If called directly, helper function '%s' requires either a model"
                             " instance, or a 'key' or 'attr' keyword argument." % helper.__name__)
        if instance is not None:
            return helper(instance, *args, **kwargs)
        if key is None and attr is None:
            attr = 'self'
        if attr:
            if attr == 'self':
                key = lambda obj: obj
            else:
                key = operator.attrgetter(attr)
        @wraps(helper)
        def helper_wrapper(instance, *args, **kwargs):
            return helper(key(instance), *args, **kwargs)
        return helper_wrapper
    wrapper._is_wrapped = True
    return wrapper