Python功能點(diǎn)實(shí)現(xiàn):函數(shù)級(jí)/代碼塊級(jí)計(jì)時(shí)器
工程中我們常常需要對(duì)某一個(gè)函數(shù)或者一塊代碼計(jì)時(shí),從而監(jiān)測(cè)系統(tǒng)關(guān)鍵位置的性能。計(jì)時(shí)方法是在代碼塊前后分別記錄當(dāng)前系統(tǒng)時(shí)間,然后兩者相減得到代碼塊的耗時(shí)。最簡(jiǎn)單原始的實(shí)現(xiàn)類似:
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))
這種方式缺點(diǎn)明顯:假如系統(tǒng)內(nèi)有很多地方都需要計(jì)時(shí),那么每個(gè)地方都需要插入這樣的計(jì)時(shí)代碼,首先是重復(fù)性工作很麻煩,其次這樣會(huì)降低代碼的可讀性,干擾對(duì)業(yè)務(wù)邏輯的理解。本文將給出一些更好的實(shí)現(xiàn),主要涉及的技術(shù)是裝飾器(Decorator)和運(yùn)行時(shí)上下文(runtime context)。
基于裝飾器的函數(shù)級(jí)計(jì)時(shí)器
第一種計(jì)時(shí)器是比較常見(jiàn)的函數(shù)級(jí)計(jì)時(shí)器,通過(guò)裝飾器完成,將原函數(shù)改裝成擁有計(jì)時(shí)功能的新函數(shù),使其可以完成運(yùn)行原來(lái)函數(shù)和計(jì)時(shí)兩件事。在使用時(shí),只用在需要計(jì)時(shí)功能的函數(shù)代碼前加上類似@timer的語(yǔ)法糖,這樣每次調(diào)用原函數(shù)時(shí),運(yùn)行的將會(huì)是新函數(shù)。這樣就大大減少了重復(fù)性勞動(dòng)。
具體實(shí)現(xiàn)如下:
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))
基于上下文的代碼塊級(jí)計(jì)時(shí)器
裝飾器實(shí)現(xiàn)的計(jì)時(shí)器可以為函數(shù)添加計(jì)時(shí)功能,可以滿足大部分情況的需要,但是假如我們想要更靈活一些,對(duì)任意一段連續(xù)的代碼塊做計(jì)時(shí),怎樣做?使用原始的插計(jì)時(shí)代碼的方法顯然不是我們想要的;也可以將代碼塊重構(gòu)成一個(gè)函數(shù),再在上面加裝飾器,然而這就顯得不夠優(yōu)雅。因此我做出了下面的實(shí)現(xiàn)。
首先了解上下文管理的概念。大致是說(shuō)Python中允許創(chuàng)建一種叫上下文管理器(Context Manager)的對(duì)象,它可以管理一個(gè)代碼塊執(zhí)行時(shí)的上下文信息。具體的方法是創(chuàng)建一個(gè)類,并為其實(shí)現(xiàn)object.__enter__和object.__exit__方法,前者在進(jìn)入代碼塊時(shí)自動(dòng)執(zhí)行,后者在完成代碼塊執(zhí)行時(shí)自動(dòng)執(zhí)行。
在使用時(shí),通過(guò)with和as關(guān)鍵字,將__enter__的返回值綁定到某一個(gè)變量名,這個(gè)返回值里可以儲(chǔ)存代碼塊運(yùn)行過(guò)程中得到的一些信息,在這里就是運(yùn)行時(shí)間啦。具體的實(shí)現(xiàn)是創(chuàng)建一個(gè)計(jì)時(shí)器類Timer,在enter時(shí)記錄代碼塊運(yùn)行的開(kāi)始時(shí)間,exit時(shí)記錄完成時(shí)間、計(jì)算并儲(chǔ)存耗時(shí)到Timer實(shí)例中。在使用時(shí),將with Timer() as t加到要計(jì)時(shí)的代碼塊前面,t.elapse中將會(huì)儲(chǔ)存代碼塊耗時(shí),可以任意使用。
在這個(gè)基礎(chǔ)上,我們還可以做出一個(gè)裝飾器timer_來(lái)實(shí)現(xiàn)基于上下文的函數(shù)級(jí)計(jì)時(shí)器。
具體實(shí)現(xiàn)如下:
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))
更靈活的實(shí)現(xiàn)
更優(yōu)雅地,我們還可以使用contextlib自帶的ContextDecorator,參考官方示例,做出既可以with又可以作為裝飾器的計(jì)時(shí)器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)
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接
- Python 實(shí)現(xiàn)一個(gè)計(jì)時(shí)器
- python實(shí)現(xiàn)屏保計(jì)時(shí)器的示例代碼
- python中的計(jì)時(shí)器timeit的使用方法
- python實(shí)現(xiàn)簡(jiǎn)單的計(jì)時(shí)器功能函數(shù)
- python 實(shí)現(xiàn)一個(gè)圖形界面的匯率計(jì)算器
- 如何Tkinter模塊編寫(xiě)Python圖形界面
- python如何實(shí)現(xiàn)讀取并顯示圖片(不需要圖形界面)
- 健身房被搭訕?用python寫(xiě)了個(gè)小米計(jì)時(shí)器助人為樂(lè)
相關(guān)文章
python運(yùn)用sklearn實(shí)現(xiàn)KNN分類算法
這篇文章主要為大家詳細(xì)介紹了python運(yùn)用sklearn實(shí)現(xiàn)KNN分類算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10python數(shù)據(jù)分析必會(huì)的Pandas技巧匯總
用Python做數(shù)據(jù)分析光是掌握numpy和matplotlib可不夠,numpy雖然能夠幫我們處理處理數(shù)值型數(shù)據(jù),但很多時(shí)候,還有字符串,還有時(shí)間序列等,比如:我們通過(guò)爬蟲(chóng)獲取到了存儲(chǔ)在數(shù)據(jù)庫(kù)中的數(shù)據(jù),一些Pandas必會(huì)的用法,讓你的數(shù)據(jù)分析水平更上一層樓2021-08-08python?包實(shí)現(xiàn)?time?時(shí)間管理操作
這篇文章主要介紹了python包實(shí)現(xiàn)time時(shí)間管理操作,文章通過(guò)獲取當(dāng)前時(shí)間戳,即當(dāng)前系統(tǒng)內(nèi)表示時(shí)間的一個(gè)浮點(diǎn)數(shù),下文更多相關(guān)內(nèi)容需要的小伙伴可以參考一下2022-04-04詳解python多線程、鎖、event事件機(jī)制的簡(jiǎn)單使用
這篇文章主要介紹了詳解python多線程、鎖、event事件機(jī)制的簡(jiǎn)單使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04pytorch學(xué)習(xí)教程之自定義數(shù)據(jù)集
這篇文章主要給大家介紹了關(guān)于pytorch學(xué)習(xí)教程之自定義數(shù)據(jù)集的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11解決jupyter (python3) 讀取文件遇到的問(wèn)題
這篇文章主要介紹了解決jupyter (python3) 讀取文件遇到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03