装饰器可以使函数执行前和执行后分别执行其他的附加功能,这种在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator)
,装饰器的功能非常强大,装饰器一般接受一个函数对象作为参数,以对其进行增强,相当于C++中的构造函数,与析构函数。
装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有迫切需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景.装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用.
装饰器本身也是一个函数,其作用是,用于装饰其他函数.
装饰器是一个闭包函数是嵌套函数,通过外层函数提供嵌套函数的环境
装饰器在权限控制,增加额外功能,如增加记录日志,缓存处理,发送邮件用的比较多
6.1 无参装饰器 原函数中不带参数的装饰器,如下例子假设:我定义了一个函数lyshark()
,现在想要在不改变原来函数定义的情况下,在函数运行前打印一段话,函数运行后打印另一段话,此时我们可以使用装饰器的装饰功能来简单的实现这个需求.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (): print ("主函数开始执行前,会先执行我!" ) result=function() print ("主函数执行结束后,要在执行我!" ) return result return inner >>> @outerdef lyshark (): print ("lyshark 的主函数体,装饰器在装饰我(*^_^*)" ) return "check ok" >>> ret=lyshark()主函数开始执行前,会先执行我! lyshark 的主函数体,装饰器在装饰我(*^_^*) 主函数执行结束后,要在执行我! >>> print ("lyshark()函数的返回值: " ,ret)lyshark()函数的返回值: check
上方代码的执行流程是这样的,步骤如下:
1.当我们调用lyshark()函数时,会自动检查lyshark()函数上是否有装饰器
2.如果有则将lyshark()函数的指针,传递给装饰器outer(function)
3.outer(function)接到指针后,执行嵌套函数内的inner(),则先执行print打印一段话
4.由于lyshark()函数指针,传递给了function变量,执行function()则相当于执行lyshark()
5.接着最后一步执行打印一段结束的话,并执行返回,返回inner
6.2 有参装饰器 原函数带一个参数的装饰器: 我们在以上的案例中,给装饰器添加一个参数,并在内部使用这个参数.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (args ): print ("主函数开始执行前,会先执行我!" ) ret=function(args) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (args ): print (args) return 0 >>> ret=lyshark("hello world!" )主函数开始执行前,会先执行我! hello world! 主函数执行结束后,要在执行我! >>> print ("lyshark 的返回值是:" ,ret)lyshark() 函数的返回值是: 0
原函数带两个参数的装饰器: 接下来继续演示一下,带有两个参数的装饰器,3个4个,以此类推.
>>> import os>>> import sys>>> >>> >>> def outer (function ): def inner (x,y ): print ("主函数开始执行前,会先执行我!" ) ret=function(x,y) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (x,y ): print (x,y) return 0 >>> ret=lyshark("Hello" ,"LyShark" )主函数开始执行前,会先执行我! Hello LyShark 主函数执行结束后,要在执行我! >>> print ("lyshark() 函数的返回值是:" ,ret)lyshark() 函数的返回值是: 0
传递一个万能参数: 装饰器也可传递一个万能参数,通过此参数传递列表字典等.
>>> import os>>> import sys>>> >>> def outer (function ): def inner (*args,**kwargs ): print ("主函数开始执行前,会先执行我!" ) ret=function(*args,**kwargs) print ("主函数执行结束后,要在执行我!" ) return ret return inner >>> @outerdef lyshark (*args ): print (args) return 0 >>> num=[1 ,2 ,3 ,4 ,5 ]>>> ret=lyshark(num)主函数开始执行前,会先执行我! ([1 , 2 , 3 , 4 , 5 ],) 主函数执行结束后,要在执行我! >>> >>> print ("lyshark() 函数的返回值是:" ,ret)lyshark() 函数的返回值是: 0 @outer def lyshark_kw (*args,**kwargs ): print (args,kwargs) return 0 num=[1 ,2 ,3 ,4 ,5 ] kw={"1001" :"admin" ,"1002" :"guest" } ret=lyshark_kw(num,kw)
一次使用两个装饰器装饰函数: 如果一个装饰器不够用的话,我们可以使用两个装饰器,首先将函数与内层装饰器结合然后在与外层装饰器相结合,要理解使用@语法
的时候到底执行了什么,是理解装饰器的关键.
>>> import os>>> import sys>>> >>> def outer2 (function2 ): def inner2 (*args,**kwargs ): print ("装饰器2--->【开始】" ) ret=function2(*args,**kwargs) print ("装饰器2--->【结束】" ) return ret return inner2 >>> def outer1 (function1 ): def inner1 (*args,**kwargs ): print ("装饰器1--->【开始】" ) ret=function1(*args,**kwargs) print ("装饰器1--->【结束】" ) return ret return inner1 @outer2 @outer1 def lyshark (): print ("lyshark 函数被执行了" ) >>> lyshark()装饰器2 --->【开始】 装饰器1 --->【开始】 lyshark 函数执行了 装饰器1 --->【结束】 装饰器2 --->【结束】 @outer1 @outer2 def lyshark_and (): print ("lyshark_and 函数被执行了" ) >>> lyshark_and()装饰器1 --->【开始】 装饰器2 --->【开始】 lyshark_and 函数执行了 装饰器2 --->【结束】 装饰器1 --->【结束】
6.3 带参装饰器 前面的装饰器本身没有带参数,如果要写一个带参数的装饰器怎么办,那么我们就需要写一个三层的装饰器,而且前面写的装饰器都不太规范,下面来写一个比较规范带参数的装饰器,下面来看一下代码,大家可以将下面的代码自我运行一下.
给装饰器本身添加参数: 接下来我们将给装饰器本身添加一些参数,使其能够实现参数传递.
>>> import functools>>> import sys>>> >>> def lyshark (temp="" ): def decorator (function ): @functools.wraps(function ) def wrapper (*args,**kwargs ): print ("主函数开始执行前,会先执行我!" ) print ("{}:{}" .format (temp,function.__name__)) ret=function(*args,**kwargs) print ("主函数执行结束后,要在执行我!" ) return ret return wrapper return decorator >>> >>> @lyshark()def test (x ): print (x+100 ) >>> test(100 )主函数开始执行前,会先执行我! :test 主函数执行结束后,要在执行我! >>> >>> @lyshark("LyShark" )def test (x ): print (x+100 ) >>> test(100 )主函数开始执行前,会先执行我! LyShark:test 主函数执行结束后,要在执行我!
给装饰器本身添加参数: 接下来我们将给装饰器本身添加两个参数,使其能够传递多个参数.
>>> import sys>>> import os>>> >>> def lyshark (x="Hello" ,y="LyShark" ): def decorator (function ): def wrapper (): print ("主函数执行前,应先执行我!" ) print (x,y) ret=function() print ("主函数执行后,要执行我!" ) return ret return wrapper return decorator >>> >>> @lyshark()def test (): print ("我是test(),主函数,装饰器在装饰我" ) >>> test()主函数执行前,应先执行我! Hello LyShark 我是test(),主函数,装饰器在装饰我 主函数执行后,要执行我! >>> >>> @lyshark("My Name Is :" ,"LyShark" )def test (): print ("我是test(),主函数,装饰器在装饰我" ) >>> test()主函数执行前,应先执行我! My Name Is : LyShark 我是test(),主函数,装饰器在装饰我 主函数执行后,要执行我!