Stampa in una riga in modo dinamico


306

Vorrei fare diverse affermazioni che forniscano un output standard senza vedere nuove righe tra le dichiarazioni.

In particolare, supponiamo di avere:

for item in range(1,100):
    print item

Il risultato è:

1
2
3
4
.
.
.

Come far sembrare invece questo:

1 2 3 4 5 ...

Ancora meglio, è possibile stampare il numero unico sopra l'ultimo numero, in modo che solo un numero è sullo schermo in un momento?


Risposte:


482

Passare print itema:

  • print item, in Python 2.7
  • print(item, end=" ") in Python 3

Se si desidera stampare i dati in modo dinamico, utilizzare la sintassi seguente:

  • print(item, sep=' ', end='', flush=True) in Python 3

Da http://docs.python.org/reference/simple_stmts.html#print :> Alla fine '\n'viene scritto un carattere, a meno che l' printistruzione non termini con una virgola. Questa è l'unica azione se l'istruzione contiene solo la parola chiave print.
ewall,

5
Cordiali saluti: print (item, end = "") può essere usato in Python2.7 aggiungendo 'from future import print_function' all'inizio del file.
Dec

2
Purtroppo flushnon funziona from __future__ import print_function.
Timmmm,

Se dovessi farlo print(item, end=", "), aggiungo anche ,all'ultimo elemento come fare per impedirne l'aggiunta ,all'ultimo elemento
MarcoBianchi,

@SamirTendulkar Se stai usando un for-loop come la domanda originale, potresti creare un caso speciale per gestire in modo diverso l'ultimo elemento dell'elenco ...
ewall

156

A proposito ...... Come aggiornarlo ogni volta in modo da stampare mi in un posto basta cambiare il numero.

In generale, il modo per farlo è con i codici di controllo del terminale . Questo è un caso particolarmente semplice, per il quale hai bisogno solo di un carattere speciale: U + 000D CARRIAGE RETURN, che è scritto '\r'in Python (e molte altre lingue). Ecco un esempio completo basato sul tuo codice:

from sys import stdout
from time import sleep
for i in range(1,20):
    stdout.write("\r%d" % i)
    stdout.flush()
    sleep(1)
stdout.write("\n") # move the cursor to the next line

Alcune cose a riguardo potrebbero essere sorprendenti:

  • La \rva all'inizio della stringa in modo che, mentre il programma è in esecuzione, il cursore sarà sempre dopo il numero. Questo non è solo estetico: alcuni emulatori terminali si confondono molto se lo si fa al contrario.
  • Se non includi l'ultima riga, al termine del programma, la shell stamperà il suo prompt sopra il numero.
  • Il stdout.flushè necessario in alcuni sistemi, o non sarà possibile ottenere alcun output. Altri sistemi potrebbero non richiederlo, ma non fa alcun danno.

Se scopri che non funziona, la prima cosa che dovresti sospettare è che il tuo emulatore di terminale sia difettoso. Il programma vttest può aiutarti a testarlo.

Potresti sostituire il stdout.writecon printun'istruzione ma preferisco non mescolarlo printcon l'uso diretto di oggetti file.


Quale funzione meen flush ()? Perché funziona per me senza quella funzione!
Pol

1
Normalmente, gli oggetti file di Python accumulano dati in modo da poterli inviare al sistema operativo in grossi blocchi. Questo è ciò che si desidera per accedere ai file su disco, di solito, ma interferisce con questo tipo di attività. flush()impone a un file di inviare tutto ciò che ha al sistema operativo in questo momento. Sono sorpreso che funzioni per te senza quello - non ha funzionato per me fino a quando non l'ho aggiunto.
zwol,

1
@ user1995839 Esistono codici di controllo per nascondere il cursore, ma se lo farai ti consiglio vivamente di usarlo ncursesper farlo.
zwol,

1
sys.stdout.flush()sembra essere mendatory sul mio FreebsdconPython 2.7
Hakim

