本文介绍的是Python装饰器的使用,分三部分记录装饰器,旨在为之后复习保留学习笔记。python装饰器在没有改变原始函数调用方式的同时,在原始函数的前后增加功能,满足开放封闭原则。
1.
目录
1.装饰器的固定模板
# 装饰器的固定模板
def wrapper(f):
def inner(*args, **kwargs):
ret = f(*args, **kwargs)
return ret
return inner
@wrapper
def f():
pass
f()
在装饰器wrapper函数定义时设置了一个参数f,此参数是用来接受被装饰函数的函数名。内部的inner函数接受动态参数用于传递给f函数,并用ret接受f调用后的返回值。以timer实例说明:
import time
def timer(f):
def inner(*args, **kwargs):
start = time.time()
ret = f(*args, **kwargs)
end = time.time()
print(end - start)
return ret
return inner
@timer
def func(a):
time.sleep(0.01)
print("大家好", a)
return '新年好'
# func = timer(func)
ret = func(1)
print(ret)
func函数是一个有参数且有返回值的普适函数,timer是装饰器函数,在内部f函数调用前后增加时间记录功能,并打印运行时间。
注释部分:# func = timer(func)等同于@timer操作,timer(func)函数执行后返回inner函数地址,此时的func=inner,之后ret=func(1)等同于ret=inner(1)
2.带参数的装饰器模板
def wrapper_out(arguments):
def wrapper(func):
def inner(*args, **kwargs):
ret = func(*args, **kwargs)
return ret
return inner
return wrapper
@wrapper_out(arguments)
def f():
pass
f()
带参数的装饰器是在装饰器函数上再增加一个闭包函数,@wrapper_out(arguments)先执行函数,wrapper_out(arguments)返回wrapper函数地址,@wrapper_out(arguments)等同于@wrapper
3.多个装饰器函数装饰一个函数
def wrapper1(func):
def inner1(*args, **kwargs):
print("wrapper1 before func")
ret = func(*args, **kwargs)
print("wrapper1 before func")
return ret
return inner1
def wrapper2(func):
def inner2(*args, **kwargs):
print("wrapper2 before func")
ret = func(*args, **kwargs)
print("wrapper2 before func")
return ret
return inner2
@wrapper2 # f = wrapper(f) f==inner1 --> f = wrapper2(inner1) = inner2
@wrapper1 # f = wrapper1(f) --> inner1
def f():
print("in f")
f() # inner2()
@wrapper1 wrapper装饰的是f,因此@wrapper1等同于 f = wrapper1(f) 此时f = inner1。Python程序是从上往下执行的,@wrapper2装饰的是包含@wrapper1在内的整个函数,而@wrapper1内部其实是在执行inner1,因此@wrapper2等同于f = wrapper2(inner1),此时f是inner2的函数地址,执行f()时,等同于执行inner2(),但是inner2函数中的func此时是inner1,然后跳转至inner1函数执行,最后执行到原始的f函数。执行结果如下:
wrapper2 before func
wrapper1 before func
in f
wrapper1 before func
wrapper2 before func
现象是:外层的装饰器先执行,然后内层的装饰器再执行,然后递归推出函数调用