On Tue, Jun 28, 2016 at 12:02 AM, Ben Finney <ben+pyt...@benfinney.id.au> 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) > > My problem with this is precisely that it is clever: it explains nothing > about what it does, has many moving parts that are not named, it is > non-obvious and lacks expressiveness. > > Even the widely-cited ActiveState recipe by Peter Hunt from 2005 > <URL:http://code.activestate.com/recipes/465427-simple-decorator-with-arguments/> > gives no clue as to what this is doing internally nor what the names of > its parts should be. > > I would like to see a more Pythonic, more explicit and expressive > replacement with its component parts easily understood.
Try this on for size: ''' import functools def decorator_with_args(decorator): """ Meta-decorator for decorators that take arguments. Usage: @decorator_with_args def some_decorator(func, foo, bar=None) if foo: func.bar = bar return func @some_decorator(True, bar='quux') def some_decorated_function(some_arg) return some_arg assert some_decorated_function.bar == 'quux' Returns a function that takes arguments which are to be passed to the decorator along with the function to be decorated. This allows you to just write your decorator as taking the arguments you want, without having to write a decorator factory that creates and returns a decorator. """ @functools.wraps(decorator) def factory(*args, **kwargs): """Generic decorator factory. Returns a decorator that calls the original decorator with the function to be decorated and all arguments passed to this factory. """ def decorator_wrapper(func): """Thin wrapper around the real decorator.""" return decorator(func, *args, **kwargs) return decorator_wrapper return factory ''' I make no guarantees about this; this is completely untested and is based solely upon how the original translated in my mind. If I misunderstood how the original works, this is worse than useless :). Also, I'm not sure how close I got on the "easily understood" part. It's certainly more explanatory than the original, but it's not the simplest of concepts anyway: a function that takes a function and returns a function that takes arbitrary arguments and returns a function that takes a function and returns the result of calling the originally passed function with arguments consisting of the passed function and the aforementioned arbitrary arguments has too many layers of indirection to keep in mind at once! -- Zach -- https://mail.python.org/mailman/listinfo/python-list