0.引入
python函数装饰器目的在于不改变原有函数的源代码情况下,给函数增加新的功能。而这正符合工程开发中的封闭开放原则,可以更好地服务于面向对象的开发。
整个设计过程可以理解为把原有函数放到新的函数当中,作为一部分功能的实现,进而实现了对于原有功能的扩充。
在下文中,笔者将分别就不同的函数情况对装饰器的设计展开讨论。
1.原函数没有需要输入的参数
def decorate(fn):
def inner():
print("你好!")
fn()
return inner
@decorate
def Test():
print("hello!")
if __name__ == "__main__" :
Test()
注意在写装饰器函数时,内层函数写完后需要在装饰器函数中返回内层函数。
2.原函数中有需要传入的参数
def decorate(fn):
def inner(a,b):
print("你好!")
fn(a,b)
return inner
@decorate
def Sum(a,b):
print(a+b)
if __name__ == "__main__" :
Sum(1,1)
注意:需要在inner和fn后面加上和原函数一样的参数。
3.原函数中有返回值
def decorate(fn):
def inner(a,b):
print("你好!")
return fn(a,b)
return inner
@decorate
def Sum(a,b):
return a+b
if __name__ == "__main__" :
print(Sum(2,1))
注意:需要在fn()前加上return,让inner函数有返回值
4.装饰器函数引入新的参数
def outter(flag):
def decorate(fn):
def inner(a,b):
print("你好!")
print(flag)
return fn(a,b)
return inner
return decorate
@outter(1)
def Sum(a,b):
return a+b
if __name__ == "__main__" :
print(Sum(2,1))
注意:这种情况相对上述比较复杂,需要在外层加上一层新的函数outter,用来传递新的参数。
(1)需要return decorate
(2)需要把@decorate 改成 @outter(外部函数的名字)
5.用于计时的装饰器的例子
import time
def decorate(fn):
def inner():
a=time.time()
fn()
b=time.time()
return b-a
return inner
@decorate
def arr():
li=[]
for i in range(1000):
li.append(i)
if __name__ =="__main__":
print(arr())
除了用装饰器计时,把算法封装在函数内,检验算法的时间复杂度,还可以用另一种方法。
import timeit
def arr():
li=[]
for i in range(1000):
li.append(i)
timeit.timeit("arr()",globals=globals(),number=1000) #number表示计算1000次取平均值
总的来说,装饰器常常具有通用性,函数经过装饰后,调用原函数,相当于调用inner函数,也可以根据此更好地设计装饰器结构。
对于多装饰器,离函数越近的先装饰,可以理解为经过内层装饰器装饰装饰后原函数变为inner1函数,inner1函数作为新的fn被外层装饰器装饰,形成新的函数inner2,相当于最后调用原函数就在调用inner2函数。