装饰器
本质上就是函数,功能是为其他函数添加附加功能
原则:不修改被修饰函数的源代码,以及调用方式,即完全不能有任何改变
装饰器 = 高阶函数+ 函数嵌套+ 闭包
高阶函数:函数作为参数或者返回一个函数
闭包:必须要有函数嵌套,内部函数调用外部函数的变量
利用现有的姿势用高阶函数来实现装饰器的效果
并没有更改foo函数的源代码,也实现了foo函数计算运算时间的附加功能
但是却改变了foo函数的调用方式,以后都要用test(foo)才能调用
1 import time 2 def foo(): 3 time.sleep(3) 4 print('你好啊林师傅') 5 6 def test(func): 7 # print(func) 8 start_time=time.time() 9 func() 10 stop_time = time.time() 11 print('函数运行时间是 %s' % (stop_time-start_time)) 12 # foo() 13 test(foo) # 改变了调用方式了
高阶函数的特性可以返回函数,可以实现不更改调用方式的问题
1 def foo(): 2 print('from the foo') 3 def test(func): 4 return func 5 6 res=test(foo) 7 print(res) 8 res() 9 10 foo=test(foo) 11 print(res) 12 foo()
不修改foo源代码,不修改foo调用方式,但是函数多运行了一次,废物
1 import time 2 def foo(): 3 time.sleep(3) 4 print('来自foo') 5 6 def timer(func): 7 start_time=time.time() 8 func() 9 stop_time = time.time() 10 print('函数运行时间是 %s' % (stop_time-start_time)) 11 return func 12 foo=timer(foo) #timer()运行了一次得出结果又赋值给foo 13 foo() # foo()又重新运行一遍,,,,
没有修改被修饰函数的源代码,也没有修改被修饰函数的调用方式,但是也没有为被修饰函数添加新功能
1 def timer(func): 2 start_time=time.time() 3 return func 4 stop_time = time.time() 5 print('函数运行时间是 %s' % (stop_time-start_time)) 6 7 foo=timer(foo) 8 foo()
由此可见,高端函数仁义尽致依然做不到我们想要的那种透明而又不加大负担的效果因此需要装饰器
装饰器的框架
1 def nnn(func): 2 def inner(*args,**kwargs): 3 """在这里我做了一些什么操作""" 4 ret = func(*args,**kwargs) 5 """在这里我又做了一些什么操作""" 6 return ret # 被装饰的函数的返回值 7 return inner 8 @nnn 9 def big(): 10 print("这是一个超级大源码") 11 big() # 本质上big() == nnn(big),但是装饰器不改变函数的调用方式,简化为big()
一个基本的计算运行时间的装饰器的例子
1 import time 2 def timmer(func): 3 def wrapper(*args,**kwargs): 4 start_time = time.time() 5 res = func(*args,**kwargs) 6 stop_time = time.time() 7 print("函数的运行时间是%s" %(stop_time - start_time)) 8 return res 9 return wrapper 10 11 @timmer 12 def cal(l): 13 res = 0 14 for i in l: 15 time.sleep(0.1) 16 res += i 17 return res 18 19 print(cal(range(20)))
带参数,返回值的装饰器使用
1 import time 2 def timmer(func): 3 def wrapper(*args,**kwargs): # *args,**kwargs 模拟一切参数 4 start_time = time.time() 5 res = func(*args,**kwargs) # 实际上就是运行test() ,将test() 的结果拿出来赋值 6 # 和上面的wrapper的参数进行一一对应的解压 7 stop_time = time.time() 8 print("运行时间: %s " %(stop_time - start_time)) 9 return res # 将赋值后的变返回值在通过wrapper再返回 10 return wrapper 11 12 13 @timmer # test = timmer(test) 14 def test(name,age): 15 time.sleep(1) 16 print("我是天才,名字是%s ,年领是 %s" %(name,age)) 17 return "我是天才返回值" 18 19 # res = test("yangtuo",18) # 就是在运行wrapper 20 # print(res) 21 test("yangtuo",18) 22 23 @timmer # test1 = timmer(test1) 24 def test1(name,age,gender): 25 time.sleep(1) 26 print("我是天才一号,名字是%s ,年领是 %s,性别是 %s" %(name,age,gender)) 27 return "我是天才一号返回值" 28 29 test1("shijieli",19,"man")