Python zum Ausdrucken der Statusleiste und des Prozentsatzes

159

So implementieren Sie eine Statusleiste wie folgt:

[==========                ]  45%
[================          ]  60%
[==========================] 100%

Ich möchte, dass dies in stdout ausgedruckt wird und weiterhin aktualisiert wird, nicht in einer anderen Zeile gedruckt wird. Wie macht man das?

Stan
quelle
Ich habe eine neue Art von Fortschrittsbalken veröffentlicht, die Sie drucken, Durchsatz und Eta anzeigen und sogar anhalten können, abgesehen von den sehr coolen Animationen! Bitte werfen Sie einen Blick darauf: github.com/rsalmei/alive-progress ! lebendiger Fortschritt
rsalmei

Antworten:

146

Es ist ein Python - Modul , dass Sie von bekommen PyPI genannt , progressbardass Geräte eine solche Funktionalität. Wenn es Ihnen nichts ausmacht, eine Abhängigkeit hinzuzufügen, ist dies eine gute Lösung. Andernfalls gehen Sie mit einer der anderen Antworten.

Ein einfaches Beispiel für die Verwendung:

import progressbar
from time import sleep
bar = progressbar.ProgressBar(maxval=20, \
    widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])
bar.start()
for i in xrange(20):
    bar.update(i+1)
    sleep(0.1)
bar.finish()

Um es zu installieren, können Sie verwenden easy_install progressbar, oder pip install progressbarwenn Sie pip bevorzugen.

icktoofay
quelle
Alle Antworten sind fantastisch, aber ich mag Modul am meisten. Danke an alle.
Stan
8
Vielleicht braucht dieses Beispiel so etwas wie bar.start()?
Jim Raynor
2
Funktioniert nicht auf meiner Maschinebar.start()
Zach
1
Dieses Modul wurde seit über 2 Jahren nicht mehr aktualisiert. Verwenden Sie es nicht für neue Software!
Navin
4
Installation : sudo -H pip install progressbar2.
Martin Thoma
253

Das '\r'Zeichen (Wagenrücklauf) setzt den Cursor auf den Zeilenanfang zurück und ermöglicht es Ihnen, über das zu schreiben, was zuvor in der Zeile stand.

from time import sleep
import sys

for i in range(21):
    sys.stdout.write('\r')
    # the exact output you're looking for:
    sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
    sys.stdout.flush()
    sleep(0.25)

Ich bin nicht 100% sicher, ob dies auf allen Systemen vollständig portierbar ist, aber es funktioniert zumindest unter Linux und OSX.

Mark Rushakoff
quelle
7
Dies ist besser als die markierte Antwort, da es auch mit Python 3 funktioniert.
Gerhard Hagerer
Gibt es eine Idee, warum ich manchmal seltsame Zeichen am Ende einer Zeile bekomme, selbst wenn ich die gerade geschriebene Zeichenfolge mit Null beende?
Reservoirman
21
Wie geschrieben, macht der Code nicht klar, wie dies an die Größe angepasst werden kann, über die Sie iterieren (nicht 21). Ich würde lassen n=21, ersetzen range(21)durch range(n), dann j = (i + 1) / ninnerhalb der Schleife hinzufügen und die writeAnweisung durch diese geringfügige Modifikation ersetzen : sys.stdout.write("[%-20s] %d%%" % ('='*int(20*j), 100*j)). Jetzt müssen Sie nur noch n=21vor der Schleife (wahrscheinlicher n=len(iterable)) Änderungen vornehmen und dann über das iterierbare Objekt aufzählen. Ich habe diese Änderung empfohlen, aber sie wurde abgelehnt. anscheinend weicht die Funktionalität "von der ursprünglichen Absicht des Beitrags ab".
Steven C. Howell
1
Adaptiv mit beliebiger Größe von n sys.stdout.write("[{:{}}] {:.1f}%".format("="*i, n-1, (100/(n-1)*i)))
,,
3
@ StevenC.Howell, warum postest du es nicht als Antwort unter Berufung auf Mark? Es ist eine andere Version und es ist sehr hilfreich, sie fertig zu machen
GM
91

Ich fand nützliche Bibliothek tqdm ( https://github.com/tqdm/tqdm/ , zuvor: https://github.com/noamraph/tqdm ). Es schätzt automatisch die Fertigstellungszeit und kann als Iterator verwendet werden.

Verwendung:

import tqdm
import time

for i in tqdm.tqdm(range(1000)):
    time.sleep(0.01)
    # or other long operations

Ergebnisse in:

|####------| 450/1000  45% [elapsed: 00:04 left: 00:05, 99.15 iters/sec]

tqdm kann jedes iterable umschließen.

Omikron
quelle
4
Das tqdm-Projekt wird jetzt hier von einem neuen Entwicklerteam gepflegt .
gaborous
1
waw, dieses tqdm ist einfach unglaublich und so einfach zu bedienen :).
Sidahmed
6
Dies ist leicht die einfachste Lösung
kd88
2
Es ist auch im Lieferumfang der Anaconda-Distribution enthalten! (mindestens für Python 3.5 und höher)
Jacquot
Danke, erstaunlich, einfach und effektiv
DavideL
23

