一、定义
1、装饰器:本质是函数。
2、功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。
二、原则
1、不能修改被装饰函数的源代码
2、不能修改被装饰函数的调用方式
装饰器为什么会有这两个原则呐?因为如果你写的这个程序在生产环境下已经运行了,如果修改别人的源代码或者修改别人的调用方式,那么出了问题,后果可想而知,所以我们要牢记上面两个原则。
三、实现装饰器知识储备
- 函数即"变量"
- 高阶函数
- 嵌套函数
最终: 高阶函数+嵌套函数 => 装饰器
四、函数即变量
1、python的内存机制
1 #变量 2 x = 1 3 #函数 4 def test(): 5 pass
以上一个变量一个函数在内存中的表现形式如下图:
在python解释器中,有一个概念叫做引用基数,那什么叫引用基数呐,就是比方说,x=1,它会先在内存当中把1这个值试试在在的存放下来,这个x其实就是1的门牌号,也是对1的一次引用。python什么时候把这个1这个屋子清空呐?它会等到1所对应的门牌号都没有了,就会把1这里面的东西给清掉,这个也是python的内存回收机制,就是靠这种方式回收的。
2、del清理
那我们用什么清理呐?用del去清理门牌号,就是对1的值引用的变量,del x就表示清理掉1对应的x的门派号。如果x没有被del,则x永远不还被删除,除非程序结束了,不然永远不会被删除。del删除的不是1,只是把门牌号x删除了,只是定期刷新时,发现1没有被其他门牌号引用了,才会被清掉。
3、函数在内存的表现形式
我们先通过三个例子来解释一下:
①bar函数在foo函数之后定义
1 #bar函数在foo函数之后定义 2 def foo(): 3 print("in the foo") 4 bar() 5 6 def bar(): 7 print("in the bar") 8 9 foo() 10 11 #输出 12 in the foo 13 in the bar
②bar函数是在foo函数之前定义
1 # bar函数是在foo函数之前定义 2 def bar(): 3 print("in the bar") 4 5 def foo(): 6 print("in the foo") 7 bar() 8 9 foo() 10 11 #输出 12 in the foo 13 in the bar
显然,两种写法效果是一样的,那我们来看看第三种情况。
③bar函数在foo函数调用之后声明
1 # bar函数在foo函数调用之后声明 2 def foo(): 3 print("in the foo") 4 bar() 5 6 foo() 7 8 def bar(): 9 print("in the bar") 10 11 #输出 12 Traceback (most recent call last): 13 in the foo 14 File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 31, in <module> 15 foo() 16 File "D:/PycharmProjects/pyhomework/day4/装饰器/函数即变量.py", line 29, in foo 17 bar() 18 NameError: name ‘bar‘ is not defined #bar函数没有定义
为啥呢?bar函数我不是定义了吗?下面我们就用一个图来解释一下。
从图中不难看出第三种错误是因为在执行foo函数时,当调用bar函数时,bar还函数还定义,所以报错。
五、高阶函数
实现高阶函数有两个条件:
- 把一个函数名当做实参传给另外一个函数
- 返回值中包含函数名
1、把一个函数名当做实参传给另外一个函数
作用:在不修改被装饰函数源代码的情况下为其添加功能
1 def bar(): 2 time.sleep(3) 3 print("in the bar") 4 5 def test1(func): 6 print(func) 7 start_time = time.time() 8 func() 9 stop_time = time.time() 10 print("the func run the is %s"%(stop_time-start_time)) 11 #没有修改bar的代码 12 test1(bar) #把bar函数名当做实参传到test1中 13 14 #输出 15 <function bar at 0x0000000000A7D378> #bar函数的内存地址 16 in the bar 17 the func run the is 2.9912972450256348
2、返回值中包括函数名
作用:不修改函数调用方式
1 import time 2 3 def bar(): 4 time.sleep(3) 5 print("in the bar") 6 7 def test2(func): 8 print(func) 9 return func #返回函数的内存地址 10 11 #调用test2函数 12 bar = test2(bar) 13 bar() #没有bar函数改变调用方式 14 15 #输出 16 <function bar at 0x0000000000B6D378> #打印bar函数的内存地址 17 in the bar