On Tuesday 28 June 2016 15:02, Ben Finney wrote: > Howdy all, > > I want an explicit replacement for a common decorator idiom. > > There is a clever one-line decorator that has been copy-pasted without > explanation in many code bases for many years:: > > decorator_with_args = lambda decorator: lambda *args, **kwargs: lambda > func: decorator(func, *args, **kwargs)
I've never seen it before, and I'll admit I really had to twist my brain to understand it, but I came up with an example showing the traditional style of decorator-factory versus this meta-decorator. # Standard idiom. def chatty(name, age, verbose=True): # the factory def decorator(func): # the decorator returned by the factory if verbose: print("decorating function...") @functools.wraps(func) def inner(*args, **kwargs): print("Hi, my name is %s and I am %d years old!" % (name, age)) return func(*args, **kwargs) return inner return decorator @chatty("Bob", 99) def calculate(x, y, z=1): return x+y-z # Meta-decorator variant. decorator_with_args = (lambda decorator: lambda *args, **kwargs: lambda func: decorator(func, *args, **kwargs)) @decorator_with_args def chatty(func, name, age, verbose=True): if verbose: print("decorating function...") @functools.wraps(func) def inner(*args, **kwargs): print("Hi, my name is %s and I am %d years old!" % (name, age)) return func(*args, **kwargs) return inner @chatty("Bob", 99) def calculate(x, y, z=1): return x+y-1 I agree -- it's very clever, and completely opaque in how it works. The easy part is expanding the lambdas: def decorator_with_args(decorator): def inner(*args, **kwargs): def innermost(func): return decorator(func, *args, **kwargs) return innermost return inner but I'm not closer to having good names for inner and innermost than you. -- Steve -- https://mail.python.org/mailman/listinfo/python-list