On Mon, Apr 27, 2015 at 12:37 PM, Makoto Kuwata <k...@kuwata-lab.com> wrote: > If function decorator notation could take arguments, > decorator definition would be more simple: > > def multiply(func, n): > def newfunc(*args, **kwargs): > return n * func(*args, **kwargs) > return newfunc > > @multiply 4 # ex: @decorator arg1, arg2, arg3 > def f1(x, y): > return x+y >
I agree it would be nice to have extra parameters directly handled, but before you go further with the proposal, I suggest having a read of the original PEP that introduced decorators: https://www.python.org/dev/peps/pep-0318/ There are a *lot* of different ways that decorators could have been done. Currently, decorators use a restricted subset of expression syntax; the bit after the @ is guaranteed [1] to be a valid expression which results in a callable which is passed one argument (the function) and whose return value replaces the function. What you propose would no longer be a valid expression, and may introduce parsing problems for the interpreter and/or for humans. But if the writing of decorators is hard and common for you, you can always use a bit of metaprogramming to simplify it. (Since decorators are already metaprogramming, this would be metametaprogramming, I guess.) Something like: import functools def decorator(deco): """Make a function into an argument-accepting decorator""" @functools.wraps(deco) def outer(*a, **kw): def inner(func): return deco(func, *a, **kw) return inner return outer @decorator def multiply(func, n): @functools.wraps(func) def newfunc(*a, **kw): return n * func(*a, **kw) return newfunc @multiply(4) def f1(x, y): return x+y print(f1(2, 3)) #=> 20 (= 4 * (2+3)) (Note that I'm using functools.wraps here so docstrings and stuff get carried over) And if you're writing a lot of functions that call the original and then do something with the result, you could push that part into the decorator too: import functools def modifier(deco): """Make a function into an argument-accepting decorator""" @functools.wraps(deco) def outer(*a1, **kw1): def middle(func): def inner(*a2, **kw2): return deco(func(*a2, **kw2), *a1, **kw1) return inner return middle return outer @modifier def multiply(result, n): return n * result @multiply(4) def f1(x, y): return x+y print(f1(2, 3)) #=> 20 (= 4 * (2+3)) Python lets you be as insane as you like :) There are a lot of places in Python code (actually, in code generally) where usage is clean and implementation is horrific, and this can be one of them. The modifier() function's implemenation is deeply nested, but it's beautifully easy to use. A namedtuple is really convenient to use (just subscript it or use attribute lookup!), creating a new namedtuple type is reasonably alright, but the implementation of namedtuple() itself is scary. Nested and complicated, I got no problem with, long as she does it quiet-like! Can you do everything you need with a metadecorator? Either way, it's worth working on as part of a plan for parameterized decorators. Either you can say "here's this new syntax, and it's equivalent to this massive block of code" (look at the definition of "yield from" in PEP 380 - sure, you *can* manage without it, but getting the edge cases right is messy), or you can say "here's this new syntax, and it allows us to do this, this, and this, which otherwise wouldn't be possible". Given how common parameterized decorators are, it's likely there'll be some support for at least the broad concept of the proposal. ChrisA [1] At least, I'm pretty sure it is; I may be wrong. -- https://mail.python.org/mailman/listinfo/python-list