Understanding Python class decorators __call__

  • background

    The decorator pattern is a Python design pattern that I often use, and it is also very easy to use. It is usually implemented with functions, but this implementation has a disadvantage.

    If the logic is very complex, writing it in a function will make the function very long and redundant. It is necessary to abstract small functions, and then combine them with class decorators, which is suitable for this scenario.

# coding=utf-8
# 深入理解类装饰器


# 一:类装饰器(都不带参数)
class ClsDeco:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Running {self.func.__name__}')
        self.func()
        print('End')

@ClsDeco  # 等价于 bar = ClsDeco(bar)
def bar():
    print('do something')

# call bar()
# OUT:
#     Running bar
#     do something
#     End









# 二:类装饰器带参数
class ClsDeco1:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, func, *args, **kwargs):
        print(f'Running {func.__name__}')
        print(f'Using x + y = {self.x + self.y}')
        return func


@ClsDeco1(1,2) # 等价于 bar1 = ClsDeco1(1,2)(bar1)
def bar1():
    print('do something')


# call bar1()
# OUT:
#     Running bar1
#     Using x + y = 3
#     do something









# 三:类装饰器不带参数,被包装对象带参数
class ClsDeco2:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Running {self.func.__name__}')
        self.func(*args, **kwargs)
        print('End')

@ClsDeco2  # 等价于bar2 = ClsDeco2(bar2)
def bar2(a,b):
    print('do something')
    print(f'return a + b = {a + b}')


# bar2(1,2)
# OUT:
#     Running bar2
#     do something
#     return a + b = 3
#     End









# 四:类装饰器带参数且被装饰对象也带参数
class ClsDeco3:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, func, *args, **kwargs):
        print(f'Using x + y = {self.x + self.y}')

        def wrapper(*args, **kwargs):
            func(*args, **kwargs)
            print('Ending')

        return wrapper



@ClsDeco3(1, 2) # 等价于 bar3 = ClsDeco3(1, 2)(bar3)
def bar3(a, b):
    print('do something')
    print(f'return a + b = {a + b}')


# call bar3(1,2)
# OUT:
#     Using x + y = 3
#     do something
#     return a + b = 3
#     Ending





if __name__ == '__main__':
    bar3(1,2)

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325367489&siteId=291194637