python 装饰器
装饰器的实质就是一个函数,可以对其他函数进行装饰,在不改变原函数代码的基础上增加新的功能,调用方式也不改变。
比如我们有两个函数sout1,sout2
import time
def sout1():
time.sleep(1)
print("this is sout1")
def sout2():
time.sleep(2)
print("this is sout2")
sout1()
sout2()
# 输出
# this is sout1
# this is sout2
现在我想让每个方法执行完时输出运行需要的时间
我们可以修改代码实现
import time
def sout1():
start = time.time()
time.sleep(1)
print("this is sout1")
end = time.time()
print("running time is",end-start)
def sout2():
start = time.time()
time.sleep(2)
print("this is sout2")
end = time.time()
print("running time is",end-start)
"""
输出
this is sout1
running time is 1.0009281635284424
this is sout2
running time is 2.0002005100250244
"""
一两个这样功能简单的还能改改,但要是许多函数,新增的功能复杂怎么办?
最好使用装饰器来实现。
在使用装饰前我们要先了解两个概念 高阶函数、嵌套函数
高阶函数
在数学和计算机科学中,高阶函数是至少满足下列一个条件的函数:
接受一个或多个函数作为输入
输出一个函数
我们已经定义了sout1这个函数
sout1() // 会调用函数
"""
输出
this is sout1
running time is 1.0009281635284424
"""
print (sout)
<function sout1 at 0x02CEB780>
万物皆对象嘛
所以函数也是对象
sout1存的是地址 是对象的引用
我们新增一个引用
hello = sout1
hello()
"""
输出
this is sout1
running time is 1.0009281635284424
"""
既然是对象 当然也能作为函数的参数和返回值
例:
def test(func):
return func
def sout():
print("hello world!")
a = test(sout)
a()
"""
输出
hello world!
"""
嵌套函数
就是函数里面又定义一个函数
例:
def outer():
print("hello")
def inner():
print("world!")
inner()
outer()
"""
输出
hello
world!
"""
实现
新增功能(修改调用方式)
既然可以把函数当作参数传入,那..
我们不就可以把原有函数当作参数传进一个新的函数中,新增点功能在返回出来?
import time
def sout1():
time.sleep(1)
print("this is sout1")
def decorate(func):
start = time.time()
func()
end = time.time()
print("running time is",end-start)
decorate(sout1)
"""
输出
this is sout1
running time is 1.0004260540008545
"""
现在已经实现了不修改原有代码添加新功能了,但是调用方式和以前不一样了。
新增功能(不修改调用方式)
那怎么实现不修改原来的调用方式?还是sout1()进行调用?
我们已经知道函数也可以和变量一样,给它一个新的引用,进行调用
如:
x = 1
y = x
print(y)
"""
输出
1
"""
def sout1():
time.sleep(1)
print("this is sout1")
hello = sout1
hello()
"""
输出
this is sout1
"""
那我们想办法让进行装饰的函数 **decorate() **也返回一个函数
然后 sout1 = decorate(sout1)
不就实现了sout1()
新增功能而不修改原代码,原调用方式?
所以我们可以把decorate()中的代码再封装一下
def sout1():
time.sleep(1)
print("this is sout1")
# 原decorate()
# def decorate(func):
# start = time.time()
# func()
# end = time.time()
# print("running time is",end-start)
#改为:
def decorate(func):
def inner():
start = time.time()
func()
end = time.time()
print("running time is",end-start)
return inner
sout1 = decorate(sout1)
sout1()
"""
输出
this is sout1
running time is 1.0003764629364014
"""
成功!
然而我们还是要在 原来的函数调用前
添加类似语句 sout1 = decorate(sout1)
这个事情python可以通过语法糖@来帮我们完成
def decorate(func):
def inner():
start = time.time()
func()
end = time.time()
print("running time is", end - start)
return inner
@decorate # 等同于 sout1 = decorate(sout1)
def sout1():
time.sleep(1)
print("this is sout1")
sout1()