Jak zapisać dane wyjściowe w tym samym miejscu na konsoli?

158

Jestem nowy w Pythonie i piszę kilka skryptów, aby zautomatyzować pobieranie plików z serwerów FTP itp. Chcę pokazać postęp pobierania, ale chcę, aby pozostał w tej samej pozycji, na przykład:

wynik:

Pobieranie pliku FooFile.txt [47%]

Próbuję uniknąć czegoś takiego:

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

Jak mam się do tego zabrać?


Duplikat : Jak mogę drukować w bieżącym wierszu w aplikacji wiersza poleceń?

scottm
źródło
1
możesz być zainteresowany tym łatwym w użyciu modułem, jest to tekstowy pasek postępu. pypi.python.org/pypi/progressbar/2.2
wim

Odpowiedzi:

254

Możesz także użyć powrotu karetki:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()
codelogic
źródło
13
Bardzo powszechne i proste rozwiązanie. Uwaga: jeśli twoja linia jest dłuższa niż szerokość twojego terminala, robi się brzydko.
ephemient
5
Musiałem również dodać wywołanie do sys.stdout.flush (), więc kursor nie podskakiwał
scottm
19
Czy można to zrobić z wieloma liniami? Powiedzmy, że mam trzy różne pliki do pobrania i chcę pokazać postęp każdego z nich w osobnym wierszu.
EarlCrapstone
11
Lubię umieszczać \rna początku wiersza i dodawać a, \x1b[Kaby usunąć poprzedni tekst.
augurar
11
Wygląda na to, że najprostszym rozwiązaniem dla Pythona 3 (jak wspomniano w odpowiedziach poniżej) jest: print("sample text", end='\r", flush=True)
Cyrus
35

Python 2

Podoba mi się:

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

Próbny:

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="")

Próbny:

import time

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

PyCharm Debugger Console z Pythonem 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
źródło
9
użyj tego dla Pythona 3+: print ('Pobieranie pliku FooFile.txt [% d %%] \ r'% i, end = "")
hkoosha
W konsoli PyCharm Debugger \ r musi znajdować się przed tekstem. W przeciwnym razie tekst może w ogóle się nie pojawiać lub pojawiać się niespójnie. Dodałem wersję, która działa dla mnie jako edycja, ponieważ nie mogłem napisać kodu wieloliniowego w tej odpowiedzi. Umieściłem to w swoim tekście, aby ludzie mogli go oglądać, gdy edycja czeka na zatwierdzenie: gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26df
Yul Kang
"\ r" na końcu łańcucha działa dla mnie w konsoli debuggera w PyCharm 2020.1 (PyCharm 2020.1.2 (Community Edition); kompilacja # PC-201.7846.77, zbudowana 31 maja 2020 r.).
battey
28

Użyj biblioteki obsługującej terminal, takiej jak moduł curses :

Moduł curses zapewnia interfejs do biblioteki curses, będącej de facto standardem do obsługi przenośnych zaawansowanych terminali.

gimel
źródło
1
Niedostępne dla systemu Windows.
Diego Herranz
3
@Diego jest teraz dostępna biblioteka obsługi modułu curses w systemie Windows. patrz stackoverflow.com/a/19851287/1426237
Plexico
15

Wydrukuj \bkilkakrotnie znak cofnięcia , a następnie zastąp stary numer nowym numerem.

Zach Scrivena
źródło
ciekawe, nie myślałem o zrobieniu tego w ten sposób.
Chris Ballance,
Podoba mi się to, ponieważ nie usuwa poprzednich poleceń (jeśli masz wiele etapów, które chcesz opuścić na ekranie)
Nathan Donnellan,
3
Użycie powrotu karetki (np. print 'Downloading.... \r') Również nie usuwa poprzednich danych, ale zapobiega konieczności określania, jak daleko wstecz należy wykonać kopię zapasową.
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
źródło
Dlaczego to jest lepsze niż powyższe (jestem Pythonem n00b, więc wybacz moją ignorancję :-))?
BalinKingOfMoria przywraca CMs
7

W przypadku Pythona 3xx:

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

Zgrabnym rozwiązaniem, które się sprawdziło, jest:

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

Jest sys.stdout.flushto ważne, w przeciwnym razie staje się naprawdę niezgrabne, a print("")wyjście z pętli jest również ważne.

AKTUALIZACJA : Jak wspomniano w komentarzach, printma również flushargument. Więc poniższe również będą działać:

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
źródło
1
W nowoczesnym Pythonie możesz podać argument flush=Truedo print, więc nie ma potrzeby dodatkowego sys.stdout.flush()wywołania.
2:00 po południu
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="")
Malajski Hazarika
źródło