一、装饰器
装饰器即不改变原函数代码及调用方式的基础上为原函数添加新的功能,即装饰器,装饰器对原函数是完全透明的
什么是函数的装饰器
装饰器指的是定义一个函数的,该函数是用来为其他函数添加额外的功能
为什么要用装饰器
开发要遵循开放封闭的原则
开放:指的是对拓展功能是开发的
封闭:指的是对修改源代码是封闭的
装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能
需求:在不修改dls函数的源代码以及调用方式的前提下为其添加统计运行时间功能
方案一:失败
没有修改被装饰队形的调用但是修改了其源代码
import time
def dls(x, y):
start = time.time()
time.sleep(3)
print(x, y)
stop = time.time()
enable = stop - start
print(enable)
dls(10, 20)
方案二:没有修改函数对象的调用方式,也没有变动函数体代码,但是出现了代码冗余的现象
import time
def dls(x, y):
time.sleep(3)
print(x, y)
start=time.time()
dls(10, 20)
stop=time.time()
print(stop - start)
start=time.time()
dls(110, 120)
stop=time.time()
print(stop - start)
方案三:解决了代码冗余问题,新问题是函数的调用方式改变,本来人家调用的dls
import time
def dls(x, y):
time.sleep(3)
print(x, y)
def wrapper(z, q):
start = time.time()
dls(z, q)
stop = time.time()
print(stop - start)
wrapper(1, 20)
方案四:解决方案三的调用问题,对方案三的定义传值做了一个优化,将dls参数写活了。
import time
def dls(x, y, z):
time.sleep(3)
print(x, y, z)
def wrapper(*args, **kwargs):
start = time.time()
dls(*args, **kwargs)
stop = time.time()
print(stop - start)
wrapper(1, 20, 222)
方案五:我们定义的的wrapper只能提供给dls使用,我们需要吧dls(*args, **kwargs)写活
import time
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
def yan(name):
time.sleep(2)
print('welcome %s to home page' % name)
def outter(dls):
def wapper(*args,**kwargs):
dls(*args,**kwargs)
return wapper
home=outter(home) #属于是偷梁换柱
home('dls')
yan=outter(yan)
yan('yanls')
方案六:完全实现需求
import time
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
return 123
def outter(func):
# 偷梁换柱:home这个名字指向的是wrapper函数的内存地址。所以返回值无法返回。需要将函数整体定义成res这样才会返回所有调用内容
def wrapper(*args, **kwargs):
start = time.time()
res=func(*args, **kwargs)
stop = time.time()
print(stop - start)
return res
return wrapper
home=outter(home)
home('dls')
res = home('dls')
print(res)
语法糖:实现功能
import time
def timmer(func):
def wrapper(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
stop = time.time()
print(stop - start)
return res
return wrapper
# 在被装饰对象正上方的单独一行写@装饰名字
@timmer # @outter # home=timmer(home)
def home(name):
time.sleep(2)
print('welcome %s to home page' % name)
return 123
home('dls')
res=home('dls')
print(res)
无参函数装饰器模板
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
#调用原函数
# 为其增加新功能
return res
return wrapper
装饰器属性的概念
from functools import wraps # 给装饰器内部添加所有属性
def outter(func):
@wraps(func)
def wrapper(*args,**kwargs):
# 手动将原函数的属性赋值给wrapper函数,但是考虑到方法比较多我们采用from的方式
# wrapper.__name__ = func.__name__
# wrapper.__doc__ = func.__doc__
res=func(*args,**kwargs) # res=index(1,2)
return res
return wrapper
@outter # index=outter(index)
def index(x,y):
"""这个是函数的主页功能"""
print(x,y)
#
# index.__name__ = 'index'
# index.__doc__ = 'index'
index(1,2)
print(index.__doc__)
# print(index.__name__) # __name__查询函数名
# print(help(index))
# 偷梁换柱,即将原函数名指向的内存地址偷梁换柱成wrapper函数
# 所以应该将wrapper做的跟原函数一样才行