python中的装饰器,是对“高阶函数”的一种延生。使用它可以对函数进行增强,这样的方式就好像是OOP中的“装饰”设计模式所体现出来的效果一样。
1,简单装饰器
先来看一个高阶函数的例子,哈,回顾一下
然后,把函数“now”用函数“log”给装饰一下,就像是这样子:
通过在函数定义时,使用“@fn”来装饰该函数,这就是python中的装饰器。
经过上面的例子,同时我们也能得到这么一个结论就是:@log == log(now)
这个,就是python装饰器最本质的东西!
于是,上面的例子,当我们直接调用“now”函数的时候就会变成这样:
那在调用函数“now”的时候,同时打印出了一条“log”信息,这样就增强了“now”的功能,这种就称为是:装饰器!
2,带参装饰器
那现在,如果你准备在调用装饰器的时候,同时可以传递一些参数,又该怎么做呢?
首先,还是要从高阶函数的角度来看,所以,可以模拟成这样子:
那上面高阶函数的写法,转换成装饰器,就应该是这样子:
然后,我么就可以直接调用函数“now”:
那这样,是不是就实现了一个带参数的装饰器呢?
其实,只要明白一点,装饰器其实也很好理解。
我们在函数“now”上,通过增加“@log”,其实就是说:在调用“now”之前,先把“now”当做参数传递到“log”方法中执行一次。然后,由于,我们后续还需要再次调用“now”,所以,传递到“log”内部的“now”必须还得再返回,那这样的一个过程,就是装饰器的“执行”过程!
3,正规的写法
上面实现的装饰器,在装饰器的内部我们直接返回了外部的那个“now”函数,那么当我们在外部手动调用“now”函数的时候就会出现函数的返回值变成了它本身,所以我们应该在装饰器的内部,显式的调用一下“now”函数,并且返回它的返回值!
首先,我们针对不带参的装饰器做一个改造。
改造的过程是这样:当我们调用装饰函数“log”的时候,它不再是直接执行,而是在其内部又定义了一个函数,然后返回这个函数。那这个过程等价于这样: @log => now = log(now);
现在,“now”函数虽然存在,但是其实它本身已经指向了不同的一个函数“wrapper”。然后当你调用这个全新的“now”的时候,其实调用的时候内部的“wrapper”函数,然后该函数打印出对应的信息,同时还调用了“最开始的那个now函数”,为了能够调用这个“最开始的now 方法”,所以需要在“wrapper”函数中去显式的调用,同时还要返回它的值,因为这个本来就是“now”方法要返回的内容!
当然,对于带参的装饰器,就可以对应的这么写:
带参数的装饰器,对于不带参的而言,只是需要再通过一层函数来包装一下而言。
备注:一定要认真理解,理解透彻,方成正道!