def reducer(*, name = None, metric = call_default):
class instrument_reducer_decorator(object):<EOL><INDENT>def __init__(self, func):<EOL><INDENT>self.orig_func = func<EOL>self.wrapping = wraps(func)<EOL>self.metric_name = name if name is not None else func.__module__ + '<STR_LIT:.>' +func.__name__<EOL>self.varargs = inspect.getargspec(func).varargs is not None<EOL>if self.varargs:<EOL><INDENT>self.method = _varargs_to_iterable_method(func)<EOL>self.func = _varargs_to_iterable_func(func)<EOL>self.callme = _iterable_to_varargs_func(self._call)<EOL><DEDENT>else:<EOL><INDENT>self.method = func<EOL>self.func = func<EOL>self.callme = self._call<EOL><DEDENT><DEDENT>def __call__(self, *args, **kwargs):<EOL><INDENT>return self.callme(*args, **kwargs)<EOL><DEDENT>def _call(self, iterable, **kwargs):<EOL><INDENT>it = counted_iterable(iterable)<EOL>t = time.time()<EOL>try:<EOL><INDENT>return self.func(it, **kwargs)<EOL><DEDENT>finally:<EOL><INDENT>metric(self.metric_name, it.count, time.time() - t)<EOL><DEDENT><DEDENT>def __get__(self, instance, class_):<EOL><INDENT>metric_name = name if name is not None else"<STR_LIT:.>".join((class_.__module__, class_.__name__, self.orig_func.__name__))<EOL>def wrapped_method(iterable, **kwargs):<EOL><INDENT>it = counted_iterable(iterable)<EOL>t = time.time()<EOL>try:<EOL><INDENT>return self.method(instance, it, **kwargs)<EOL><DEDENT>finally:<EOL><INDENT>metric(metric_name, it.count, time.time() - t)<EOL><DEDENT><DEDENT>if self.varargs: wrapped_method = _iterable_to_varargs_func(wrapped_method)<EOL>wrapped_method = self.wrapping(wrapped_method)<EOL>return wrapped_method<EOL><DEDENT><DEDENT>return instrument_reducer_decorator<EOL>
Decorator to measure a function that consumes many items.

    The wrapped ``func`` should take either a single ``iterable`` argument or
    ``*args`` (plus keyword arguments).

    :arg function metric: f(name, count, total_time)
    :arg str name: name for the metric