Stampare sulla stessa riga e non su una nuova riga?


89

Fondamentalmente voglio fare l'opposto di quello che ha fatto questo ragazzo ... hehe.

Script Python: stampa una nuova riga ogni volta nella shell anziché aggiornare la riga esistente

Ho un programma che mi sta dicendo a che punto è.

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

Quindi se len (some_list) fosse 50, l'ultima riga verrà stampata 50 volte. Voglio stampare una riga e continuare ad aggiornare quella riga. So di sapere che questa è probabilmente la domanda più stupida che leggerai tutto il giorno. Non riesco proprio a capire le quattro parole che devo inserire in Google per ottenere la risposta.

Aggiornare! Ho provato il suggerimento di mvds che SEMBRAVA giusto. Il nuovo codice

print percent_complete,"           \r",

La percentuale di completamento è solo una stringa (stavo astraggendo la prima volta ora che sto cercando di essere letterale). Il risultato ora è che esegue il programma, non stampa NULLA fino a quando il programma non è finito, quindi stampa "100 percento completo" su una sola riga.

Senza il ritorno a capo (ma con la virgola, metà del suggerimento di mvds) non stampa nulla fino alla fine. E poi stampa:

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

E così via. Quindi ora il nuovo problema è che con la virgola non viene stampata fino al termine del programma.

Con il ritorno a capo e senza virgola si comporta esattamente come con nessuno dei due.


Potresti anche voler controllare in sys.stdout.isatty()modo da non sputare queste cose quando non sei in esecuzione in un terminale.
mvds

Lo sto eseguendo da un terminale ... buona idea però. Sono sicuro che ad un certo punto ne avrò bisogno.
chriscauley

1
lo sfondo è, tra l'altro, che in diverse lingue il \ n (che ora omettiamo) serve come un segnale implicito per eseguire il flush allo stdout. In caso contrario, molte persone saranno confuse.
mvds

Risposte:


86

Si chiama ritorno a capo, o \r

Uso

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

La virgola impedisce alla stampa di aggiungere una nuova riga. (e gli spazi manterranno la linea libera dall'output precedente)

Inoltre, non dimenticare di terminare con un print ""per ottenere almeno una nuova riga di finalizzazione!


12
Assicurati solo di stampare sempre la stessa quantità di dati (o più di qualsiasi stampa precedente) sulla riga, altrimenti ti ritroverai con cruft alla fine.
Nicholas Knight

Così vicino ... aggiornerò la domanda con il risultato di questo.
chriscauley

2
@dustynachos: Heh, dimenticato quella ruga. Vedi la domanda sul buffer di output di Python: stackoverflow.com/questions/107705/python-output-buffering
Nicholas Knight

1
@dustynachos: (o usa semplicemente sys.stdout.flush () dopo ogni chiamata di stampa, che potrebbe effettivamente essere migliore se non ti interessa il buffering dell'output per il resto del tuo programma)
Nicholas Knight

2
questo non funziona per me. In realtà l'ho provato numerose volte e non ha mai funzionato per me. Sto usando iterm2 su un Mac, ma per la maggior parte del tempo sono ssh su un server Linux. Non ho mai trovato un metodo per farlo che funzioni davvero.
bgenchel

33

Da python 3.x puoi fare:

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

(che può essere utilizzato anche in Python 2.6 o 2.7 mettendolo from __future__ import print_functionin cima al tuo script / modulo)

Esempio di barra di avanzamento della console Python:

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)

Sembra che \ r aggiunga anche una nuova riga
fccoelho

3
questo elimina la nuova riga, ma non consente la sovrascrittura, che penso sia ciò che vuole l'autore.
bgenchel

1
@bgenchel usato con '\ r' (come nel codice di esempio) fa esattamente quello che vuole l'OP
Milo Wielondek

33

Per me, ciò che ha funzionato è stata una combinazione delle risposte di Remi e Sirius:

from __future__ import print_function
import sys

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

Non aggiornato .. A partire da Python 3.8.5 solo per me funziona: print ("some string", end = '\ r')
rroger

23

In Python 3.3+ non è necessario sys.stdout.flush(). print(string, end='', flush=True)lavori.

Così

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

sovrascriverà "foo" con "bar".


2
Funziona, a condizione che il testo stampato termini con un "\r".
bli

13

per Console probabilmente avrai bisogno di

sys.stdout.flush()

per forzare l'aggiornamento. Penso che l'uso ,in stampa bloccherà lo svuotamento di stdout e in qualche modo non si aggiornerà


Terminator aggiornava la riga solo ogni 30 secondi quando utilizzavo print ("...", end = '\ r') per me a meno che non eseguissi questo comando immediatamente dopo l'istruzione print. Grazie
Bryce Guinta

4

In ritardo per il gioco - ma poiché nessuna delle risposte ha funzionato per me (non le ho provate tutte) e ho trovato questa risposta più di una volta nella mia ricerca ... In Python 3, questa soluzione è piuttosto elegante e credo che faccia esattamente ciò che l'autore sta cercando, aggiorna una singola affermazione sulla stessa riga. Nota, potresti dover fare qualcosa di speciale se la linea si restringe invece di crescere (come forse rendere la stringa una lunghezza fissa con spazi imbottiti alla fine)

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)

