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?
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.
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.
However, development using the decorator pattern does have some disadvantages. Using the pattern increases the complexity of the software.
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.
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.
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