看了海峰老师讲解的装饰器视频,讲解的非常棒。根据视频,记录笔记如下:
装饰器:
1、本质是函数,用def来定义。功能就是用来(装饰)其他函数,为其他函数添加附加功能
现有两个函数如下,
1 def test1(): 2 pass 3 4 def test2() 5 pass 6 7 test1() 8 test2()
需要添加一个记录日志的功能
原始方法,在每个函数里添加
1 def test1(): 2 pass 3 print('logging') 4 5 def test2() 6 pass 7 print('logging') 8 9 test1() 10 test2()
再进一步,增加一个函数,test1和test2来调用
1 def logger(): 2 print('logging') 3 4 def test1(): 5 pass 6 logger() 7 8 def test2() 9 pass 10 logger() 11 12 test1() 13 test2()
那假如有上百上千个函数,并且是正常在线的代码,也这样处理吗?很显然这是不可能的
因此装饰器的原则
2、a. 不能修改被装饰的函数的源代码
b.不能修改被装饰的函数的调用方式
实现装饰器知识储备:
3、a. 函数即“变量”
b. 高阶函数
c.嵌套函数
高阶函数+嵌套函数==装饰器
============================================
再来看一下以下几个场景
场景一
1 def bar(): 2 print("in the bar") 3 4 def foo(): 5 print ("in the foo") 6 bar() 7 8 foo()
场景二
1 def foo(): 2 print ("in the foo") 3 bar() 4 5 def bar(): 6 print("in the bar") 7 8 foo()
场景一和场景二的不同之处在于,一个bar()在foo()之前,一个在foo()之后,但两者结果一样,按理说python应该是从上往下一行一行执行,为啥场景二也没有问题呢
经过断点debug调试,发现在debug的过程中,程序会先把函数都过一遍,顺序是 def foo() ----> def bar() ----> foo() ----> print ("in the foo") ---> bar() -----> print (in the bar)
那再看场景三
1 def foo(): 2 print ("in the foo") 3 bar() 4 5 foo() 6 7 def bar(): 8 print("in the bar")
按照之前的解释,程序也会先把函数都过一遍,然后去执行。但场景三确报错了,会提示 name 'bar' is not defined,debug显示 def foo() 后直接到 foo(), 就直接执行foo()函数了,并没有往下走。
因为遇到foo(),就表示要去执行foo函数,而此时 bar并未在内存建立‘’门牌号‘’,因此会报错
看下面这张图,函数相当于变量的集合。
高阶函数:
a:把一个函数名当做实参传给另外一个函数
(在不修改被装饰函数源代码的情况下为其添加功能)
b:返回值中包含函数名(不修改函数的调用方式),一定要有return,返回该函数的内存地址
如下面的代码
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 6 def test1(func): 7 start_time = time.time() 8 func() 9 stop_time = time.time() 10 print("the func run time is %s" %(stop_time-start_time)) 11 12 test1(bar)
此时相当于 func=bar, func() 会执行bar函数
执行结果
in the bar
the func run time is 3.0004918575286865
返回值包含函数名,如
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 6 def test2(func): 7 print(func) 8 return func 9 10 test2(bar) 11 print("================") 12 print(test2(bar))
结果
<function bar at 0x000001B343BF3EA0>
================
<function bar at 0x000001B343BF3EA0>
<function bar at 0x000001B343BF3EA0>
print(test2(bar))先打印 func,然后返回func的内存地址。于是又打印一遍
换一种方式
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 6 def test2(func): 7 print(func) 8 return func 9 10 t=test2(bar) 11 print("================") 12 # print(test2(bar)) 13 t()
此时会去执行bar函数
结果
<function bar at 0x00000246AECB3EA0>
================
in the bar
那把 t 换成 bar 呢
1 import time 2 def bar(): 3 time.sleep(3) 4 print('in the bar') 5 6 def test2(func): 7 print(func) 8 return func 9 10 bar=test2(bar) 11 print("================") 12 # print(test2(bar)) 13 bar()
结果和上面是一样的。可以看出函数的调用方式没有改变,结果是一样的
因此引出了装饰器
1 import time 2 def test2(func): 3 # print(func) 4 print("auth---") 5 return func 6 7 @test2 8 def bar(): 9 time.sleep(1) 10 print('in the bar') 11 bar()
执行结果:
auth---
in the bar
在 in the bar 前面加了一段auth---,没有改变bar()的代码
这样装饰器就解释明白了
当然还有多层嵌套和装饰,带参数的装饰器,以后需要加强练习再补充。