I’m trying to understand how to decorate decorators, and wanted to try out the following:
Let’s say I have two decorators and apply them to the function hello()
:
def wrap(f): def wrapper(): return " ".join(f()) return wrapper def upper(f): def uppercase(*args, **kargs): a,b = f(*args, **kargs) return a.upper(), b.upper() return uppercase @wrap @upper def hello(): return "hello","world" print(hello())
Then I have to start adding other decorators for other functions, but in general the @wrap
decorator will “wrap all of them”
def lower(f): def lowercase(*args, **kargs): a,b = f(*args, **kargs) return a.lower(), b.lower() return lowercase @wrap @lower def byebye(): return "bye", "bye"
How do I write a decorator, which decorates my @lower
and @upper
decorators? See below:
@wrap def lower(): ... @wrap def upper(): ...
To achieve the same result as above by only doing:
@upper def hello(): ... @lower def byebye(): ...
Advertisement
Answer
Here’s a generic (and slightly convoluted) solution for decorating decorators with decorators (Yay!).
# A second-order decorator def decdec(inner_dec): def ddmain(outer_dec): def decwrapper(f): wrapped = inner_dec(outer_dec(f)) def fwrapper(*args, **kwargs): return wrapped(*args, **kwargs) return fwrapper return decwrapper return ddmain def wrap(f): def wrapper(): return " ".join(f()) return wrapper # Decorate upper (a decorator) with wrap (another decorator) @decdec(wrap) def upper(f): def uppercase(*args, **kargs): a,b = f(*args, **kargs) return a.upper(), b.upper() return uppercase @upper def hello(): return "hello","world" print(hello())