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天)
答:沒錯(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剿伞!践剂!
因?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í)間)