装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个实例对象重写了 call() 方法,那么这个对象就是callable的。
不带参数的类装饰器
class Test(object):
def __init__(self, func):
print("---初始化---")
print("func name is %s"%func.__name__)
self.__func = func
def __call__(self):
print("---装饰器中的功能---")
self.__func()
@Test #相当于test = Test(test)
def test():
print("----test---")
test()
说明:
1. 当用Test来装作装饰器对test函数进行装饰的时候,首先会创建Test的实例对象并且会把test这个函数名当做参数传递到init方法中即在init方法中的属性__func指向了test指向的函数;
2. test指向了用Test创建出来的实例对象;
3. 当在使用test()进行调用时,就相当于让这个对象(),因此会调用这个对象的call方法;
4. 为了能够在call方法中调用原来test指向的函数体,所以在init方法中就需要一个实例属性来保存这个函数体的引用所以才有了self.func = func这句代码,从而在调用__call方法中能够调用到test之前的函数体。
运行结果如下:
---初始化---
func name is test
---装饰器中的功能---
----test---
带参数的类装饰器
class Log(object):
def __init__(self, num):
self.num = num # self.num---->666 # 保存参数
def __call__(self, func):
self.func = func # 保存原函数的引用
return self.call_func
def call_func(self, *args, **kwargs):
# 这里新添加的功能......
print(self.num) # 获取装饰的时候的参数
return self.func(*args, **kwargs) # 调用被装饰的函数
@Log(666)
def test():
print("-------test----")
test()
- 调用Log(666)—->用Log创建一个实例对象,将1当做实参传递到init方法中;
- 调用实例对象对test函数进行装饰,可以理解为 test = 实例对象(test) ,装饰完成之后,test指向了
__call__
方法中返回的self.call_func
方法
运行结果如下:
666
-------test----
类当作装饰器的意义
如果装饰器想实现的功能比较少,那我们用普通的装饰器即可,但如果我们想实现多种功能,会在一个装饰器里写很多代码,显然用普通的装饰器实现起来很费劲,但如果用类装饰器的话,我们可以把各种功能封装在一个个实例方法中,然后在__call__
方法中调用不同的实例方法。