Sie können verwenden \r( Wagenrücklauf ). Demo:

import sys
total = 10000000
point = total / 100
increment = total / 20
for i in xrange(total):
    if(i % (5 * point) == 0):
        sys.stdout.write("\r[" + "=" * (i / increment) +  " " * ((total - i)/ increment) + "]" +  str(i / point) + "%")
        sys.stdout.flush()
Matthew Flaschen
quelle
Versuchen Sie es totalals 10, dann erhalten Sie eine FehlermeldungZeroDivisionError: long division or modulo by zero
unseen_rider
19

Hier können Sie folgenden Code als Funktion verwenden:

def drawProgressBar(percent, barLen = 20):
    sys.stdout.write("\r")
    progress = ""
    for i in range(barLen):
        if i < int(barLen * percent):
            progress += "="
        else:
            progress += " "
    sys.stdout.write("[ %s ] %.2f%%" % (progress, percent * 100))
    sys.stdout.flush()

Bei Verwendung von .format:

def drawProgressBar(percent, barLen = 20):
    # percent float from 0 to 1. 
    sys.stdout.write("\r")
    sys.stdout.write("[{:<{}}] {:.0f}%".format("=" * int(barLen * percent), barLen, percent * 100))
    sys.stdout.flush()
Jacob CUI
quelle
Für mich wird die erste Zeile nicht durch den Cursor geändert - nur die zweite Zeile. Daher mehrere Zeilen für den Fortschrittsbalken und eine für zB] percent * 100 %
unseen_rider
6

Aufgrund der obigen Antworten und anderer ähnlicher Fragen zum CLI-Fortschrittsbalken habe ich eine allgemeine Antwort auf alle Fragen erhalten. Überprüfen Sie es unter https://stackoverflow.com/a/15860757/2254146

Hier ist eine Kopie der Funktion, die jedoch an Ihren Stil angepasst wurde:

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

Sieht aus wie

Prozent: [===================] 99,0%

Brian Khuu
quelle
Der Fortschrittsbalken erscheint für mich nicht
unseen_rider
Ich denke, dass es nicht so viele Dezimalstellen braucht, dh rund (Fortschritt * 100,2)
Andrés Sánchez
4

Wenn Sie eine Befehlszeilenschnittstelle entwickeln, empfehle ich Ihnen, einen Blick darauf zu werfen, clickwas sehr schön ist:

import click
import time

for filename in range(3):
    with click.progressbar(range(100), fill_char='=', empty_char=' ') as bar:
        for user in bar:
            time.sleep(0.01)

Hier die Ausgabe, die Sie erhalten:

$ python test.py
  [====================================]  100%
  [====================================]  100%
  [=========                           ]   27%
nowox
quelle
4

Weitere Verbesserung durch Verwendung einer Funktion als:

import sys

def printProgressBar(i,max,postText):
    n_bar =10 #size of progress bar
    j= i/max
    sys.stdout.write('\r')
    sys.stdout.write(f"[{'=' * int(n_bar * j):{n_bar}s}] {int(100 * j)}%  {postText}")
    sys.stdout.flush()

Aufrufbeispiel:

total=33
for i in range(total):
    printProgressBar(i,total,"blah")
    sleep(0.05)  

Ausgabe:

[================================================  ] 96%  blah  
STG
quelle
perfekt! und keine Module erforderlich
Uhr
3

Ich bin heute auf diesen Thread gestoßen, nachdem ich diese Lösung von Mark Rushakoff ausprobiert hatte

from time import sleep
import sys

for i in range(21):
sys.stdout.write('\r')
# the exact output you're looking for:
sys.stdout.write("[%-20s] %d%%" % ('='*i, 5*i))
sys.stdout.flush()
sleep(0.25)

Ich kann sagen, dass dies auf W7-64 mit Python 3.4.3 64-Bit gut funktioniert, aber nur in der nativen Konsole. Bei Verwendung der integrierten Konsole von spyder 3.0.0dev sind die Zeilenumbrüche jedoch weiterhin vorhanden. Da ich einige Zeit gebraucht habe, um dies herauszufinden, möchte ich diese Beobachtung hier berichten.

Mr.Bum
quelle
2

Aufbauend auf einigen der Antworten hier und anderswo habe ich diese einfache Funktion geschrieben, die einen Fortschrittsbalken und die verstrichene / geschätzte verbleibende Zeit anzeigt. Sollte auf den meisten Unix-basierten Computern funktionieren.

import time
import sys

percent = 50.0
start = time.time()
draw_progress_bar(percent, start)


def draw_progress_bar(percent, start, barLen=20):
sys.stdout.write("\r")
progress = ""
for i in range(barLen):
    if i < int(barLen * percent):
        progress += "="
    else:
        progress += " "

elapsedTime = time.time() - start;
estimatedRemaining = int(elapsedTime * (1.0/percent) - elapsedTime)

if (percent == 1.0):
    sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: Done!\n" % 
        (progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60))
    sys.stdout.flush()
    return
