web-dev-qa-db-fra.com

Barre de progression du texte dans la console

Y at-il un bon moyen de faire ce qui suit?

J'ai écrit une application de console simple pour télécharger et télécharger des fichiers à partir d'un serveur FTP à l'aide de ftplib.

Chaque fois que des morceaux de données sont téléchargés, je souhaite mettre à jour une barre de progression du texte, même s'il ne s'agit que d'un nombre.

Mais je ne veux pas effacer tout le texte qui a été imprimé sur la console. (Effectuer un "effacer" puis imprimer le pourcentage mis à jour.)

370
bobber205

Une barre de progression simple et personnalisable

Voici un ensemble des nombreuses réponses ci-dessous que j'utilise régulièrement (aucune importation requise).

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r')
    # Print New Line on Complete
    if iteration == total: 
        print()

Remarque: Ceci est pour Python 3; voir les commentaires pour plus de détails sur son utilisation dans Python 2.

Exemple d'utilisation

import time

# A List of Items
items = list(range(0, 57))
l = len(items)

# Initial call to print 0% progress
printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
for i, item in enumerate(items):
    # Do stuff...
    time.sleep(0.1)
    # Update Progress Bar
    printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)

Exemple de sortie:

Progress: |█████████████████████████████████████████████-----| 90.0% Complete

Mise à jour

Il a été question dans les commentaires d’une option permettant à la barre de progression de s’ajuster de manière dynamique à la largeur de la fenêtre du terminal. Bien que je ne le recommande pas, voici un Gist qui implémente cette fonctionnalité (et note les mises en garde).

343
Greenstick

En écrivant '\ r', le curseur reviendra au début de la ligne.

Ceci affiche un compteur de pourcentage:

import time
import sys

for i in range(100):
    time.sleep(1)
    sys.stdout.write("\r%d%%" % i)
    sys.stdout.flush()
294
Stephen

tqdm: ajoute un indicateur de progression à vos boucles en une seconde :

>>> import time
>>> from tqdm import tqdm
>>> for i in tqdm(range(100)):
...     time.sleep(1)
... 
|###-------| 35/100  35% [elapsed: 00:35 left: 01:05,  1.00 iters/sec]

tqdm repl session

153
jfs

Ecrivez un \r sur la console. C'est un "retour de chariot" qui provoque l'écho de tout le texte qui le suit au début de la ligne. Quelque chose comme:

def update_progress(progress):
    print '\r[{0}] {1}%'.format('#'*(progress/10), progress)

qui vous donnera quelque chose comme: [ ########## ] 100%

109
aviraldg

C'est moins de 10 lignes de code.

The Gist ici: https://Gist.github.com/vladignatyev/06860ec2040cb497f0f

import sys


def progress(count, total, suffix=''):
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)

    sys.stdout.write('[%s] %s%s ...%s\r' % (bar, percents, '%', suffix))
    sys.stdout.flush()  # As suggested by Rom Ruben

enter image description here

66
Vladimir Ignatyev

Essayez la bibliothèque click écrite par Mozart of Python, Armin Ronacher.

$ pip install click # both 2 and 3 compatible

Pour créer une barre de progression simple:

import click

with click.progressbar(range(1000000)) as bar:
    for i in bar:
        pass 

Voici à quoi ça ressemble:

# [###-------------------------------]    9%  00:01:14

Personnalisez au contenu de votre coeur:

import click, sys

with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template='(_(_)=%(bar)sD(_(_| %(info)s', fill_char='=', empty_char=' ') as bar:
    for i in bar:
        pass

Look personnalisé:

