文档内容学习于
装饰器 :
定义: 装饰器 本质是函数,功能是装饰其他函数,就是为其他函数添加附加功能。
原则:
1、不能修改被装饰的函数的源代码
2、不能修改被装饰的函数的调用方式
看以下
[root@localhost day4]# cat decorator.py #!/usr/bin/env python3import timedef timmer(func): #装饰器。 其实编写当时和写函数 是一样的 def warpper(*args,**kwargs): start_time = time.time() func() stop_time =time.time() print ("the func run time is %s" %(stop_time-start_time)) return warpper@timmer #使用装饰器(这个装饰器的作用其实是统计test1 这个函数的运行时间),然后这个装饰器 对被修饰的 test1这个函数 这个其实是不影响的。 并没有违背以上2条原则。 def test1(): time.sleep(3) print ("this is test") return 0test1()[root@localhost day4]# ./decorator.py this is testthe func run time is 3.0033674240112305 #装饰器的效果 ,统计test1 函数的运行时时间。
我们 一步 一步 把装饰器 拆开来 慢慢 理解 。
装饰器的知识储备
1. 函数即“变量”
这个概念 可以看视屏day4__5. 简单说就是 python通过内存地址(函数名,变量名)来调用变量(函数)。
2.高阶函数
3.嵌套函数
高阶函数+ 嵌套函数==> 装饰器
然后 我们 引用
1.函数即“变量”
2.高阶函数
之前我们提到了 高阶函数的 概念
1. 把一个函数名当做实参传给另一个函数
2. 返回值中包含函数名
的概念 其实功能 就类似以下。 但是以下不是装饰器。只是功能类似。因为他违背了2、不能修改被装饰的函数的调用方式 的规则(这个说明只是为了帮助理解)
import timedef bar(): #定义了bar 这个函数 time.sleep(3) print ("in the bar")def test(func): # bar作为实参传进来, 这个 其实这个时候func就等于bar 这个函数了 start_time = time.time() func() # 运行 func这个变量(函数),, 其实就运行了bar这个函数 stop_time =time.time() print ("the func run time is %s" %(stop_time-start_time))test(bar) # 将bar作为时实参传进去, 此处还需要注意,这边是传函数,不是传函数的执行结果,所有不能bar()这么写
PS :
在以上 例子中bar其实是源代码, 虽然我们没有变化bar的源代码 。 但到最后其实调用bar的方式改变了(将bar作为实参使用了)。违背了第2条原则。 所以以上并不是装饰器。
然后我们上面看到了 高阶函数的 第二条定义
2. 返回值中包含函数名
我们做以下尝试
import timedef bar(): print ("in the bar")def test(func): start_time = time.time() func() stop_time =time.time() print ("the func run time is %s" %(stop_time-start_time)) return func # 进行这个变量(函数)作为返回值 ,这样这个函数的执行结果就是这个函数的内存地址(这个函数的变量名),就可以定义在外面定义变量了。bar = test(bar) #这样再定义bar,就可以不修改 bar这个源代码的调用方式了。 bar()
通过以上例子 我们可以发现
返回值中包含函数名 的 作用相当于 不修改函数的调用方式
这样,我们对于高阶函数的定义 ,在装饰器中可以理解为
1. 把一个函数名当做实参传给另一个函数(不修改被装饰函数的情况下不修改源代码 )
2. 返回值中包含函数名(不修改函数的调用方式 )
嵌套函数
就是在函数里面 在再定义一个函数
def foo(): print("in the foo") def bar (): #这里定义的bar函数,一定要在foo里面才能调用, 作用类似于局部变量,bar这个函数在全局是不生效的。 print ("in the bar") bar()foo()
看以下
[root@master day4]# cat decarate.py #!/usr/bin/env python3x = 0def grandba(): x = 1 def dad(): x = 2 def son(): x = 3 print (x) son() dad()grandba()[root@master day4]# ./decarate.py 3
然后将高阶函数和 嵌套函数结合起来使用
[root@localhost day4]# cat decorator2.py #!/usr/bin/env python3import timedef timer(func): # 高阶函数: 把函数作为实参进来 def deco(): # 嵌套函数:函数里面定义函数 start_time=time.time() func() stop_time=time.time() print ("the func run time is %s" %(stop_time-start_time)) return deco #高阶函数:用函数作为返回值。 这边定义的返回值其实是deco这个函数, 在timer这个函数里面无需执行def test1(): time.sleep(3) print ("in the test1") test1 = timer(test1) # 外部调用函数test1() [root@localhost day4]# ./decorator2.py in the test1the func run time is 3.0034003257751465
@符
在python3中可以直接使用 @ 符号来调用装饰器。
1.它一定要写在被修饰函数的前面
[root@localhost day4]# cat decorator2.py #!/usr/bin/env python3import timedef timer(func): def deco(): start_time=time.time() func() stop_time=time.time() print ("the func run time is %s" %(stop_time-start_time)) return deco@timer #直接@符加修饰器名字。 但是一定要写在被修饰函数的前面 @time ==== test1=timer(test1)def test1(): time.sleep(3) print ("in the test1")test1()[root@localhost day4]# ./decorator2.py in the test1the func run time is 3.003570795059204
完整的装饰器
装饰器使用传参
理解 一下。 是在理解不了,就死记吧。 要传参就是,需要deco和 func这边也将形参写好。
[root@localhost day4]# cat decorator2.py #!/usr/bin/env python3import timedef timer(func): def deco(*args,**kwargs): ### 进行传参 start_time=time.time() func(*args,**kwargs) ### 因为这个func函数在这边是直接调用的,不是定义的。所以参数需要deco传进来 stop_time=time.time() print ("the func run time is %s" %(stop_time-start_time)) return deco@timer # test2 = timer(test2) ==> 其实 test2()== fun() 执行是 deco(),所以test2()传参就是 deco() 传参 再传给func() def test2(name,age): time.sleep(1) print ("this is %s,%s" %(name,age) )test2("haha",55)[root@localhost day4]# ./decorator2.py this is haha,55the func run time is 1.0164666175842285