tqdm 是 Python 生态中最流行的进度条库,名字源自阿拉伯语 **"taqaddum"**(تقدّم),意为"进步"或"进展"。它的发音近似 "tee-ku-dum",在中文社区常被戏称为"太酷的姆"。
tqdm 会显示一条美观、实时更新的进度条,它能告诉我们:
- 预计还要多久:
<00:06](ETA,Estimated Time of Arrival)
此外,tqdm 还能在进度条尾部显示自定义的实时数据(如损失值、准确率等),让它从"进度指示器"升级为"实时监控面板"。
tqdm 的优势
| |
|---|
| 极简 API | 大多数场景只需 for i in tqdm(range(100)): 一行代码 |
| 性能开销小 | |
| 自动计算 ETA | |
| 智能自适应 | |
| 生态集成广泛 | 原生支持 Pandas、Keras、PyTorch、Dask、Joblib 等主流框架 |
| 跨平台 | 同时支持 Linux、macOS、Windows,在 Jupyter 中也有专属美化版本 |
tqdm 的典型输出效果
当在终端运行一个带有 tqdm 的循环时,会看到类似这样的动态进度条:
from tqdm import tqdmimport timefor i in tqdm(range(100)): time.sleep(0.02)
输出效果:
100%|███████████████████████████████| 100/100 [00:02<00:00, 49.98it/s]
如果添加了 desc 和 set_postfix,会变成:
训练 Epoch 5: 78%|████████████▎ | 78/100 [00:01<00:00, 52.31it/s, loss=0.0032, acc=0.981]
安装
tqdm 是第三方库,首先需要通过 pip 安装:
pip install tqdm
如果使用 Conda 环境,安装命令如下:
conda install -c conda-forge tqdm
选择提示:
- 普通终端/脚本:直接使用
from tqdm import tqdm - Jupyter Notebook:推荐使用
from tqdm.notebook import tqdm,进度条更美观 - 自动适配:最新版本支持
from tqdm.autonotebook import tqdm,可自动检测运行环境
基础用法——装饰可迭代对象
这是 tqdm 经典、最简单的用法。只需用 tqdm() 包裹可迭代对象:
from tqdm import tqdmimport time# 基本用法:包裹 rangefor i in tqdm(range(100)): time.sleep(0.01) # 模拟耗时任务
运行后会看到类似这样的进度条:
100%|██████████| 100/100 [00:01<00:00, 99.85it/s]
快捷方式:trange 是 tqdm(range()) 的缩写:
from tqdm import trangefor i in trange(100): time.sleep(0.01)
适用于任何可迭代对象:列表、元组、字典、文件、生成器都可以:
# 处理列表for item in tqdm(["a", "b", "c", "d"]): time.sleep(0.1)# 处理文件行with open('large_file.txt', 'r') as f:for line in tqdm(f, total=1000): # total 指定总行数 process_line(line)
手动控制进度——应对非标准循环
当进度不是均匀的,或无法直接用可迭代对象表示时,可以手动控制进度条更新。
场景:从 API 分页获取数据,每页数据量不确定。
from tqdm import tqdmimport timeimport randomtotal_items = 1000# 预知的大致总数fetched = 0page = 1# 创建进度条对象,指定总数with tqdm(total=total_items, desc="获取数据", unit="条") as pbar:while fetched < total_items:# 模拟 API 调用,每次返回不定量的数据 items_this_page = random.randint(5, 25) time.sleep(0.1)# 处理数据... fetched += items_this_page# 手动更新进度条,增加本次获取的数量 pbar.update(items_this_page) pbar.set_description(f"获取数据 (第{page}页)") page += 1
提示:
tqdm(total=...):创建进度条对象,指定总步数pbar.update(n):每次增加 n 个单位进度with 语句会自动在结束时关闭进度条,比手动调用 close() 更安全
让进度条更智能、更美观
常用自定义参数
from tqdm import tqdmimport timefor i in tqdm( range(1000), desc="训练模型", # 左侧描述文字 ncols=80, # 固定宽度(字符数) colour="green", # 颜色:'green', 'cyan', 'red', 'yellow' unit="样本", # 单位名称 unit_scale=True, # 自动缩放单位(如 1000 -> 1k) leave=True, # 完成后保留进度条 mininterval=0.5, # 最小刷新间隔(秒)): time.sleep(0.001)
效果预览:
训练模型: 100%|████████████████| 1000/1000 [00:01<00:00, 998.00样本/s]
动态更新描述和附加信息
在循环中实时显示关键指标(如损失值、处理速度),让进度条变成"仪表盘":
from tqdm import tqdmimport timepbar = tqdm(range(100), desc="训练中")for i in pbar: time.sleep(0.02)# 方式1:通过 set_description 更新描述 pbar.set_description(f"训练中 (epoch {i//10})")# 方式2:通过 set_postfix 在尾部显示附加信息 loss = 1.0 / (i + 1) accuracy = min(0.9, i / 100) pbar.set_postfix({'loss': f'{loss:.4f}', 'acc': f'{accuracy:.3f}'})
进度条会变成这样:
训练中 (epoch 5): 45%|████▌ | 45/100 [00:00<00:01, 49.92it/s, loss=0.0217, acc=0.450]
延迟显示——短任务不刷屏
对于执行很快的循环,可以设置延迟时间,只有超过该时长才显示进度条:
from tqdm import tqdmimport time# 任务执行 0.5 秒,低于 delay=1,不显示进度条for i in tqdm(range(50), delay=1): time.sleep(0.01) # 总共 0.5 秒
嵌套循环——多层进度同时显示
tqdm 支持多层进度条,适用于网格搜索、模拟等场景:
from tqdm import tqdmimport timefor i in tqdm(range(3), desc="外层", position=0):for j in tqdm(range(50), desc="内层", position=1, leave=False): time.sleep(0.01)
关键参数:
position:指定进度条在终端中的行位置(从0开始)leave=False:内层进度完成后自动消失,避免输出混乱
与数据处理库集成
Pandas
tqdm 对 Pandas 有原生支持,只需一行启用:
import pandas as pdfrom tqdm import tqdm# 启用 tqdm 的 pandas 集成tqdm.pandas()df = pd.DataFrame({'a': range(1000)})# 使用 progress_apply 替代 apply,自动显示进度df['b'] = df['a'].progress_apply(lambda x: x ** 2)
并发编程——concurrent.futures
与线程池/进程池结合,跟踪并行任务的完成情况:
import concurrent.futuresfrom tqdm import tqdmimport timedeftask(n): time.sleep(0.1)return n * nnumbers = list(range(100))with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:# executor.map 返回的结果列表用 tqdm 包装 results = list(tqdm(executor.map(task, numbers), total=len(numbers)))
Joblib
如果使用 Joblib 做并行计算,官方文档提供了多种集成方案。最简单的是使用 return_as="generator_unordered",进度条会随着任务完成而平滑更新:
from joblib import Parallel, delayedfrom tqdm import tqdmdeftask(t): time.sleep(0.1 * t)return ttimes = [7, 2, 3, 5, 6, 4, 1]p = Parallel(n_jobs=2, return_as="generator_unordered")out = p(delayed(task)(t) for t in times)results = list(tqdm(out, total=len(times)))
案例——文件夹大小统计
以下是一个实际项目中的案例,展示了如何从"卡顿无反馈"优化为"进度实时可见"。
问题:统计包含数万个子文件夹的目录大小时,传统 os.walk 先收集所有文件路径再计算,收集过程耗时且无进度显示。
方案:分层遍历 + tqdm 显示进度。
import osfrom tqdm import tqdmdefget_folder_size(folder_path):"""计算文件夹总大小,并显示进度条"""ifnot os.path.exists(folder_path):return0# 获取第一级子文件夹 first_level_dirs = [] total_size = 0for item in os.listdir(folder_path): item_path = os.path.join(folder_path, item)if os.path.isfile(item_path): total_size += os.path.getsize(item_path)elif os.path.isdir(item_path): first_level_dirs.append(item_path)ifnot first_level_dirs:return total_size# 用 tqdm 遍历第一级文件夹,每个内部再递归计算 pbar = tqdm(first_level_dirs, desc="处理中", unit="个文件夹")for dir_path in pbar:# 计算子文件夹大小 sub_size = calculate_dir_size(dir_path) total_size += sub_size# 动态更新描述,显示当前累计大小 pbar.set_description(f"累计: {format_size(total_size)}")return total_sizedefcalculate_dir_size(directory):"""递归计算单个目录的大小""" total = 0for root, dirs, files in os.walk(directory):for file in files: file_path = os.path.join(root, file)try: total += os.path.getsize(file_path)except OSError:continuereturn totaldefformat_size(size_bytes): units = ['B', 'KB', 'MB', 'GB', 'TB'] size = size_bytes idx = 0while size >= 1024and idx < len(units) - 1: size /= 1024 idx += 1returnf"{size:.2f}{units[idx]}"
tqdm 用法归纳
- 装饰可迭代对象是最常用的方式,一行代码搞定 80% 场景
- 动态信息更新(
set_description / set_postfix)让进度条变成实时仪表盘 - 嵌套循环 用
position 和 leave=False 保持输出整洁 - 集成工具:Pandas、Joblib、concurrent.futures 都有成熟的配合方案