1
opzione più semplice e pulita per python => 3.6
DaveR

3

Questo funziona per me, l'ho hackerato una volta per vedere se è possibile, ma non è mai stato effettivamente utilizzato nel mio programma (la GUI è molto più carina):

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')

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)

\b sposterà la posizione del cursore indietro di uno spazio
Quindi lo spostiamo indietro fino all'inizio della riga
Quindi scriviamo spazi per cancellare la riga corrente - mentre scriviamo spazi il cursore si sposta avanti / destra di uno
Quindi abbiamo per riportare il cursore all'inizio della riga prima di scrivere i nuovi dati

Testato su Windows cmd utilizzando Python 2.7


1

Provalo in questo modo:

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

(Con una virgola alla fine.)


Questo aggiunge semplicemente il nuovo testo al vecchio (funzionalmente simile ma brutto).
chriscauley

1

Se stai usando Spyder, le linee vengono stampate in modo continuo con tutte le soluzioni precedenti. Un modo per evitarlo è usare:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()

Questa era l'unica soluzione funzionante per me (Python 3.8, Windows, PyCharm).
z33k

1

Per Python 3+

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

0

Basato sulla risposta di Remi per Python 2.7+usare questo:

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)

0

Per Python 3.6+e per qualsiasi listpiuttosto che soloint s, oltre a utilizzare l'intera larghezza della finestra della console e non passare a una nuova riga, puoi utilizzare quanto segue:

nota: tieni presente che la funzione get_console_with()funzionerà solo su sistemi basati su Linux, e come tale devi riscriverla per funzionare su 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)


0

Se stai usando Python 3, questo è per te e funziona davvero.

print(value , sep='',end ='', file = sys.stdout , flush = False)

0

L'ho capito da solo per aver mostrato un conto alla rovescia, ma funzionerebbe anche per una percentuale.

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

Finché tutto ciò che viene dopo "/ r" è della stessa lunghezza o più lunga (spazi inclusi) della stringa precedente, la sovrascriverà sulla stessa riga. Assicurati solo di includere end = '' altrimenti verrà stampato in una nuova riga. Spero possa aiutare!


0

per l'oggetto "pega" che fornisce StartRunning (), StopRunning (), booleano getIsRunning () e intero getProgress100 () restituendo un valore compreso tra 0 e 100, fornisce una barra di avanzamento del testo durante l'esecuzione ...

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)

0

A partire dalla fine del 2020 e Python 3.8.5 su console Linux per me funziona solo questo:

print('some string', end='\r')

Il merito va a: questo post

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.