else:
    sys.stdout.write("[ %s ] %.1f%% Elapsed: %im %02is ETA: %im%02is " % 
        (progress, percent * 100, int(elapsedTime)/60, int(elapsedTime)%60,
         estimatedRemaining/60, estimatedRemaining%60))
    sys.stdout.flush()
    return
Sam Jordan
quelle
2

Dies ist ein recht einfacher Ansatz, der mit jeder Schleife verwendet werden kann.

#!/usr/bin/python
for i in range(100001):
    s =  ((i/5000)*'#')+str(i)+(' %')
    print ('\r'+s),
NILESH KUMAR
quelle
Was macht das '#'?
unseen_rider
@unseen_rider Hier ist '#' nur ein Symbol, das wiederholt wird, wenn die Schleifeniteration zunimmt.
NILESH KUMAR
2

Am einfachsten ist es noch

import sys
total_records = 1000
for i in range (total_records):
    sys.stdout.write('\rUpdated record: ' + str(i) + ' of ' + str(total_records))
    sys.stdout.flush()

Der Schlüssel ist, den Integer-Typ in einen String zu konvertieren.

bfree67
quelle
2

Wie in Mark Rushakoffs Lösung beschrieben , können Sie das Wagenrücklaufzeichen ausgeben sys.stdout.write('\r'), um den Cursor auf den Zeilenanfang zurückzusetzen. Um diese Lösung zu verallgemeinern und gleichzeitig die f-Strings von Python 3 zu implementieren , können Sie sie verwenden

from time import sleep
import sys

n_bar = 50
iterable = range(33)  # for demo purposes
n_iter = len(iterable)
for i, item in enumerate(iterable):
    j = (i + 1) / n_iter

    sys.stdout.write('\r')
    sys.stdout.write(f"[{'=' * int(n_bar * j):{n_bar}s}] {int(100 * j)}%")
    sys.stdout.flush()

    sleep(0.05)  
    # do something with <item> here
Steven C. Howell
quelle
1

Versuchen Sie PyProg. PyProg ist eine Open-Source-Bibliothek für Python, mit der Sie super anpassbare Fortschrittsanzeigen und Balken erstellen können.

Es ist derzeit in Version 1.0.2; Es wird auf Github gehostet und ist auf PyPI verfügbar (Links unten). Es ist kompatibel mit Python 3 & 2 und kann auch mit Qt Console verwendet werden.

Es ist wirklich einfach zu bedienen. Der folgende Code:

import pyprog
from time import sleep

# Create Object
prog = pyprog.ProgressBar(" ", " ", total=34, bar_length=26, complete_symbol="=", not_complete_symbol=" ", wrap_bar_prefix=" [", wrap_bar_suffix="] ", progress_explain="", progress_loc=pyprog.ProgressBar.PROGRESS_LOC_END)
# Update Progress Bar
prog.update()

for i in range(34):
    # Do something
    sleep(0.1)
    # Set current status
    prog.set_stat(i + 1)
    # Update Progress Bar again
    prog.update()

# Make the Progress Bar final
prog.end()

produziert genau das, was Sie wollen (sogar die Stablänge!):

[===========               ] 45%
[===============           ] 60%
[==========================] 100%

Weitere Optionen zum Anpassen des Fortschrittsbalkens finden Sie auf der Github-Seite dieser Website.

Ich habe PyProg tatsächlich gemacht, weil ich eine einfache, aber super anpassbare Fortschrittsbalkenbibliothek brauchte. Sie können es einfach installieren mit : pip install pyprog.

PyProg Github: https://github.com/Bill13579/pyprog
PyPI: https://pypi.python.org/pypi/pyprog/

Bill Kudo
quelle
1

Mit der Antwort von @ Mark-Rushakoff habe ich einen einfacheren Ansatz erarbeitet, ohne die sys-Bibliothek aufrufen zu müssen. Es funktioniert mit Python 3. Getestet in Windows:

from time import sleep
for i in range(21):
    # the exact output you're looking for:
    print ("\r[%-20s] %d%%" % ('='*i, 5*i), end='')
    sleep(0.25)
Stein
quelle
Wie in der Antwort auf eine andere Frage beschrieben, print handelt es sich um einen Thin Wrapper, der die Eingabe formatiert und die Schreibfunktion eines bestimmten Objekts aufruft. Standardmäßig ist dieses Objekt sys.stdout.
Steven C. Howell
0

Hier ist etwas, das ich mit der Lösung von @ Mark-Rushakoff gemacht habe. Adaptive Anpassung an die Klemmenbreite.

from time import sleep
import os
import sys
from math import ceil

l = list(map(int,os.popen('stty size','r').read().split()))
col = l[1]
col = col - 6

for i in range(col):
    sys.stdout.write('\r')
    getStr = "[%s " % ('='*i)
    sys.stdout.write(getStr.ljust(col)+"]"+"%d%%" % (ceil((100/col)*i)))
    sys.stdout.flush()
    sleep(0.25)
print("")
swarnava112
quelle