python第44課練習(xí)—魔法方法:簡單定制(計(jì)時(shí)器的類)

1税弃、按照課堂中的程序降盹,如果開始計(jì)時(shí)的時(shí)間是(2022年2月26日16:30:30)馅笙,停止時(shí)間是(2025年1月23日15:30:30)骏令,那按照我們用停止時(shí)間減去開始時(shí)間的計(jì)算方式就會(huì)出現(xiàn)負(fù)數(shù)蔬捷,你應(yīng)該如何對此進(jìn)行一些轉(zhuǎn)換?

參考代碼:

import time as t

class MyTimer():
    def __init__(self):
        self.unit = ['年','月','天','小時(shí)','分鐘','秒']
        self.borrow = [0,12,31,24,60,60] # 新增
        self.prompt = '未開始計(jì)時(shí)榔袋!'
        self.lasted = []
        self.begin = 0
        self.end = 0

    def __str__(self):
        return self.prompt
    
    __repr__=__str__

    def __add__(self,other):    # 可以計(jì)算多個(gè)計(jì)時(shí)結(jié)果的和
        prompt = '總共運(yùn)行了'
        result = []
        for index in range(6):
            result.append(self.lasted[index])
            if result[index]:
                prompt += (str(result[index]) + self.unit[index])
        return prompt

    # 開始計(jì)時(shí)
    def start(self):
        self.begin = t.localtime()
        self.prompt = '提示周拐,請先調(diào)用stop()停止計(jì)時(shí)!'
        print('計(jì)時(shí)開始....')

    # 停止計(jì)時(shí)
    def stop(self):
        if not self.begin:  # if后面為真(1)才執(zhí)行
            print('提示:請先調(diào)用start()進(jìn)行計(jì)時(shí)凰兑!')
        else:
            self.end = t.localtime()
            self._calc()
            print('計(jì)時(shí)結(jié)束妥粟!')
            
    # 內(nèi)部方法,計(jì)算運(yùn)行時(shí)間
    def _calc(self):
        self.lasted = []
        self.prompt = '總共運(yùn)行了'
        for index in range(6):  # 這里新增修改
            temp = self.end[index] - self.begin[index]
            # 低位不夠減吏够,需向高位借位
            if temp < 0:
                # 測試高位是否有得“借”勾给,沒得借的話再向高位借....
                i = 1
                while self.lasted[index - i] < 1:
                    self.lasted[index - i] += self.borrow[index - i] - 1 # 高位-1
                    self.lasted[index - i -1] -= 1
                    i += 1

                    self.lasted.append(self.borrow[index] + temp)
                    self.lasted[index - 1] -= 1
            else:
                self.lasted.append(temp)
                
        # 由于高位隨時(shí)會(huì)被借位,所以打印要放在最后
        for index in range(6):
            if self.lasted[index]:
                self.prompt += str(self.lasted[index]) + self.unit[index]
                
        # 為下一輪計(jì)時(shí)初始化變量
        self.begin = 0
        self.end = 0 

借位那里還需要再理解理解锅知。

2播急、改進(jìn)課堂中的例子,這次使用perf_counter()和process_time()作為計(jì)時(shí)器售睹。另外增加一個(gè)set_timer()桩警,方法,用于設(shè)置默認(rèn)計(jì)時(shí)器(默認(rèn)是perf_counter()昌妹,可以通過此方法修改為process_time())

相信大家已經(jīng)意識到不對勁了:為什么一個(gè)月一定要有31天捶枢?不知道有可能也是30或29天嗎握截?(上一題我們的答案是假設(shè)一個(gè)月有31天)

image.png

答:沒錯(cuò),如果要正確得到月份的天數(shù)柱蟀,我們還需要考慮是否閏年川蒙,還有每月的最大天數(shù),所以太麻煩了.....如果我們不及時(shí)糾正长已,就會(huì)再錯(cuò)誤的道路上越走越遠(yuǎn)......