(_(_)===================================D(_(_| 100000/100000 00:00:02

Il y a encore plus d'options, voir le docs de l'API :

 click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char='#', empty_char='-', bar_template='%(label)s [%(bar)s] %(info)s', info_sep=' ', width=36, file=None, color=None)
58
The Unfun Cat

Je me rends compte que je suis en retard pour le jeu, mais voici un scénario légèrement à la Yum (Red Hat) que je vous ai écrit (sans aller pour une précision de 100% ici, mais si vous utilisez une barre de progression pour ce niveau de précision, alors vous sommes faux de toute façon):

import sys

def cli_progress_test(end_val, bar_length=20):
    for i in xrange(0, end_val):
        percent = float(i) / end_val
        hashes = '#' * int(round(percent * bar_length))
        spaces = ' ' * (bar_length - len(hashes))
        sys.stdout.write("\rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100))))
        sys.stdout.flush()

Devrait produire quelque chose qui ressemble à ceci:

Percent: [##############      ] 69%

... où les supports restent immobiles et que seuls les hachages augmentent.

Cela pourrait mieux fonctionner en tant que décorateur. Pour un autre jour ...

32
JoeLinux

Vérifiez cette bibliothèque: clint

il a beaucoup de fonctionnalités, y compris une barre de progression:

from time import sleep  
from random import random  
from clint.textui import progress  
if __== '__main__':
    for i in progress.bar(range(100)):
        sleep(random() * 0.2)

    for i in progress.dots(range(100)):
        sleep(random() * 0.2)

this link fournit un aperçu rapide de ses fonctionnalités

17
scripts

Voici un bel exemple de barre de progression écrite en Python: http://nadiana.com/animated-terminal-progress-bar-in-python

Mais si vous voulez l'écrire vous-même. Vous pouvez utiliser le module curses pour simplifier les choses :)

[edit] Peut-être que ce n'est pas plus facile, ce n'est pas la Parole pour les malédictions. Mais si vous voulez créer un cui complet, les malédictions s’occupent de beaucoup de choses pour vous.

[edit] Puisque l'ancien lien est mort, j'ai mis en place ma propre version d'un Python Progressbar, obtenez-le ici: https://github.com/WoLpH/python-progressbar =

12
Wolph
import time,sys

for i in range(100+1):
    time.sleep(0.1)
    sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] "))
    sys.stdout.flush()

sortie

[29%] ====================

10
ashish2py

et, juste pour ajouter à la pile, voici un objet que vous pouvez utiliser

import sys

class ProgressBar(object):
    DEFAULT_BAR_LENGTH = 65
    DEFAULT_CHAR_ON  = '='
    DEFAULT_CHAR_OFF = ' '

    def __init__(self, end, start=0):
        self.end    = end
        self.start  = start
        self._barLength = self.__class__.DEFAULT_BAR_LENGTH

        self.setLevel(self.start)
        self._plotted = False

    def setLevel(self, level):
        self._level = level
        if level < self.start:  self._level = self.start
        if level > self.end:    self._level = self.end

        self._ratio = float(self._level - self.start) / float(self.end - self.start)
        self._levelChars = int(self._ratio * self._barLength)

    def plotProgress(self):
        sys.stdout.write("\r  %3i%% [%s%s]" %(
            int(self._ratio * 100.0),
            self.__class__.DEFAULT_CHAR_ON  * int(self._levelChars),
            self.__class__.DEFAULT_CHAR_OFF * int(self._barLength - self._levelChars),
        ))
        sys.stdout.flush()
        self._plotted = True

    def setAndPlot(self, level):
        oldChars = self._levelChars
        self.setLevel(level)
        if (not self._plotted) or (oldChars != self._levelChars):
            self.plotProgress()

    def __add__(self, other):
        assert type(other) in [float, int], "can only add a number"
        self.setAndPlot(self._level + other)
        return self
    def __sub__(self, other):
        return self.__add__(-other)
    def __iadd__(self, other):
        return self.__add__(other)
    def __isub__(self, other):
        return self.__add__(-other)

    def __del__(self):
        sys.stdout.write("\n")

if __== "__main__":
    import time
    count = 150
    print "starting things:"

    pb = ProgressBar(count)

    #pb.plotProgress()
    for i in range(0, count):
        pb += 1
        #pb.setAndPlot(i + 1)
        time.sleep(0.01)
    del pb

    print "done"

résulte en:

starting things:
  100% [=================================================================]
done

Cela serait généralement considéré comme "excessif", mais il est pratique lorsque vous l'utilisez beaucoup

7
FraggaMuffin

Installez tqdm. (pip install tqdm) et utilisez-le comme suit:

import time
from tqdm import tqdm
for i in tqdm(range(1000)):
    time.sleep(0.01)

C'est une barre de progression de 10 secondes qui produira quelque chose comme ceci:

47%|██████████████████▊                     | 470/1000 [00:04<00:05, 98.61it/s]
6
Tux

Exécutez ceci à la Python ligne de commande (pas dans n’importe quel IDE ou environnement de développement):

>>> import threading
>>> for i in range(50+1):
...   threading._sleep(0.5)
...   print "\r%3d" % i, ('='*i)+('-'*(50-i)),

Fonctionne bien sur mon système Windows.

6
PaulMcG

J'utilise progrès de reddit . Je l’aime bien parce qu’il peut imprimer la progression de chaque élément d’une ligne et qu’il ne devrait pas effacer les impressions du programme.

Edit: lien fixe

4
Ib33X
4
Andy Mikhaylenko

sur la base des réponses ci-dessus et d’autres questions similaires sur la barre de progression de la CLI, je pense avoir obtenu une réponse commune à chacune d’elles. Vérifiez-le à https://stackoverflow.com/a/15860757/2254146

En résumé, le code est le suivant:

import time, sys

# update_progress() : Displays or updates a console progress bar
## Accepts a float between 0 and 1. Any int will be converted to a float.
## A value under 0 represents a 'halt'.
## A value at 1 or bigger represents 100%
def update_progress(progress):
    barLength = 10 # Modify this to change the length of the progress bar
    status = ""
    if isinstance(progress, int):
        progress = float(progress)
    if not isinstance(progress, float):
        progress = 0
        status = "error: progress var must be float\r\n"
    if progress < 0:
        progress = 0
        status = "Halt...\r\n"
    if progress >= 1:
        progress = 1
        status = "Done...\r\n"
    block = int(round(barLength*progress))
    text = "\rPercent: [{0}] {1}% {2}".format( "#"*block + "-"*(barLength-block), progress*100, status)
    sys.stdout.write(text)
    sys.stdout.flush()

Ressemble à

Pourcentage: [##########] 99,0%

3
Brian Khuu

Je recommande d'utiliser tqdm - https://pypi.python.org/pypi/tqdm - ce qui facilite la transformation de tout processus itérable ou itératif en barre de progression et gère tout le fouillis avec les terminaux nécessaires.

Dans la documentation: "tqdm peut facilement prendre en charge les callbacks/hooks et les mises à jour manuelles. Voici un exemple avec urllib"

import urllib
from tqdm import tqdm

def my_hook(t):
  """
  Wraps tqdm instance. Don't forget to close() or __exit__()
  the tqdm instance once you're done with it (easiest using `with` syntax).

  Example
  -------

  >>> with tqdm(...) as t:
  ...     reporthook = my_hook(t)
  ...     urllib.urlretrieve(..., reporthook=reporthook)

  """
  last_b = [0]

  def inner(b=1, bsize=1, tsize=None):
    """
    b  : int, optional
        Number of blocks just transferred [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:
        t.total = tsize
    t.update((b - last_b[0]) * bsize)
    last_b[0] = b
  return inner

eg_link = 'http://www.doc.ic.ac.uk/~cod11/matryoshka.Zip'
with tqdm(unit='B', unit_scale=True, miniters=1,
          desc=eg_link.split('/')[-1]) as t:  # all optional kwargs
    urllib.urlretrieve(eg_link, filename='/dev/null',
                       reporthook=my_hook(t), data=None)
3
Malcolm Box

Essayez d'installer ce paquet: pip install progressbar2:

import time
import progressbar

for i in progressbar.progressbar(range(100)):
    time.sleep(0.02)

barre de progression github: https://github.com/WoLpH/python-progressbar

3
Chris Cui

lol je viens d'écrire tout un truc pour cette heres le code garder à l'esprit que vous ne pouvez pas utiliser Unicode lorsque vous faites bloquer ascii j'utilise cp437

import os
import time
def load(left_side, right_side, length, time):
    x = 0
    y = ""
    print "\r"
    while x < length:
        space = length - len(y)
        space = " " * space
        z = left + y + space + right
        print "\r", z,
        y += "█"
        time.sleep(time)
        x += 1
    cls()

et vous l'appelez comme si

print "loading something awesome"
load("|", "|", 10, .01)

alors ça ressemble à ça

loading something awesome
|█████     |
2
ryan

Avec les bons conseils ci-dessus, je travaille sur la barre de progression.

Cependant, je voudrais souligner certaines lacunes

  1. Chaque fois que la barre de progression est vidée, elle commence sur une nouvelle ligne.

    print('\r[{0}]{1}%'.format('#' * progress* 10, progress))  
    

    comme ça:
    [] 0%
    [#]dix%
    [##] 20%
    [###] 30%

2.Le crochet ']' et le nombre pour cent sur le côté droit se décalent à droite, tandis que '###' s'allonge.
3. Une erreur se produira si l'expression 'progress/10' ne peut pas renvoyer un entier.

Et le code suivant résoudra le problème ci-dessus.

def update_progress(progress, total):  
    print('\r[{0:10}]{1:>2}%'.format('#' * int(progress * 10 /total), progress), end='')
2
Storm-Eyes
import sys
def progresssbar():
         for i in range(100):
            time.sleep(1)
            sys.stdout.write("%i\r" % i)

progressbar()

NOTE: si vous utilisez ceci dans un interpréteur interactif, vous obtenez des numéros supplémentaires imprimés

2
Ramchandra Apte

Une solution très simple consiste à mettre ce code dans votre boucle:

Mettez ceci dans le corps (c'est-à-dire en haut) de votre fichier:

import sys

Mettez ceci dans le corps de votre boucle:

sys.stdout.write("-") # prints a dash for each iteration of loop
sys.stdout.flush() # ensures bar is displayed incrementally
2

Réunissant certaines des idées que j'ai trouvées ici et en ajoutant le temps estimé qui reste:

import datetime, sys

start = datetime.datetime.now()

def print_progress_bar (iteration, total):

    process_duration_samples = []
    average_samples = 5

    end = datetime.datetime.now()

    process_duration = end - start

    if len(process_duration_samples) == 0:
        process_duration_samples = [process_duration] * average_samples

    process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration]
    average_process_duration = sum(process_duration_samples, datetime.timedelta()) / len(process_duration_samples)
    remaining_steps = total - iteration
    remaining_time_estimation = remaining_steps * average_process_duration

    bars_string = int(float(iteration) / float(total) * 20.)
    sys.stdout.write(
        "\r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
            '='*bars_string, float(iteration) / float(total) * 100,
            iteration,
            total,
            remaining_time_estimation
        ) 
    )
    sys.stdout.flush()
    if iteration + 1 == total:
        print 


# Sample usage

for i in range(0,300):
    print_progress_bar(i, 300)
1
Ivan Chaer

Code pour la barre de progression du terminal python

import sys
import time

max_length = 5
at_length = max_length
empty = "-"
used = "%"

bar = empty * max_length

for i in range(0, max_length):
    at_length -= 1

    #setting empty and full spots
    bar = used * i
    bar = bar+empty * at_length

    #\r is carriage return(sets cursor position in terminal to start of line)
    #\0 character escape

    sys.stdout.write("[{}]\0\r".format(bar))
    sys.stdout.flush()

    #do your stuff here instead of time.sleep
    time.sleep(1)

sys.stdout.write("\n")
sys.stdout.flush()
1
emd_22

Voici ma solution Python 3:

import time
for i in range(100):
    time.sleep(1)
    s = "{}% Complete".format(i)
    print(s,end=len(s) * '\b')

'\ b' est une barre oblique inverse pour chaque caractère de votre chaîne. Cela ne fonctionne pas dans la fenêtre de commande Windows.

0
Matt-the-Bat

https://pypi.python.org/pypi/progressbar2/3.30.2

Progressbar2 est une bonne bibliothèque pour la barre de progression ascii pour la barre de progression de l'importation de la ligne de commande

bar = progressbar.ProgressBar()
for i in bar(range(100)):
    time.sleep(0.02)
bar.finish()

https://pypi.python.org/pypi/tqdm

tqdm est une alternative de progressbar2 et je pense l'utiliser dans pip3 mais je ne suis pas sûr de cela

from tqdm import tqdm
for i in tqdm(range(10000)):
...
0
Antoine Boucher

Eh bien voici le code qui fonctionne et je l’ai testé avant de poster:

import sys
def prg(prog, fillchar, emptchar):
    fillt = 0
    emptt = 20
    if prog < 100 and prog > 0:
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%")
        sys.stdout.flush()
    Elif prog >= 100:
        prog = 100
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nDone!")
        sys.stdout.flush()
    Elif prog < 0:
        prog = 0
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nHalted!")
        sys.stdout.flush()

Avantages:

  • Barre de 20 caractères (1 caractère pour chaque 5 (nombre de chiffres))
  • Caractères de remplissage personnalisés
  • Personnages vides
  • Halte (n'importe quel nombre inférieur à 0)
  • Fait (100 et n'importe quel nombre supérieur à 100)
  • Compte d'avancement (0-100 (en dessous et au dessus utilisés pour des fonctions spéciales))
  • Nombre en pourcentage à côté de la barre, et c'est une seule ligne

Les inconvénients:

  • Prend en charge uniquement les nombres entiers (il peut être modifié pour les prendre en charge, en faisant de la division une division en nombre entier, il suffit donc de changer prog2 = prog/5 en prog2 = int(prog/5))
0
Cold Diamondz

fonction de Greenstick pour 2.7:

def printProgressBar (iteration, total, prefix = '', suffix = '',decimals = 1, length = 100, fill = '#'):

percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print'\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix),
sys.stdout.flush()
# Print New Line on Complete                                                                                                                                                                                                              
if iteration == total:
    print()
0

Pour python 3:

def progress_bar(current_value, total):
    increments = 50
    percentual = ((current_value/ total) * 100)
    i = int(percentual // (100 / increments ))
    text = "\r[{0: <{1}}] {2}%".format('=' * i, increments, percentual)
    print(text, end="\n" if percentual == 100 else "")
0
Rodrigo López

Le module python barre de progression est un bon choix. Voici mon code typique:

import time
import progressbar

widgets = [
    ' ', progressbar.Percentage(),
    ' ', progressbar.SimpleProgress(format='(%(value_s)s of %(max_value_s)s)'),
    ' ', progressbar.Bar('>', fill='.'),
    ' ', progressbar.ETA(format_finished='- %(seconds)s  -', format='ETA: %(seconds)s', ),
    ' - ', progressbar.DynamicMessage('loss'),
    ' - ', progressbar.DynamicMessage('error'),
    '                          '
]

bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets)
bar.start(100)
for i in range(100):
    time.sleep(0.1)
    bar.update(i + 1, loss=i / 100., error=i)
bar.finish()
0
Aimin Huang

j'ai écrit une barre de progression simple:

def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""):
    if len(border) != 2:
        print("parameter 'border' must include exactly 2 symbols!")
        return None

    print(prefix + border[0] + (filler * int(current / total * length) +
                                      (space * (length - int(current / total * length)))) + border[1], suffix, "\r", end="")
    if total == current:
        if oncomp:
            print(prefix + border[0] + space * int(((length - len(oncomp)) / 2)) +
                  oncomp + space * int(((length - len(oncomp)) / 2)) + border[1], suffix)
        if not oncomp:
            print(prefix + border[0] + (filler * int(current / total * length) +
                                        (space * (length - int(current / total * length)))) + border[1], suffix)

comme vous pouvez le voir, il a: longueur de la barre, préfixe et suffixe, remplissage, espace, texte en barre sur 100% (oncomp) et bordures

voici un exemple:

from time import sleep, time
start_time = time()
for i in range(10):
    pref = str((i+1) * 10) + "% "
    complete_text = "done in %s sec" % str(round(time() - start_time))
    sleep(1)
    bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text)

en cours:

30% [######              ]

out on complete:

100% [   done in 9 sec   ] 
0
jenkins