Python多重装饰器

王朝学院·作者佚名  2016-08-27
窄屏简体版  字體: 小  |  中  |  大  |  超大  

多重装饰器,即多个装饰器修饰同一个对象【实际上并非完全如此,且看下文详解】

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的责任。

像上面这种,对代码有两种互不相干的检验时,就可以使用多重装饰器。

 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
© 2005- 王朝網路 版權所有 導航