所以畜眨,這一次小甲魚提出了更優(yōu)秀的解決方案(Python官方推薦使用):用time模塊的perf_counter()process_time()來計(jì)算,其中perf_counter()返回計(jì)時(shí)器的精準(zhǔn)時(shí)間(系統(tǒng)運(yùn)行的時(shí)間)术瓮;process_time()返回當(dāng)前進(jìn)程執(zhí)行CPU的時(shí)間總和康聂。
參考代碼:

import time as t

class MyTimer:
    def __init__(self):
        self.prompt = '未開始計(jì)時(shí)!'
        self.lasted = 0.0
        self.begin = 0
        self.end = 0
        self.default_timer = t.perf_counter

    def __str__(self):
        return self.prompt

    __repr__ = __str__

    def __add__(self,other):
        result = self.lasted + other.lasted
        prompt = '總共運(yùn)行了 %0.2f 秒' % result
        return prompt

    # 開始計(jì)時(shí)
    def start(self):
        self.begin = self.default_timer()
        self.prompt = '提示:請先調(diào)用 stop() 停止計(jì)時(shí)胞四!'
        print('計(jì)時(shí)開始....')

    # 停止計(jì)時(shí)
    def stop(self):
        if not self.begin:
            print('提示:請先調(diào)用 start() 計(jì)時(shí)恬汁!')
        else:
            self.end = self.default_timer()
            self._calc()
            print('計(jì)時(shí)結(jié)束!')

    # 內(nèi)部方法辜伟,計(jì)算運(yùn)行時(shí)間
    def _calc(self):
        self.lasted = self.end - self.begin
        self.prompt = '總共運(yùn)行了 %0.2f 秒' % self.lasted

        # 為下一輪計(jì)時(shí)初始化變量
        self.begin = 0
        self.end = 0

    # 設(shè)置計(jì)時(shí)器(time.perf_counter()或 time.process_time())
    
def set_timer(self,timer):
        if timer == 'process_time':
            self.default_timer = t.process_time
        elif timer == 'perf_counter':
            self.default_timer = t.perf_counter
        else:
            print('輸入無效氓侧,請輸入perf_counter 或process_time')

3、既然已經(jīng)到了這一步导狡,那不如再深入一下约巷。再次改進(jìn)我們的代碼,讓它能夠統(tǒng)計(jì)一個(gè)函數(shù)運(yùn)行的若干次的時(shí)間旱捧。

  • 要求一:函數(shù)調(diào)用次數(shù)可以設(shè)置(默認(rèn)是1000000次)
  • 要求二:新增一個(gè)timing()方法独郎,用于啟動(dòng)計(jì)時(shí)器。
    函數(shù)演示:
def test():
    text = 'I love FishC.com!'
    char = 'o'
    if char in text:
        pass

    
>>> t1 = MyTimer(test)
>>> t1.timing()
>>> print(t1)
總共運(yùn)行了  1.43 秒
>>> t2 = MyTimer(test,100000)
>>> t2.timing()
>>> print(t2)
總共運(yùn)行了  0.14 秒

參考代碼:

import time as t

class MyTimer:
    def __init__(self,func,number = 1000000):
        self.prompt = '未開始計(jì)時(shí)枚赡!'
        self.lasted = 0.0
        self.default_timer = t.perf_counter
        self.func = func
        self.number = number

    def __str__(self):
        return self.prompt

    __repr__ = __str__

    def __add__(self,other):
        result = self.lasted + other.lasted
        prompt = '總共運(yùn)行了%0.2f秒' % result
        return prompt

    # 內(nèi)部方法氓癌,計(jì)算運(yùn)行時(shí)間
    def timing(self):
        self.begin = self.default_timer()
        for i in range(self.number):
                self.func()
            self.end = self.default_timer()
            self.lasted = self.end - self.begin
            self.prompt = '總共運(yùn)行了 % 0.2f 秒' % self.lasted

    # 設(shè)置計(jì)時(shí)器(time.perf_counter()或time.process_time())
    def set_timer(self,timer):
        if timer == 'process_time':
            self.default_timer = t.process_time
        elif timer == 'perf_counter':
            self.defalut_timer = t.perf_counter
        else:
            print('輸入無效,請輸入 perf_counter 或 process_time')

