Украшающие декораторы: постарайтесь понять мою мысль
Я пытаюсь понять декорирование декораторов и хотел попробовать следующее:
Скажем, у меня есть два декоратора и примените их к функции 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()
Затем я должен начать добавлять другие декораторы для других функций,
но в целом декоратор обертывания "обернет их все"
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"
Теперь, как мне написать декоратор, с ведьмой я могу украсить мои нижние и верхние декораторы:
@wrap
def lower():
...
@wrap
def upper():
...
Чтобы достичь того же результата, что и выше, только:
@upper
def hello():
...
@lower
def byebye():
...
Ответы
Ответ 1
Вот общее (и слегка запутанное) решение для украшения декораторов декораторами (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()
Ответ 2
def upper(f):
@wrap
def uppercase(*args, **kargs):
a,b = f(*args, **kargs)
return a.upper(), b.upper()
return uppercase
Декоратор в Python
@foo
def bar(...): ...
просто эквивалентно
def bar(...): ...
bar = foo(bar)
Вы хотите получить эффект
@wrap
@upper
def hello(): ....
то есть.
hello = wrap(upper(hello))
поэтому wrap
следует вызвать на возвращаемое значение upper
:
def upper_with_wrap(f):
def uppercase(...): ...
return wrap(uppercase)
что также эквивалентно применению декоратора на этой функции:
def upper_with_wrap(f):
@wrap
def uppercase(...): ...
# ^ equivalent to 'uppercase = wrap(uppercase)'
return uppercase