作者:麦叔
来源:麦叔编程
装饰器的本质先简单说一下什么是装饰器。
装饰器,顾名思义,就是起装饰作用的东西。手机壳是一种装饰品。手机膜也是一种装饰品。
在编程的世界里,装饰器的作用,就是用一个壳子把一个函数包起来。以后每次调用的时候,实际上调用的是这个壳子。这个壳子先做一些操作,然后壳子再调用真正的函数。
装饰器可以是一个函数,也可以是一个类。今天就聊一下类装饰器。
类装饰器昨天我们举了一个类装饰器的例子。我把它稍微改造了一下:
- 有一个函数cook(),也就是做饭。不是苹果CEO那个库克,是做饭的厨师。
- 我们希望每次做饭之前,都要先洗手。
- 这里的WashHandDecorator就是一个类装饰器。
- 我们通过@WashHandDecorator声明了用这个装饰器来装饰cook()函数
先看一下代码和执行结果,思考一下:
class WashHandDecorator(object): def __init__(self, f): self.f = f print("洗手装饰器组装中...") def __call__(self): print("先洗手,再做饭...") self.f() @WashHandDecorator def cook(): print("做饭中...美味香喷喷...但是自己不能吃...")cook()cook()cook()打印结果:
洗手装饰器组装中...先洗手,再做饭...做饭中...美味香喷喷...但是自己不能吃...先洗手,再做饭...做饭中...美味香喷喷...但是自己不能吃...先洗手,再做饭...做饭中...美味香喷喷...但是自己不能吃...原理解释上面的原理已经解释了一半了,还不够透彻。所以继续:
- WashHandDecorator是装饰器。
- 它装饰了函数cook()以后,以后每次调用cook(),实际上是调用的WashHandDecorator类的实例,也就是调用了 __call__函数,这个函数会再调用cook()。也就是先洗手,洗完手再去做饭。
其实装饰器的语法,也就是那个@WashHandDecorator,只是一个语法糖衣。不用这个语法,我们也可以实现同样的效果:
class WashHandDecorator(object): def __init__(self, f): self.f = f print("洗手装饰器组装中...") def __call__(self): print("先洗手,再做饭...") self.f() def cook(): print("做饭中...美味香喷喷...但是自己不能吃...") ## 最关键的一行,魔法就在这里!!!!!! cook = WashHandDecorator(cook) cook()cook()cook()这个的执行结果和上面是完全一样的。
来看最关键的这一行cook = WashHandDecorator(cook):
- 参数中的cook代表的是上面定义的cook()函数,它作为参数传给了WashHandDecorator的构造函数。
- 而前面的变量名cook是新构造出来的WashHandDecorator的实例,只是故意让它的名字和函数名相同。
- 这样后面再调用cook()的时候,实际上不是调用的cook()函数,而是调用的这个对象实例。
- 对象一般不可以直接这样cook()调用的,除非它有__call__函数,而WashHandDecorator正好有这个函数。
- __call__函数里实现了:先洗手,然后再调用原本的cook()函数。
- 这就是整个装饰的过程。使用装饰器的语法不过是自动帮我们实现了上面的过程。
- 所以一个类要成为装饰的,最重要的就是必须有__call__函数,这就和上一个三分钟呼应上了。
懂了吗?没懂再看一遍。如果真懂了,有没有一种恍然大悟,甚至醍醐灌顶的感觉?
相关帖子DA内容精选
|


雷达卡





京公网安备 11010802022788号







