多重裝飾器,即多個裝飾器修飾同一個對象【實際上並非完全如此,且看下文詳解】
1.裝飾器無參數:
1 >>> def first(func): 2 print '%s() was post to first()'%func.func_name 3 def _first(*args,**kw): 4 print 'Call the function %s() in _first().'%func.func_name 5 return func(*args,**kw) 6 return _first 7 8 9 >>> def second(func): 10 print '%s() was post to second()'%func.func_name 11 def _second(*args,**kw): 12 print 'Call the function %s() in _second().'%func.func_name 13 return func(*args,**kw) 14 return _second 15 16 17 >>> @first 18 @second 19 def test():return 'hello world' 20 21 test() was post to second() 22 _second() was post to first() 23 >>> test() 24 Call the function _second() in _first(). 25 Call the function test() in _second(). 26 'hello world' 27 >>>
實際上它是相當於下面的代碼:
1 >>> def test(): 2 return 'hello world' 3 4 >>> test=second(test) 5 test() was post to second() 6 >>> test 7 <function _second at 0x000000000316D3C8> 8 >>> test=first(test) 9 _second() was post to first() 10 >>> test 11 <function _first at 0x000000000316D358> 12 >>> test() 13 Call the function _second() in _first(). 14 Call the function test() in _second(). 15 'hello world' 16 >>>
2.裝飾器有參數:
1 >>> def first(printResult=False): 2 def _first(func): 3 print '%s() was post to _first()'%func.func_name 4 def __first(*args,**kw): 5 print 'Call the function %s() in __first().'%\ 6 func.func_name 7 if printResult: 8 print func(*args,**kw),'#print in __first().' 9 else: 10 return func(*args,**kw) 11 return __first 12 return _first 13 14 >>> def second(printResult=False): 15 def _second(func): 16 print '%s() was post to _second()'%func.func_name 17 def __second(*args,**kw): 18 print 'Call the function %s() in __second().'%\ 19 func.func_name 20 if printResult: 21 print func(*args,**kw),'#print in __second().' 22 else: 23 return func(*args,**kw) 24 return __second 25 return _second 26 27 >>> @first(True) 28 @second(True) 29 def test(): 30 return 'hello world' 31 32 test() was post to _second() 33 __second() was post to _first() 34 >>> test() 35 Call the function __second() in __first(). 36 Call the function test() in __second(). 37 hello world #print in __second(). 38 None #print in __first(). 39 >>>
如上,第35行輸出后調用__second(),而__second()中又調用了test()並print test(),而后返回__first()中繼續執行print,而這個print語句print的內容是__second()返回的None
它等同於:
>>> def test(): return 'hello world' >>> test=second(True)(test) test() was post to _second() >>> >>> test <function __second at 0x000000000316D2E8> >>> test=first(True)(test) __second() was post to _first() >>> test <function __first at 0x0000000003344C18> >>>
3.多重裝飾器的應用:
比如你是項目經理,你要求每一個代碼塊都必須有參數檢查ArgsType和責任檢查ResponsibilityRegister,這樣就需要兩個裝飾器對此代碼塊進行監督。
#coding=utf-8 import os,sys,re from collections import OrderedDict def ArgsType(*argTypes,**kwTypes): u'''ArgsType(*argTypes,**kwTypes) options=[('opt_UseTypeOfDefaultValue',False)] 以下為本函數相關的開關,並非類型檢驗相關的關鍵字參數,所有options: opt_UseTypeOfDefaultValue=>bool:False,為True時,將對沒有指定類型的帶默 認值的參數使用其默認值的類型 ''' def _ArgsType(func): #確定所有的parameter name argNames=func.func_code.co_varnames[:func.func_code.co_argcount] #確定所有的default parameter defaults=func.func_defaults if defaults: defaults=dict(zip(argNames[-len(defaults):],defaults)) else:defaults=None #將“參數類型關鍵字參數”中的所有“options關鍵字參數”提出 options=dict() for option,default in [('opt_UseTypeOfDefaultValue',False)]: options[option]=kwTypes.pop(option,default) #argTypes和kwTypes的總長度應該與argNames一致 if len(argTypes)+len(kwTypes)>len(argNames): raise Exception('Too much types to check %s().'%func.func_name) #所有kwTypes中的鍵不能覆蓋在argTypes中已經占用的names if not set(argNames[len(argTypes):]).issuperset( set(kwTypes.keys())): raise Exception('There is some key in kwTypes '+ 'which is not in argNames.') #確定所有的參數應該有的types types=OrderedDict() for name in argNames:types[name]=None if len(argTypes): for i in range(len(argTypes)): name=argNames[i] types[name]=argTypes[i] else: for name,t in kwTypes.items(): types[name]=t if len(kwTypes): for name,t in kwTypes.items(): types[name]=t #關於default parameter的type if options['opt_UseTypeOfDefaultValue']: for k,v in defaults.items(): #如果default parameter的type沒有另外指定,那么就使用 #default parameter的default value的type if types[k]==None: types[k]=type(v) def __ArgsType(*args,**kw): #order the args Args=OrderedDict() #init keys for name in argNames:Args[name]=None #init default values if defaults is not None: for k,v in defaults.items(): Args[k]=v #fill in all args for i in range(len(args)): Args[argNames[i]]=args[i] #fill in all keyword args for k,v in kw.items(): Args[k]=v #check if there is some None in the values if defaults==None: for k in Args: if Args[k]==None: if defaults==None: raise Exception(('%s() needs %r parameter, '+ 'which was not given')%(func.func_name,k)) else: if not defaults.has_key(k): raise Exception(('Parameter %r of %s() is'+ ' not a default parameter')%\ (k,func.func_name)) #check all types for k in Args: if not isinstance(Args[k],types[k]): raise TypeError(('Parameter %r of %s() must be '+ 'a %r object, but you post: %r')%\ (k,func.func_name,types[k],Args[k])) return func(*args,**kw) return __ArgsType return _ArgsType def ResponsibilityRegister(author): def _ResponsibilityRegister(func): def __ResponsibilityRegister(*args,**kw): try: return func(*args,**kw) except Exception as e: print ("Something is wrong, It's %s's responsibility."%\ author).center(80,'*') raise e return __ResponsibilityRegister return _ResponsibilityRegister @ResponsibilityRegister('Kate') @ArgsType(str,int) def left(Str,Len=1): return Str[:Len] print 'Good calling:' print left('hello world',8) print 'Bad calling:' print left(3,7)
這里沒有文檔,所以調用者不知道,使用了錯誤的調用,導致出錯,這是Kate的責任。
像上面這種,對代碼有兩種互不相干的檢驗時,就可以使用多重裝飾器。