Piszę program do pobierania FTP. Część kodu wygląda mniej więcej tak:
ftp.retrbinary("RETR " + file_name, process)
Wzywam proces funkcji do obsługi wywołania zwrotnego:
def process(data):
print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
file.write(data)
a wynik wygląda mniej więcej tak:
1784 KB / KB 1829 downloaded!
1788 KB / KB 1829 downloaded!
etc...
ale chcę, aby wydrukowało tę linię i następnym razem ponownie wydrukowało / odświeżyło ją, aby wyświetliło się tylko raz i zobaczę postęp pobierania.
Jak można to zrobić?
python
refresh
progress-bar
Kristian
źródło
źródło
Odpowiedzi:
Oto kod dla Pythona 3.x:
print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!', end='\r')
Tutaj
end=
działa słowo kluczowe - domyślnieprint()
kończy się znakiem nowej linii (\n
), ale można go zastąpić innym ciągiem. W takim przypadku zakończenie wiersza znakiem powrotu karetki powoduje zamiast tego powrót kursora na początek bieżącego wiersza. Dlatego nie ma potrzeby importowaniasys
modułu do tego rodzaju prostego użycia.print()
w rzeczywistości ma wiele argumentów słów kluczowych których można użyć do znacznego uproszczenia kodu.Aby użyć tego samego kodu w Pythonie 2.6+, umieść następujący wiersz na górze pliku:
from __future__ import print_function
źródło
from __future__ import print_function
.print "foo",
Jednak nadal musisz spłukać po tym, aby zobaczyć zmianę:sys.stdout.flush()
\r
znak na początku ciągu iend=''
zamiast tego ustawić, aby działało. Myślę, że mój terminal nie lubi, kiedy kończę\r
flush=True
doprint()
funkcji, aby upewnić się, że bufor zostanie opróżniony (standardowy bufor linii zostanie opróżniony tylko wtedy, gdy\n
zostanie zapisany znak nowej linii).\r
na początkuend=''
działało najlepiej i płynnie. Używanieflush=True
z\r
na końcu, jeśli ciąg iend='\r'
również działał, ale nie był gładki, i usunął linię i jej wysunięcie.Jeśli chcesz tylko zmienić jedną linię, użyj
\r
.\r
oznacza powrót karetki. Jego efektem jest wyłącznie umieszczenie karetki z powrotem na początku bieżącej linii. Nic nie kasuje. Podobnie,\b
można użyć do cofnięcia się o jeden znak. (niektóre terminale mogą nie obsługiwać wszystkich tych funkcji)import sys def process(data): size_str = os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!' sys.stdout.write('%s\r' % size_str) sys.stdout.flush() file.write(data)
źródło
\r
oznacza to powrót karetki. jego efekt polega wyłącznie na umieszczeniu karetki z powrotem na początku bieżącej linii. to niczego nie wymazuje. podobnie,\b
może posłużyć do cofnięcia się o jeden znak. (niektóre terminale mogą nie obsługiwać wszystkich tych funkcji)sys.stdout.write('%s\r', size_str')
Myślę, że miałeś na myśli,sys.stdout.write('%s\r' % size_str)
ale to nie działa.print
zamiast,sys.stdout.write
jeśli wolisz:print size_str + "\r",
działa dobrze. Na,
końcu instrukcji print usuwa znak nowej linii;sys.stdout.flush()
jest nadal potrzebnyZajrzyj do dokumentacji modułu curses i modułu curses HOWTO .
Naprawdę podstawowy przykład:
import time import curses stdscr = curses.initscr() stdscr.addstr(0, 0, "Hello") stdscr.refresh() time.sleep(1) stdscr.addstr(0, 0, "World! (with curses)") stdscr.refresh()
źródło
clrtoeol
dla gdy druga linia jest krótsza niż pierwsza.Oto moja mała klasa, która może ponownie drukować bloki tekstu. Prawidłowo czyści poprzedni tekst, dzięki czemu można zastąpić stary tekst krótszym nowym tekstem bez tworzenia bałaganu.
import re, sys class Reprinter: def __init__(self): self.text = '' def moveup(self, lines): for _ in range(lines): sys.stdout.write("\x1b[A") def reprint(self, text): # Clear previous text by overwritig non-spaces with spaces self.moveup(self.text.count("\n")) sys.stdout.write(re.sub(r"[^\s]", " ", self.text)) # Print new text lines = min(self.text.count("\n"), text.count("\n")) self.moveup(lines) sys.stdout.write(text) self.text = text reprinter = Reprinter() reprinter.reprint("Foobar\nBazbar") reprinter.reprint("Foo\nbar")
źródło
Zauważyłem, że w przypadku prostej instrukcji print w Pythonie 2.7 po prostu umieść przecinek na końcu po
'\r'
.print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!\r',
Jest to krótsze niż w przypadku innych rozwiązań innych niż Python 3, ale także trudniejsze w utrzymaniu.
źródło
Możesz po prostu dodać „\ r” na końcu ciągu oraz przecinek na końcu funkcji print. Na przykład:
print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!\r'),
źródło
end
parametrem ustawionym na\n
so u print(...)KB downloaded!\r\n
. Czy się mylę?end = '\r'
zamiast tego rozwiązuje problem w Pythonie 3.Używam Spyder 3.3.1 - Windows 7 - Python 3.6, chociaż flush może nie być potrzebny. na podstawie tego postu - https://github.com/spyder-ide/spyder/issues/3437
#works in spyder ipython console - \r at start of string , end="" import time import sys for i in range(20): time.sleep(0.5) print(f"\rnumber{i}",end="") sys.stdout.flush()
źródło
aby nadpisać poprzednią linię w Pythonie, wystarczy dodać end = '\ r' do funkcji print, przetestuj ten przykład:
import time for j in range(1,5): print('waiting : '+j, end='\r') time.sleep(1)
źródło