Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

decorating decorators: try to get my head around understanding it

Tags:

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():     ... 
like image 506
ashwoods Avatar asked May 10 '11 15:05

ashwoods


People also ask

What is the point of a decorator?

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.

Can a decorator access self?

If you want to access self (instanse where decorator is called from) you can use args[0] inside the decorator.

What is the function of decorating?

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.

What are the Python decorators?

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.


2 Answers

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 
like image 160
kennytm Avatar answered Nov 30 '22 23:11

kennytm


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()) 
like image 27
Boaz Yaniv Avatar answered Nov 30 '22 22:11

Boaz Yaniv