前言前几天在看Flask框架,但不是很了解,所以回来补装饰器的功课。看了很多关于装饰器的文章,自己整理,把适合自己思路的方法和例子分享给大家。app=Flask(__name__)@app.route("/")defhello():返回“HelloWorld!”1.什么是装饰器?装饰器是Python语言中的一种高级语法。主要功能是处理一个函数、方法或类。它的作用是为已有的对象增加额外的功能,提高代码的可读性。装饰器是一种设计模式,用于有横切需求的场景,如插入日志、性能测试、事务处理等。2.装饰器的语法装饰器的语法如下:目前Python装饰器语法如下:@dec2@dec1deffunc(arg1,arg2,...):....returnfunx上面的代码相当于:deffunc(arg1,arg2,...):passfunc=dec2(dec1(func))装饰器可以使用def形式来定义。装饰器将可调用对象作为输入参数并返回一个新的可调用对象。装饰器创建了一个新的可调用对象,即return返回的函数funx。在新添加的函数中,我们可以添加我们需要的函数,通过调用原函数来实现原函数的功能。3.装饰器的使用3.1无参装饰器装饰器的定义很简单:defdeco(func):"""调用无参装饰器声明时,必须有一个参数,该参数将接收要被装饰的方法"""print"beforemyfunc()called."func()print"aftermyfunc()called."returnfunc@decodefmyfunc():print"myfunc()called."myfunc()myfunc()装饰器定义后,,,可以用过的。上面的装饰器在使用的时候有个问题,就是只调用了第一次,原来的函数又执行了一次。执行输出如下:beforemyfunc()called.myfunc()called.aftermyfunc()called.myfunc()called.--再执行一次函数的输出myfunc()called.--第二次调用,装饰器不生效保证每次调用新函数时,使用如下方法定义装饰器defdeco(func):"""调用无参装饰器声明时,必须有一个参数,该参数将接收到方法被装饰。"""def_deco():print"beforemyfunc()called."func()print"aftermyfunc()called."#returnfunc不需要返回funcretrun_deco@decodefmyfunc():print"myfunc()called."return'OK'myfunc()myfunc()函数的输出如下:beforemyfunc()called.myfunc()called.aftermyfunc()called.beforemyfunc()called.myfunc()called.aftermyfunc()called.如您所见,每次都会调用装饰器。3.2带参数函数的装饰器defdeco(func):def_deco(a,b):print("beforemyfunc()called.")ret=func(a,b)print("aftermyfunc()called.result:%s"%ret)returnreturn_deco@decodefmyfunc(a,b):print("myfunc(%s,%s)called."%(a,b))return+bmyfunc(1,2)myfunc(3,4)输出:beforemyfunc()called.myfunc()called.Aftermyfunc()called.result:3beforemyfunc()called.myfunc()called.Aftermyfunc()called.result:7内嵌函数的形参和返回值同原始函数,装饰函数返回一个内联包装函数。3.3带参装饰器defdecoWithArgs(arg):"""由于带参装饰器函数只会在应用时使用参数,调用时不会接收被装饰函数作为参数,因此必须返回一个装饰器函数,该装饰器函数将decoratedfunctionisencapsulated."""defnewDeco(func):#定义一个新的装饰器函数defreplaceFunc():#在装饰器函数中定义一个内嵌函数,里面封装了具体的操作print"Enterdecorator%s"%arg#额外的操作returnfunc()#调用装饰函数returnreplaceFuncreturnnewDeco#返回一个新的装饰函数@decoWithArgs("demo")defMyFunc():#应用@decoWithArgs修饰的方法print"EnterMyFunc"MyFunc()#调用装饰函数输出:nterdecoratordemoEnterMyFuncThissituation适用于原函数无参数,新增打印的情况。一个普遍适用的地方就是增加函数的打印日志。3.4装饰一个参数个数不确定的函数下面的例子是一个异步发送邮件的例子。函数的参数数据确定,装饰器实现邮件发送功能的异步发送。fromthreadingimportThreaddefasync(f):defwrapper(*args,**kwargs):thr=线程(target=f,args=args,kwargs=kwargs)thr.start()returnwrapper@asyncdefsend_async_email(msg):mail.send(msg)defsend_email(subject,sender,recipients,text_body,html_body):msg=Message(subject,sender=sender,recipients=recipients)msg.body=text_bodymsg.html=html_bodysend_async_email(msg)这个装饰器可以应用于所有需要异步的函数处理,实现很好的代码重用。3.5让装饰器带类参数classlocker:def__init__(self):print("locker.__init__()shouldbenotcalled.")@staticmethoddefacquire():print("locker.acquire()called.(这是静态方法)")@staticmethoddefrelease():print("locker.release()called.(Noobjectinstancerequired)")defdeco(cls):'''cls必须实现获取和释放静态方法'''def_deco(func):def__deco():print("before%scalled[%s]."%(func.__name__,cls))cls.acquire()try:returnfunc()finally:cls.release()return__decoreturn_deco@deco(locker)defmyfunc():print("myfunc()called.")myfunc()myfunc()输出是:beforemyfunccalled[__main__.locker].locker.acquire()called.(thisisstaticmethon)myfunc()called.locker.release()called.(do'tneedobject)beforemyfunccalled[__main__.locker].locker.acquire()called.(thisisstaticmethon)myfunc()called.locker.release()called.(do'tneedobject)装饰器总结当我们将装饰方法应用到一个方法时,在其实就是dec所指的函数代码块的入口点被修饰的函数名称被更改为指向被修饰方法返回的函数的入口点。由此我们可以使用装饰器来改变一个原来的函数的功能,增加各种操作,或者完全改变原来的实现。参考文章感谢以下大神:http://www.cnblogs.com/rhcad/archive/2011/12/21/2295507.htmlhttp://www.cnblogs.com/Jifangliang/archive/2008/07/22/1248313.htmlhttp://www.cnblogs.com/vamei/archive/2013/02/16/2820212.html