1
Si noti che il ritorno a capo non funziona correttamente con Python REPL (almeno per me, su Ubuntu); è necessario eseguire uno script , non solo eseguire un comando REPL, affinché tutto ciò funzioni.
Mark Amery,

50

Utilizzare print item,per fare in modo che l'istruzione print ometta la nuova riga.

In Python 3, lo è print(item, end=" ").

Se si desidera che tutti i numeri vengano visualizzati nello stesso posto, utilizzare ad esempio (Python 2.7):

to = 20
digits = len(str(to - 1))
delete = "\b" * (digits + 1)
for i in range(to):
    print "{0}{1:{2}}".format(delete, i, digits),

In Python 3, è un po 'più complicato; qui è necessario svuotare sys.stdouto non stampa nulla fino al termine del ciclo:

import sys
to = 20
digits = len(str(to - 1))
delete = "\b" * (digits)
for i in range(to):
   print("{0}{1:{2}}".format(delete, i, digits), end="")
   sys.stdout.flush()

In realtà, mi sembra che la tua soluzione stamperà sempre lo stesso numero di backspaces. Quindi, se to è 20, stamperà un backspace aggiuntivo durante la stampa delle cifre 1..9. Non dovresti calcolare le cifre all'interno del loop e basarlo sul valore di i?
Adam Crossland,

Giustifica il numero e cancella sempre tutto. Non ho testato se è più veloce farlo o calcolare in ogni iterazione quante cifre ci devono essere cancellate proprio ora.
Tim Pietzcker,

Oppure, basalo sul valore precedente di i per tenere conto di quando cambia il numero di cifre.
Adam Crossland,

Ah, sì, avevo trascurato la giustificazione giusta. Buona soluzione
Adam Crossland,

Sembra abbastanza complicato. Probabilmente non avrei capito cosa avrei fatto lì se avessi dovuto guardare il mio codice tra un anno. (Ho dovuto leggere un programma che ho scritto nel 2007 - Sono così felice di averlo scritto in Python.)
Tim Pietzcker,

16

Come gli altri esempi,
utilizzo un approccio simile ma invece di dedicare tempo a calcolare l'ultima lunghezza dell'output, ecc.

Uso semplicemente le escape del codice ANSI per tornare all'inizio della riga e quindi cancellare l'intera riga prima di stampare l'output del mio stato corrente.

import sys

class Printer():
    """Print things to stdout on one line dynamically"""
    def __init__(self,data):
        sys.stdout.write("\r\x1b[K"+data.__str__())
        sys.stdout.flush()

Per usare nel tuo ciclo di iterazione, dovresti semplicemente chiamare qualcosa del tipo:

x = 1
for f in fileList:
    ProcessFile(f)
    output = "File number %d completed." % x
    Printer(output)
    x += 1   

Vedi di più qui


14

È possibile aggiungere una virgola finale all'istruzione print per stampare uno spazio anziché una nuova riga in ogni iterazione:

print item,

In alternativa, se stai usando Python 2.6 o successivo, puoi usare la nuova funzione di stampa, che ti permetterebbe di specificare che nemmeno uno spazio dovrebbe arrivare alla fine di ogni oggetto in stampa (o che ti permetta di specificare qualunque fine tu volere):

from __future__ import print_function
...
print(item, end="")

Infine, puoi scrivere direttamente nello standard output importandolo dal modulo sys, che restituisce un oggetto simile a un file:

from sys import stdout
...
stdout.write( str(item) )

13

modificare

print item

per

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" cancella fino alla fine della riga
  • il \ r, ritorna all'inizio della riga
  • l'istruzione flush assicura che venga visualizzata immediatamente in modo da ottenere un output in tempo reale.

Questo è ottimo per Python 2.7. Puoi fornire un riferimento a dove hai imparato a conoscere il \033[Kcodice? Mi piacerebbe saperne di più su di loro.
Klik,

printarrossisce già internamente. Non c'è bisogno di chiamarlo. printè diverso da sys.stdout.write()dove devi scaricare lo schermo
Gabriel Fair

5

Penso che un semplice join dovrebbe funzionare:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)

