裝飾器其實就是對函數進行的一次包裝,渲染函數用的,例如下面這個最簡單的例子:
def say_hi(fn): def improve(): print("Welcome from decorator: ") fn() return improve @say_hi def hi(): print("hi there in hi function") hi()
在Python中,一個函數可以作為參數傳遞給另一個函數,因此,可否這麼考慮,我們把一個函數傳遞給另一個函數之後,
在這個被傳遞的函數的外部補充一些操作(裝飾),而後,把這個額外添加了補充裝飾的函數得新吐回來。使用裝飾器時,
就相當於把裝飾器符號下面定義的函數作為參數傳遞給前面的裝飾器對應的函數作為參數。
def timeit(fn): def warp(*args, **kwargs): print('----start------') fn(*args, **kwargs) print('----stop--------') return warp @timeit def hi(*args, **kwargs): for i in args: print('* {0}'.format(i)) for k, v in kwargs.items(): print('k/v: {0} ---> {1}'.format(k, v)) hi('a', 'b', 'c', name='topic', email='[email protected]')
# 這樣一看似乎很難理解,下面拆分一下進行理解:
# hi()函數執行的時候,
# 1. 首先第一步會調用timeit函數,timeit(hi) 此時hi函數作為參數傳入了timeit函數,
# 即 tmp = timeit(hi), 可以使用type(tmp)看下返回值是function,即warp函數
#
# 2. 執行warp函數: 首先會打印start,隨後執行1步驟中傳入的函數,最後再打印stop
#
# 至此,函數執行完畢.
# PS : *args 和 **args是作為函數的 可變位置參數和可變關鍵字參數.
# warp 函數中的fn(*args, **args) 稱為解包.
# 裝飾器等同於這樣調用: timeit(hi)('a', 'b', 'c', name='topic', email='[email protected]')
第二版: (添加傳入函數的返回值)
def timeit(fn): def warp(*args, **kwargs): print('----start------') ret=fn(*args, **kwargs) print('----stop--------') return ret return warp #@timeit def hi(*args, **kwargs): for i in args: print('* {0}'.format(i)) for k, v in kwargs.items(): print('k/v: {0} ---> {1}'.format(k, v)) @timeit def add(x, y): return x + y a=add(5, 6) print(a)