Domanda

C'è un buon modo per fare quanto segue?

Ho scritto una semplice console app per caricare e scaricare file da un server FTP utilizzando il ftplib.

Ogni volta che alcuni blocchi di dati vengono scaricati, voglio aggiornare una barra di avanzamento di testo, anche se è solo un numero.

Ma io non voglio cancellare tutto il testo che è stato stampato sulla console. (Facendo un "chiaro" e quindi la stampa la percentuale aggiornata.)

È stato utile?

Soluzione

Un semplice, personalizzabile Barra di avanzamento

Ecco un aggregato di molte delle risposte qui sotto che uso regolarmente (nessuna importazione richiesti).

# 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: Questo è per Python 3; vedere i commenti per dettagli sull'utilizzo di questo in Python 2.

Utilizzo Esempio

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)

Output di esempio:

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

Aggiorna

Non c'era discussione nei commenti un'opzione che consente la barra di avanzamento per regolare in modo dinamico alla larghezza della finestra del terminale. Mentre io non consiglio questo, ecco un succo che implementa questa funzione (e note i caveat) .

Altri suggerimenti

La scrittura '\ r' si sposterà sul retro cursore all'inizio della riga.

Questo mostrerà un contatore percentuale:

import time
import sys

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

TQdM: aggiungere un indicatore di avanzamento ai vostri cicli in un secondo :

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

 sessione TQdM repl

Si tratta di meno di 10 righe di codice.

Il succo qui: 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

entrare descrizione dell'immagine qui

Prova il clicca libreria scritta da parte del Mozart di Python, Armin Ronacher.

$ pip install click # both 2 and 3 compatible

Per creare una semplice barra di avanzamento:

import click

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

Questo è ciò che sembra:

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

Personalizza ai vostri cuori contenuto:

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

aspetto personalizzato:

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

Non ci sono ancora più opzioni, vedere la Documentazione 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)

mi accorgo di essere in ritardo al gioco, ma qui è un po 'Yum-style (Red Hat) che ho scritto (non andare per il 100% di precisione qui, ma se si sta utilizzando una barra di avanzamento per quel livello di accuratezza , allora ti sbagli in ogni caso):

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

dovrebbe produrre qualcosa di simile a questo:

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

... dove le parentesi rimanere fermo e solo gli hash aumentano.

Questo lavoro potrebbe meglio come un decoratore. Per un altro giorno ...

Controlla questa libreria: Clint

ha un sacco di funzioni, tra cui una barra di avanzamento:

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)

link fornisce una rapida panoramica delle sue caratteristiche

Ecco un bel esempio di un ProgressBar scritto in Python: http : //nadiana.com/animated-terminal-progress-bar-in-python

Ma se si vuole scrivere da soli. È possibile utilizzare il modulo curses per rendere le cose più facili:)

[modifica] Forse più facile non è la parola per maledizioni. Ma se si desidera creare un cui conclamata di maledizioni si prende cura di un sacco di roba per te.

[modifica] Dal momento che il vecchio link è morto ho messo la mia versione di un pitone Progressbar, farlo qui: 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()

uscita

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

e, solo per aggiungere al mucchio, ecco un oggetto è possibile utilizzare

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"

Risultati in:

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

Questo sarebbe più comunemente essere considerato "over the top", ma è a portata di mano quando si utilizza un sacco

Esegui questo nella riga di comando Python ( non in qualsiasi ambiente IDE o sviluppo):

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

funziona bene sul mio sistema di Windows.

Installa tqdm. (pip install tqdm) e usarlo come segue:

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

Questo è un 10 secondi barra di avanzamento che sarà in uscita qualcosa di simile:

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

progresso da reddit . Mi piace perché è possibile stampare il progresso per ogni elemento in una linea, e non deve cancellare le stampe dal programma.

Modifica: collegamento fisso

sulla base delle risposte di cui sopra e altre domande simili riguardo CLI barra di avanzamento, penso che ho avuto una risposta generale comune a tutti loro. Controllarla https://stackoverflow.com/a/15860757/2254146

In sintesi, il codice è questo:

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

appare come

Percentuale: [##########] 99.0%

Mi consiglia di utilizzare TQdM - https://pypi.python.org/pypi/tqdm -. che rende semplice per trasformare qualsiasi iterabile o processo in una barra di avanzamento, e gestisce tutte Messing circa con terminali necessari

Dalla documentazione: "TQdM può facilmente sostenere callback / ganci e gli aggiornamenti manuali Ecco un esempio 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)

Prova a installare questo pacchetto: 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: se si esegue questo in interepter interattivo si ottiene numeri in più stampato fuori

lol ho appena scritto un intero thingy per questo Heres il codice tenere a mente che si cant utilizzare unicode quando si fa blocco ascii io 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()

e si chiamano in questo modo

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

in modo che appaia come questo

loading something awesome
|█████     |

Con le grandi consigli sopra io lavoro fuori la barra di avanzamento.

Tuttavia vorrei sottolineare alcune lacune

  1. Ogni volta che la barra di avanzamento viene lavata, inizierà su una nuova linea

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

    in questo modo:
    [] 0%
    [#] 10%
    [##] 20%
    [###] 30%

2. parentesi quadra ']' e il numero di cento a destra spostamento a destra lato del '###' allungarsi.
3. Un errore si verificherà se l'espressione 'avanzamento / 10' non può restituire un numero intero.

E il seguente codice risolverà il problema di cui sopra.

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

Una soluzione molto semplice è quella di inserire questo codice nel vostro ciclo:

Mettere questo nel corpo (cioè in alto) del file:

import sys

Mettere questo nel corpo del ciclo:

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

Codice per Python barra di avanzamento del terminale

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

Mettendo insieme alcune delle idee che ho trovato qui, e l'aggiunta di tempo stimato rimanente:

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)

Bene, qui è il codice che funziona e ho provato prima dell'inserimento:

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

Pro:

  • 20 bar carattere (1 carattere per ogni 5 (numero di saggio))
  • caratteri di riempimento personalizzati
  • personalizzati caratteri vuoti
  • Halt (qualsiasi numero sotto 0)
  • Fatto (100 e qualsiasi numero superiore a 100)
  • count Progress (0-100 (sotto e sopra utilizzato per funzioni speciali))
  • Numero Percentuale accanto al bar, ed è una sola riga

Contro:

  • Supporti solo interi (E possono essere modificati per sostenerli però, facendo divisione una divisione intera, quindi basta cambiare prog2 = prog/5 a prog2 = int(prog/5))

Ecco la mia soluzione Python 3:

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

'\ b' è una barra inversa, per ogni carattere nella stringa. Ciò non funziona all'interno di Windows finestra CMD.

funzione dal legno verde per 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()

Il modulo python progressbar è una scelta piacevole. Ecco il mio codice tipico:

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 è una libreria bene per progressbar di base ASCII per la riga di comando     tempo di importazione     import progressbar

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

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

TQdM è un'alternativa di progressbar2 e penso che l'uso in PIP3 ma non sono sicuro di questo

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

Ho scritto un semplice progressbar:

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)

come si può vedere, si hanno: lunghezza della barra, prefisso e suffisso, riempitivo, lo spazio, il testo nella barra sul 100% (oncomp) e bordi

qui un esempio:

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)

in corso:

30% [######              ]

sul completo:

100% [   done in 9 sec   ] 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top