ZhangZhihui's Blog  

We have used functions to decorate functions and to decorate classes. Now, we will see how to define a class as a decorator.

At the start of this chapter, in the definition of decorator, we had seen that a decorator is a callable; a callable is any object that can be called a function. If a class has the __call__ method defined inside it, then instance objects of that class become callable objects. When these instance objects are called like a function using parentheses, the code inside the __call__ method is executed. Now, let us see how we can use such a class as a decorator.

复制代码
class MyDecorator:
    def __init__(self, fn):
        self.fn = fn

    def __call__(self,*args, **kwargs):
        print('Decoration before execution of function') 
        self.fn(*args, **kwargs)
        print('Decoration after execution of function\n') 


def func(message, name):
    print(message, name)

func = MyDecorator(func)
复制代码

The class MyDecorator is going to serve as a decorator. We have a simple function named func and we have decorated it using the class MyDecorator by using the manual decoration syntax. In the statement func = MyDecorator(func), we are sending the undecorated function to the class and getting back the decorated function. We know that when we call a class object ( MyDecorator(func) ), the __init__ method of the class is executed. This is why we have made __init__ method accept a function. The call MyDecorator(func) returns an instance object of the class. So, after the statement func = MyDecorator(func), func is actually an instance object of the MyDecorator class.

So, this is how we can create a decorator class. The second parameter to __init__ accepts the function to be decorated, and this function is stored as an instance variable. Inside the __call__ method the original undecorated function is called and the decoration code is also placed before or after the call. The class is instantiated at the decoration time, and the instance object that is created is assigned to the function name. After decoration, the function name refers to an instance object, and so when the function name is called, the __call__ method of the class is executed.

Instead of using the manual decoration statement, we can use the automatic decoration syntax to get the same effect.

@MyDecorator
def func(message, name):
    print(message, name)

 

You can return the result from the __call__ method, so that the return value of the original function is not lost.

def __call__(self,*args, **kwargs):
    print('Decoration before execution of function') 
    result = self.fn(*args, **kwargs)
    print('Decoration after execution of function\n') 

    return result

If you want to preserve the metadata, then you have to call the wraps decorator.

def __init__(self, fn):
    self.fn = fn
    wraps(fn)(self)
    self.author = 'Jim'   # Add a new attribute here

If you want the decorator to add an attribute to the function, you have to add it inside the __init__ method, not inside the __call__ method. This is because we do not want to add the attribute each time the function is called. We want to add the attribute just once when the function is decorated.

 

posted on   ZhangZhihuiAAA  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
历史上的今天:
2023-07-31 Go - go.work, go.mod, go.sum
2023-07-31 Go - installation
2023-07-31 Go - env
2023-07-31 Python - match case
 
点击右上角即可分享
微信分享提示