10

I have several decorators on each function, is there a way to pack them in to one instead?

@fun1
@fun2
@fun3
def do_stuf():
    pass

change to:

@all_funs #runs fun1 fun2 and fun3, how should all_funs look like?
def do_stuf():
    pass
BenMorel
  • 34,448
  • 50
  • 182
  • 322
pprzemek
  • 2,455
  • 3
  • 25
  • 25
  • Duplicate: http://stackoverflow.com/questions/2094008/why-cant-python-decorators-be-chained-across-definitions – S.Lott Feb 02 '10 at 11:11
  • @Torsten Marek: Any reasoning or evidence for that claim? – S.Lott Feb 02 '10 at 11:42
  • @S.Lott: This question is specifically about writing a function that encapsulates several decorator calls, the other why a decorator on a decorator does not work. It's maybe possible to deduce the answer to this question from the other one, but not straightforward, especially not for someone who struggles with the concept of decorators. – Torsten Marek Feb 02 '10 at 12:29
  • They both seem to be "chaining" decorators to create composite decorators. – S.Lott Feb 02 '10 at 12:56

3 Answers3

10

A decorator is in principle only syntactic sugar for this:

def do_stuf():
    pass

do_stuf = fun1(do_stuf)

So in your all_fun, all you should need to do is to wrap the function in the same kind of chain of decorators:

def all_funs(funky):
    return fun1(fun2(fun3(fun4(funky)))

Things get a little bit (but only a litte) more complex if you have parameters to the decorators.

Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251
7

It's also possible to write a generic decorator that supports decorator chaining:

def fun1(f):
    print "fun1"
    return f

def fun2(f):
    print "fun2"
    return f

def fun3(f):
    print "fun3"
    return f

def chained(*dec_funs):
    def _inner_chain(f):
        for dec in reversed(dec_funs):
            f = dec(f)
        return f

   return _inner_chain

@fun1
@fun2
@fun3
def do_stuff():
    pass

@chained(fun1, fun2, fun3)
def do_stuff2():
    pass

all_funs = chained(fun1, fun2, fun3)

@all_funs
def do_stuff3():
    pass
Torsten Marek
  • 83,780
  • 21
  • 91
  • 98
1
def all_funs(f):
    return fun1(fun2(fun3(f)))
nkrkv
  • 7,030
  • 4
  • 28
  • 36