An easier syntax for writing decorators (& similar things)?

When writing decorators especially when it's one that needs arguments other than the function to be wrapped, it often gets rather ugly... def dec(a, b, foo=bar): def inner(func): def something(*a, **k): ...stuff... return func(*a, **k) return something return inner Perhaps we could allow functions to be defined with multiple argument lists, basically partially applying the function until all of them are filled. (Sort of like currying, but sort of not.) def dec(a, b, foo=bar)(func)(*a, **k): ...stuff... return func(*a, **k) So, calling `dec` will fill the first argument list and return a callable, which when called will fill the second argument list and return a third callable, which will be the fully-decorated function. Basically, exactly as it looks -- def func(a)(b)(c) is called as func (1)(2)(3). Except, obviously, you can partially apply it by only calling the first one or two or however many. I'm not sure how this would look internally, but I imagine each successive call would return an object something like a partial. I expect that the main argument against this will be that it is not a common enough idiom to warrant adding syntax. Perhaps; I don't know. The decorator pattern is very useful (and not only in the @blah function decorator sense -- also the future class decorators, WSGI middleware, etc.), and I do think it makes their definitions quite a bit nicer and easier to read. Any thoughts?

On 10/7/07, Adam Atlas <adam@atlas.st> wrote:
My argument against it is it's ugly and hard to notice. It is not obvious unless you really look carefully at the signature to notice that there are three sets of parentheses there. -Brett

Brett Cannon wrote:
I think it's rather elegant in its own way. There's something exactly analogous in Scheme, where you can write (define (f (g x)) ... ) and it gets macro-expanded into the corresponding nested sequence of lambdas. (The really elegant part about it in Scheme is that it's not a separate feature -- it just automatically falls out of the way define is defined in terms of lambda.)
I imagine each successive call would return an object something like a partial.
I would implement it by compiling it exactly as though it were written out as nested defs. -- Greg

On 7 Oct 2007, at 23:49, Brett Cannon wrote:
My argument against it is it's ugly
Do you really think so? I think it looks rather elegant, at least in comparison to the indentation-pyramids we have now.
Spaces would be allowed, of course. Do you think this looks better (less ugly and/or more obvious)? def dec(a, b, foo=bar) (func) (*a, **k): Or maybe they could be separated by commas? I can't decide whether I like that or not... leaning towards not.

On Mon, October 8, 2007 4:33 am, Adam Atlas wrote:
Whhy not create a (meta-)decorator to do this? Something like: def decorator_withargs(decf): def decorator(*args, **kwargs): def decorated(f): return decf(f, *args, **kwargs) return decorated return decorator Then you can write your decorator as: @decorator_withargs def deco(f, a, b, foo='bar'): ...stuff... return f(...) I can't try this now (no python) but it seems to me it should work, even though it makes my head hurt a bit :) OTOH it might be utterly rubbish. -- Arnaud

On 8 Oct 2007, at 10:57, Arnaud Delobelle wrote:
[...]
Whhy not create a (meta-)decorator to do this? Something like: [...]
To follow up on my untested suggestion, here's one that is tested: # This metadecorator hasn't changed def decorator_withargs(decf): def decorator(*args, **kwargs): def decorated(f): return decf(f, *args, **kwargs) return decorated return decorator # Here's how to use it to create a decorator @decorator_withargs def mydec(f, before='entering %s', after='%s returns %%s'): before = before % f.__name__ after = after % f.__name__ def decorated(*args, **kwargs): print before result = f(*args, **kwargs) print after % result return result return decorated # Now I can decorate a function with my new decorator @mydec(before='-> %s', after='%s -> %%s') def f(x): print x return x+1 Then
-- Arnaud

On 10/7/07, Adam Atlas <adam@atlas.st> wrote:
My argument against it is it's ugly and hard to notice. It is not obvious unless you really look carefully at the signature to notice that there are three sets of parentheses there. -Brett

Brett Cannon wrote:
I think it's rather elegant in its own way. There's something exactly analogous in Scheme, where you can write (define (f (g x)) ... ) and it gets macro-expanded into the corresponding nested sequence of lambdas. (The really elegant part about it in Scheme is that it's not a separate feature -- it just automatically falls out of the way define is defined in terms of lambda.)
I imagine each successive call would return an object something like a partial.
I would implement it by compiling it exactly as though it were written out as nested defs. -- Greg

On 7 Oct 2007, at 23:49, Brett Cannon wrote:
My argument against it is it's ugly
Do you really think so? I think it looks rather elegant, at least in comparison to the indentation-pyramids we have now.
Spaces would be allowed, of course. Do you think this looks better (less ugly and/or more obvious)? def dec(a, b, foo=bar) (func) (*a, **k): Or maybe they could be separated by commas? I can't decide whether I like that or not... leaning towards not.

On Mon, October 8, 2007 4:33 am, Adam Atlas wrote:
Whhy not create a (meta-)decorator to do this? Something like: def decorator_withargs(decf): def decorator(*args, **kwargs): def decorated(f): return decf(f, *args, **kwargs) return decorated return decorator Then you can write your decorator as: @decorator_withargs def deco(f, a, b, foo='bar'): ...stuff... return f(...) I can't try this now (no python) but it seems to me it should work, even though it makes my head hurt a bit :) OTOH it might be utterly rubbish. -- Arnaud

On 8 Oct 2007, at 10:57, Arnaud Delobelle wrote:
[...]
Whhy not create a (meta-)decorator to do this? Something like: [...]
To follow up on my untested suggestion, here's one that is tested: # This metadecorator hasn't changed def decorator_withargs(decf): def decorator(*args, **kwargs): def decorated(f): return decf(f, *args, **kwargs) return decorated return decorator # Here's how to use it to create a decorator @decorator_withargs def mydec(f, before='entering %s', after='%s returns %%s'): before = before % f.__name__ after = after % f.__name__ def decorated(*args, **kwargs): print before result = f(*args, **kwargs) print after % result return result return decorated # Now I can decorate a function with my new decorator @mydec(before='-> %s', after='%s -> %%s') def f(x): print x return x+1 Then
-- Arnaud
participants (4)
-
Adam Atlas
-
Arnaud Delobelle
-
Brett Cannon
-
Greg Ewing