python3装饰器例子_python 装饰器(三):装饰器实例(一)
示例 7-15 定義了一個裝飾器,它會在每次調用被裝飾的函數時計時,然后把經過的時間、傳入的參數和調用的結果打印出來。
示例 7-15 一個簡單的裝飾器,輸出函數的運行時間
importtimedefclock(func):def clocked(*args): #?
t0 =time.perf_counter()
result= func(*args) #?
elapsed = time.perf_counter() -t0
name= func.__name__arg_str= ','.join(repr(arg) for arg inargs)print('[%0.8fs] %s(%s) -> %r' %(elapsed, name, arg_str, result))returnresultreturn clocked #?
? 定義內部函數 clocked,它接受任意個定位參數。
? 這行代碼可用,是因為 clocked 的閉包中包含自由變量 func。
? 返回內部函數,取代被裝飾的函數。示例 7-16 演示了 clock 裝飾器的用法。
示例 7-16 使用 clock 裝飾器
#clockdeco_demo.py
importtimefrom clockdeco importclock
@clockdefsnooze(seconds):
time.sleep(seconds)
@clockdeffactorial(n):return 1 if n < 2 else n*factorial(n-1)if __name__=='__main__':print('*' * 40, 'Calling snooze(.123)')
snooze(.123)print('*' * 40, 'Calling factorial(6)')print('6! =', factorial(6))
運行示例 7-16 得到的輸出如下:
$ python3 clockdeco_demo.py**************************************** Calling snooze(123)
[0.12405610s] snooze(.123) ->None**************************************** Calling factorial(6)
[0.00000191s] factorial(1) -> 1[0.00004911s] factorial(2) -> 2[0.00008488s] factorial(3) -> 6[0.00013208s] factorial(4) -> 24[0.00019193s] factorial(5) -> 120[0.00026107s] factorial(6) -> 720
6! = 720
工作原理
記得嗎,如下代碼
@clockdeffactorial(n):return 1 if n < 2 else n*factorial(n-1)
其實等價于:
deffactorial(n):return 1 if n < 2 else n*factorial(n-1)
factorial= clock(factorial)
因此,在兩個示例中,factorial 會作為 func 參數傳給 clock(參見示例 7-15)。然后, clock 函數會返回 clocked 函數,Python 解釋器在背后會把 clocked 賦值給 factorial。
其實,導入clockdeco_demo 模塊后查看 factorial 的 __name__ 屬性,會得到如下結果:
>>> importclockdeco_demo>>> clockdeco_demo.factorial.__name__
'clocked'
>>>
所以,現在 factorial 保存的是 clocked 函數的引用。自此之后,每次調用 factorial(n),執行的都是 clocked(n)。clocked 大致做了下面幾件事。
(1) 記錄初始時間 t0。
(2) 調用原來的 factorial 函數,保存結果。
(3) 計算經過的時間。
(4) 格式化收集的數據,然后打印出來。
(5) 返回第 2 步保存的結果。
這是裝飾器的典型行為:把被裝飾的函數替換成新函數,二者接受相同的參數,而且(通常)返回被裝飾的函數本該返回的值,同時還會做些額外操作。
示例 7-15 中實現的 clock 裝飾器有幾個缺點:不支持關鍵字參數,而且遮蓋了被裝飾函數的 __name__ 和 __doc__ 屬性。示例 7-17 使用
functools.wraps 裝飾器把相關的屬性從 func 復制到 clocked 中。此外,這個新版還能正確處理關鍵字參數。
示例 7-17 改進后的 clock 裝飾器
#clockdeco2.py
importtimeimportfunctoolsdefclock(func):
@functools.wraps(func)def clocked(*args, **kwargs):
t0=time.time()
result= func(*args, **kwargs)
elapsed= time.time() -t0
name= func.__name__arg_lst=[]ifargs:
arg_lst.append(','.join(repr(arg) for arg inargs))ifkwargs:
pairs= ['%s=%r' % (k, w) for k, w insorted(kwargs.items())]
arg_lst.append(','.join(pairs))
arg_str= ','.join(arg_lst)print('[%0.8fs] %s(%s) -> %r' %(elapsed, name, arg_str, result))returnresultreturn clocked
functools.wraps 只是標準庫中拿來即用的裝飾器之一。下一節將介紹 functools 模塊中最讓人印象深刻的兩個裝飾器:lru_cache 和singledispatch。
總結
以上是生活随笔為你收集整理的python3装饰器例子_python 装饰器(三):装饰器实例(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux系统下安装USB无线网卡驱动方
- 下一篇: php sslbug,PHP错误抑制符(