tqdm
dérive du mot arabe taqaddum (تقدّم) qui peut signifier « progrès » et est une abréviation de « je t'aime tellement » en espagnol ( te quiero demasiado ).
Faites instantanément afficher à vos boucles un indicateur de progression intelligent - enveloppez simplement n'importe quel itérable avec tqdm(iterable)
, et vous avez terminé !
from tqdm import tqdm
for i in tqdm ( range ( 10000 )):
...
76%|████████████████████████ | 7568/10000 [00:33<00:10, 229.00it/s]
trange(N)
peut également être utilisé comme raccourci pratique pour tqdm(range(N))
.
Il peut également être exécuté sous forme de module avec des tuyaux :
$ 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]
Les frais généraux sont faibles - environ 60 ns par itération (80 ns avec tqdm.gui
) et sont testés unitairement contre la régression des performances. En comparaison, la ProgressBar bien établie a une surcharge de 800 ns/iter.
En plus de sa faible surcharge, tqdm
utilise des algorithmes intelligents pour prédire le temps restant et éviter les affichages d'itérations inutiles, ce qui permet une surcharge négligeable dans la plupart des cas.
tqdm
fonctionne sur n'importe quelle plateforme (Linux, Windows, Mac, FreeBSD, NetBSD, Solaris/SunOS), sur n'importe quelle console ou dans une interface graphique, et est également compatible avec les notebooks IPython/Jupyter.
tqdm
ne nécessite aucune dépendance (pas même curses
!), juste Python et un environnement prenant en charge les caractères de contrôle carriage return r
et line feed n
.
Table des matières
contrib
asyncio
logging
pip install tqdm
Extrayez et installez la branche devel
préliminaire :
pip install " git+https://github.com/tqdm/tqdm.git@devel#egg=tqdm "
conda install -c conda-forge tqdm
Vous avez le choix entre 3 chaînes :
snap install tqdm # implies --stable, i.e. latest tagged release
snap install tqdm --candidate # master branch
snap install tqdm --edge # devel branch
Notez que les binaires snap
sont uniquement destinés à une utilisation en CLI (non import
) et configurent automatiquement la complétion des tabulations bash
.
docker pull tqdm/tqdm
docker run -i --rm tqdm/tqdm --help
Il existe d'autres endroits (non officiels) où tqdm
peut être téléchargé, notamment pour une utilisation CLI :
La liste de toutes les modifications est disponible soit sur les versions de GitHub : , sur le wiki ou sur le site Web.
tqdm
est très polyvalent et peut être utilisé de plusieurs manières. Les trois principaux sont présentés ci-dessous.
Enroulez tqdm()
autour de n'importe quel itérable :
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)
est une instance optimisée spéciale de tqdm(range(i))
:
from tqdm import trange
for i in trange ( 100 ):
sleep ( 0.01 )
L'instanciation en dehors de la boucle permet un contrôle manuel sur tqdm()
:
pbar = tqdm ([ "a" , "b" , "c" , "d" ])
for char in pbar :
sleep ( 0.25 )
pbar . set_description ( "Processing %s" % char )
Contrôle manuel des mises à jour de tqdm()
à l'aide d'une instruction with
:
with tqdm ( total = 100 ) as pbar :
for i in range ( 10 ):
sleep ( 0.1 )
pbar . update ( 10 )
Si la variable facultative total
(ou un itérable avec len()
) est fournie, les statistiques prédictives sont affichées.
with
est également facultatif (vous pouvez simplement affecter tqdm()
à une variable, mais dans ce cas n'oubliez pas de del
ou close()
à la fin :
pbar = tqdm ( total = 100 )
for i in range ( 10 ):
sleep ( 0.1 )
pbar . update ( 10 )
pbar . close ()
L'utilisation la plus merveilleuse de tqdm
est peut-être dans un script ou sur la ligne de commande. L'insertion simple tqdm
(ou python -m tqdm
) entre les tuyaux passera par tous stdin
vers stdout
lors de l'impression de la progression sur stderr
.
L'exemple ci-dessous montre le comptage du nombre de lignes dans tous les fichiers Python du répertoire actuel, avec les informations de synchronisation incluses.
$ 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
Notez que les arguments habituels de tqdm
peuvent également être spécifiés.
$ 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]
Sauvegarder un grand répertoire ?
$ tar -zcf - docs/ | tqdm --bytes --total ` du -sb docs/ | cut -f1 `
> backup.tgz
44% | ██████████████▊ | 153M/352M [00: 14< 00:18, 11.0MB/s]
Cela peut être encore embelli :
$ 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]
Ou effectué au niveau du fichier en utilisant 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]
Les programmes CLI préexistants produisant déjà des informations de progression de base bénéficieront des indicateurs --update
et --update_to
de tqdm
:
$ 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]
Les problèmes les plus courants sont liés à une sortie excessive sur plusieurs lignes, au lieu d'une barre de progression soignée sur une seule ligne.
CR
, r
).r
correctement (cloudwatch, K8s) peuvent bénéficier de export TQDM_POSITION=-1
.colorama
pour garantir que les barres imbriquées restent dans leurs lignes respectives.ascii
uniquement.tqdm
ne le fait pas.tqdm(enumerate(...))
par enumerate(tqdm(...))
ou tqdm(enumerate(x), total=len(x), ...)
. La même chose s'applique à numpy.ndenumerate
.tqdm(zip(a, b))
par zip(tqdm(a), b)
ou même zip(tqdm(a), tqdm(b))
.itertools
.tqdm.contrib
.docker-compose run
au lieu de docker-compose up
et tty: true
.export TQDM_MININTERVAL=5
pour éviter le spam des journaux. Cette logique de remplacement est gérée par le décorateur tqdm.utils.envwrap
(utile indépendamment de tqdm
).Si vous rencontrez d’autres difficultés, parcourez et déposez les fichiers .
(Depuis le 19 mai 2016)
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 ):
Itérable à décorer avec une barre de progression. Laissez vide pour gérer manuellement les mises à jour.
Préfixe pour la barre de progression.
Le nombre d'itérations attendues. S’il n’est pas spécifié, len(iterable) est utilisé si possible. Si float("inf") ou en dernier recours, seules les statistiques de progression de base sont affichées (pas d'ETA, pas de barre de progression). Si gui
est True et que ce paramètre nécessite une mise à jour ultérieure, spécifiez un grand nombre positif arbitraire initial, par exemple 9e9.
Si [par défaut : True], conserve toutes les traces de la barre de progression à la fin de l'itération. Si None
, ne partira que si position
est 0
.
io.TextIOWrapper
ou io.StringIO
, facultatif Spécifie où afficher les messages de progression (par défaut : sys.stderr). Utilise les méthodes file.write(str)
et file.flush()
. Pour le codage, voir write_bytes
.
La largeur de l’intégralité du message de sortie. Si spécifié, redimensionne dynamiquement la barre de progression pour rester dans cette limite. Si non spécifié, tente d'utiliser la largeur de l'environnement. La solution de repli est une largeur de 10 mètres et aucune limite pour le compteur et les statistiques. Si 0, n'imprimera aucun compteur (uniquement les statistiques).
Intervalle minimum de mise à jour de l'affichage de la progression [par défaut : 0,1] secondes.
Intervalle maximum de mise à jour de l'affichage de la progression [par défaut : 10] secondes. Ajuste automatiquement miniters
pour correspondre à mininterval
après un long décalage de mise à jour de l'affichage. Fonctionne uniquement si dynamic_miniters
ou le thread de surveillance est activé.
Intervalle minimum de mise à jour de l'affichage de la progression, en itérations. Si 0 et dynamic_miniters
, s'ajusteront automatiquement à mininterval
égal (plus efficace du processeur, bon pour les boucles serrées). Si > 0, ignorera l’affichage du nombre d’itérations spécifié. Ajustez ceci et mininterval
pour obtenir des boucles très efficaces. Si votre progression est irrégulière avec des itérations rapides et lentes (réseau, éléments sautés, etc.), vous devez définir miniters=1.
Si non spécifié ou faux, utilisez Unicode (blocs lisses) pour remplir le compteur. La solution de rechange consiste à utiliser les caractères ASCII " 123456789#".
S'il faut désactiver l'intégralité du wrapper de la barre de progression [par défaut : False]. Si défini sur Aucun, désactivez-le sur les non-TTY.
Chaîne qui sera utilisée pour définir l'unité de chaque itération [par défaut : it].
Si 1 ou True, le nombre d'itérations sera réduit/mis à l'échelle automatiquement et un préfixe métrique suivant la norme du Système international d'unités sera ajouté (kilo, méga, etc.) [par défaut : False]. S'il existe un autre nombre non nul, total
et n
seront mis à l'échelle.
S'il est défini, modifie constamment ncols
et nrows
en fonction de l'environnement (permettant le redimensionnement des fenêtres) [par défaut : False].
Facteur de lissage de la moyenne mobile exponentielle pour les estimations de vitesse (ignoré en mode GUI). Va de 0 (vitesse moyenne) à 1 (vitesse actuelle/instantanée) [par défaut : 0,3].
Spécifiez un formatage de chaîne de barres personnalisé. Peut avoir un impact sur les performances. [par défaut : '{l_bar}{bar}{r_bar}'], où l_bar='{desc} : {percentage:3.0f}%|' et r_bar='| {n_fmt}/{total_fmt} [{elapsed}<{remaining}, ' '{rate_fmt}{postfix}]' Vars possibles : l_bar, bar, r_bar, n, n_fmt, total, total_fmt, pourcentage, écoulé, écoulé_s, ncols , nrows, desc, unité, taux, rate_fmt, rate_noinv, rate_noinv_fmt, rate_inv, rate_inv_fmt, postfix, unit_divisor, restant, restant_s, eta. Notez qu'un ':' final est automatiquement supprimé après {desc} si ce dernier est vide.
La valeur initiale du compteur. Utile lors du redémarrage d'une barre de progression [par défaut : 0]. Si vous utilisez float, envisagez de spécifier {n:.3f}
ou similaire dans bar_format
, ou de spécifier unit_scale
.
Spécifiez le décalage de ligne pour imprimer cette barre (à partir de 0). Automatique si non spécifié. Utile pour gérer plusieurs barres à la fois (par exemple, à partir de fils de discussion).
*
, facultatif Spécifiez des statistiques supplémentaires à afficher à la fin de la barre. Appelle set_postfix(**postfix)
si possible (dict).
[par défaut : 1000], ignoré sauf si unit_scale
est True.
S'il faut écrire des octets. If (par défaut : False) écrira Unicode.
Passé pour refresh
pour la sortie intermédiaire (initialisation, itération et mise à jour).
La hauteur de l'écran. Si spécifié, masque les barres imbriquées en dehors de cette limite. Si non spécifié, tente d'utiliser la hauteur de l'environnement. La solution de repli est de 20.
Couleur de la barre (par exemple « vert », « #00ff00 »).
Ne s'affiche pas avant que [par défaut : 0] secondes ne se soient écoulées.
delim
est spécifié.delim
et unit_scale
par défaut à True, unit_divisor
à 1024 et unit
à 'B'.stdin
à stderr
et stdout
.update()
. Notez que c'est lent (~2e5 it/s) puisque chaque entrée doit être décodée sous forme de nombre.self.n
. Notez que c'est lent (~2e5 it/s) puisque chaque entrée doit être décodée sous forme de nombre. 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
Le package tqdm.contrib
contient également des modules expérimentaux :
tqdm.contrib.itertools
: Wrappers fins autour itertools
tqdm.contrib.concurrent
: Wrappers minces autour de concurrent.futures
tqdm.contrib.slack
: publications sur les robots Slacktqdm.contrib.discord
: Publications sur les robots Discordtqdm.contrib.telegram
: publications sur les robots Telegramtqdm.contrib.bells
: active automatiquement toutes les fonctionnalités facultativesauto
, pandas
, slack
, discord
, telegram
help()
; Les informations personnalisées peuvent être affichées et mises à jour dynamiquement sur les barres tqdm
avec les arguments desc
et 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" , { "value" : 0 }]) as t :
for i in range ( 10 ):
sleep ( 0.1 )
t . postfix [ 1 ][ "value" ] = i / 2
t . update ()
Points à retenir lors de l'utilisation {postfix[...]}
dans la chaîne bar_format
:
postfix
doit également être passé comme argument initial dans un format compatible, etpostfix
sera automatiquement converti en chaîne s'il s'agit d'un objet de type dict
. Pour éviter ce comportement, insérez un élément supplémentaire dans le dictionnaire où la clé n'est pas une chaîne. Des paramètres bar_format
supplémentaires peuvent également être définis en remplaçant format_dict
, et la barre elle-même peut être modifiée en utilisant 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 (