多重装饰器,即多个装饰器修饰同一个对象【实际上并非完全如此,且看下文详解】
1.装饰器无参数:
1>>>deffirst(func):2PRint'%s() was post to first()'%func.func_name3def_first(*args,**kw):4print'Call the function %s() in _first().'%func.func_name5returnfunc(*args,**kw)6return_first789>>>defsecond(func):10print'%s() was post to second()'%func.func_name11def_second(*args,**kw):12print'Call the function %s() in _second().'%func.func_name13returnfunc(*args,**kw)14return_second151617>>>@first18@second19deftest():return'hello world'2021test() was post to second()22_second() was post to first()23>>>test()24Call the function _second()in_first().25Call the function test()in_second().26'hello world'27>>>
实际上它是相当于下面的代码:
1>>>deftest():2return'hello world'34>>> test=second(test)5test() was post to second()6>>>test7<function _second at 0x000000000316D3C8>8>>> test=first(test)9_second() was post to first()10>>>test11<function _first at 0x000000000316D358>12>>>test()13Call the function _second()in_first().14Call the function test()in_second().15'hello world'16>>>
2.装饰器有参数:
1>>>deffirst(printResult=False):2def_first(func):3print'%s() was post to _first()'%func.func_name4def__first(*args,**kw):5print'Call the function %s() in __first().'%\6func.func_name7ifprintResult:8printfunc(*args,**kw),'#print in __first().'9else:10returnfunc(*args,**kw)11return__first12return_first1314>>>defsecond(printResult=False):15def_second(func):16print'%s() was post to _second()'%func.func_name17def__second(*args,**kw):18print'Call the function %s() in __second().'%\19func.func_name20ifprintResult:21printfunc(*args,**kw),'#print in __second().'22else:23returnfunc(*args,**kw)24return__second25return_second2627>>>@first(True)28@second(True)29deftest():30return'hello world'3132test() was post to _second()33__second() was post to _first()34>>>test()35Call the function__second()in__first().36Call the function test()in__second().37hello world#print in __second().38None#print in __first().39>>>
如上,第35行输出后调用__second(),而__second()中又调用了test()并print test(),而后返回__first()中继续执行print,而这个print语句print的内容是__second()返回的None
它等同于:
>>>deftest():return'hello world'>>> test=second(True)(test)
test() was post to _second()>>>
>>>test<function__secondat 0x000000000316D2E8>
>>> test=first(True)(test)__second() was post to _first()>>>test<function__firstat 0x0000000003344C18>
>>>
3.多重装饰器的应用:
比如你是项目经理,你要求每一个代码块都必须有参数检查ArgsType和责任检查ResponsibilityRegister,这样就需要两个装饰器对此代码块进行监督。
#coding=utf-8importos,sys,refromcollectionsimportOrderedDictdefArgsType(*argTypes,**kwTypes):
u'''ArgsType(*argTypes,**kwTypes)
options=[('opt_UseTypeOfDefaultValue',False)]
以下为本函数相关的开关,并非类型检验相关的关键字参数,所有options:
opt_UseTypeOfDefaultValue=>bool:False,为True时,将对没有指定类型的带默
认值的参数使用其默认值的类型'''def_ArgsType(func):#确定所有的parameter nameargNames=func.func_code.co_varnames[:func.func_code.co_argcount]#确定所有的default parameterdefaults=func.func_defaultsifdefaults:
defaults=dict(zip(argNames[-len(defaults):],defaults))else:defaults=None#将“参数类型关键字参数”中的所有“options关键字参数”提出options=dict()foroption,defaultin[('opt_UseTypeOfDefaultValue',False)]:
options[option]=kwTypes.pop(option,default)#argTypes和kwTypes的总长度应该与argNames一致iflen(argTypes)+len(kwTypes)>len(argNames):raiseException('Too much types to check %s().'%func.func_name)#所有kwTypes中的键不能覆盖在argTypes中已经占用的namesifnotset(argNames[len(argTypes):]).issuperset(
set(kwTypes.keys())):raiseException('There is some key in kwTypes'+'which is not in argNames.')#确定所有的参数应该有的typestypes=OrderedDict()fornameinargNames:types[name]=Noneiflen(argTypes):foriinrange(len(argTypes)):
name=argNames[i]
types[name]=argTypes[i]else:forname,tinkwTypes.items():
types[name]=tiflen(kwTypes):forname,tinkwTypes.items():
types[name]=t#关于default parameter的typeifoptions['opt_UseTypeOfDefaultValue']:fork,vindefaults.items():#如果default parameter的type没有另外指定,那么就使用#default parameter的default value的typeiftypes[k]==None:
types[k]=type(v)def__ArgsType(*args,**kw):#order the argsArgs=OrderedDict()#init keysfornameinargNames:Args[name]=None#init default valuesifdefaultsisnotNone:fork,vindefaults.items():
Args[k]=v#fill in all argsforiinrange(len(args)):
Args[argNames[i]]=args[i]#fill in all keyWordargsfork,vinkw.items():
Args[k]=v#check if there is some None in the valuesifdefaults==None:forkinArgs:ifArgs[k]==None:ifdefaults==None:raiseException(('%s() needs %r parameter,'+'which was not given')%(func.func_name,k))else:ifnotdefaults.has_key(k):raiseException(('Parameter %r of %s() is'+'not a default parameter')%\
(k,func.func_name))#check all typesforkinArgs:ifnotisinstance(Args[k],types[k]):raiseTypeError(('Parameter %r of %s() must be'+'a %r object, but you post: %r')%\
(k,func.func_name,types[k],Args[k]))returnfunc(*args,**kw)return__ArgsTypereturn_ArgsTypedefResponsibilityRegister(author):def_ResponsibilityRegister(func):def__ResponsibilityRegister(*args,**kw):try:returnfunc(*args,**kw)exceptException as e:print("Something is wrong, It's %s's responsibility."%\
author).center(80,'*')raiseereturn__ResponsibilityRegisterreturn_ResponsibilityRegister
@ResponsibilityRegister('Kate')
@ArgsType(str,int)defleft(Str,Len=1):returnStr[:Len]print'Good calling:'printleft('hello world',8)print'Bad calling:'printleft(3,7)
这里没有文档,所以调用者不知道,使用了错误的调用,导致出错,这是Kate的责任。
像上面这种,对代码有两种互不相干的检验时,就可以使用多重装饰器。