今天小編就爲大家分享一篇關於Python功能點實現:函數級/代碼塊級計時器,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
工程中我們常常需要對某一個函數或者一塊代碼計時,從而監測系統關鍵位置的性能。計時方法是在代碼塊前後分別記錄當前系統時間,然後兩者相減得到代碼塊的耗時。最簡單原始的實現類似:
from datetime import datetime start = datetime.now() # some code you want to measure end = datetime.now() print("Processing time for {} is: {} seconds".format('You Name It', elapse))
這種方式缺點明顯:假如系統內有很多地方都需要計時,那麼每個地方都需要插入這樣的計時代碼,首先是重複性工作很麻煩,其次這樣會降低代碼的可讀性,干擾對業務邏輯的理解。本文將給出一些更好的實現,主要涉及的技術是裝飾器(Decorator)和運行時上下文(runtime context)。
基於裝飾器的函數級計時器
第一種計時器是比較常見的函數級計時器,通過裝飾器完成,將原函數改裝成擁有計時功能的新函數,使其可以完成運行原來函數和計時兩件事。在使用時,只用在需要計時功能的函數代碼前加上類似@timer的語法糖,這樣每次調用原函數時,運行的將會是新函數。這樣就大大減少了重複性勞動。
具體實現如下:
from datetime import datetime def timer(func): '''Function Level Timer via Decorator''' def timed(*args, **kwargs): start = datetime.now() result = func(*args, **kwargs) end = datetime.now() elapse = (end - start).total_seconds() print("Processing time for {} is: {} seconds".format(func.__name__, elapse)) return result return timed @timer def test_1(a): '''Function Level''' a *= 2 return a if __name__ == '__main__': print(test_1(1))
基於上下文的代碼塊級計時器
裝飾器實現的計時器可以爲函數添加計時功能,可以滿足大部分情況的需要,但是假如我們想要更靈活一些,對任意一段連續的代碼塊做計時,怎樣做?使用原始的插計時代碼的方法顯然不是我們想要的;也可以將代碼塊重構成一個函數,再在上面加裝飾器,然而這就顯得不夠優雅。因此我做出了下面的實現。
首先了解上下文管理的概念。大致是說Python中允許創建一種叫上下文管理器(Context Manager)的對象,它可以管理一個代碼塊執行時的上下文信息。具體的方法是創建一個類,併爲其實現object.__enter__和object.__exit__方法,前者在進入代碼塊時自動執行,後者在完成代碼塊執行時自動執行。
在使用時,通過with和as關鍵字,將__enter__的返回值綁定到某一個變量名,這個返回值裏可以儲存代碼塊運行過程中得到的一些信息,在這裏就是運行時間啦。具體的實現是創建一個計時器類Timer,在enter時記錄代碼塊運行的開始時間,exit時記錄完成時間、計算並儲存耗時到Timer實例中。在使用時,將with Timer() as t加到要計時的代碼塊前面,t.elapse中將會儲存代碼塊耗時,可以任意使用。
在這個基礎上,我們還可以做出一個裝飾器timer_來實現基於上下文的函數級計時器。
具體實現如下:
class Timer(object): '''Code Block Level Timer via Context''' def __enter__(self): self.start = datetime.now() return self def __exit__(self, *args): self.end = datetime.now() self.elapse = (self.end - self.start).total_seconds() def timer_(func): '''Function Level Timer via Context & with Statement''' def timed(*args, **kw): with Timer() as t: result = func(*args, **kw) print("Processing time for {} is: {} seconds".format(func.__name__, t.elapse)) return result return timed def test_2(a): '''Code Block Level''' with Timer() as t: a *= 2 print("Processing time for {} is: {} seconds".format('You Name It', t.elapse)) return a @timer_ def test_3(a): '''Function Level''' a *= 2 return a if __name__ == '__main__': print(test_2(2)) print(test_3(3))
更靈活的實現
更優雅地,我們還可以使用contextlib自帶的ContextDecorator,參考官方示例,做出既可以with又可以作爲裝飾器的計時器timer_elegant:
from datetime import datetime from contextlib import ContextDecorator class timer_elegant(ContextDecorator): '''Elegant Timer via ContextDecorator''' def __init__(self, name): self.name = name def __enter__(self): self.start = datetime.now() def __exit__(self, *args): self.end = datetime.now() self.elapse = (self.end - self.start).total_seconds() print("Processing time for {} is: {} seconds".format(self.name, self.elapse)) @timer_elegant('test_4') def test_4(a): a *= 2 return a def test_5(a): a *= 2 return a if __name__ == '__main__': print(test_4(4)) with timer_elegant('test 5'): result_5 = test_5(5) print(result_5)
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對神馬文庫的支持。如果你想了解更多相關內容請查看下面相關鏈接