Drukuj w tej samej linii, a nie w nowej linii w Pythonie

85

Zasadniczo chcę zrobić coś przeciwnego do tego, co zrobił ten facet ... hehe.

Python Script: Drukuj nową linię za każdym razem, aby powłoka zamiast aktualizować istniejącą linię

Mam program, który mówi mi, jak daleko jest.

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

Więc jeśli len (some_list) wynosi 50, ostatnia linia została wydrukowana 50 razy. Chcę wydrukować jedną linię i aktualizować tę linię. Wiem, że wiem, że to chyba najtrudniejsze pytanie, które przeczytasz przez cały dzień. Po prostu nie mogę wymyślić czterech słów, które muszę umieścić w Google, aby uzyskać odpowiedź.

Aktualizacja! Wypróbowałem sugestię mvds, która WYDAJE SIĘ słuszna. Nowy kod

print percent_complete,"           \r",

Procent ukończenia to po prostu ciąg znaków (za pierwszym razem starałem się być dosłowny). W rezultacie uruchamia program, nie drukuje NICZEGO przed zakończeniem programu, a następnie wypisuje „100 procent ukończenia” w jednym i tylko jednym wierszu.

Bez powrotu karetki (ale z przecinkiem, połową sugestii mvds) nic nie drukuje do końca. A potem drukuje:

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

I tak dalej. Więc teraz nowym problemem jest to, że przecinek nie jest drukowany, dopóki program nie zostanie zakończony.

Z powrotem karetki i bez przecinka zachowuje się dokładnie tak samo, jak w przypadku żadnego z nich.

chriscauley
źródło
Możesz również sprawdzić, sys.stdout.isatty()aby nie wypluwać tych rzeczy, gdy nie używasz terminala.
mvds
Uruchamiam to z terminala ... dobra myśl. Jestem pewien, że będę tego potrzebować w pewnym momencie.
chriscauley
1
przy okazji, tło jest takie, że w kilku językach \ n (który teraz pomijamy) służy jako niejawny sygnał do wyrównywania na standardowe wyjście. W przeciwnym razie wiele osób będzie zdezorientowanych.
mvds

Odpowiedzi:

85

Nazywa się to powrotem karetki lub \r

Posługiwać się

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

Przecinek zapobiega dodaniu nowej linii przez print. (a spacje sprawią, że linia będzie wolna od poprzedniego wyjścia)

Nie zapomnij też zakończyć za pomocą a, print ""aby uzyskać co najmniej końcowy znak nowej linii!

mvds
źródło
12
Po prostu upewnij się, że zawsze drukujesz taką samą ilość danych (lub więcej niż jakikolwiek poprzedni wydruk) w wierszu, w przeciwnym razie na końcu skończy się cruft.
Nicholas Knight,
Tak blisko ... Zaktualizuję pytanie o wynik tego.
chriscauley
2
@dustynachos: Heh, zapomniałem o tej zmarszczce. Zobacz pytanie o buforowanie danych wyjściowych w języku Python: stackoverflow.com/questions/107705/python-output-buffering
Nicholas Knight,
1
@dustynachos: (lub po prostu użyj sys.stdout.flush () po każdym wywołaniu print, to może być lepsze, jeśli nie zależy ci na buforowaniu wyjścia dla reszty programu)
Nicholas Knight
2
to nie działa dla mnie. Próbowałem tego wiele razy i nigdy mi się to nie udało. Używam iterm2 na komputerze Mac, ale przez większość czasu korzystam z serwera linuxowego. Nigdy nie znalazłem metody, która faktycznie działa.
bgenchel
35

Dla mnie zadziałało połączenie odpowiedzi Remiego i Siriusda:

from __future__ import print_function
import sys

print(str, end='\r')
sys.stdout.flush()
dlchambers
źródło
33

Z Pythona 3.x możesz:

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

(którego można również używać w Pythonie 2.6 lub 2.7, umieszczając from __future__ import print_functionna górze skryptu / modułu)

Przykład paska postępu konsoli Pythona:

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
źródło
Wydaje się, że \ r również dodaje nową linię
fccoelho
2
pozbywa się nowej linii, ale nie pozwala na nadpisywanie, a myślę, że tego chce autor.
bgenchel
1
@bgenchel używany z '\ r' (jak w przykładowym kodzie) robi dokładnie to, czego chce OP
Milo Wielondek
20

