Wie schreibe ich die Ausgabe an derselben Stelle auf der Konsole?

158

Ich bin neu in Python und schreibe einige Skripte, um das Herunterladen von Dateien von FTP-Servern usw. zu automatisieren. Ich möchte den Fortschritt des Downloads anzeigen, aber ich möchte, dass er an derselben Position bleibt, wie z.

Ausgabe:

Herunterladen der Datei FooFile.txt [47%]

Ich versuche so etwas zu vermeiden:

     Downloading File FooFile.txt [47%]
     Downloading File FooFile.txt [48%]
     Downloading File FooFile.txt [49%]

Wie soll ich das machen?


Duplizieren : Wie kann ich in einer Befehlszeilenanwendung über die aktuelle Zeile drucken?

Scottm
quelle
1
Vielleicht interessiert Sie dieses benutzerfreundliche Modul, es ist eine Textfortschrittsleiste. pypi.python.org/pypi/progressbar/2.2
wim

Antworten:

254

Sie können auch den Wagenrücklauf verwenden:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()
codelogic
quelle
13
Sehr häufige und einfache Lösung. Hinweis: Wenn Ihre Leitung länger als die Breite Ihres Terminals ist, wird dies hässlich.
Ephemient
5
Ich musste auch einen Aufruf an sys.stdout.flush () hinzufügen, damit der Cursor nicht
herumsprang
19
Ist dies mit mehreren Zeilen möglich? Nehmen wir an, ich habe drei verschiedene Downloads und möchte den Fortschritt jedes einzelnen in einer eigenen Zeile anzeigen.
EarlCrapstone
11
Ich setze das gerne \ran den Anfang der Zeile und füge ein hinzu \x1b[K, um den vorherigen Text zu löschen.
August
11
Es scheint, als ob die einfachste Lösung für Python 3 (wie in den Antworten unten erwähnt) ist: print("sample text", end='\r", flush=True)
Cyrus
35

Python 2

Ich mag folgendes:

print 'Downloading File FooFile.txt [%d%%]\r'%i,

Demo:

import time

for i in range(100):
    time.sleep(0.1)
    print 'Downloading File FooFile.txt [%d%%]\r'%i,

Python 3

print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

Demo:

import time

for i in range(100):
    time.sleep(0.1)
    print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

PyCharm Debugger Console mit Python 3

# On PyCharm Debugger console, \r needs to come before the text.
# Otherwise, the text may not appear at all, or appear inconsistently.
# tested on PyCharm 2019.3, Python 3.6

import time

print('Start.')
for i in range(100):
    time.sleep(0.02)
    print('\rDownloading File FooFile.txt [%d%%]'%i, end="")
print('\nDone.')
RSabet
quelle
9
Verwenden Sie dies für Python 3+: print ('Herunterladen der Datei FooFile.txt [% d %%] \ r'% i, end = "")
hkoosha
Auf der PyCharm Debugger-Konsole muss \ r vor dem Text stehen. Andernfalls wird der Text möglicherweise überhaupt nicht oder inkonsistent angezeigt. Ich habe die Version hinzugefügt, die für mich als Bearbeitung funktioniert, da ich in dieser Antwort keinen mehrzeiligen Code schreiben konnte. Ich habe es auf meinen Kern gesetzt, damit die Leute es sehen können, während die Bearbeitung auf die Genehmigung wartet: gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26df
Yul Kang
"\ r" am Ende der Zeichenfolge funktioniert für mich in der Debugger-Konsole von PyCharm 2020.1 (PyCharm 2020.1.2 (Community Edition); Build # PC-201.7846.77, erstellt am 31. Mai 2020).
Battey
28

Verwenden Sie eine Terminal-Handling-Bibliothek wie das Curses-Modul :

Das Curses-Modul bietet eine Schnittstelle zur Curses-Bibliothek, dem De-facto-Standard für die tragbare erweiterte Terminalhandhabung.

Gimel
quelle
1
Nicht verfügbar für Windows.
Diego Herranz
3
@Diego gibt es jetzt eine Unterstützungsbibliothek für das Fluchmodul unter Windows. siehe stackoverflow.com/a/19851287/1426237
Plexico
15

Drucken Sie das Rücktastezeichen \bmehrmals aus und überschreiben Sie dann die alte Nummer mit der neuen Nummer.

Zach Scrivena
quelle
Interessant, ich hatte nicht daran gedacht, es so zu machen.
Chris Ballance
Ich mag das, weil es vorherige Befehle nicht löscht (wenn Sie mehrere Stufen haben, die Sie auf dem Bildschirm lassen möchten)
Nathan Donnellan
3
Die Verwendung des Wagenrücklaufs (z. B. print 'Downloading.... \r') löscht auch keine vorherigen Daten, verhindert jedoch, dass Sie wissen müssen, wie weit die Sicherung zurückliegt.
cod3monk3y
8
#kinda like the one above but better :P

from __future__ import print_function
from time import sleep

for i in range(101):
  str1="Downloading File FooFile.txt [{}%]".format(i)
  back="\b"*len(str1)
  print(str1, end="")
  sleep(0.1)
  print(back, end="")
Christian Calderon
quelle
Warum ist das besser als oben (ich bin ein Python n00b, bitte entschuldigen Sie meine Unwissenheit :-))?
BalinKingOfMoria CMs
7

Für Python 3xx:

import time
for i in range(10):
    time.sleep(0.2) 
    print ("\r Loading... {}".format(i)+str(i), end="")
TheRutubeify
quelle
4

Eine nette Lösung, die für mich funktioniert hat, ist:

from __future__ import print_function
import sys
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r')
    sys.stdout.flush()
print("")

Das sys.stdout.flushist wichtig, sonst wird es sehr klobig und der print("")On-for-Loop-Ausgang ist ebenfalls wichtig.

UPDATE : Wie in den Kommentaren erwähnt, printhat auch ein flushArgument. Also wird auch folgendes funktionieren:

from __future__ import print_function
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r', flush=True)
print("")
Michael Hall
quelle
1
In modernem Python können Sie ein Argument von flush=Trueto angeben print, sodass kein zusätzlicher sys.stdout.flush()Aufruf erforderlich ist .
PM 2Ring
0
x="A Sting {}"
   for i in range(0,1000000):
y=list(x.format(i))
print(x.format(i),end="")

for j in range(0,len(y)):
    print("\b",end="")
Malaiische Hazarika
quelle