【💊 Python的解憂錦囊】 tqdm進度條客製化工序

2023/09/14閱讀時間約 9 分鐘
圖片來源

圖片來源

我們在「【Python 軍火庫🧨 - tqdm】讓我們為工作加上進度條吧」介紹了tqdm進度條的基本用法, 基本上的使用案例都沒什麼問題, 通常也都是以「數量」為單位進行進度的回報, 但假設我們今天處理的任務是關於音訊的部份呢? 這時候更新的單位就需要從「數量」轉為「時間」了, 那tqdm有提供這樣的功能嗎? 答案是有的, 讓我們教您怎麼做。

怎麼做?

我們先從官方文件來看 🔗 請點我看連結, 它是有支援Wrapper功能的, 我們可以自訂一個類別來繼承並修改。

from tqdm import tqdm  # 匯入tqdm庫

class TqdmWrapper(tqdm):
"""提供了一個 `total_time` 格式參數"""

@property
def format_dict(self):
# 取得父類別的format_dict
d = super().format_dict

# 計算總共花費的時間
total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1)

# 更新字典以包含總共花費的時間
d.update(total_time='總計: ' + self.format_interval(total_time))

# 返回更新後的字典
return d

接著我們將原本的tqdm替換成這個客製化類別即可。

for i in TqdmWrapper(
range(10000),
bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"):
""""""
time.sleep(0.1)

預計呈現如下:

總計: 16:43: 2%|██▉     | 239/10000 [00:23<16:19,  9.96it/s]

那以時間為單位呢?

假設我們最小單位是毫秒(millisecond), 我們會希望看到的是總共「hh:mm:ss」目前執行了「hh:mm:ss」, 這時候就需要來點單位的轉換了,首先我們設計個函式是將「毫秒轉換為hh:mm:ss」, 詳細實作細節請參考「【💊 Python的解憂錦囊】Milliseconds To hh:mm:ss(毫秒轉成小時、分鐘和秒)」。

from datetime import timedelta
def milliseconds_to_hms(milliseconds: int) -> str:
"""毫秒轉hh:mm:ss.ffff
"""
time_delta = timedelta(milliseconds=milliseconds)
total_seconds = time_delta.total_seconds()

# 1小時3600
seconds_in_hours = timedelta(hours=1).total_seconds()

# 1分鐘60
seconds_in_minute = timedelta(minutes=1).total_seconds()

# 小時, 剩餘小時的秒數 = 總秒數/3600(1小時=3600)
hours, remainder = divmod(total_seconds, seconds_in_hours)

# 分鐘, 剩餘秒數 = 剩餘小時的秒數/60(1分鐘=60)
minutes, seconds = divmod(remainder, seconds_in_minute)

# 秒, 毫秒 = 剩餘秒數的整數部分和毫秒部分
seconds_int = int(seconds)

return f'{int(hours):02}:{int(minutes):02}:{seconds_int:02}'

接著我們可以設計一下擴展進度條功能。

class TqdmWrapper(tqdm):
"""Tqdm wrapper"""
@property
def format_dict(self):
d = super().format_dict
# 將目前進度ms轉換成hh:mm:ss的格式
n_fmt = milliseconds_to_hms(d['n'])

# 將總數ms轉換成hh:mm:ss的格式
total_fmt = milliseconds_to_hms(d['total'])
d.update(total_fmt=total_fmt, n_fmt=n_fmt)
return d

這邊我們會在tqdm傳參數時設計一個bar_format的樣版。

# n_fmt 對應到客制轉換的hh:mm:ss
# total_fmt 對應到客制轉換的hh:mm:ss
bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}, [{elapsed}<{remaining}, ' '{rate_fmt}]'

好了, 事前準備作業都完成了, 接下來我們只要規劃一下總共有多少單位的時間需要執行, 每次完成多少時間的資訊即可, 接著預計有多少個工作需要執行。

# 總共需要處理1500000ms
total_ms = 150000

# 每個工作完成1500ms
per_job_ms = 1500

job_nums = round(total_ms / per_job_ms)

with TqdmWrapper(
total=total_ms,
unit='ms',
bar_format='{l_bar}{bar}| {n_fmt}/{total_fmt}, [{elapsed}<{remaining}, ' '{rate_fmt}]'
) as pbar:
for i in range(job_nums):
time.sleep(0.1)
pbar.update(per_job_ms)

我們可以看到總量與目前進度都已經順利被更換成「hh:mm:ss」囉。

35%|██████████   | 00:00:52/00:02:30, [00:03<00:06, 14948.44ms/s]

那可以format哪些內容呢? 🔗 請點我看更多…

圖片來源

圖片來源

l_bar: 進度條的左側部分
bar: 進度條本身
r_bar: 進度條的右側部分
n: 當前進度
n_fmt: 格式化後的當前進度
total: 總進度
total_fmt: 格式化後的總進度
percentage: 完成百分比
elapsed: 已過時間
elapsed_s: 已過時間(以秒為單位)
ncols: 進度條的列數
nrows: 進度條的行數
desc: 描述文字
unit: 單位
rate: 速率
rate_fmt: 格式化後的速率
rate_noinv: 非反比例速率
rate_noinv_fmt: 格式化後的非反比例速率
rate_inv: 反比例速率
rate_inv_fmt: 格式化後的反比例速率
postfix: 附加文字
unit_divisor: 單位除數
remaining: 剩餘時間
remaining_s: 剩餘時間(以秒為單位)
eta: 預計完成時間

結語

這次的主題主要在教您如何對於tqdm這套套件進行客製化, 同時也觀察到這個套件的強大之處, 除了本身就是一套工具之外, 還能夠被引用進行二次開發, 甚至彈性的設計客製化呈現方式, 對於有命令列進度條開發需求的我們來說是非用不可的一套工具。

學習軟體開發的路上常常苦於網路資訊爆炸嗎? 教學何其多,但卻遇到無法明確選擇的困境呢? 歡迎加入「🔒 阿Han的軟體心法實戰營」, 這裡不給您冗餘的雜訊, 單刀直入直接送您業界開發重點, 避開選擇障礙的困境, 讓您獲得業界標準的開發起手式, 成為Top 1的頂尖人才。

91會員
260內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
發表第一個留言支持創作者!