装饰器--万能传参
装饰器的万能传参(*args,**kwargs)
案例
一、环境:以上为线上代码,需要添加1个统计执行时间的功能。线上代码如下:
1 #!/usr/bin/env python 2 # -*- coding:utf8 -*- 3 # Author:Dong Ye 4 5 import time 6 7 8 def test1(): 9 time.sleep(3) 10 print('in the test1') 11 def test2(): 12 time.sleep(3) 13 print('in the test2') 14 15 16 test1() 17 test2()
二、需求:在不修改源代码(test1 & test2)和原代码调用方式的情况下,给test1新增这个功能。
三、思路:
1、结合装饰器的特点:高阶函数 + 嵌套函数 =装饰器
2、使用嵌套函数把新增功能和源代码结合起来,并返回嵌套函数的内存地址。
3、通过高阶函数把内存地址返回,然后重新覆盖掉test1的函数名。
代码实现1
一、操作步骤:
1、先定义个高阶函数的decorator。
2、嵌套函数将高阶函数的内存地址返回给test1。
3、在高阶函数中调用test1的函数体与新增结果结合。
实例:(以下是装饰器的执行顺序)
1 def timer(func): #2、timer(test1) func = test1 2 def deco(): #3、在内存里定义了一个变量 3 start_time = time.time() #7、执行开始时间 4 func() #8、func()执行,其实就是执行了原代码test1 5 stop_time = time.time() #9、执行结束时间 6 print('the func run time is %s' % (stop_time-start_time)) #10、打印出test1的执行时间 7 return deco #4、 返回deco函数的内存地址 8 9 test1 = timer(test1) #1、调用timer函数,将test1的变量传给func 10 #5、将deco的内存地址返回给test1 11 test1() #6、执行test1(),其实是执行了deco()函数体 12 13 #test2 = timer(test2) 14 #test2()
代码实现2
优化第一个装饰器代码(无参数传值):
1、由于第一个装饰器是按照函数调用传值的方式展现的。
2、如果装饰函数体过多则会显得装饰器很乱,不易读写。
优化后代码:
1 import time #1导入time模块 2 def timer(func): #2相当于在内存中定义一个变量 #4 @timer其实是tist1 = timer(test1),所以会调用到timer函数。 3 def deco(): #5、将func定义成一个高阶函数 #8 在调用test1时,实际调用的是deco函数 4 start_time = time.time() #9 获取当前值 5 func() #10 调用源代码函数 6 stop_time = time.time() #14返回装饰器,继续下一个功能 7 print('the func run time is %s'%(stop_time-start_time)) #15打印 8 return deco #6返回高阶函数的内存地址 9 10 @timer #这个表示test1 = timer(test1) #3指定需要装饰的源代码 11 def test1(): #11 调用源代码 12 time.sleep(3) #12 调用源代码 13 print('in the test1') #13 调用源代码 14 15 16 17 test1() #7 调用test1(),实际执行的是装饰器中的deco。
代码实现3
一旦这个函数被装饰器装饰,那么这个函数将会被重新赋值,赋值成装饰器函数的内存函数。
1 #定义嵌套函数 2 def timer(func): #定义timer函数为了传递test参数 func = test1 3 def deco(*args,**kwargs): #定义功能函数 #由于在工作中产的参数和参数功能不统一,所以在deco()和func()函数中使用2个万能参数*args和**wargs; 4 start_time=time.time() 5 func(*args,**kwargs) #执行test传参的函数 func() = test1() 6 stop_time = time.time() 7 print('the func run time is %s' % (stop_time-start_time)) 8 return deco #返回deco函数的内存地址 9 10 11 @timer #test1 = timer(test1) = deco test1() = deco() 12 def test1(): 13 time.sleep(3) 14 print('in the test1') 15 16 @timer #test2 = timer(test2) = deco test2(name,age) = deco(name,age) 17 def test2(name,age): 18 time.sleep(3) 19 print('name: %s age: %s' % (name, age)) 20 21 test1() # test1() = deco() 22 test2('dongye',33) #test2(name,age) = deco(name,age) 23 24 25 26 # 注释: 27 # test2的赋值是嵌套函数timer(test2)返回来的deco的内存地址; 28 # 在调用test2()的时候,实际上是在调用deco()函数 29 # 需要注意的2个地方: 30 # 1、调用test2()函数时,传值的neme和age实际是传值给了deco嵌套函数中; 31 # 2、如果deco()函数与内部执行的func()中,没有指定形参,则会报错; 32 # 3、由于在工作中产的参数和参数功能不统一,所以在deco()和func()函数中使用2个万能参数*args和**wargs;