tqdm
源自阿拉伯语单词taqaddum (Yuقdeّm),意思是“进步”,是西班牙语“我非常爱你”的缩写 ( te quiero demasiado )。
立即让您的循环显示智能进度表 - 只需用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 纳秒( tqdm.gui
为 80 纳秒),并且针对性能回归进行了单元测试。相比之下,成熟的 ProgressBar 的开销为 800ns/iter。
除了较低的开销之外, tqdm
还使用智能算法来预测剩余时间并跳过不必要的迭代显示,这在大多数情况下允许忽略不计的开销。
tqdm
可在任何平台(Linux、Windows、Mac、FreeBSD、NetBSD、Solaris/SunOS)、任何控制台或 GUI 中工作,并且对 IPython/Jupyter 笔记本也很友好。
tqdm
不需要任何依赖项(甚至不需要curses
!),只需要 Python 和支持carriage return r
和line feed n
控制字符的环境。
目录
contrib
asyncio
logging
pip install tqdm
拉取并安装预发布devel
分支:
pip install " git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm "
conda install -c conda-forge tqdm
有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
tab 补全。
docker pull tqdm/tqdm
docker run -i --rm tqdm/tqdm --help
还有其他(非官方)地方可以下载tqdm
,特别是对于 CLI 使用:
所有更改的列表均可在 GitHub 的版本:、wiki 或网站上找到。
tqdm
用途广泛,可以通过多种方式使用。下面给出三个主要的。
将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 )
使用with
语句手动控制tqdm()
更新:
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 ()
也许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
的--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]
最常见的问题与多行输出过多有关,而不是整洁的单行进度条。
CR
、 r
)。r
云日志控制台(cloudwatch、K8s)可能会受益于export TQDM_POSITION=-1
。colorama
以确保嵌套条形保持在各自的行内。ascii
码。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
下找到。docker-compose run
而不是docker-compose up
和tty: true
。export TQDM_MININTERVAL=5
以避免日志垃圾邮件。此覆盖逻辑由tqdm.utils.envwrap
装饰器处理(独立于tqdm
有用)。如果您遇到任何其他困难,请浏览并归档。
(自2016年5月19日起)
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.
"""
@ envwrap ( "TQDM_" ) # override defaults via env vars
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 , write_bytes = False ,
lock_args = None , nrows = None , colour = None , delay = 0 ):
可迭代地用进度条装饰。留空以手动管理更新。
进度条的前缀。
预期的迭代次数。如果未指定,则尽可能使用 len(iterable)。如果 float("inf") 或作为最后的手段,则仅显示基本进度统计信息(无预计到达时间,无进度条)。如果gui
为 True 并且该参数需要后续更新,请指定一个初始任意大正数,例如 9e9。
如果[默认值: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
以获得非常有效的循环。如果你的进度在快速和慢速迭代(网络、跳过项目等)中都不稳定,你应该设置 minters=1。
如果未指定或为 False,则使用 unicode(平滑块)来填充仪表。后备方法是使用 ASCII 字符“123456789#”。
是否禁用整个进度条包装器[默认值:False]。如果设置为“无”,则在非 TTY 上禁用。
将用于定义每次迭代的单位的字符串[默认值:it]。
如果为 1 或 True,则迭代次数将自动减少/缩放,并添加遵循国际单位制标准的公制前缀(千、兆等)[默认值:False]。如果有任何其他非零数字,将缩放total
和n
。
如果设置,则不断更改环境中的ncols
和nrows
(允许调整窗口大小)[默认值:False]。
用于速度估计的指数移动平均平滑因子(在 GUI 模式下被忽略)。范围从 0(平均速度)到 1(当前/瞬时速度)[默认值:0.3]。
指定自定义条形字符串格式。可能会影响性能。 [默认值:'{l_bar}{bar}{r_bar}'],其中 l_bar='{desc}: {percentage:3.0f}%|'和 r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' '{rate_fmt}{postfix}]' 可能的变量:l_bar、bar、r_bar、n、n_fmt、total、total_fmt、percentage、elapsed、elapsed_s、ncols 、nrows、desc、单位、速率、rate_fmt、rate_noinv、 rate_noinv_fmt、rate_inv、rate_inv_fmt、后缀、unit_divisor、剩余、剩余_s、eta。请注意,如果 {desc} 为空,则后面的“:”会自动删除。
初始计数器值。重新启动进度条时很有用[默认值:0]。如果使用 float,请考虑在bar_format
中指定{n:.3f}
或类似内容,或指定unit_scale
。
指定打印此条的行偏移量(从 0 开始)如果未指定则自动。对于一次管理多个栏很有用(例如,从线程)。
*
,可选指定要在栏末尾显示的其他统计信息。如果可能的话,调用set_postfix(**postfix)
(dict)。
[默认值:1000],除非unit_scale
为 True,否则将被忽略。
是否写入字节。如果(默认值:False)将写入 unicode。
传递给中间输出的refresh
(初始化、迭代和更新)。
屏幕高度。如果指定,则隐藏此边界之外的嵌套栏。如果未指定,则尝试使用环境高度。后备值为 20。
条形颜色(例如“绿色”、“#00ff00”)。
在 [默认值:0] 秒过去之前不显示。
delim
时使用的字符串缓冲区大小(以字节为单位)[默认值:256]。delim
,并将默认的unit_scale
设置为True, unit_divisor
为1024,将unit
设置为“B”。stdin
传递给stderr
和stdout
。update()
数字。请注意,这很慢(~2e5 it/s),因为每个输入都必须解码为数字。self.n
数字。请注意,这很慢(~2e5 it/s),因为每个输入都必须解码为数字。 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 ):
"""Shortcut for `tqdm(range(*args), **tqdm_kwargs)`."""
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`."""
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.slack
:发布到 Slack 机器人tqdm.contrib.discord
:发布到 Discord 机器人tqdm.contrib.telegram
:发布到 Telegram 机器人tqdm.contrib.bells
:自动启用所有可选功能auto
、 pandas
、 slack
、 discord
、 telegram
help()
;可以使用desc
和postfix
参数在tqdm
栏上动态显示和更新自定义信息:
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" , { "value" : 0 }]) as t :
for i in range ( 10 ):
sleep ( 0.1 )
t . postfix [ 1 ][ "value" ] = i / 2
t . update ()
在bar_format
字符串中使用{postfix[...]}
时要记住的要点:
postfix
还需要以兼容的格式作为初始参数传递,并且postfix
是类似dict
对象,它会自动转换为字符串。为了防止这种行为,请在字典中插入一个额外的项目,其中键不是字符串。额外的bar_format
参数也可以通过覆盖format_dict
来定义,并且 bar 本身可以使用ascii
进行修改:
from tqdm import tqdm
class TqdmExtraFormat ( tqdm ):
"""Provides a `total_time` format parameter"""
@ property
def format_dict ( self ):
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 ) + " in total" )
return d
for i in TqdmExtraFormat (
range (