Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How decorator works? [duplicate]

I'm trying to figure out how decorator works in python. But, there are two things that I can't make clear, so I appreciate it if anyone helps me understand how decorator works in python!

This is the sample code I've just written to see how it works.

In [22]: def deco(f):
   ....:     def wrapper():
   ....:         print("start")
   ....:         f()
   ....:         print("end")
   ....:     return wrapper

In [23]: @deco
   ....: def test():
   ....:     print("hello world")
   ....:     

OUTPUT 1

In [24]: test()
start
hello world
end

The first thing I don't understand is why it outputs "start","hello world","end" when I call test(). I learned that when I call test(), it calls "deco(test)" internally. If so, it should return a "wrapper" function object instead of outputting strings. But, it outputs strings as the result. I'm wondering how it's doing the job internally.

OUTPUT 2

In [28]: i = deco(test)

In [29]: i
Out[29]: <function __main__.wrapper>

In [30]: i()
start
start
hello world
end
end

I called "deco(test)" just to see what it outputs as the result. As it's shown above, it returns "wrapper" function object and after I assign it to a variable and call "wrapper" function, it outputs two "start"s and one "hello world" and two "end"s. What is going on internally? Why "start" and "end" are outputted twice respectively?

Could anyone please help me understand how this is working?

like image 543
crzyonez777 Avatar asked Mar 11 '14 05:03

crzyonez777


People also ask

Can a function have 2 decorators?

So, here in this post, we are going to learn about Decorator Chaining. Chaining decorators means applying more than one decorator inside a function. Python allows us to implement more than one decorator to a function.

How does the decorator pattern work?

Decorator patterns allow a user to add new functionality to an existing object without altering its structure. So, there is no change to the original class. The decorator design pattern is a structural pattern, which provides a wrapper to the existing class.

What is a disadvantage of the decorator pattern?

However, development using the decorator pattern does have some disadvantages. Using the pattern increases the complexity of the software.

What are two capabilities of the decorator pattern?

Here are some of the properties of decorators: Decorators have the same super type as the object they decorate. You can use multiple decorators to wrap an object. Since decorators have same type as object, we can pass around decorated object instead of original.


1 Answers

I learned that when I call test(), it calls "deco(test)" internally. If so, it should return a "wrapper" function object instead of outputting strings. But, it outputs strings as the result. I'm wondering how it's doing the job internally.

Not quite, applying a decorator is syntatic sugar (meaning a nice way of doing something that is otherwise possible). The equivalent operation is

def test():
    print("Hello, world!")
test = deco(test) # note that test is overwritten by the wrapper that deco returns

To illustrate this, consider the following example

>>> def deco(f):
...     print 'applying deco' # this will print when deco is applied to test
...     def wrapper():
...             print("start")
...             f()
...             print("end")
...     return wrapper
...
>>> @deco
... def test():
...     print("Hello world!")
...
applying deco

Notice that the decorator is applied as soon as the function is defined. This matches up with the above "equivalent operation".

In the second case, you are seeing the double print statements as you are manually applying deco to an already decorated test function.

like image 189
Peter Gibson Avatar answered Oct 04 '22 19:10

Peter Gibson