类装饰器

上篇介绍了函数的装饰器以及如何保留元信息接下来接续介绍装饰器

__call__方法

call 方法可通过类的实例对象()方式调用,将实例对象变为可调用对象(通过()方式调用)

class CLanguage:
    # 定义__call__方法
    def __call__(self,name,add):
        print("调用__call__()方法",name,add)

clangs = CLanguage() #对象
clangs("C语言中文网","http://c.biancheng.net") #实例对象变为可调用对象,调用__call__()
clangs.__call__("C语言中文网","http://c.biancheng.net")
#输出
上述两种方法输出结果一致为 调用__call__()方法 C语言中文网 http://c.biancheng.net

类装饰器

调用__call__方法实现类装饰器的功能,此方法相当于函数装饰器中的wrapper

# 用类装饰函数,无任何参数
class MyDemoDecorator:
    def __init__(self, f): #将函数当作参数传入
        self.f = f  #self.f现在就是func
        print('加油!宝贝')
    def __call__(self):
        self.f()
@MyDemoDecorator
def func():
    print("Learning!")
func()
func()

class MyDemoDecorator:
    def __init__(self, f): #将函数当作参数传入
        self.f = f  
        print('加油!宝贝')
    def __call__(self):
        self.f()

def func():
    print("Learning!")

func = MyDemoDecorator(func)
func()
func()

上述两种输出一致:
加油!宝贝
Learning!
Learning!

1.@MyDemoDecorator相当于func = MyDemoDecorator(func),将函数func()作为参数传递给MyDemoDecorator的构造函数,现在func是类的一个实例对象
2.后面调用的func()调用的不是func()函数,而是调用这个实例对象
3.对象一般不可以func()调用,但当有__call__函数时可以,func()直接调用__call__函数
4.加油!宝贝只输出一次,是因为在在运行程序之前会将类与函数加载进来但没运行,当遇到@MyDemoDecorator时会调用构造函数所以输出一次

# 用类装饰函数,当函数有参数时
class animal:
    def __init__(self, func): # 函数传进来
        self.func = func # t

    # @wraps
    def __call__(self, *args, **kwargs): # 传进来的参数,相当于函数装饰器的wrapper
        print('working here')
        res = self.func(*args, **kwargs)  # 调用函数
        return res

@animal  # t = animal(t)
def t(name, kind):
    word = f'{name} belongs to {kind}'
    return word

A = t('cow', 'mammals') #调用实例对象
print(type(t))
print(A)

# 输出working here
<class '__main__.animal'>
cow belongs to mammals

函数t已经改变元信息,看其他说打开wraps就可传入但我失败了

# 用类装饰函数,装饰器含有参数时
class BaiyuDecorator:
    def __init__(self, arg1, arg2):  # init()方法里面的参数都是装饰器的参数
        print('执行类Decorator的__init__()方法')
        self.arg1 = arg1
        self.arg2 = arg2

    def __call__(self, func):  # 因为装饰器带了参数,所以接收传入函数变量的位置是这里
        print('执行类Decorator的__call__()方法')

        def baiyu_warp(*args):  # 这里装饰器的函数名字可以随便命名,只要跟return的函数名相同即可
            print('执行wrap()')
            print('装饰器参数:', self.arg1, self.arg2)
            print('执行' + func.__name__ + '()')
            func(*args)
            print(func.__name__ + '()执行完毕')

        return baiyu_warp

@BaiyuDecorator('Hello', 'Baiyu')  # example = BaiyuDecorator('Hello', 'Baiyu')(example)
def example(a1, a2, a3):
    print('传入example()的参数:', a1, a2, a3)

if __name__ == '__main__':
    print('准备调用example()')
    example('Baiyu', 'Happy', 'Coder')
    print('测试代码执行完毕')

输出:执行类Decorator的__init__()方法
执行类Decorator的__call__()方法
准备调用example()
执行wrap()
装饰器参数: Hello Baiyu
执行example()
传入example()的参数: Baiyu Happy Coder
example()执行完毕
测试代码执行完毕

在不运行主函数时也会输出 执行类Decorator的__init__()方法,执行类Decorator的__call__()方法的结果。
我的理解在加载代码遇到装饰器时由于装饰器带有参数等价于 example = BaiyuDecorator('Hello', 'Baiyu')(example),先执行BaiyuDecorator('Hello', 'Baiyu')输出 执行类Decorator的__init__()方法,
随后BaiyuDecorator('Hello', 'Baiyu')作为类的实例调用了__call__输出执行类Decorator的__call__()方法

类装饰器含参数和类装饰器不带参数比较

#含参数                             
#1.init()方法里面的参数都是装饰器的参数
#2.__call__() 接收传入函数变量的位置是这里(传入函数)
#3.在__call__()函数 下定义了个函数,传入定义的装饰器函数的参数,如example('Baiyu', 'Happy', 'Coder')中的内容
 #不含参数
#1. init()方法里面的参数时被装饰的函数(传入函数)
#2.__call__()定义的装饰器函数的参数
posted @   凡凡的宝贝  阅读(178)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示