day14装饰器
-
开放封闭原则:
- 开放:对源码的拓展是开放的。
- 封闭:对源码的修改是封闭的。
-
装饰器:完全遵循开放封闭原则,即在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。(装饰器的本质是闭包)
- 举例:计算func1函数的运行效率。
def func1(): for i in range(10000): i+=1
此问题相当于为函数func1增加一个方法,可以计算函数的运行时间。用简单的time模块就可以完成,如下:
import time time.perf_counter() func1() print(f'程序运行的时间为:{time.perf_counter()}')
但这样做不满足开放封闭原则,可更改为如下:
import time def timer(f): def inner(): time.perf_counter() f() print(f'程序运行的时间为:{time.perf_counter()}') return inner func1=timer(func1) func1() #这样在不改变原函数的调用方式下为原函数增加了新的功能。即为原始的装饰器模型。在运行大型平台时非常有用。 #装饰器的本质是闭包 import time def timer(f): f=func1 #f为自由变量,指向函数func1的内存地址。 def inner(): time.perf_counter() f() print(f'程序运行的时间为:{time.perf_counter()}') return inner func1=timer(func1) func1()
但如果想要测试另一个函数(例如func3)的效率,则仍然需要增加一句语法:
func3=timer(func3)
。假设要测试的函数过多的话,就会比较麻烦。 -
原始装饰器模型的升级版本:python做了一个优化,提出了一个‘语法糖’的概念。即在编写了装饰器后,需要将装饰器代码放在所有代码的前方。
import time #装饰器函数 def timer(f): def inner(): time.perf_counter() f() print(f'程序运行的时间为:{time.perf_counter()}') return inner #当要对装饰器函数调用时,在要装饰函数的前方使用@+装饰器函数名,如下: @timer #相当于func1=timer(func1) def func1(): for i in range(10000): i+=1 func1() #此时即使有func3,也可以直接在函数前调用装饰器: @timer #会将两行并为一行读取:func3=timer(func3) def func3(): pass
-
当函数有返回值时(被装饰函数有返回值时):
import time #装饰器函数 def timer(f): def inner(): time.perf_counter() f() print(f'程序运行的时间为:{time.perf_counter()}') return inner @timer def func1(): for i in range(10000): i+=1 return i print(func1()) #None,无法打印出函数func1的返回值。
此时要对装饰器进行改进:
import time #装饰器函数 def timer(f): def inner(): time.perf_counter() r = f() #将返回值赋值给r print(f'程序运行的时间为:{time.perf_counter()}') return r #将返回值给inner函数。 return inner @timer def func1(): for i in range(10000): i+=1 return i print(func1()) #10000
加上装饰器不应该改变原函数的返回值,所有func1的返回值i应该返回给inner函数。
-
当函数有参数时(被装饰函数带参数):
import time #装饰器函数 def timer(f): def inner(*arg,**kargs): #*的聚合 time.perf_counter() r = f(*arg,**kargs) #*的打散 ,并将返回值传给inner函数。 print(f'程序运行的时间为:{time.perf_counter()}') return r #将返回值给inner函数。 return inner @timer def func1(num1,num2): for i in range(num1,num2): i+=1 return i print(func1()) #
-
标准版的装饰器:
def wrapper(f): def inner(*arg,**kargs): '''添加额外的功能:执行被装饰函数之前的操作''' ret = f(*arg,**kargs) '''添加额外的功能:执行被装饰函数之前的操作''' return ret return inner #装饰器的调用 @wrapper def func(): pass
-
装饰器的应用: