装饰器本身也是一个函数,作用就是将给一个函数添加额外的功能。但是不能改变这个函数的源代码以及这个函数的调用方式。
比如有个test1函数,调用函数就是用test1()【函数名+()】的方式就能调用。函数在内存中存储的方式跟x=1这种变量存储方式实际是一样的,先把test1这个函数的函数体当做字符串形式存在内存空间中,然后和test1变量名建立联系,这样通过test1()就能激活在内存中的函数体。
import time
def test1():
time.sleep(0.5)
print("in the test1")
test1()
----------------
in the test1
现在如果我想给test1这个函数添加一个test1函数体运行时间的额外功能,最好的方法就是添加有个timer装饰器。装饰器=高阶函数+嵌套函数。
如下代码片,添加了timer装饰器后,我既没改变test1函数的源代码以及这个函数的调用方式,但是却出现了一个test1函数的运行时间。工作原理:py解释器先运行def timer(func):这行,然后直接运行到def test1(): 这行(其实就是在内存中做了一个相当于变量的赋值操作),然后读取test1 = timer(test1)(timer(test1):将test1函数名赋值给func形参,然后返回deco函数名[即获取了deco函数的内存地址],然后将deco的内存地址赋值给test1变量名。最后,py解释器读取test1()这行,就激活deco函数在内存中的代码:运行t1,deco函数体中的func()就激活test1函数体,运行t2,打印运行时间,这样就给test1函数添加了计时功能
import time
def timer(func):
def deco():
t1 = time.time()
func()
t2 = time.time()
print("run the func time is %s " % (t2-t1))
return deco
def test1():
time.sleep(0.5)
print("in the test1")
return "test1"
test1 = timer(test1)
print(test1())
-------------------------------------
in the test1
run the func time is 0.5001699924468994
None #为什么不返回test1,因为timer(test1)的返回值是deco这个变量名,然后将deco这个变量名指向的内存地址传递给test1,所以test1指向的也是deco函数体的内存地址,而deco函数值没有返回值,所以打印None
装饰器在调用的时候只要在你想装饰的函数上写上@timer就可以了,这句话就等于test1 = timer(test1)。下面在把该装饰器做个升级,如果有个test2函数,且这个函数有形参。那么该装饰器就要写成如下。
import time
def timer(func):
def deco(*args,**kwargs):
t1 = time.time()
func(*args,**kwargs)
t2 = time.time()
print("run the func time is %s " % (t2-t1))
return deco
@timer #== test2 = timer(test2)
def test2(name):
time.sleep(0.5)
print("my name is %s " % name)
test2("乔布斯")
----------------------------------
my name is 乔布斯
run the func time is 0.5009970664978027