装饰器:
定义:本质是一个函数,就是为了在不改变函数的源代码以及调用方式的条件下给已经编写的函数添加新的功能 原则:不能改变原函数的代码以及调用方式 实现装饰器知识储备: 1、函数即“变量” 2、高阶函数 a:把一个函数名当做一个实参传给另外一个函数 b:返回值中包含函数名 3、嵌套函数 高阶函数+嵌套函数===》装饰器
1.函数即“变量”
这里说的意思是函数的在内存中的存储方式和变量的存储方式是一样的,只不过变量存储的是数值、数组、矩阵等,而函数存储的是它的函数体,而函数名和变量名就是方法内存信息的门牌号,即它们内存地址。
2.高阶函数
所谓的高阶函数,只需要满足a,b中任意一个,就可以把它称之高阶函数。这里为了方便理解,先定一个简单的函数
import time # 调用time模块
def test():
time.sleep(3) # 延迟3秒之后再执行下面的语句
print("in the test")
test()
运行结果:
in the test
这是源函数的基本功能以及调用方式,现在来实现a:把一个函数名当做一个实参传给另外一个函数
import time
def test():
time.sleep(3)
print("in the test")
def bar(func):
start_time = time.time()
func()
stop_time = time.time()
print("the bar running time is %s"%(stop_time-start_time))
bar(test) # 将test函数当一个实参给了bar函数
运行结果:
in the test
the bar running time is 3.0
可以看出,起到了修饰的效果,源函数也没有被修改,但调用方式改变了。这是高阶函数a的特点,再来看b:返回值中包含函数名
import time
def test():
time.sleep(3)
print("in the test")
# test()
def bar(func):
start_time = time.time()
print(func)
return func # 返回func,其实返回的是test函数
stop_time = time.time()
print("the bar running time is %s"%(stop_time-start_time))
test =bar(test)
test()
运行结果:
<function test at 0x00000000021A2488>
in the test
可以看出,高阶函数b没有改变源函数的调用方式,但是没有起到装饰的作用。有人可能就会说,为什么不把return func放在函数定义的最后,我们来看一下效果:
import time
def test():
time.sleep(3)
print("in the test")
def bar(func):
start_time = time.time()
print(func)
func()
stop_time = time.time()
print("the bar running time is %s"%(stop_time-start_time))
return func
test =bar(test)
test()
运行结果:
<function test at 0x0000000001E92488>
in the test
the bar running time is 3.0
in the test
细心的可能就发现,怎么又两个 in the test ,因为这种方式其实和方式a没什么区别,你不返回一个函数,把最后两行代码换成bar(test),就和a的结果一样。<function test at 0x0000000001E92488>表示的就是函数test的内存地址,这一块需要自己好好理解。
3.嵌套函数:
顾名思义,就是在函数定义中再定义一个函数。
4.装饰器的实现:
理解了前面的知识,再来看最后的实现:高阶函数+嵌套函数===》装饰器
import time
def timmer(func):
def foo():
start_time = time.time()
func()
stop_time = time.time()
print("the func running time is %s"%(stop_time-start_time))
return foo # 这里就是实现装饰最经典的地方,这个时候test1和test2的地址就偷偷被foo的地址所代替,当函数test1()和test2()在运行时,其实是在运行foo(),但
# 但test1()和test2()的地址被func所记住,最终由func()执行test的函数体
@timmer # 这里的@timmer相当于 test1 = timmer(test1)
def test1():
time.sleep(3)
print("in the test1")
@timmer # 在每一需要被装饰的函数前面都要加一个@timmer
def test2():
time.sleep(3)
print("in the test2")
# test1 = timmer(test1)
test1()
# test2 = timmer(test2)
test2()
运行结果:
in the test1
the func running time is 3.0
in the test2
the func running time is 3.0