类装饰器
在理解类装饰器之前,先回忆一下有关装饰器的知识。装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的引用)。
__call__方法
一个对象是否可调用,看其中是否实现了__call__方法。例如,类的对象是不可调用的,因为其中没有实现__call__方法。如果我们在一个类中定义了__call__方法,那么这个类对象将变得可调用。只要某个对象定义了__call__()方法,那么这个对象就是callable的。
类中没有实现__call__方法: >>> class A: # 类中没有实现__call__方法 ... pass >>> a = A() >>> a() # 类对象不可调用 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'A' object is not callable 类中实现了__call__方法: >>> class B: ... def __init__(self): ... self.name = 'zhangsan' ... def __call__(self): # 类中实现了__call__方法 ... print('类中实现了__call__方法:', self.name) ... >>> b = B() >>> b() # 类对象可调用,并在调用类对象的时候,自动执行__call__方法 类中实现了__call__方法: zhangsan
类装饰器
类装饰器本质上和函数装饰器原理、作用相同,都是为其它函数增加额外的功能。但是相比于函数装饰器,类装饰器具有灵活度大、高内聚、封装性等优点。使用类装饰器可以直接依靠类内部的__call__方法来实现,当使用 @ 形式将类装饰器附加到函数上时,就会调用类装饰器的__call__方法。而不需要向函数装饰器那样,在装饰器函数中定义嵌套函数,来实现装饰功能。
使用类装饰器为一个函数的执行增加计时功能。
>>> import time >>> class Foo(): ... def __init__(self, func): # 初始化函数中传入函数对象的参数 ... self._func = func ... def __call__(self): # 定义__call__方法,直接实现装饰功能 ... start_time = time.time() ... self._func() ... end_time = time.time() ... print('花费了 %.2f' % (end_time - start_time)) ... >>> @Foo # bar=Foo(bar) ... def bar(): ... print('bar函数的执行时间为:') ... time.sleep(2.5) ... >>> bar() # bar=Foo(bar)(),没有嵌套关系了,直接执行Foo的 __call__方法,实现装饰功能 bar函数的执行时间为: 花费了 2.51
上面的@Foo相当于bar = Foo(bar),等号左边的bar是类Foo的实例对象,等号右边的bar是类装饰器所装饰的函数名bar作为参数传递给类Foo。下面执行bar()即为调用类Foo的对象bar,此时会自动调用类中定义的__call__方法。