W Pythonie 3.3+ nie potrzebujesz sys.stdout.flush(). print(string, end='', flush=True)Pracuje.

Więc

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

nadpisze „foo” słowem „bar”.

LeopardShark
źródło
2
Działa, pod warunkiem, że wydrukowany tekst kończy się rozszerzeniem "\r".
bli
13

na konsolę prawdopodobnie będziesz potrzebować

sys.stdout.flush()

wymusić aktualizację. Myślę, że użycie ,w print zablokuje stdout przed opróżnianiem i jakoś się nie zaktualizuje

siriusd
źródło
Terminator tylko odświeżał linię co 30 sekund podczas używania print ("...", end = '\ r'), chyba że uruchomiłem to polecenie natychmiast po instrukcji print. Dzięki
Bryce Guinta
4

Spóźniony do gry - ale ponieważ żadna z odpowiedzi nie zadziałała dla mnie (nie wypróbowałem ich wszystkich) i natknąłem się na tę odpowiedź więcej niż raz podczas moich poszukiwań ... W Pythonie 3 to rozwiązanie jest dość eleganckie i uważam, że robi dokładnie to, czego szuka autor, aktualizuje pojedyncze oświadczenie w tej samej linii. Uwaga, być może będziesz musiał zrobić coś specjalnego, jeśli linia kurczy się zamiast rosnąć (na przykład może sprawić, że ciąg ma stałą długość z dopełnionymi spacjami na końcu)

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)
SteveJ
źródło
najprostsza i najczystsza opcja dla Pythona => 3.6
DaveR
3

To działa dla mnie, zhakowałem go raz, aby sprawdzić, czy jest to możliwe, ale nigdy nie zostało użyte w moim programie (GUI jest o wiele ładniejsze):

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
źródło
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)

\bprzesunie położenie kursora o jedno miejsce wstecz
Więc cofniemy go na początek wiersza
Następnie piszemy spacje, aby wyczyścić bieżący wiersz - gdy piszemy spacje, kursor przesuwa się o jeden do przodu / w prawo
Więc mamy aby przesunąć kursor z powrotem na początek wiersza, zanim zapiszemy nasze nowe dane

Testowane w Windows cmd przy użyciu Pythona 2.7

Robert
źródło
1

Spróbuj tak:

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

(Z przecinkiem na końcu.)

chryss
źródło
To po prostu dodaje nowy tekst do starego (podobnego funkcjonalnie, ale brzydkiego).
chriscauley
1

Jeśli używasz Spydera, linie są drukowane w sposób ciągły ze wszystkimi poprzednimi rozwiązaniami. Sposobem na uniknięcie tego jest użycie:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()
bfree67
źródło
To było jedyne działające rozwiązanie dla mnie (Python 3.8, Windows, PyCharm).
z33k
0

Na podstawie odpowiedzi Remi do Python 2.7+użycia tego:

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
źródło
0

Dla Python 3.6+i dla dowolnego, lista nie tylko ints, a także wykorzystując całą szerokość okna konsoli i nie przechodząc do nowej linii, możesz użyć następującego:

uwaga: informujemy, że funkcja get_console_with()będzie działać tylko na systemach opartych na Linuksie, dlatego należy ją przepisać, aby działała w systemie Windows.

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)

tamarotka
źródło
0

Jeśli używasz Pythona 3, to jest to dla Ciebie i naprawdę działa.

print(value , sep='',end ='', file = sys.stdout , flush = False)
Azaz-ul-Haque
źródło
0

Dla Pythona 3+

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

Po prostu wymyśliłem to samodzielnie, aby wyświetlić odliczanie, ale zadziała również dla procentu.

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

Dopóki cokolwiek występuje po „/ r” ma taką samą długość lub więcej (łącznie ze spacjami) niż poprzedni ciąg, nadpisze go w tej samej linii. Po prostu upewnij się, że wstawiłeś end = '', w przeciwnym razie zostanie wydrukowany do nowej linii. Mam nadzieję, że to pomoże!

ReconGator
źródło
0

dla obiektu "pega", który udostępnia StartRunning (), StopRunning (), boolean getIsRunning () i integer getProgress100 () zwracający wartość w zakresie od 0 do 100, zapewnia to tekstowy pasek postępu podczas działania ...

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
źródło