Decorators, with optional arguments

Nathan Rice nathan.alexander.rice at gmail.com
Fri Jul 2 14:58:46 EDT 2010


I like to think of decorators with arguments as decorator factory functions.
 I try and unroll them as much as possible... I have some decorators that
work like so (and please note that the wraps and returns_as_output are
separate so that I can mutate the behavior as needed, if you just wanted a
single decorator this could be condensed):

def wrap(f, wrapping_function, *args):
    argspec = inspect.getargspec(f)
    without_defaults = len(argspec.args) - len(argspec.defaults or [])
    f._args = {}
    f._varkw = []
    f._arg_defaults = (None,) * without_defaults + (argspec.defaults or
tuple())
    for arg in args:
        if arg in argspec.args:
            f._args[arg] = argspec.args.index(arg)
        else:
            if argspec.keywords:
                f._varkw.append(arg)
    return decorator.decorator(wrapping_function, f)


def return_as_output(output_f):
    def func(f, *args, **kwargs):
        new_args = list(args)
        for (dict_name, index) in f._args.items():
            if len(args) > index:
                new_args[index] = output_f(args[index])
            else:
                d = f._arg_defaults[index]
                kwargs[dict_name] = output_f(kwargs.pop(dict_name, d))
        for dict_name in f._varkw:
            kwargs[dict_name] = output_f(kwargs.pop(dict_name, None))
        return f(*new_args, **kwargs)
    return func

def iterables(*args):
    '''
    Decorator that guarantees that the named arguments will be iterable.
    '''
    as_iterables = return_as_output(iter_)
    return lambda f: wrap(f, as_iterables, *args)

Just as an example... I have a family of decorators that check compliance
with abstract base classes, then try to mutate variables to provide it if
duck typing would fail.  I don't know if this helps, it is kind of
convoluted, but hopefully it gives you another example to work from.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20100702/03ee77d4/attachment-0001.html>


More information about the Python-list mailing list