TQDM
tqdm
派生自阿拉伯语单词塔卡杜姆(تقدّم)可以是“进步”的意思,在西班牙语中是“我非常爱你”的缩写(德马西亚多)
立即使您的循环显示一个智能进度表-只需用tqdm(iterable)
,你就完了!
from tqdm import tqdm for i in tqdm(range(10000)):
...
76%|████████████████████████ | 7568/10000 [00:33<00:10, 229.00it/s]
trange(N)
还可以用作以下操作的便捷快捷方式tqdm(range(N))
它还可以作为带有管道的模块执行:
$ seq 9999999 | tqdm --bytes | wc -l
75.2MB [00:00, 217MB/s]
9999999
$ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
> backup.tgz
32%|██████████▍ | 8.89G/27.9G [00:42<01:31, 223MB/s]
开销很低–每次迭代约60 ns(80 ns,tqdm.gui
),并针对性能回归进行单元测试。相比之下,久负盛名的ProgressBar具有800 ns/ITER开销
除了开销低之外,tqdm
使用智能算法预测剩余时间并跳过不必要的迭代显示,这在大多数情况下可以忽略不计的开销
tqdm
可在任何平台(Linux、Windows、Mac、FreeBSD、NetBSD、Solaris/SunOS)、任何控制台或GUI中运行,并且与IPython/Jupyter笔记本电脑也很友好
tqdm
不需要任何依赖项(甚至不需要curses
!),只有Python和一个支持carriage return \r
和line feed \n
控制字符
目录
- Installation
- Changelog
- Usage
- FAQ and Known Issues
- Documentation
- Examples and Advanced Usage
- Description and additional stats
- Nested progress bars
- Hooks and callbacks
asyncio
- Pandas Integration
- Keras Integration
- Dask Integration
- IPython/Jupyter Integration
- Custom Integration
- Dynamic Monitor/Meter
- Writing messages
- Redirecting writing
- Redirecting
logging
- Monitoring thread, intervals and miniters
- Merch
- Contributions
- LICENCE
Installation
Latest PyPI stable release
pip install tqdm
Latest development release on GitHub
拉入并安装预发行版devel
分支机构:
pip install "git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm"
Latest Conda release
conda install -c conda-forge tqdm
Latest Snapcraft release
有3个频道可供选择:
snap install tqdm # implies --stable, i.e. latest tagged release
snap install tqdm --candidate # master branch
snap install tqdm --edge # devel branch
请注意,snap
二进制文件仅供CLI使用(而不是import
-可用),并自动设置bash
制表符完成
Latest Docker release
docker pull tqdm/tqdm
docker run -i --rm tqdm/tqdm --help
Other
还有其他(非官方的)地方tqdm
可以下载,特别是对于CLI使用:
Changelog
所有更改的列表可在GitHub的版本上获得:,在wiki,或在website
Usage
tqdm
是非常多才多艺的,可以有多种用途。下面给出了三个主要的原因
Iterable-based
包装tqdm()
围绕任何可迭代:
from tqdm import tqdm from time import sleep text = "" for char in tqdm(["a", "b", "c", "d"]):
sleep(0.25)
text = text + char
trange(i)
是一个特殊的优化实例tqdm(range(i))
:
from tqdm import trange for i in trange(100):
sleep(0.01)
循环外的实例化允许手动控制tqdm()
:
pbar = tqdm(["a", "b", "c", "d"])
for char in pbar:
sleep(0.25)
pbar.set_description("Processing %s" % char)
Manual
手动控制tqdm()
使用with
声明:
with tqdm(total=100) as pbar:
for i in range(10):
sleep(0.1)
pbar.update(10)
如果可选变量total
(或使用可迭代的len()
),则显示预测统计信息
with
也是可选的(您可以直接将tqdm()
赋给一个变量,但在这种情况下,不要忘记del
或close()
在结尾处:
pbar = tqdm(total=100)
for i in range(10):
sleep(0.1)
pbar.update(10)
pbar.close()
Module
也许最奇妙的用法就是tqdm
是在脚本中还是在命令行上。简单地插入tqdm
(或python -m tqdm
)之间的管道将通过所有stdin
至stdout
将进度打印到时stderr
下面的示例演示了如何计算当前目录中所有Python文件中的行数,其中包括计时信息
$ time find . -name '*.py' -type f -exec cat \{} \; | wc -l
857365
real 0m3.458s
user 0m0.274s
sys 0m3.325s
$ time find . -name '*.py' -type f -exec cat \{} \; | tqdm | wc -l
857366it [00:03, 246471.31it/s]
857365
real 0m3.585s
user 0m0.862s
sys 0m3.358s
请注意,通常的论点是tqdm
也可以指定
$ find . -name '*.py' -type f -exec cat \{} \; |
tqdm --unit loc --unit_scale --total 857366 >> /dev/null
100%|█████████████████████████████████| 857K/857K [00:04<00:00, 246Kloc/s]
备份一个大目录吗?
$ tar -zcf - docs/ | tqdm --bytes --total `du -sb docs/ | cut -f1` \
> backup.tgz
44%|██████████████▊ | 153M/352M [00:14<00:18, 11.0MB/s]
这还可以进一步美化:
$ BYTES="$(du -sb docs/ | cut -f1)"
$ tar -cf - docs/ \
| tqdm --bytes --total "$BYTES" --desc Processing | gzip \
| tqdm --bytes --total "$BYTES" --desc Compressed --position 1 \
> ~/backup.tgz
Processing: 100%|██████████████████████| 352M/352M [00:14<00:00, 30.2MB/s]
Compressed: 42%|█████████▎ | 148M/352M [00:14<00:19, 10.9MB/s]
或使用7-zip在文件级完成:
$ 7z a -bd -r backup.7z docs/ | grep Compressing \
| tqdm --total $(find docs/ -type f | wc -l) --unit files \
| grep -v Compressing
100%|██████████████████████████▉| 15327/15327 [01:00<00:00, 712.96files/s]
已经输出基本进度信息的现有CLI程序将受益于tqdm
%s--update
和--update_to
标志:
$ seq 3 0.1 5 | tqdm --total 5 --update_to --null
100%|████████████████████████████████████| 5.0/5 [00:00<00:00, 9673.21it/s]
$ seq 10 | tqdm --update --null # 1 + 2 + ... + 10 = 55 iterations
55it [00:00, 90006.52it/s]
FAQ and Known Issues
最常见的问题与多行输出过多有关,而不是整齐的单行进度条
- 一般控制台:需要回车支持(
CR
,\r
) - 嵌套进度条:
- Unicode:
- 报告支持Unicode的环境将具有稳定、平滑的进度条。后备方案是一个
ascii
-仅限栏 - Windows控制台通常只部分支持Unicode,因此often require explicit ascii=True(亦请参阅here)。这是因为普通宽度的Unicode字符错误地显示为“宽”,或者某些Unicode字符未呈现
- 报告支持Unicode的环境将具有稳定、平滑的进度条。后备方案是一个
- 包裹生成器:
- 生成器包装函数倾向于隐藏可迭代的长度
tqdm
不会 - 替换
tqdm(enumerate(...))
使用enumerate(tqdm(...))
或tqdm(enumerate(x), total=len(x), ...)
同样的道理也适用于numpy.ndenumerate
- 替换
tqdm(zip(a, b))
使用zip(tqdm(a), b)
甚至是zip(tqdm(a), tqdm(b))
- 同样的道理也适用于
itertools
- 一些有用的方便函数可以在下面的
tqdm.contrib
- 生成器包装函数倾向于隐藏可迭代的长度
- Hanging pipes in python2:使用时
tqdm
在CLI上,您可能需要使用Python 3.5+才能正确缓冲 - No intermediate output in docker-compose:使用
docker-compose run
而不是docker-compose up
和tty: true
Documentation
class tqdm():
""" Decorate an iterable object, returning an iterator which acts exactly like the original iterable, but prints a dynamically updating progressbar every time a value is requested. """ def __init__(self, iterable=None, desc=None, total=None, leave=True,
file=None, ncols=None, mininterval=0.1,
maxinterval=10.0, miniters=None, ascii=None, disable=False,
unit='it', unit_scale=False, dynamic_ncols=False,
smoothing=0.3, bar_format=None, initial=0, position=None,
postfix=None, unit_divisor=1000):
Parameters
- 可迭代的:可迭代,可选
- 可重复使用进度条进行装饰。保留为空可手动管理更新
- 说明:字符串,可选
- 进度栏的前缀
- 总计:整型或浮点型,可选
- 预期迭代次数。如果未指定,则在可能的情况下使用len(可迭代)。如果为FLOAT(“inf”)或作为最后手段,则仅显示基本进度统计信息(无ETA,无进度条)。如果
gui
为True并且此参数需要后续更新,请指定初始任意大正数,例如9e9
- 离开吧:布尔值,可选
- 如果为[default:true],则在迭代终止时保留进度条的所有痕迹。如果
None
,只有在以下情况下才会离开position
是0
- 文件:
io.TextIOWrapper
或io.StringIO
,可选 - 指定输出进度消息的位置(默认值:sys.stderr)。用途
file.write(str)
和file.flush()
方法。有关编码信息,请参见write_bytes
- 文件:
- 乙二醇:整型,可选
- 整个输出消息的宽度。如果指定,则动态调整进度条的大小以保持在此范围内。如果未指定,则尝试使用环境宽度。后备宽度为10米,对计数器和统计数据没有限制。如果为0,则不打印任何仪表(仅打印统计数据)
- 最小间隔:浮动,可选
- 最小进度显示更新间隔[默认值:0.1]秒
- 最大间隔:浮动,可选
- 最大进度显示更新间隔[默认值:10]秒。自动调整
miniters
与…相对应mininterval
在长时间显示更新延迟之后。仅在以下情况下才有效dynamic_miniters
或者启用了监视器线程
- 小型矿车:整型或浮点型,可选
- 最小进度显示更新间隔,以迭代为单位。如果为0且
dynamic_miniters
,将自动调整为等于mininterval
(CPU效率更高,适用于紧密循环)。如果>0,将跳过指定迭代次数的显示。调整此选项,然后mininterval
以获得非常有效的循环。如果快速迭代和慢速迭代(网络、跳过项目等)的进度都不稳定,则应该将miniters设置为1
- ASCII:布尔值或字符串,可选
- 如果未指定或为False,则使用Unicode(平滑块)填充仪表。备用方法是使用ASCII码字符“123456789#”
- 禁用:布尔值,可选
- 是否禁用整个进度栏包装[默认值:false]。如果设置为None,则在非TTY上禁用
- 单位:字符串,可选
- 将用于定义每个迭代的单位的字符串[默认值:it]
- 单位_刻度:Bool、int或Float,可选
- 如果为1或True,则迭代次数将自动减少/缩放,并将添加遵循国际单位制标准的公制前缀(千、兆等)[默认值:FALSE]。如果有任何其他非零数,将缩放
total
和n
- 动态参数(_N):布尔值,可选
- 如果设置,则会不断更改
ncols
和nrows
到环境(允许调整窗口大小)[默认值:FALSE]
- 平滑:浮动,可选
- 速度估计的指数移动平均平滑系数(在GUI模式中忽略)。范围从0(平均速度)到1(当前/瞬时速度)[默认值:0.3]
- 条形图格式(_F):字符串,可选
- 指定自定义条形字符串格式。可能会影响性能。[默认值:‘{l_bar}{bar}{r_bar}’],其中l_bar=‘{desc}:{percentage:3.0f}%|’,r_bar=‘|{n_fmt}/{total_fmt}[{elapsed}<{reaving},’{rate_fmt}{postfix}]‘’可能的变量:l_bar,bar,r_bar,n,n_fmt,total,total_fmt,百分比,已用rate_noinv、rate_noinv_fmt、rate_inv、rate_inv_fmt、后缀、unit_ditor、剩余、剩余_s、eta。请注意,如果{desc}为空,则会在{desc}之后自动删除尾随的“:”
- 首字母:整型或浮点型,可选
- 初始计数器值。重新启动进度条时非常有用[默认值:0]。如果使用浮点,请考虑指定
{n:.3f}
或类似于bar_format
,或指定unit_scale
- 职位:整型,可选
- 如果未指定,请指定自动打印此条形图的行偏移量(从0开始)。一次管理多个条形图非常有用(例如,从线程)
- 后缀:DICT或
*
,可选 - 指定要在条末尾显示的其他统计信息。呼叫
set_postfix(**postfix)
如果可能(DICT)
- 后缀:DICT或
- 单位_除数:浮动,可选
- [默认值:1000],除非忽略
unit_scale
是真的吗?
- 写入字节(_B):布尔值,可选
- 如果(默认值:无)和
file
未指定,则将使用Python 2写入字节。如果True
还将写入字节。在所有其他情况下,将默认为Unicode
- 锁定参数(_A):元组,可选
- 已传递给
refresh
用于中间输出(初始化、迭代和更新)
- n行:整型,可选
- 屏幕高度。如果指定,则隐藏此边界之外的嵌套条。如果未指定,则尝试使用环境高度。退而求其次是20
- 颜色:字符串,可选
- 条形图颜色(例如“绿色”、“#00ff00”)
- 延迟:浮动,可选
- 在经过[默认值:0]秒之前不显示
Extra CLI Options
- 神志不清:CHR,可选
- 分隔字符[默认值:‘n’]。使用“0”表示NULL。注:在Windows系统上,Python将‘n’转换为‘rn’
- buf_size:整型,可选
- 字符串缓冲区大小(以字节为单位)[默认值:256]在以下情况下使用
delim
已指定
- 字节数:布尔值,可选
- 如果为true,将计算字节数,忽略
delim
和Defaultunit_scale
为了真的,unit_divisor
设置为1024,并且unit
到“B”
- T形三通:布尔值,可选
- 如果为true,则通过
stdin
对两个人都是stderr
和stdout
- 更新:布尔值,可选
- 如果为true,则将输入视为新经过的迭代,即要传递到的数字
update()
请注意,这很慢(~2e5 it/s),因为每个输入都必须解码为数字
- 更新目标(_T):布尔值,可选
- 如果为true,则将输入视为已用迭代总数,即要分配给的数字
self.n
请注意,这很慢(~2e5 it/s),因为每个输入都必须解码为数字
- 空:布尔值,可选
- 如果为true,将丢弃输入(无标准输出)
- 人工路径:字符串,可选
- 要安装tqdm手册页的目录
- 压缩路径:字符串,可选
- 放置tqdm完成的目录
- 日志:字符串,可选
- 严重|致命|错误|警告(ING)|[默认值:‘INFO’]|DEBUG|NOTSET
Returns
- 输出:修饰迭代器
class tqdm():
def update(self, n=1):
""" Manually update the progress bar, useful for streams such as reading files. E.g.: >>> t = tqdm(total=filesize) # Initialise >>> for current_buffer in stream: ... ... ... t.update(len(current_buffer)) >>> t.close() The last line is highly recommended, but possibly not necessary if ``t.update()`` will be called in such a way that ``filesize`` will be exactly reached and printed. Parameters ---------- n : int or float, optional Increment to add to the internal counter of iterations [default: 1]. If using float, consider specifying ``{n:.3f}`` or similar in ``bar_format``, or specifying ``unit_scale``. Returns ------- out : bool or None True if a ``display()`` was triggered. """ def close(self):
"""Cleanup and (if leave=False) close the progressbar.""" def clear(self, nomove=False):
"""Clear current bar display.""" def refresh(self):
""" Force refresh the display of this bar. Parameters ---------- nolock : bool, optional If ``True``, does not lock. If [default: ``False``]: calls ``acquire()`` on internal lock. lock_args : tuple, optional Passed to internal lock's ``acquire()``. If specified, will only ``display()`` if ``acquire()`` returns ``True``. """ def unpause(self):
"""Restart tqdm timer from last print time.""" def reset(self, total=None):
""" Resets to 0 iterations for repeated use. Consider combining with ``leave=True``. Parameters ---------- total : int or float, optional. Total to use for the new bar. """ def set_description(self, desc=None, refresh=True):
""" Set/modify description of the progress bar. Parameters ---------- desc : str, optional refresh : bool, optional Forces refresh [default: True]. """ def set_postfix(self, ordered_dict=None, refresh=True, **tqdm_kwargs):
""" Set/modify postfix (additional stats) with automatic formatting based on datatype. Parameters ---------- ordered_dict : dict or OrderedDict, optional refresh : bool, optional Forces refresh [default: True]. kwargs : dict, optional """ @classmethod def write(cls, s, file=sys.stdout, end="\n"):
"""Print a message via tqdm (without overlap with bars).""" @property def format_dict(self):
"""Public API for read-only member access.""" def display(self, msg=None, pos=None):
""" Use ``self.sp`` to display ``msg`` in the specified ``pos``. Consider overloading this function when inheriting to use e.g.: ``self.some_frontend(**self.format_dict)`` instead of ``self.sp``. Parameters ---------- msg : str, optional. What to display (default: ``repr(self)``). pos : int, optional. Position to ``moveto`` (default: ``abs(self.pos)``). """ @classmethod @contextmanager def wrapattr(cls, stream, method, total=None, bytes=True, **tqdm_kwargs):
""" stream : file-like object. method : str, "read" or "write". The result of ``read()`` and the first argument of ``write()`` should have a ``len()``. >>> with tqdm.wrapattr(file_obj, "read", total=file_obj.size) as fobj: ... while True: ... chunk = fobj.read(chunk_size) ... if not chunk: ... break """ @classmethod def pandas(cls, *targs, **tqdm_kwargs):
"""Registers the current `tqdm` class with `pandas`.""" def trange(*args, **tqdm_kwargs):
""" A shortcut for `tqdm(xrange(*args), **tqdm_kwargs)`. On Python3+, `range` is used instead of `xrange`. """
Convenience Functions
def tqdm.contrib.tenumerate(iterable, start=0, total=None,
tqdm_class=tqdm.auto.tqdm, **tqdm_kwargs):
"""Equivalent of `numpy.ndenumerate` or builtin `enumerate`.""" def tqdm.contrib.tzip(iter1, *iter2plus, **tqdm_kwargs):
"""Equivalent of builtin `zip`.""" def tqdm.contrib.tmap(function, *sequences, **tqdm_kwargs):
"""Equivalent of builtin `map`."""
Submodules
class tqdm.notebook.tqdm(tqdm.tqdm):
"""IPython/Jupyter Notebook widget.""" class tqdm.auto.tqdm(tqdm.tqdm):
"""Automatically chooses beween `tqdm.notebook` and `tqdm.tqdm`.""" class tqdm.asyncio.tqdm(tqdm.tqdm):
"""Asynchronous version.""" @classmethod def as_completed(cls, fs, *, loop=None, timeout=None, total=None,
**tqdm_kwargs):
"""Wrapper for `asyncio.as_completed`.""" class tqdm.gui.tqdm(tqdm.tqdm):
"""Matplotlib GUI version.""" class tqdm.tk.tqdm(tqdm.tqdm):
"""Tkinter GUI version.""" class tqdm.rich.tqdm(tqdm.tqdm):
"""`rich.progress` version.""" class tqdm.keras.TqdmCallback(keras.callbacks.Callback):
"""Keras callback for epoch and batch progress.""" class tqdm.dask.TqdmCallback(dask.callbacks.Callback):
"""Dask callback for task progress."""
contrib
这个tqdm.contrib
软件包还包含实验模块:
tqdm.contrib.itertools
:周围有薄薄的包装纸itertools
tqdm.contrib.concurrent
:周围有薄薄的包装纸concurrent.futures
tqdm.contrib.discord
:发布到Discord机器人tqdm.contrib.telegram
:发布到Telegram机器人tqdm.contrib.bells
:自动启用所有可选功能-
auto
,pandas
,discord
,telegram
-
Examples and Advanced Usage
- 请参阅examples文件夹;
- 导入模块并运行
help()
; - 请查阅wiki;
- 这有一个excellent article关于如何做一个太棒了进度条;
- 请查看slides from PyData London,或
- 运行
Description and additional stats
自定义信息可以在上动态显示和更新tqdm
带有条形图的条形图desc
和postfix
参数:
from tqdm import tqdm, trange from random import random, randint from time import sleep with trange(10) as t:
for i in t:
# Description will be displayed on the left t.set_description('GEN %i' % i)
# Postfix will be displayed on the right, # formatted automatically based on argument's datatype t.set_postfix(loss=random(), gen=randint(1,999), str='h',
lst=[1, 2])
sleep(0.1)
with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}",
postfix=["Batch", dict(value=0)]) as t:
for i in range(10):
sleep(0.1)
t.postfix[1]["value"] = i / 2 t.update()
使用时要记住的要点{postfix[...]}
在bar_format
字符串:
postfix
还需要以兼容格式作为初始参数传递,并且postfix
将自动转换为字符串(如果它是dict
-类物体。要防止此行为,请在键不是字符串的字典中插入额外的项
附加内容bar_format
参数也可以通过重写format_dict
,并且可以使用以下命令修改栏本身ascii
:
from tqdm import tqdm class TqdmExtraFormat(tqdm):
"""Provides a `total_time` format parameter""" @property def format_dict(self):
d = super(TqdmExtraFormat, self).format_dict total_time = d["elapsed"] * (d["total"] or 0) / max(d["n"], 1)
d.update(total_time=self.format_interval(total_time) + " in total")
return d for i in TqdmExtraFormat(
range(9), ascii=" .oO0",
bar_format="{total_time}: {percentage:.0f}%|{bar}{r_bar}"):
if i == 4:
break
00:00 in total: 44%|0000. | 4/9 [00:00<00:00, 962.93it/s]
请注意,{bar}
还支持格式说明符[width][type]
width
- 未指定(默认):自动填充
ncols
-
int >= 0
:固定宽度替代ncols
逻辑 -
int < 0
:从自动缺省值中减去
- 未指定(默认):自动填充
type
-
a
:ASCII(ascii=True
覆盖) -
u
:unicode(ascii=False
覆盖) -
b
:空白(ascii=" "
覆盖)
-
这意味着可以使用以下方法创建具有右对齐文本的固定栏:bar_format="{l_bar}{bar:10}|{bar:-10b}right-justified"
Nested progress bars
tqdm
支持嵌套进度条。下面是一个示例:
from tqdm.auto import trange from time import sleep for i in trange(4, desc='1st loop'):
for j in trange(5, desc='2nd loop'):
for k in trange(50, desc='3rd loop', leave=False):
sleep(0.01)
要手动控制定位(例如,用于多处理),您可以指定position=n
哪里n=0
对于最外面的酒吧,n=1
下一个,以此类推。不过,最好还是检查一下tqdm
无需手动即可工作position
第一
from time import sleep from tqdm import trange, tqdm from multiprocessing import Pool, RLock, freeze_support L = list(range(9))
def progresser(n):
interval = 0.001 / (n + 2)
total = 5000 text = "#{}, est. {:<04.2}s".format(n, interval * total)
for _ in trange(total, desc=text, position=n):
sleep(interval)
if __name__ == '__main__':
freeze_support() # for Windows support tqdm.set_lock(RLock()) # for managing output contention p = Pool(initializer=tqdm.set_lock, initargs=(tqdm.get_lock(),))
p.map(progresser, L)
请注意,在Python3中,tqdm.write
是否线程安全:
from time import sleep from tqdm import tqdm, trange from concurrent.futures import ThreadPoolExecutor L = list(range(9))
def progresser(n):
interval = 0.001 / (n + 2)
total = 5000 text = "#{}, est. {:<04.2}s".format(n, interval * total)
for _ in trange(total, desc=text):
sleep(interval)
if n == 6:
tqdm.write("n == 6 completed.")
tqdm.write("`tqdm.write()` is thread-safe in py3!")
if __name__ == '__main__':
with ThreadPoolExecutor() as p:
p.map(progresser, L)
Hooks and callbacks
tqdm
可以轻松支持回调/挂钩和手动更新。下面是一个包含以下内容的示例urllib
:
“urllib.urlsearche“文档
[.]如果存在,将调用一次钩子函数关于网络连接的建立和每次挡路阅读后的一次之后。将向挂钩传递三个参数;块计数到目前为止已传输的挡路大小(以字节为单位)和文件的总大小[.]
import urllib, os from tqdm import tqdm urllib = getattr(urllib, 'request', urllib)
class TqdmUpTo(tqdm):
"""Provides `update_to(n)` which uses `tqdm.update(delta_n)`.""" def update_to(self, b=1, bsize=1, tsize=None):
""" b : int, optional Number of blocks transferred so far [default: 1]. bsize : int, optional Size of each block (in tqdm units) [default: 1]. tsize : int, optional Total size (in tqdm units). If [default: None] remains unchanged. """ if tsize is not None:
self.total = tsize return self.update(b * bsize - self.n) # also sets self.n = b * bsize eg_link = "https://caspersci.uk.to/matryoshka.zip" with TqdmUpTo(unit='B', unit_scale=True, unit_divisor=1024, miniters=1,
desc=eg_link.split('/')[-1]) as t: # all optional kwargs urllib.urlretrieve(eg_link, filename=os.devnull,
reporthook=t.update_to, data=None)
t.total = t.n
灵感来自twine#242中的功能替代examples/tqdm_wget.py
建议使用miniters=1
每当迭代速度存在潜在较大差异时(例如,通过补丁连接下载文件)
包装读/写方法
要通过类似文件的对象测量吞吐量,请执行以下操作read
或write
方法,使用CallbackIOWrapper
:
from tqdm.auto import tqdm from tqdm.utils import CallbackIOWrapper with tqdm(total=file_obj.size,
unit='B', unit_scale=True, unit_divisor=1024) as t:
fobj = CallbackIOWrapper(t.update, file_obj, "read")
while True:
chunk = fobj.read(chunk_size)
if not chunk:
break t.reset()
# ... continue to use `t` for something else
或者,使用更简单的wrapattr
便利函数,该函数将压缩两个urllib
和CallbackIOWrapper
下面是示例:
import urllib, os from tqdm import tqdm eg_link = "https://caspersci.uk.to/matryoshka.zip" response = getattr(urllib, 'request', urllib).urlopen(eg_link)
with tqdm.wrapattr(open(os.devnull, "wb"), "write",
miniters=1, desc=eg_link.split('/')[-1],
total=getattr(response, 'length', None)) as fout:
for chunk in response:
fout.write(chunk)
这个requests
等价物几乎完全相同:
import requests, os from tqdm import tqdm eg_link = "https://caspersci.uk.to/matryoshka.zip" response = requests.get(eg_link, stream=True)
with tqdm.wrapattr(open(os.devnull, "wb"), "write",
miniters=1, desc=eg_link.split('/')[-1],
total=int(response.headers.get('content-length', 0))) as fout:
for chunk in response.iter_content(chunk_size=4096):
fout.write(chunk)
自定义回调
tqdm
以智能地跳过不必要的显示而闻名。要使自定义回调利用这一点,只需使用update()
这设置为True
如果一个display()
已被触发
from tqdm.auto import tqdm as std_tqdm def external_callback(*args, **kwargs):
...
class TqdmExt(std_tqdm):
def update(self, n=1):
displayed = super(TqdmExt, self).update(n):
if displayed:
external_callback(**self.format_dict)
return displayed
asyncio
请注意,break
当前未被异步迭代器捕获。这意味着tqdm
在这种情况下,无法自行清理:
from tqdm.asyncio import tqdm async for i in tqdm(range(9)):
if i == 2:
break
取而代之的是,或者调用pbar.close()
手动或使用上下文管理器语法:
from tqdm.asyncio import tqdm with tqdm(range(9)) as pbar:
async for i in pbar:
if i == 2:
break
Pandas Integration
由于大众的需求,我们增加了对pandas
–这里有一个例子DataFrame.progress_apply
和DataFrameGroupBy.progress_apply
:
import pandas as pd import numpy as np from tqdm import tqdm df = pd.DataFrame(np.random.randint(0, 100, (100000, 6)))
# Register `pandas.progress_apply` and `pandas.Series.map_apply` with `tqdm` # (can use `tqdm.gui.tqdm`, `tqdm.notebook.tqdm`, optional kwargs, etc.) tqdm.pandas(desc="my bar!")
# Now you can use `progress_apply` instead of `apply` # and `progress_map` instead of `map` df.progress_apply(lambda x: x**2)
# can also groupby: # df.groupby(0).progress_apply(lambda x: x**2)
如果您对这是如何工作的(以及如何为您自己的回调修改它)感兴趣,请参阅examples文件夹或导入模块,然后运行help()
Keras Integration
一个keras
也可以回调:
from tqdm.keras import TqdmCallback
...
model.fit(..., verbose=0, callbacks=[TqdmCallback()])
Dask Integration
一个dask
也可以回调:
from tqdm.dask import TqdmCallback with TqdmCallback(desc="compute"):
...
arr.compute()
# or use callback globally cb = TqdmCallback(desc="global")
cb.register()
arr.compute()
IPython/Jupyter Integration
IPython/Jupyter通过tqdm.notebook
子模块:
from tqdm.notebook import trange, tqdm from time import sleep for i in trange(3, desc='1st loop'):
for j in tqdm(range(100), desc='2nd loop'):
sleep(0.01)
除了……之外tqdm
功能方面,该子模块提供原生Jupyter小部件(与IPythonv1-v4和Jupyter兼容)、完全工作的嵌套条和颜色提示(蓝色:正常、绿色:已完成、红色:错误/中断、浅蓝色:无ETA);如下所示
这个notebook
版本支持总宽度的百分比或像素(例如:ncols='100%'
或ncols='480px'
)
也可以让tqdm
自动选择控制台或笔记本电脑版本,方法是使用autonotebook
子模块:
from tqdm.autonotebook import tqdm tqdm.pandas()
请注意,这将发出一个TqdmExperimentalWarning
如果在笔记本中运行,因为它不能区分jupyter notebook
和jupyter console
使用auto
而不是autonotebook
要取消显示此警告,请执行以下操作
请注意,笔记本将在创建它的单元格中显示该条。这可能是与使用它的单元格不同的单元格。如果这也不是我们想要的,
- 将栏的创建延迟到必须显示它的单元格,或者
- 使用创建条形图
display=False
,并且在稍后的蜂窝呼叫中display(bar.container)
:
from tqdm.notebook import tqdm pbar = tqdm(..., display=False)
# different cell display(pbar.container)
这个keras
回调有一个display()
同样可以使用的方法:
from tqdm.keras import TqdmCallback cbk = TqdmCallback(display=False)
# different cell cbk.display()
model.fit(..., verbose=0, callbacks=[cbk])
另一种可能是拥有一个不断重复使用的条(靠近笔记本顶部)(使用reset()
而不是close()
)。因此,笔记本版本(与CLI版本不同)不会自动调用close()
在此基础上Exception
from tqdm.notebook import tqdm pbar = tqdm()
# different cell iterable = range(100)
pbar.reset(total=len(iterable)) # initialise with new `total` for i in iterable:
pbar.update()
pbar.refresh() # force print final status but don't `close()`
Custom Integration
要更改默认参数(如进行dynamic_ncols=True
),只需使用内置的Python魔术:
from functools import partial from tqdm import tqdm as std_tqdm tqdm = partial(std_tqdm, dynamic_ncols=True)
要进一步自定义,请参见tqdm
可以从继承以创建自定义回调(与TqdmUpTo
示例above)或用于自定义前端(例如,诸如笔记本或绘图包之类的GUI)。在后一种情况下:
def __init__()
要呼叫,请执行以下操作super().__init__(..., gui=True)
禁用端子的步骤status_printer
创作- 重新定义:
close()
,clear()
,display()
考虑超载display()
使用,例如,使用self.frontend(**self.format_dict)
而不是self.sp(repr(self))
继承的一些子模块示例:
Dynamic Monitor/Meter
您可以使用tqdm
作为一个不是单调递增的韵律。这可能是因为n
减少(例如CPU使用情况监视器)或total
变化
递归搜索文件就是一个例子。这个total
是到目前为止找到的对象数,而n
是属于文件(而不是文件夹)的那些对象的数量:
from tqdm import tqdm import os.path def find_files_recursively(path, show_progress=True):
files = []
# total=1 assumes `path` is a file t = tqdm(total=1, unit="file", disable=not show_progress)
if not os.path.exists(path):
raise IOError("Cannot find:" + path)
def append_found_file(f):
files.append(f)
t.update()
def list_found_dir(path):
"""returns os.listdir(path) assuming os.path.isdir(path)""" listing = os.listdir(path)
# subtract 1 since a "file" we found was actually this directory t.total += len(listing) - 1 # fancy way to give info without forcing a refresh t.set_postfix(dir=path[-10:], refresh=False)
t.update(0) # may trigger a refresh return listing def recursively_search(path):
if os.path.isdir(path):
for f in list_found_dir(path):
recursively_search(os.path.join(path, f))
else:
append_found_file(path)
recursively_search(path)
t.set_postfix(dir=path)
t.close()
return files
使用update(0)
是一种方便的方式来让tqdm
决定何时触发显示刷新以避免控制台垃圾邮件
Writing messages
这是一项正在进行的工作(请参见#737)
因为tqdm
使用简单的打印机制显示进度条,您不应该在终端中使用print()
当进度条打开时
在终端中写入消息而不与其发生任何冲突tqdm
条形图显示,a.write()
提供了一种方法:
from tqdm.auto import tqdm, trange from time import sleep bar = trange(10)
for i in bar:
# Print using tqdm class method .write() sleep(0.1)
if not (i % 3):
tqdm.write("Done task %i" % i)
# Can also use bar.write()
默认情况下,这将打印到标准输出sys.stdout
但是您可以使用file
论点。例如,这可用于将写入日志文件或类的消息重定向
Redirecting writing
如果使用可以将消息打印到控制台的库,请通过替换print()
使用tqdm.write()
可能不是我们想要的。在这种情况下,重定向sys.stdout
至tqdm.write()
是一种选择
要重定向,请执行以下操作sys.stdout
,创建一个类似文件的类,该类将把任何输入字符串写入tqdm.write()
,并提供参数file=sys.stdout, dynamic_ncols=True
下面给出了一个可重用的规范示例:
from time import sleep import contextlib import sys from tqdm import tqdm from tqdm.contrib import DummyTqdmFile @contextlib.contextmanager def std_out_err_redirect_tqdm():
orig_out_err = sys.stdout, sys.stderr try:
sys.stdout, sys.stderr = map(DummyTqdmFile, orig_out_err)
yield orig_out_err[0]
# Relay exceptions except Exception as exc:
raise exc # Always restore sys.stdout/err if necessary finally:
sys.stdout, sys.stderr = orig_out_err def some_fun(i):
print("Fee, fi, fo,".split()[i])
# Redirect stdout to tqdm.write() (don't forget the `as save_stdout`) with std_out_err_redirect_tqdm() as orig_stdout:
# tqdm needs the original stdout # and dynamic_ncols=True to autodetect console width for i in tqdm(range(3), file=orig_stdout, dynamic_ncols=True):
sleep(.5)
some_fun(i)
# After the `with`, printing is restored print("Done!")
Redirecting logging
类似于sys.stdout
/sys.stderr
如上所述,控制台logging
也可以重定向到tqdm.write()
警告:如果还重定向sys.stdout
/sys.stderr
,请务必重定向logging
如果需要,先来
中提供了帮助器方法tqdm.contrib.logging
例如:
import logging from tqdm import trange from tqdm.contrib.logging import logging_redirect_tqdm LOG = logging.getLogger(__name__)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
with logging_redirect_tqdm():
for i in trange(9):
if i == 4:
LOG.info("console logging redirected to `tqdm.write()`")
# logging restored
Monitoring thread, intervals and miniters
tqdm
实施一些技巧来提高效率和降低管理费用
- 避免不必要的频繁条刷新:
mininterval
定义每次刷新之间等待的时间。tqdm
始终在后台更新,但它将仅在mininterval
- 减少检查系统时钟/时间的调用次数
mininterval
比起配置更直观miniters
巧妙的调整系统dynamic_miniters
将自动调整miniters
与时间相适应的迭代次数mininterval
从本质上讲,tqdm
将在不实际检查时间的情况下检查是否到了打印时间。通过手动设置,仍可绕过此行为miniters
但是,请考虑快速迭代和慢速迭代相结合的情况。在几次快速迭代之后,dynamic_miniters
将设置miniters
变成了一个大数目。当迭代速率随后减慢时,miniters
将保持较大,从而降低显示更新频率。要解决此问题,请执行以下操作:
maxinterval
定义显示刷新之间的最长时间。并发监视线程检查过期的更新,并在必要时强制更新
监视线程不应该有明显的开销,并且默认情况下保证至少每10秒更新一次。该值可以通过设置monitor_interval
任何tqdm
实例(即t = tqdm.tqdm(...); t.monitor_interval = 2
)。可以通过设置在应用程序范围内禁用监视线程tqdm.tqdm.monitor_interval = 0
在实例化任何tqdm
钢筋
Merch
你可以买到tqdm branded merch现在!
Contributions
所有源代码都托管在GitHub欢迎投稿
请参阅CONTRIBUTING有关详细信息,请参阅文件
做出重大贡献的开发人员,按SLOC(幸存的代码行,git fame-wMC --excl '\.(png|gif|jpg)$'
),包括:
名字 | ID号 | SLOC | 注意事项 |
---|---|---|---|
卡斯珀·达·科斯塔-路易斯 | casperdcl | ~81% | 主要维护人员 |
斯蒂芬·拉罗克 | lrq3000 | ~10% | 团队成员 |
马丁·祖格诺尼 | martinzugnoni | ~3% | 他说: |
理查德·谢里登 | richardsheridan | ~1% | 他说: |
陈广硕 | chengs | ~1% | 他说: |
凯尔·阿尔滕多夫 | altendky | <1% | 他说: |
马修·史蒂文斯 | mjstevens777 | <1% | 他说: |
哈德琳·玛丽 | hadim | <1% | 团队成员 |
伊万·伊万诺夫 | obiwanus | <1% | 他说: |
丹尼尔·潘特莱特 | danielpanteleit | <1% | 他说: |
乔纳斯·哈格 | jonashaag | <1% | 他说: |
詹姆斯·E·金三世 | jeking3 | <1% | 他说: |
诺姆·约拉夫-拉斐尔 | noamraph | <1% | 原作者 |
米哈伊尔·科罗博夫 | kmike | <1% | 团队成员 |
Ports to Other Languages
有关列表,请访问this wiki page