python函数式编程之装饰器(一)

1.开放封闭原则

简单来说,就是对扩展开放,对修改封闭

在面向对象的编程方式中,经常会定义各种函数。

一个函数的使用分为定义阶段和使用阶段,一个函数定义完成以后,可能会在很多位置被调用

这意味着如果函数的定义阶段代码被修改,受到影响的地方就会有很多,此时很容易因为一个小地方的修改而影响整套系统的崩溃,

所以对于现代程序开发行业来说,一套系统一旦上线,系统的源代码就一定不能够再改动了。

然而一套系统上线以后,随着用户数量的不断增加,一定会为一套系统扩展添加新的功能。

此时,又不能修改原有系统的源代码,又要为原有系统开发增加新功能,这就是程序开发行业的开放封闭原则,这时就要用到装饰器了。

2.什么是装饰器??

装饰器,顾名思义,就是装饰,修饰别的对象的一种工具。

所以装饰器可以是任意可调用的对象,被装饰的对象也可以是任意可调用对象

3.装饰器的作用

在不修改被装饰对象的源代码以及调用方式的前提下为被装饰对象添加新功能

原则:

1.不修改被装饰对象的源代码 2.不修改被装饰对象的调用方式

目标:

为被装饰对象添加新功能 4.装饰器的定义和使用

来看下面的代码:

import time import random def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index()

index函数的作用是程序在随机睡眠1到5秒之后,打印一句话

现在想为index函数添加一个新功能:统计index函数的运行时间,该怎么做呢??

修改index函数如下:

import time import random def index(): start_time=time.time() time.sleep(random.randrange(1,5)) print("welcome to index page") end_time=time.time() print("cost time: %s" %(end_time - start_time)) index()

运行程序,执行结果如下:

welcome to index page cost time: 2.000999927520752

可以看到,为index函数添加新功能确实实现了,但是却违反了开放封闭原则。

在符合开放封闭原则的前提下,如果想为index函数添加新功能,此时就要使用装饰器了

修改代码

import time import random def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") def timmer(): def inner(): start_time=time.time() index() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner f=timmer() f()

运行程序,查看执行结果

welcome to index page run time: 1.0

从程序执行结果可以看出,index函数的运行时间已经被统计出来了

但是查看源码可以知道,index函数的源码确实没有被修改,但是index的调用方式被修改了

而且还有一个问题就是,timmer这个装饰器只能被用来装饰index这个函数,如果以后想统计别的函数的运行时间,又要重新定义别的装饰器,这样也太不灵活了。

修改上面的代码

import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") index=timmer(index) index()

运行程序,查看程序执行结果

welcome to index page run time: 4.0

可以看到,index函数的源代码没有被修改,index函数的调用方式也没有改变,但是依然为index函数添加了统计时间的功能,这里使用的就是装饰器了。

来分析下上面代码的执行流程:

1.导入time和random模块,定义index函数和timmer函数 2.把原始的index函数的内存地址作为参数传给timmer函数。 3.timmer函数内部嵌套定义一个函数inner,然后返回inner函数的内存地址 4.timmer函数执行完成,返回timmer函数的内部函数inner的内存地址,然后把inner的内存地址赋值给index变量 5.index是inner函数的内存地址,index变量加括号运行,实际上就是在运行inner函数 6.运行inner函数,定义程序开始时间。 7.执行timmer函数的变量func,在第2步知道,func这个变量就是index的内存地址,所以这里实际上是执行被装饰过后的index函数 8.index函数执行完成,定义程序的终止时间 9.统计并打印整个程序的执行过程中所花费的时间

这就是装饰器装饰index函数的执行流程

5.装饰器的简化使用

现在我又有另外一个函数home,现在我也想统计home函数的运行时间,可以把代码修改如下

import time import random def timmer(func): def inner(): start_time=time.time() func() end_time=time.time() print("run time: %s " %(end_time-start_time)) return inner def index(): time.sleep(random.randrange(1,5)) print("welcome to index page") def home(): time.sleep(random.randrange(1,5)) print("welcome to home page") index=timmer(index) index() home=timmer(home) home()

运行程序,执行结果如下

welcome to index page run time: 3.0 welcome to home page run time: 4.0

可以看到,每次调用统计程序运行时间的装饰器timmer,都要先把被调用的函数的函数名作为参数传给timmer装饰器

然后再把timmer装饰器的执行结果赋值给被调用的函数名本身,最后才能调用被装饰的函数,太麻烦了有没有??

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyzwgp.html