Greg Ewing wrote:
Jason R. Coombs wrote:
I had a use case that was compelling enough that I thought there should be something in functools to do what I wanted.
I think this is one of those things that a small minority of people would use frequently, but everyone else would use very rarely or never. The decision on whether to include something in the stdlib needs to be based on the wider picture.
In this case, it's trivial to write your own if you want it. As they say, "not every one-line function needs to be in the stdlib".
I have never found these arguments compelling. They are obviously not true (e.g., itertools.compress() added in 2.7/3.1), and so what I really hear is: "I don't like it and I outrank you."
I can't help invoke part of PEP309's justification for functools.partial():
""" I agree that lambda is usually good enough, just not always. And I want the possibility of useful introspection and subclassing. """
The same reasoning would seem to apply here. In the OP's example, the meta-decorator becomes opaque due to the use of a lambda. If one could introspect a compose(), then introspection tools could actually know the set of decorators being applied. As it is, the "preferred" method of using a lambda actually makes it quite hard to know anything.
class compose(): def __init__(self, *funcs): if not funcs: raise ValueError(funcs) self.funcs = funcs
def __call__(self, *args, **kwargs): v = self.funcs[-1](*args, **kwargs) for func in reversed(self.funcs[:-1]): v = func(v) return v
meta = functools.compose(decorator_a, decorator_b) print meta.funcs
meta = lambda f: decorator_a(decorator_b(f)) # impossible, short of disassembling the lambda
""" def compress(data, selectors): # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F return (d for d, s in zip(data, selectors) if s) """