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())