4
Una comprensione sarebbe leggere meglio e probabilmente essere più veloce: print ' '.join(str(x) for x in range(1, 10)).
Mu Mind,

Secondo, l'uso di una comprensione dell'elenco. In questo caso, renderebbe più facile la lettura anche.
Austin Henley,

5

Un'altra risposta che sto usando su 2.7 dove sto solo stampando un "." ogni volta che viene eseguito un ciclo (per indicare all'utente che le cose sono ancora in esecuzione) è questo:

print "\b.",

Stampa il "." personaggi senza spazi tra ciascuno. Sembra un po 'meglio e funziona abbastanza bene. Il \ b è un personaggio backspace per coloro che si chiedono.


4

Tante risposte complicate. Se hai Python 3, metti semplicemente \rall'inizio della stampa e aggiungi end='', flush=Truead esso:

import time

for i in range(10):
    print(f'\r{i} foo bar', end='', flush=True)
    time.sleep(0.5)

Questo scriverà 0 foo bar, quindi 1 foo barecc. Sul posto.


Grazie, era proprio quello di cui avevo bisognoprint('\r' + filename + " ", end = '', flush=True)
McPeppr il

3

Per sovrascrivere i numeri, puoi fare qualcosa del genere:

for i in range(1,100):
    print "\r",i,

Dovrebbe funzionare fintanto che il numero è stampato nella prima colonna.

EDIT: ecco una versione che funzionerà anche se non è stampata nella prima colonna.

prev_digits = -1
for i in range(0,1000):
    print("%s%d" % ("\b"*(prev_digits + 1), i)),
    prev_digits = len(str(i))

Dovrei notare che questo codice è stato testato e funziona perfettamente in Python 2.5 su Windows, nella console di Windows. Secondo alcuni altri, per vedere i risultati potrebbe essere necessario il lavaggio dello stdout. YMMV.


3

"A proposito ...... Come aggiornarlo ogni volta in modo da stampare mi in un unico posto basta cambiare il numero."

È un argomento davvero complicato. Ciò che zack ha suggerito (emettere codici di controllo della console) è un modo per raggiungere questo obiettivo.

Puoi usare (n) maledizioni, ma questo funziona principalmente su * nix.

