一.装饰器引入
def func():
print('我是一句话')
1.如何输出上面这段程序的运行时间?
在没学习装饰器之前一定会通过修改原函数来实现程序附加功能。
import time
def func():
start = time.time() # 记录开始时间
print('这是一句话')
end = time.time() # 记录结束时间
print(start - end)
2.但如果有成千上万的函数都需要加这个功能,又该怎么办?
下面就是一个最简单的装饰器
装饰器的作用:
不想修改函数的调用方式 但是还想在原来的函数前后添加功能
装饰器的原则:
原则:(开放封闭原则开放:对扩展是开放的; 封闭:对修改是封闭的;)
语法糖:@
"""
第一步:def timmer(f)并且def inner() 都是先声明不掉用
第二步:@timmer 即 func = timmer(func) 此时的 f = func
第三步:return inner 即 func = inner 注意:inner不加括号
第四步:调用func()即调用inner(),此刻的f已经是fun,因此就实现了功能附加
"""
import time
def timmer(f):
def inner():
start = time.time()
f()
end = time.time()
print(end - start)
return inner
@timmer # @timmer 等价于 func = timmer(func)
def func():
print('这是一句话')
func()
3.给装饰器加上返回值,并且带多个参数
"""
第一步:声明wrapper
第二步:@wrapper 即func = wrapper(func)
第三步:return inner 即 func = inner
第四步:调用func(a,b)即调用inner(*args, **kwargs),并传入参数a,b
第五步:ret = f(*args, **kwargs) ret = ‘哈哈哈’ 并return ret
"""
def wrapper(f): 1
def inner(*args, **kwargs): 3(声明)
ret = f(*args, **kwargs) 6
return ret 8
return inner 4
@wrapper #语法糖 func = wrapper(func) 2
def func(a,b): 7
print('这是一个被装饰的函数',a,b)
return '哈哈哈'
func() 5
4.装饰器的固定模式形成
def wrappr(f):#f为被装饰函数
def inner(*args,**kwargs): #*args,**kwargs万能参数
ret = f(*args,**kwargs)
return ret
return inner
@wrapper #语法糖
二.装饰器进阶
1.带参数的装饰器
如果今天一万个函数需要使用装饰器,明天又不需要装饰器,后天又需要装饰器,该怎么办?
不能删了加,加了再删吧,因此引出了才参数的装饰器、
原理:在装饰器外再加在加一层装饰器 如:def timmer(func)外面加一层timmer_out(flag),然后在执行inner的通过判断flag的值来决定是否要附加功能。此时的语法糖也有所改变,原先是@timmer,加一层装饰器之后变成了@timmer_out(FLAG),其中FLAG为全局变量,@timmer_out(FLAG) 分为两步执行:第一步:timmer_out(FLAG) ,然后@接受返回值timmer,形成@timmer,而后执行步骤与不带参数的装饰器一样
带参数的装饰器主要目的是传入FLAG
import time
FLAG = False
def timmer_out(flag):
def timmer(func):
def inner(*args, **kwargs):
if flag:
start = time.time()
ret = func(*args, **kwargs)
end = time.time()
print(start - end)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer
# timmer = timmer_out(FLAG)
@timmer_out(FLAG)
def wahaha():
time.sleep(0.1)
print('hahahaha')
@timmer_out(FLAGE)
def erguotou():
time.sleep(0.1)
print('ttttt')
2.多个装饰器修饰一个函数(数字为执行步骤)
def wrapper1(func): 1
def inner1(): 4
print('wrapper1,before func') 15
func() 16
print('wrapper1,after func') 18
return inner1 5
def wrapper2(func): 2
def inner2(): 8
print('wrapper2,before func') 13
func() 14
print('wrapper2,after func') 19
return inner2 9
@wrapper2 7:f = wrapper2(inner) 10:f = inner2
@wrapper1 3:f = wrapper(f) 6:f=inner1
def f():
print('in f') 17
f() 11:inner2()
输出顺序如下:
三.其他
def timmer(f): # 装饰器函数
def inner(*args, **kwargs):
'''
******inner******
'''
start = time.time()
ret = f(*args, **kwargs) # 被装饰的函数
end = time.time()
print(end - start)
return ret
return inner
@timmer
def func(a, b):
"""
******func******
"""
print('大家好', a, b)
print(func.__name__)
print(func.__doc__)
输出结果:
可以发现装饰器装饰过的函数,用__name__以及__doc__方法输出的函数名以及注视都变成了inner,而非原函数的名字和注释
解决方法:
通过加入:
from functools import wraps
@wraps(f)
from functools import wraps
def timmer(f): # 装饰器函数
@wraps(f)
def inner(*args, **kwargs):
'''
******inner******
'''
start = time.time()
ret = f(*args, **kwargs) # 被装饰的函数
end = time.time()
print(end - start)
return ret
return inner
@timmer
def func(a, b):
"""
******func******
"""
print('大家好', a, b)
print(func.__name__)
print(func.__doc__)
输出结果: