Drucken Sie in derselben Zeile und nicht in einer neuen Zeile in Python

85

Grundsätzlich möchte ich das Gegenteil von dem tun, was dieser Typ getan hat ... hehe.

Python-Skript: Drucken Sie jedes Mal eine neue Zeile in die Shell, anstatt die vorhandene Zeile zu aktualisieren

Ich habe ein Programm, das mir sagt, wie weit es ist.

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete"

Wenn also len (some_list) 50 wäre, würde ich diese letzte Zeile 50 Mal drucken lassen. Ich möchte eine Zeile drucken und diese Zeile ständig aktualisieren. Ich weiß, ich weiß, dass dies wahrscheinlich die lahmste Frage ist, die Sie den ganzen Tag lesen werden. Ich kann einfach nicht herausfinden, welche vier Wörter ich in Google eingeben muss, um die Antwort zu erhalten.

Aktualisieren! Ich habe den Vorschlag von mvds ausprobiert, der richtig schien. Der neue Code

print percent_complete,"           \r",

Prozent vollständig ist nur eine Zeichenfolge (ich habe das erste Mal abstrahiert, jetzt habe ich versucht, wörtlich zu sein). Das Ergebnis ist nun, dass es das Programm ausführt, nichts druckt, bis das Programm beendet ist, und dann "100 Prozent vollständig" in einer und nur einer Zeile druckt.

Ohne den Wagenrücklauf (aber mit dem Komma, der Hälfte des Vorschlags von mvds) wird bis zum Ende nichts gedruckt. Und druckt dann:

0 percent complete     2 percent complete     3 percent complete     4 percent complete    

Und so weiter. Das neue Problem ist nun, dass das Komma erst gedruckt wird, wenn das Programm beendet ist.

Mit dem Wagenrücklauf und ohne Komma verhält es sich genauso wie mit keinem.

chriscauley
quelle
Vielleicht möchten Sie auch überprüfen sys.stdout.isatty(), ob Sie diese Dinge nicht ausspucken, wenn Sie nicht in einem Terminal ausgeführt werden.
MVDS
Ich leite das von einem Terminal aus ... aber gute Gedanken. Ich bin sicher, dass ich das irgendwann brauchen werde.
Chriscauley
1
Der Hintergrund ist übrigens, dass in mehreren Sprachen das \ n (das wir jetzt weglassen) als implizites Signal dient, um auf stdout zu spülen. Denn sonst werden viele Leute verwirrt sein.
MVDS

Antworten:

85

Es heißt Wagenrücklauf, oder \r

Verwenden

print i/len(some_list)*100," percent complete         \r",

Das Komma verhindert, dass beim Drucken eine neue Zeile hinzugefügt wird. (und die Leerzeichen halten die Linie von der vorherigen Ausgabe frei)

Vergessen Sie auch nicht, mit a zu beenden print "", um mindestens eine abschließende Newline zu erhalten!

mvds
quelle
12
Stellen Sie einfach sicher, dass Sie immer die gleiche Datenmenge (oder mehr als alle vorherigen Drucke) in die Zeile drucken, da Sie sonst am Ende Cruft erhalten.
Nicholas Knight
So nah ... Ich werde die Frage mit dem Ergebnis aktualisieren.
Chriscauley
2
@dustynachos: Heh, habe diese Falte vergessen. Siehe die Frage zur Python- Ausgabepufferung
Nicholas Knight
1
@dustynachos: (oder verwenden Sie einfach sys.stdout.flush () nach jedem Druckaufruf, das kann tatsächlich besser sein, wenn Sie sich nicht um die Ausgabepufferung für den Rest Ihres Programms kümmern)
Nicholas Knight
2
das funktioniert bei mir nicht Ich habe es tatsächlich viele Male versucht und es hat bei mir nie funktioniert. Ich benutze iterm2 auf einem Mac, aber ich bin die meiste Zeit auf einem Linux-Server. Ich habe nie eine Methode gefunden, die tatsächlich funktioniert.
Bgenchel
35

Für mich funktionierte eine Kombination aus Remis und Siriusds Antworten:

from __future__ import print_function
import sys

print(str, end='\r')
sys.stdout.flush()
Dlchambers
quelle
33

Ab Python 3.x können Sie Folgendes tun:

print('bla bla', end='')

(Dies kann auch in Python 2.6 oder 2.7 verwendet werden, indem Sie es from __future__ import print_functionoben in Ihr Skript / Modul einfügen.)

Beispiel für die Fortschrittsleiste der Python-Konsole:

import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    n=0
    while n<total:
        done = '#'*(n+1)
        todo = '-'*(total-n-1)
        s = '<{0}>'.format(done+todo)
        if not todo:
            s+='\n'        
        if n>0:
            s = '\r'+s
        print(s, end='')
        yield n
        n+=1

# example for use of status generator
for i in range_with_status(10):
    time.sleep(0.1)
Remi
quelle
Das \ r scheint auch eine neue Zeile hinzuzufügen
fccoelho
2
Dadurch wird der Zeilenumbruch beseitigt, das Überschreiben ist jedoch nicht zulässig, was meiner Meinung nach der Autor wünscht.
Bgenchel
1
@bgenchel verwendet mit '\ r' (wie im Codebeispiel) genau das, was OP will
Milo Wielondek
20

In Python 3.3+ brauchen Sie nicht sys.stdout.flush(). print(string, end='', flush=True)funktioniert.

Damit

print('foo', end='')
print('\rbar', end='', flush=True)

überschreibt 'foo' mit 'bar'.

LeopardShark
quelle
2
Es funktioniert, vorausgesetzt, der gedruckte Text endet mit einem "\r".
bli
13

Für die Konsole benötigen Sie wahrscheinlich

sys.stdout.flush()

Update erzwingen. Ich denke, dass die Verwendung ,im Druck das Löschen von stdout blockiert und irgendwie nicht aktualisiert wird

Siriusd
quelle
Terminator hat die Zeile nur alle 30 Sekunden aktualisiert, wenn print ("...", end = '\ r') für mich verwendet wurde, es sei denn, ich habe diesen Befehl unmittelbar nach der print-Anweisung ausgeführt. Vielen Dank
Bryce Guinta
4

Spät zum Spiel - aber da keine der Antworten für mich funktioniert hat (ich habe nicht alle ausprobiert) und ich bei meiner Suche mehr als einmal auf diese Antwort gestoßen bin ... In Python 3 ist diese Lösung ziemlich elegant und ich glaube, es macht genau das, wonach der Autor sucht, es aktualisiert eine einzelne Aussage in derselben Zeile. Beachten Sie, dass Sie möglicherweise etwas Besonderes tun müssen, wenn die Linie schrumpft anstatt zu wachsen (z. B. die Zeichenfolge auf eine feste Länge mit gepolsterten Leerzeichen am Ende festlegen).

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)
SteveJ
quelle
einfachste und sauberste Option für Python => 3.6
DaveR
3

Das funktioniert bei mir, habe es einmal gehackt, um zu sehen, ob es möglich ist, aber nie in meinem Programm verwendet (GUI ist so viel schöner):

import time
f = '%4i %%'
len_to_clear = len(f)+1
clear = '\x08'* len_to_clear
print 'Progress in percent:'+' '*(len_to_clear),
for i in range(123):
    print clear+f % (i*100//123),
    time.sleep(0.4)
raw_input('\nDone')
Tony Veijalainen
quelle
2
import time
import sys


def update_pct(w_str):
    w_str = str(w_str)
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(" " * len(w_str))
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(w_str)
    sys.stdout.flush()

for pct in range(0, 101):
    update_pct("{n}%".format(n=str(pct)))
    time.sleep(0.1)

\bVerschiebt die Position des Cursors um ein Leerzeichen zurück.
Wir verschieben ihn also bis zum Zeilenanfang zurück.
Wir schreiben dann Leerzeichen, um die aktuelle Zeile zu löschen. Während wir Leerzeichen schreiben, bewegt sich der Cursor um eins vorwärts / rechts.
Also haben wir Bewegen Sie den Cursor am Zeilenanfang zurück, bevor Sie unsere neuen Daten schreiben

Getestet unter Windows cmd mit Python 2.7

Robert
quelle
1

Versuchen Sie es so:

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete",

(Mit einem Komma am Ende.)

Chrys
quelle
Dadurch wird nur der neue Text an den alten angehängt (funktional ähnlich, aber hässlich).
Chriscauley
1

Wenn Sie Spyder verwenden, werden die Zeilen mit allen vorherigen Lösungen kontinuierlich gedruckt. Eine Möglichkeit, dies zu vermeiden, besteht darin, Folgendes zu verwenden:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()
bfree67
quelle
Dies war die einzige funktionierende Lösung für mich (Python 3.8, Windows, PyCharm).
z33k
0

Basierend auf Remi Antwort für die Python 2.7+Verwendung dieser:

from __future__ import print_function
import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    import sys
    n = 0
    while n < total:
        done = '#' * (n + 1)
        todo = '-' * (total - n - 1)
        s = '<{0}>'.format(done + todo)
        if not todo:
            s += '\n'
        if n > 0:
            s = '\r' + s
        print(s, end='\r')
        sys.stdout.flush()
        yield n
        n += 1


# example for use of status generator
for i in range_with_status(50):
    time.sleep(0.2)
Francisco Costa
quelle
0

Für Python 3.6+und für alle listanstatt nur für ints sowie für die Verwendung der gesamten Breite Ihres Konsolenfensters und ohne Übergang zu einer neuen Zeile können Sie Folgendes verwenden:

Hinweis: Bitte beachten Sie, dass die Funktion get_console_with()nur auf Linux-basierten Systemen funktioniert und Sie sie daher neu schreiben müssen, um unter Windows zu funktionieren.

import os
import time

def get_console_width():
    """Returns the width of console.

    NOTE: The below implementation works only on Linux-based operating systems.
    If you wish to use it on another OS, please make sure to modify it appropriately.
    """
    return int(os.popen('stty size', 'r').read().split()[1])


def range_with_progress(list_of_elements):
    """Iterate through list with a progress bar shown in console."""

    # Get the total number of elements of the given list.
    total = len(list_of_elements)
    # Get the width of currently used console. Subtract 2 from the value for the
    # edge characters "[" and "]"
    max_width = get_console_width() - 2
    # Start iterating over the list.
    for index, element in enumerate(list_of_elements):
        # Compute how many characters should be printed as "done". It is simply
        # a percentage of work done multiplied by the width of the console. That
        # is: if we're on element 50 out of 100, that means we're 50% done, or
        # 0.5, and we should mark half of the entire console as "done".
        done = int(index / total * max_width)
        # Whatever is left, should be printed as "unfinished"
        remaining = max_width - done
        # Print to the console.
        print(f'[{done * "#"}{remaining * "."}]', end='\r')
        # yield the element to work with it
        yield element
    # Finally, print the full line. If you wish, you can also print whitespace
    # so that the progress bar disappears once you are done. In that case do not
    # forget to add the "end" parameter to print function.
    print(f'[{max_width * "#"}]')


if __name__ == '__main__':
    list_of_elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    for e in range_with_progress(list_of_elements):
        time.sleep(0.2)

Tamaroth
quelle
0

Wenn Sie Python 3 verwenden, ist dies für Sie und es funktioniert wirklich.

print(value , sep='',end ='', file = sys.stdout , flush = False)
Azaz-ul-Haque
quelle
0

Für Python 3+

for i in range(5):
    print(str(i) + '\r', sep='', end ='', file = sys.stdout , flush = False)
maximusdooku
quelle
0

Ich habe das nur selbst herausgefunden, weil ich einen Countdown gezeigt habe, aber es würde auch für einen Prozentsatz funktionieren.

import time
#Number of seconds to wait
i=15
#Until seconds has reached zero
while i > -1:
    #Ensure string overwrites the previous line by adding spaces at end
    print("\r{} seconds left.   ".format(i),end='')
        time.sleep(1)
        i-=1
    print("") #Adds newline after it's done

Solange alles, was nach '/ r' kommt, dieselbe Länge oder länger (einschließlich Leerzeichen) als die vorherige Zeichenfolge hat, wird es in derselben Zeile überschrieben. Stellen Sie einfach sicher, dass Sie das Ende = '' einfügen, da es sonst in einer neuen Zeile gedruckt wird. Hoffentlich hilft das!

Aufklärer
quelle
0

Für das Objekt "pega", das StartRunning (), StopRunning (), boolean getIsRunning () und die Ganzzahl getProgress100 () bereitstellt und einen Wert im Bereich von 0 bis 100 zurückgibt, wird beim Ausführen ein Textfortschrittsbalken angezeigt ...

now = time.time()
timeout = now + 30.0
last_progress = -1

pega.StartRunning()

while now < timeout and pega.getIsRunning():
    time.sleep(0.5)
    now = time.time()

    progress = pega.getTubProgress100()
    if progress != last_progress:
        print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", end='', flush=True)
        last_progress = progress

pega.StopRunning()

progress = pega.getTubProgress100()
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", flush=True)
jwasch
quelle