Su Windows (e qui va una parte interessante) che viene raramente menzionata (non riesco a capire perché) è possibile utilizzare i collegamenti Python su WinAPI ( http://sourceforge.net/projects/pywin32/ anche con ActivePython per impostazione predefinita) - non è che duro e funziona bene. Ecco un piccolo esempio:

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    output_handle.WriteConsoleOutputCharacter( i, pos )
    time.sleep( 1 )

Oppure, se si desidera utilizzare print(istruzione o funzione, nessuna differenza):

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    print i
    output_handle.SetConsoleCursorPosition( pos )
    time.sleep( 1 )

win32console Il modulo ti consente di fare molte altre cose interessanti con la console di Windows ... Non sono un grande fan di WinAPI, ma di recente mi sono reso conto che almeno la metà della mia antipatia nei suoi confronti era causata dalla scrittura del codice WinAPI in C - i collegamenti pythonic sono molto più facile da usare.

Tutte le altre risposte sono ottime e pitoniche, ovviamente, ma ... E se volessi stampare sulla riga precedente ? O scrivere un testo su più righe, che cancellarlo e scrivere di nuovo le stesse righe? La mia soluzione lo rende possibile.


2

per Python 2.7

for x in range(0, 3):
    print x,

per Python 3

for x in range(0, 3):
    print(x, end=" ")

1
In [9]: print?
Type:           builtin_function_or_method
Base Class:     <type 'builtin_function_or_method'>
String Form:    <built-in function print>
Namespace:      Python builtin
Docstring:
    print(value, ..., sep=' ', end='\n', file=sys.stdout)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep:  string inserted between values, default a space.
end:  string appended after the last value, default a newline.

0

Se vuoi solo stampare i numeri, puoi evitare il ciclo.

# python 3
import time

startnumber = 1
endnumber = 100

# solution A without a for loop
start_time = time.clock()
m = map(str, range(startnumber, endnumber + 1))
print(' '.join(m))
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('took {0}ms\n'.format(timetaken))

# solution B: with a for loop
start_time = time.clock()
for i in range(startnumber, endnumber + 1):
    print(i, end=' ')
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('\ntook {0}ms\n'.format(timetaken))

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 ha impiegato 21.1986929975ms

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 ha impiegato 491.466823551ms


Dovrebbe essere ancora più veloce con la comprensione dell'elenco anziché map.
cji,

Sì, buoni esempi. Mi piace, ma devo mostrare il risultato dell'analisi. In primo luogo conto gli elementi nel database che stampo quanto rimane.
Pol

0

Il modo migliore per ottenere questo risultato è usare il \rpersonaggio

Prova il codice seguente:

import time
for n in range(500):
  print(n, end='\r')
  time.sleep(0.01)
print()  # start new line so most recently printed number stays

0

In Python 3 puoi farlo in questo modo:

for item in range(1,10):
    print(item, end =" ")

Uscite:

1 2 3 4 5 6 7 8 9 

Tupla: puoi fare la stessa cosa con una tupla:

tup = (1,2,3,4,5)

for n in tup:
    print(n, end = " - ")

Uscite:

1 - 2 - 3 - 4 - 5 - 

Un altro esempio:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for item in list_of_tuples:
    print(item)

Uscite:

(1, 2)
('A', 'B')
(3, 4)
('Cat', 'Dog')

Puoi anche decomprimere la tua tupla in questo modo:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]

# Tuple unpacking so that you can deal with elements inside of the tuple individually
for (item1, item2) in list_of_tuples:
    print(item1, item2)   

Uscite:

1 2
A B
3 4
Cat Dog

un'altra variante:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for (item1, item2) in list_of_tuples:
    print(item1)
    print(item2)
    print('\n')

Uscite:

1
2


A
B


3
4


Cat
Dog

Ho provato tutti gli esempi qui e nessuno funziona in Python 3.8 Per favore, ottieni più risposte.
KOTZ,

L'ho provato con Python 3.7
Stryker il

Ciò che intendo è che nessuna di queste opzioni sovrascrive l'ultimo numero come suggerito alla fine della domanda.
KOTZ

0

Una virgola alla fine dell'istruzione print omette la nuova riga.

for i in xrange(1,100):
  print i,

ma questo non sovrascrive.


0

Per quelli che lottano come ho fatto, ho pensato a quanto segue che sembra funzionare sia in Python 3.7.4 che in 3.5.2.

Ho ampliato l'intervallo da 100 a 1.000.000 perché funziona molto velocemente e potresti non vedere l'output. Questo perché un effetto collaterale dell'impostazione end='\r'è che l'iterazione del ciclo finale cancella tutto l'output. Era necessario un numero più lungo per dimostrare che funziona. Questo risultato potrebbe non essere desiderabile in tutti i casi, ma andava bene nel mio e OP non specificava in un modo o nell'altro. Si potrebbe potenzialmente aggirare questo con un'istruzione if che valuta la lunghezza dell'essere matrice iterata, ecc La chiave per farlo funzionare nel mio caso è stato quello di accoppiare le staffe "{}"con .format(). Altrimenti, non ha funzionato.

Di seguito dovrebbe funzionare così com'è:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)

0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Produzione: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, 50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74, 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99


0

O ancora più semplice:

import time
a = 0
while True:
    print (a, end="\r")
    a += 1
    time.sleep(0.1)

end="\r" sovrascriverà dall'inizio [0:] della prima stampa.

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.