其實(shí)贫橙,小甲魚有一件事一直瞞著大家.....就是......關(guān)于Python代碼優(yōu)化你需要知道的最重要的問題是贪婉,絕不要自己編寫計(jì)時(shí)函數(shù)!B唷N剿伞!践剂!

image.png

因?yàn)楹芏痰囊粋€(gè)代碼計(jì)時(shí)都很復(fù)雜鬼譬,因?yàn)槟悴恢捞幚砥饔卸嗌贂r(shí)間用于運(yùn)行這個(gè)代碼?有什么在后臺運(yùn)行逊脯?小小的疏忽可能會(huì)破壞你的百年大計(jì)优质,后臺服務(wù)偶爾被“喚醒”在最后千分之一秒做一些像查收信件、連接計(jì)時(shí)通信服務(wù)器、檢查應(yīng)用程序更新巩螃、掃描病毒演怎、查看是否有磁盤被插入光驅(qū)之類很有意義的事。在開始計(jì)時(shí)測試之前避乏,把一切都關(guān)掉爷耀,斷開網(wǎng)絡(luò)的連接。再次確定一切都關(guān)上后關(guān)掉那些不斷查看網(wǎng)絡(luò)是否恢復(fù)的服務(wù)等等拍皮。

接下來是計(jì)時(shí)框架本身引入的變化因素歹叮。Python解釋器是否緩存了方法名的查找?是否緩存代碼塊的編譯結(jié)果铆帽?正則表達(dá)式呢咆耿?你的代碼運(yùn)行時(shí)有副作用嗎?不要忘記爹橱,你的工作結(jié)果是以比秒更小的單位呈現(xiàn)萨螺,你的計(jì)時(shí)框架中的小錯(cuò)誤將會(huì)帶來不可挽回的結(jié)果扭曲。

Python社區(qū)有句俗語:“Python自己帶著電池愧驱∥考迹”別自己寫計(jì)時(shí)框架。Python具備一個(gè)叫做timeit的完美計(jì)時(shí)工具组砚。

或許你現(xiàn)在怨恨小甲魚為什么不早點(diǎn)說惹盼,但如果你在這節(jié)課的折騰中已經(jīng)掌握了類的定制和使用,那目的就達(dá)到了惫确。接下來,請認(rèn)真閱讀更為專業(yè)的計(jì)時(shí)器用法及實(shí)現(xiàn)源碼:timeit模塊詳解(準(zhǔn)確測量小段代碼的執(zhí)行時(shí)間)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蚯舱,一起剝皮案震驚了整個(gè)濱河市改化,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌枉昏,老刑警劉巖陈肛,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兄裂,居然都是意外死亡句旱,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門晰奖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谈撒,“玉大人,你說我怎么就攤上這事匾南】心洌” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長溯乒。 經(jīng)常有香客問我夹厌,道長,這世上最難降的妖魔是什么裆悄? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任矛纹,我火速辦了婚禮,結(jié)果婚禮上光稼,老公的妹妹穿的比我還像新娘或南。我一直安慰自己,他們只是感情好钟哥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布迎献。 她就那樣靜靜地躺著,像睡著了一般腻贰。 火紅的嫁衣襯著肌膚如雪吁恍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天播演,我揣著相機(jī)與錄音冀瓦,去河邊找鬼。 笑死写烤,一個(gè)胖子當(dāng)著我的面吹牛翼闽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播洲炊,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼感局,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了暂衡?” 一聲冷哼從身側(cè)響起询微,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狂巢,沒想到半個(gè)月后撑毛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唧领,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年藻雌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩个。...
    茶點(diǎn)故事閱讀 40,015評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡胯杭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出受啥,到底是詐尸還是另有隱情歉摧,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站叁温,受9級特大地震影響再悼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜膝但,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一冲九、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跟束,春花似錦莺奸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至略贮,卻和暖如春甚疟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背逃延。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工览妖, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揽祥。 一個(gè)月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓讽膏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拄丰。 傳聞我的和親對象是個(gè)殘疾皇子府树,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容