装饰器模式,装饰器python的通俗理解
Yyds干货库存
Decorator介绍了为什么decorator软件的设计要遵循开闭原则,即对扩展开放,对修改封闭。对扩展开放意味着当有新的需求或变化时,现有的代码可以被扩展以适应新的情况。封闭修改是指对象一旦被设计出来,就可以独立完成工作,不需要修改。
软件中包含的所有函数的源代码和调用方法都应该避免被修改,否则一旦错误被改正,很有可能会产生连锁反应,最终导致程序的崩溃。对于在线软件,新的需求或变化层出不穷,所以我们必须为程序提供扩展的可能性,所以我们使用装饰器。
什么是室内设计师?“装饰”是指给被装饰的对象添加新的功能,“实现”是指器具/工具。装饰者和被装饰的对象可以是任何可调用的对象。一般来说,装饰器的作用是在不修改被装饰对象的源代码和调用方式的情况下,给被装饰对象增加额外的功能。Decorators常用于有截止需求的场景,比如日志插入、性能测试、事务处理、缓存、权限检查等应用场景。装修工是解决这类问题的优秀设计。有了decorators,大量与函数本身无关的完全相同的代码可以被提取出来并重用。
提示:可调用对象是函数、方法或类。
decorator Decorators的实现函数可以分为无参数decorator和无参数decorator两种,两者实现原理相同,都是‘函数嵌套闭包函数对象’结合的产物。
无参数装饰导入时间的实现
定义索引():
时间.睡眠(3)
打印(“欢迎使用索引页”)
返回200
Index() #函数执行遵循不修改被修饰对象源代码的原则,我们想到的解决方案可能如下
start_time=time.time()
Index() #函数执行
stop_time=time.time()
打印(运行时间为%s %(停止时间-开始时间))
考虑到可以统计其他函数的执行时间,我们把它做成一个单独的工具。函数体需要外部传入修饰函数进行调用,我们可以作为参数传入。
Def le(func): #通过参数接收外部值
start_time=time.time()
res=le()
stop_time=time.time()
打印(运行时间为%s %(停止时间-开始时间))
返回res,但是在这之后,函数的调用方法需要改为
乐(指数)
Le(其他函数)这违反了被修饰对象的调用模式不可修改的原则,所以我们改变了函数体的传值方式,也就是将值包装到函数中,如下所示
定义定时器(功能):
Def le(): #引用外部作用域的变量func
start_time=time.time()
res=func()
stop_time=time.time()
打印(运行时间为%s %(停止时间-开始时间))
返回资源
Return le可以在不修改修饰函数的源代码和调用方式的情况下,在修饰函数中增加计时的功能,但只需要提前执行一次timer传入修饰函数,并返回一个闭包函数le重新赋给变量名/函数名索引,如下
索引=计时器(索引)
Index()到目前为止,我们已经实现了一个无参数装饰定时器,它可以在不修改其源代码和调用方式的情况下,向装饰对象索引添加新的函数。但是我们忽略了,如果修饰函数是参数函数,会抛出异常。
定义家庭(姓名):
时间.睡眠(5)
打印(“欢迎来到主页”,姓名)
主页=计时器(主页)
家(了)
#抛出异常
类型错误:wrapper()接受0个位置参数,但1wasgiven引发了异常,因为home(le le )调用的实际上是ler (le ),并且包装函数没有参数。包装函数接收的参数实际上是针对原始func的。为了满足装饰函数的参数的所有条件,使用args *kwargs组合(参见4.3节),因此装饰器的计时器修改如下
ef定时器(功能):
def le(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
打印(运行时间为%s %(停止时间-开始时间))
返回资源
Return le在这一点上,我们可以用timer来修饰有参数或者没有参数的函数。但是,为了简洁优雅地使用decorator,Python提供了一种特殊的decorator语法来代替index=timer(index)的形式。您需要将@timer添加到装饰对象正上方的单独一行中。解释器解释@timer的时候会调用timer函数,它正下方的函数名会作为参数传入,然后返回的结果会重新赋给原来的。
@timer # index=timer(索引)
定义索引():
时间.睡眠(3)
打印(“欢迎使用索引页”)
返回200
@ timer # index=timer(home)def home(name):
时间.睡眠(5)
Print(欢迎来到主页,name)如果我们有多个装饰者,我们可以叠加多个。
@deco3
@deco2
@deco1
定义索引():
在pass上叠加多个decorators并没有什么特别的。上面的代码语义如下:
Index=deco3(deco2(deco1(index))参数化decorator的实现在了解了无参数decorator的实现原理之后,我们就可以实现另一个decorator来为被修饰的对象添加认证功能了。实现的基本形式如下
def deco(功能):
def wc(*args,**kwargs):
编写基于文件的身份验证。如果认证通过,将执行res=func(*args,**kwargs)并返回res。
返回wc如果要提供多种不同的认证方式供选择,从wc函数实现的角度重新编写如下即可
def deco(功能):
def wc(*args,**kwargs):
if driver==file :
编写基于文件的身份验证。如果认证通过,将执行res=func(*args,**kwargs)并返回res。
elif driver==mysql :
编写基于mysql的认证。如果认证通过,执行res=func(*args,**kwargs)并返回res。
返回wc函数需要一个驱动参数,而函数deco和wc的参数都有自己特定的函数,不能用来接受其他类型的参数。可以在deco外面包装一层函数auth专门接受附加参数,这样就保证了无论auth函数中有多少层都可以被引用。
定义验证(驱动程序):
def deco(功能):
……
在这一点上,我们已经实现了一个参数装饰器,它可以如下使用
先调用auth_type(driver=file )得到@deco,这是一个闭包函数,
包含对外部作用域名驱动程序的引用,并且@deco的语法意义与无参数修饰符的语法意义相同。
@auth(driver=file )
定义索引():
及格
@auth(driver=mysql )
def home():
Pass可以使用help(函数名)查看函数的文档注释,本质上是查看函数的doc属性,但是对于修饰函数,查看文档注释。
@定时器
定义家庭(姓名):
主页功能
:参数名称:字符串
:返回:无
时间.睡眠(5)
打印(“欢迎来到主页”,姓名)
打印(帮助(主页))
打印结果:
模块__main__中函数包装器的帮助:
包装(*args,**kwargs)
无一装修后,home=wc。看home.name,还可以发现home的函数名确实是wc。如果希望保留原始函数的文档和函数名属性,需要修改装饰器。
定义定时器(功能):
def wc(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
打印(运行时间为%s %(停止时间-开始时间))
返回资源
包装纸。__doc__=func。__doc__
包装纸。__name__=func。__姓名_ _
返回厕所
转载请联系作者获得授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。