Pregunta

¿Hay una buena manera de hacer lo siguiente?

Me escribió una aplicación de consola sencilla para cargar y descargar archivos desde un servidor FTP usando el ftplib.

Cada vez algunos fragmentos de datos se descargan, quiero actualizar una barra de progreso de texto, incluso si es sólo un número.

Pero no quiero borrar todo el texto que ha sido impreso en la consola. (Haciendo un "claro" y luego imprimir el porcentaje actualizada).

¿Fue útil?

Solución

Una simple y personalizable Barra de progreso

Aquí hay un agregado de muchas de las respuestas a continuación que utilizo regularmente (no hay importaciones requeridas).

# 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()

Nota: Esto es para Python 3; ver los comentarios para detalles sobre el uso de este en Python 2.

Uso de muestra

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)

Salida de muestra:

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

Actualizar

Hubo una discusión en los comentarios con respecto a una opción que permite que la barra de progreso para ajustar dinámicamente el ancho de ventana de terminal. Si bien no recomiendo esto, aquí hay un GIST que implementa esta característica (y las notas de las salvedades) .

Otros consejos

Escritura '\ r' se moverá la parte posterior cursor al principio de la línea.

Esto muestra un contador de porcentaje:

import time
import sys

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

tqdm: añadir un indicador de progreso a sus bucles en un segundo :

>>> 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]

 sesión tqdm repl

Es menos de 10 líneas de código.

Lo esencial aquí: https://gist.github.com/vladignatyev/06860ec2040cb497f0f3

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

introducir descripción de la imagen aquí

clic librería escrita por el Mozart de Python, Armin Ronacher.

$ pip install click # both 2 and 3 compatible

Para crear una barra de progreso sencilla:

import click

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

Esto es lo que parece:

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

Personalizar contenido de su corazón:

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

aspecto personalizado:

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

Hay aún más opciones, consulte la API docs :

 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)

Me doy cuenta de que estoy tarde para el juego, pero aquí hay un poco de estilo Yum (Red Hat) que escribí (no va por el 100% de precisión aquí, pero si usted está utilizando una barra de progreso para ese nivel de precisión , entonces usted está equivocado de todos modos):

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()

debe producir algo parecido a esto:

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

... donde los soportes se mantienen estacionarios y aumentan sólo los hashes.

Esto podría funcionar mejor como decorador. Por otro día ...

Comprobar esta biblioteca: Clint

que tiene un montón de características que incluyen una barra de progreso:

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

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

enlace ofrece un breve resumen de sus características

Este es un ejemplo agradable de un progressbar escrito en Python: http : //nadiana.com/animated-terminal-progress-bar-in-python

Pero si desea escribir usted mismo. Se podría utilizar el módulo curses para facilitar las cosas:)

[editar] Tal vez más fácil no es la palabra de maldiciones. Pero si desea crear una cui en toda regla de maldiciones se ocupa de un montón de cosas para usted.

[editar] Desde el antiguo enlace está muerto He puesto mi propia versión de un Progressbar Python, obtenerlo aquí: https: //github.com/WoLpH/python-progressbar

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()

salida

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

y, sólo para añadir a la pila, aquí es un objeto que puede utilizar

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 __name__ == "__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"

resultados en:

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

Esto sería más comúnmente se considera que es "por encima", pero es muy útil cuando se está usando mucho

Ejecutar este en la línea de comandos de Python ( no en cualquier entorno IDE o desarrollo):

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

funciona bien en mi sistema de Windows.

Instalar tqdm. (pip install tqdm) y utilizarlo como sigue:

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

Esto es una barra de progreso de 10 segundos que la producción'LL algo como esto:

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

Estoy utilizando el progreso de Reddit . Me gusta porque puedo imprimir progreso para todos los elementos de una línea, y no debería borrar las impresiones del programa.

Editar: enlace fijo

basado en las respuestas anteriores y otras preguntas similares acerca de la CLI barra de progreso, creo que tengo una respuesta general común a todos ellos. Comprobarlo en https://stackoverflow.com/a/15860757/2254146

En resumen, el código es el siguiente:

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()

Las apariencias como

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

Le recomiendo usar tqdm - https://pypi.python.org/pypi/tqdm -. lo que hace que sea fácil de convertir cualquier iterable o proceso en una barra de progreso y maneja todas estas perder el tiempo con los terminales necesarios

A partir de la documentación: "tqdm puede soportar fácilmente las devoluciones de llamada / ganchos y actualizaciones manuales He aquí un ejemplo con 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)

Trate de instalar este paquete: pip install progressbar2:

import time
import progressbar

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

progresssbar github: https://github.com/WoLpH/python-progressbar

import sys
def progresssbar():
         for i in range(100):
            time.sleep(1)
            sys.stdout.write("%i\r" % i)

progressbar()

NOTA: si ejecuta esto en interepter interactiva te números adicionales imprimió

lol que acabo de escribir toda una cosita para este aquí está el mantener el código en cuenta que no puede utilizar Unicode cuando se hace el bloque ascii yo uso 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()

y se llame igual que

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

lo que parece que este

loading something awesome
|█████     |

Con los consejos grandes por encima de Trabajo fuera la barra de progreso.

Sin embargo, me gustaría señalar algunas deficiencias

  1. Cada vez que se vacía la barra de progreso, que se iniciará en una nueva línea

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

    así:
    [] 0%
    [#] 10%
    [##] 20%
    [###] 30%

2. El corchete ']' y el número ciento en el turno de mano derecha, como el '###' hacen más largos.
3. error Un ocurrirá si 'progreso / 10' la expresión no puede devolver un entero.

Y el código siguiente se solucionará el problema anterior.

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

Una solución muy simple es poner este código en su bucle:

Ponga esto en el cuerpo (es decir, superior) de su archivo:

import sys

Ponga esto en el cuerpo de su bucle:

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

Código para el pitón barra de progreso del terminal

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()

La elaboración de algunas de las ideas que encontrar aquí, y la adición de tiempo restante que queda:

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)

Bueno, aquí está el código que funciona y lo probaron antes de la publicación:

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()

Pros:

  • 20 barra de caracteres (1 carácter para cada 5 (número racional))
  • caracteres de relleno personalizados
  • Custom caracteres vacíos
  • Halt (cualquier número por debajo de 0)
  • Listo (100 y cualquier número por encima de 100)
  • recuento Progreso (0-100 (por debajo y por encima utilizado para funciones especiales))
  • Número Porcentaje junto al bar, y es una sola línea

Contras:

  • Apoyos sólo enteros (que puede ser modificado para apoyarlos, sin embargo, al hacer la división de una división entera, por lo que acaba de cambiar a prog2 = prog/5 prog2 = int(prog/5))

Aquí está mi solución Python 3:

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

'\ b' es una barra invertida, para cada carácter en la cadena. Esto no funciona dentro de la ventana de CMD de Windows.

función de tallo verde para 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()

El módulo de Python progressbar es una opción agradable. Aquí está mi código típico:

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()

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

Progressbar2 es una biblioteca bueno para progressbar base de ASCII para la línea de comandos     tiempo de importación     progressbar importación

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

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

tqdm es una alternativa de progressbar2 y creo que su uso en PIP3 pero no estoy seguro de eso

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

i escribió una progressbar 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)

como se puede ver, se tiene: longitud de la barra, prefijo y un sufijo, relleno, espacio, texto en bar en 100% (oncomp) y las fronteras

aquí un ejemplo:

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)

a cabo en curso:

30% [######              ]

a cabo en completa:

100% [   done in 9 sec   ] 
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top