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(): ...
You'll use a decorator when you need to change the behavior of a function without modifying the function itself. A few good examples are when you want to add logging, test performance, perform caching, verify permissions, and so on. You can also use one when you need to run the same code on multiple functions.
If you want to access self (instanse where decorator is called from) you can use args[0] inside the decorator.
The purpose of decoration is to make the space more aesthetically pleasing and functionally useful for the occupants, but this may include consideration of wider contextual issues such as fashion, culture, and so on.
A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.
def upper(f): @wrap def uppercase(*args, **kargs): a,b = f(*args, **kargs) return a.upper(), b.upper() return uppercase
A decorator in Python
@foo def bar(...): ...
is just equivalent to
def bar(...): ... bar = foo(bar)
You want to get the effect of
@wrap @upper def hello(): ....
i.e.
hello = wrap(upper(hello))
so the wrap
should be called on the return value of upper
:
def upper_with_wrap(f): def uppercase(...): ... return wrap(uppercase)
which is also equivalent to applying the decorator on that function:
def upper_with_wrap(f): @wrap def uppercase(...): ... # ^ equivalent to 'uppercase = wrap(uppercase)' return uppercase
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())
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With