python 學習彙總23:裝飾器 decorator( tcy)
阿新 • • 發佈:2018-11-19
裝飾器 decorator 2018 / 8 / 11 ================================================================== 1.1.定義: # 在程式碼執行期間動態增加功能的方式,稱之為裝飾器Decorator # decorator是一個返回函式的高階函式;函式賦值給變數,通過變數呼叫該函式。 ================================================================== 1.2.例 # 例項1:定義decorator無引數: import functools def log(func): print('裝飾器開始...') @functools.wraps(func) def inner(*args, **kwargs): print('ready call add...') return func(*args, **kwargs) # 無返回值可省略return return inner @log # 相當於add=log(add) def add(a, b): print('runing add...' ) return a + b #呼叫 print('a+b= %s' % add(2, 4)) #裝飾器開始... #ready call add... #runing add... #a+b= 6 # 例項2:裝飾器輸入引數 import functools def log(name='Tom'): print('裝飾器開始...') def inner_log(func): print('inner_log start...') def inner(*args, **kwargs): inner.__name__ = func.__name__ print('%s ready call %s...' % (name,inner.__name__)) return func(*args, **kwargs) return inner return inner_log @log('John') # add = log('John')(add) def add(a, b): print('runing add...') return a + b #呼叫: print('a+b= %s' % add(2, 4)) # 裝飾器開始... # inner_log start... # John ready call add... # runing add... # a+b= 6 # 例項3:協程 def coroutine(func): def start(*args, **kwargs): g = func(*args, **kwargs) next(g) return g return start @coroutine def receiver(): print('ready to receive') while True: n = (yield) print('got %s' % n) #呼叫: r = receiver() r.send('hello world') #ready to receive # got hello world =================================================================== 2.類裝飾器 #裝飾器函式是一個介面約束,必須接受callable物件作為引數,返回callable物件。 #callable物件是函式,物件重寫call方法 #例項1:無引數類裝飾器 class log (object): def __init__(self, func): print('func name = %s ' % func.__name__) self.__func = func def __call__(self, *args, **kwargs): print('裝飾器開始...') return self.__func(*args, **kwargs) @log def add(x, y): print('runing add...' ) return x + y #呼叫: print('add()=', add(2, 4)) #func name = add #裝飾器開始... #runing add... #add()= 6 #例項2:帶引數類裝飾器 class log(object): def __init__(self, level='INFO'): self.level = level def __call__(self, func): # 接受函式 def wrapper(*args, **kwargs): print("裝飾器{}開始...[ enter function {}()]".format( self.level,func.__name__)) func(*args, **kwargs) return wrapper # 返回函式 @log('INFO') def add(x,y): print("runing add...[z={}]".format(x+y)) #呼叫: add(2,3) # 裝飾器INFO開始...[ enter function add()] # runing add...[z=5] ================================================================= 3.兩個裝飾器執行流程 def log1(func): print('----a----') def inner(*args, **kwargs): print('----1----') return ('log1=%s' % func(*args, **kwargs)) return inner def log2(func): print('----b----') def inner(*args, **kwargs): print('----2----') return ('log2=%s' % func(*args, **kwargs)) return inner @log1 @log2 def add(x, y): print('----3----') return x + y #呼叫: ret = add(2, 4) print(ret) ##輸出結果: #----b---- #----a---- #----1---- #----2---- #----3---- #log1=log2=6 # """ 說明: 1)先用第二個裝飾器(log2)進行裝飾再用第一個裝飾器(log1)進行裝飾 呼叫過程中,先執行第一個裝飾器(log1),接著再執行第二個裝飾器(log2)。 2)裝飾時機 在執行到 @ log1時,需要對下面的函式進行裝飾,此時直譯器繼續往下走, 發現並不是一個函式名,而又是一個裝飾器,這時@log1裝飾器暫停執行 , 執行接下來裝飾器 @ log2,接著把add函式名傳入裝飾器函式從而列印’b’ 在log2裝飾完後此時add指向log2的inner函式地址,這時返回來執行 @ log1 接著把新add傳入log1裝飾器函式中,因此列印了’a’。 呼叫add函式的時候,根據上述分析,此時add指向log1.inner函式,因此會 先列印‘1‘,接下來,在呼叫func()的時候,其實是呼叫的log2.inner()函式, 所以列印‘2‘,在log2.inner中,呼叫的func其實才是我們最原聲的add函式, 所以列印原add函式中的‘3‘,所以在一層層調完之後,列印的結果為 log1 = log2 = 6 """ ================================================================= 4.other 4.1.裝飾器函式—傳遞文件說明 def wrap(func): def call(*args,**kwargs): return func(*args,**kwargs) call.__doc__=func.__doc__ call.__name__=func.__name__ return call ================================================================= 4.2. from functools import wraps #模組@wraps(func)裝飾器可以將屬性從func傳遞給要定義的包裝器函式 def wrap(func): @wraps(func) def call(*args,**kwargs): return func(*args,**kwargs) return call @wrap def factorial(n): """tcy define function used wraps.""" # 呼叫: help(factorial) # 結果: # Help on function factorial in module __main__: # factorial(n) # tcy define function used wraps. ================================================================ 4.3.#函式屬性 def wrap(func): def call(*args,**kwargs): return func(*args,**kwargs) call.__doc__=func.__doc__ call.__name__=func.__name__ call.__dict__.update(func.__dict__) return call @wrap def foo(): 'foo function define' pass #呼叫: foo.secure=1 foo.private=1 help(foo) print(foo.__dict__) # 結果 ''''''''' Help on function foo in module __main__: foo(*args, **kwargs) foo function define {'secure': 1, 'private': 1} ''' =================================================================