登录
首页精彩阅读哪有那么复杂?类装饰器,一个小例子就彻底懂了
哪有那么复杂?类装饰器,一个小例子就彻底懂了
2022-03-18
收藏
哪有那么复杂?类装饰器,一个小例子就彻底懂了

作者:麦叔

来源:麦叔编程

装饰器的本质

先简单说一下什么是装饰器。

装饰器,顾名思义,就是起装饰作用的东西。手机壳是一种装饰品。手机膜也是一种装饰品。

在编程的世界里,装饰器的作用,就是用一个壳子把一个函数包起来。以后每次调用的时候,实际上调用的是这个壳子。这个壳子先做一些操作,然后壳子再调用真正的函数。

装饰器可以是一个函数,也可以是一个类。今天就聊一下类装饰器。

类装饰器

昨天我们举了一个类装饰器的例子。我把它稍微改造了一下:

  • 有一个函数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__函数,这就和上一个三分钟呼应上了。

懂了吗?没懂再看一遍。如果真懂了,有没有一种恍然大悟,甚至醍醐灌顶的感觉?

数据分析咨询请扫描二维码

最新资讯
更多
客服在线
立即咨询