Dynamisch in einer Zeile drucken

306

Ich möchte mehrere Anweisungen machen, die eine Standardausgabe liefern, ohne Zeilenumbrüche zwischen den Anweisungen zu sehen.

Angenommen, ich habe:

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

Das Ergebnis ist:

1
2
3
4
.
.
.

Wie soll das stattdessen aussehen:

1 2 3 4 5 ...

Ist es noch besser, die einzelne Nummer über die letzte Nummer zu drucken , sodass immer nur eine Nummer auf dem Bildschirm angezeigt wird?

Pol
quelle
In Verbindung stehender Beitrag - Wie drucke ich ohne Zeilenumbruch oder Leerzeichen?
RBT

Antworten:

482

Wechseln print itemzu:

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

Wenn Sie die Daten dynamisch drucken möchten, verwenden Sie die folgende Syntax:

  • print(item, sep=' ', end='', flush=True) in Python 3
ewall
quelle
Von http://docs.python.org/reference/simple_stmts.html#print :> Am '\n'Ende wird ein Zeichen geschrieben, es sei denn, die printAnweisung endet mit einem Komma. Dies ist die einzige Aktion, wenn die Anweisung nur das Schlüsselwort enthält print.
Ewall
5
Zu Ihrer Information: print (item, end = "") kann in Python2.7 verwendet werden, indem oben in der Datei 'from future import print_function' hinzugefügt wird.
Hec
2
Funktioniert aber leider flushnicht mit from __future__ import print_function.
Timmmm
@ewall, wenn ich es tun sollte print(item, end=", "), fügt dann auch ,zum letzten Element hinzu , wie zu verhindern ist, dass es ,zum letzten Element
hinzugefügt wird
@ SamirTendulkar Wenn Sie eine for-Schleife wie die ursprüngliche Frage verwenden, können Sie einen Sonderfall
erstellen
156

Übrigens ...... Wie man es jedes Mal aktualisiert, damit es mi an einer Stelle druckt, ändere einfach die Nummer.

Im Allgemeinen erfolgt dies mit Terminalsteuerungscodes . Dies ist ein besonders einfacher Fall, für den Sie nur ein Sonderzeichen benötigen: U + 000D CARRIAGE RETURN, das '\r'in Python (und vielen anderen Sprachen) geschrieben ist. Hier ist ein vollständiges Beispiel basierend auf Ihrem Code:

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

Einige Dinge darüber, die überraschend sein können:

  • Das steht \ram Anfang der Zeichenfolge, sodass der Cursor während der Ausführung des Programms immer hinter der Zahl steht. Dies ist nicht nur kosmetisch: Einige Terminalemulatoren sind sehr verwirrt, wenn Sie es umgekehrt machen.
  • Wenn Sie die letzte Zeile nicht einfügen, druckt Ihre Shell nach Beendigung des Programms die Eingabeaufforderung über die Nummer.
  • Dies stdout.flushist auf einigen Systemen erforderlich, oder Sie erhalten keine Ausgabe. Andere Systeme benötigen es möglicherweise nicht, aber es schadet nicht.

Wenn Sie feststellen, dass dies nicht funktioniert, sollten Sie zunächst vermuten, dass Ihr Terminalemulator fehlerhaft ist. Das vttest- Programm kann Ihnen beim Testen helfen.

Sie könnten das stdout.writedurch eine printAnweisung ersetzen, aber ich bevorzuge es, nicht printmit der direkten Verwendung von Dateiobjekten zu mischen .

zwol
quelle
Welche meen flush () Funktion? Weil es für mich ohne diese Funktion funktioniert!
Pol
1
Normalerweise sammeln Pythons Dateiobjekte Daten, damit sie sie in großen Stücken an das Betriebssystem senden können. Dies ist normalerweise das, was Sie für den Zugriff auf Dateien auf der Festplatte wünschen, aber es stört diese Art von Aufgabe. flush()zwingt eine Datei, alles, was sie gerade hat, an das Betriebssystem zu senden. Ich bin überrascht, dass es für Sie ohne das funktioniert - es hat für mich nicht funktioniert, bis ich es hinzugefügt habe.
zwol
1
@ user1995839 Es gibt Steuercodes zum Ausblenden des Cursors, aber wenn Sie dies tun möchten, empfehle ich Ihnen dringend ncurses, dies zu tun.
zwol
1
sys.stdout.flush()scheint auf meinem Freebsdmit zu heilenPython 2.7
Hakim
1
Beachten Sie, dass der Wagenrücklauf in Python REPL nicht richtig funktioniert (zumindest für mich unter Ubuntu). Sie müssen ein Skript ausführen und nicht nur einen REPL-Befehl ausführen , damit dies funktioniert.
Mark Amery
50

Verwenden Sie print item,diese Option, um die print-Anweisung den Zeilenumbruch wegzulassen.

In Python 3 ist es print(item, end=" ").

Wenn Sie möchten, dass jede Nummer an derselben Stelle angezeigt wird, verwenden Sie beispielsweise (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 ist es etwas komplizierter. Hier müssen Sie spülen sys.stdoutoder es wird nichts gedruckt, bis die Schleife beendet ist:

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()
Tim Pietzcker
quelle
Eigentlich sieht es für mich so aus, als würde Ihre Lösung jedes Mal die gleiche Anzahl von Backspaces drucken. Wenn also 20 ist, wird beim Drucken der Ziffern 1..9 eine zusätzliche Rücktaste gedruckt. Sollten Sie nicht die Ziffern innerhalb der Schleife berechnen und sie auf dem Wert von i basieren?
Adam Crossland
Es rechtfertigt die Nummer richtig und löscht immer alles. Ich habe nicht getestet, ob es schneller ist, dies zu tun oder in jeder Iteration zu berechnen, wie viele Ziffern gerade gelöscht werden sollen.
Tim Pietzcker
Oder stützen Sie sich auf den vorherigen Wert von i, um zu berücksichtigen, wann sich die Anzahl der Stellen ändert.
Adam Crossland
Ah ja, ich hatte die richtige Rechtfertigung übersehen. Gute Lösung.
Adam Crossland
Klingt ziemlich kompliziert. Ich würde wahrscheinlich nicht verstehen, was ich dort getan habe, wenn ich mir in einem Jahr meinen Code ansehen müsste. (Ich musste nur ein Programm lesen, das ich 2007 geschrieben habe - ich bin so froh , dass ich es in Python geschrieben habe.)
Tim Pietzcker
16

Wie die anderen Beispiele verwende
ich einen ähnlichen Ansatz, aber anstatt Zeit damit zu verbringen, die letzte Ausgabelänge usw. zu berechnen.

Ich verwende einfach ANSI-Code-Escapezeichen, um zum Zeilenanfang zurückzukehren und dann die gesamte Zeile zu löschen, bevor ich meine aktuelle Statusausgabe drucke.

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

Zur Verwendung in Ihrer Iterationsschleife würden Sie einfach Folgendes aufrufen:

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

Sehen Sie hier mehr

Matthew
quelle
14

Sie können Ihrer print-Anweisung ein nachfolgendes Komma hinzufügen, um in jeder Iteration ein Leerzeichen anstelle einer neuen Zeile zu drucken:

print item,

Wenn Sie Python 2.6 oder höher verwenden, können Sie alternativ die neue Druckfunktion verwenden, mit der Sie festlegen können, dass am Ende jedes zu druckenden Elements nicht einmal ein Leerzeichen stehen soll (oder ob Sie ein beliebiges Ende angeben möchten) wollen):

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

Schließlich können Sie direkt in die Standardausgabe schreiben, indem Sie sie aus dem sys-Modul importieren, das ein dateiähnliches Objekt zurückgibt:

from sys import stdout
...
stdout.write( str(item) )
Eli Courtwright
quelle
13

Veränderung

print item

zu

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" wird bis zum Ende der Zeile gelöscht
  • Das \ r kehrt zum Zeilenanfang zurück
  • Die Flush-Anweisung stellt sicher, dass sie sofort angezeigt wird, damit Sie eine Echtzeitausgabe erhalten.
Brooks
quelle
Dies ist großartig für Python 2.7. Können Sie einen Verweis darauf geben, wo Sie von dem \033[KCode erfahren haben ? Ich würde gerne mehr über sie erfahren.
Klik
printspült bereits intern. Keine Notwendigkeit, es anzurufen. printist anders als dort, sys.stdout.write()wo Sie zum Bildschirm spülen müssen
Gabriel Fair
5

Ich denke, ein einfacher Join sollte funktionieren:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
xortion
quelle
4
Ein Verständnis würde besser lesen und wahrscheinlich schneller sein : print ' '.join(str(x) for x in range(1, 10)).
Mu Mind
Ich unterstütze die Verwendung eines Listenverständnisses. In diesem Fall würde es das Lesen sogar erleichtern.
Austin Henley
5

Eine andere Antwort, die ich in 2.7 verwende, wo ich nur ein "." Jedes Mal, wenn eine Schleife ausgeführt wird (um dem Benutzer anzuzeigen, dass die Dinge noch ausgeführt werden), gilt Folgendes:

print "\b.",

Es druckt das "." Zeichen ohne Leerzeichen dazwischen. Es sieht ein bisschen besser aus und funktioniert ziemlich gut. Das \ b ist ein Rücktastezeichen für diejenigen, die sich fragen.

copeland3300
quelle
4

So viele komplizierte Antworten. Wenn Sie Python 3 haben, setzen Sie es einfach \ran den Anfang des Drucks und fügen Sie end='', flush=Truees hinzu:

import time

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

Dies wird 0 foo bardann 1 foo barusw. an Ort und Stelle schreiben .

Hugh Perkins
quelle
Vielen Dank, das war genau das, was ich brauchteprint('\r' + filename + " ", end = '', flush=True)
McPeppr
3

Um die Zahlen gegenseitig zu überschreiben, können Sie Folgendes tun:

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

Das sollte funktionieren, solange die Nummer in der ersten Spalte gedruckt ist.

BEARBEITEN: Hier ist eine Version, die auch dann funktioniert, wenn sie nicht in der ersten Spalte gedruckt wird.

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

Ich sollte beachten, dass dieser Code getestet wurde und in Python 2.5 unter Windows in der Windows-Konsole einwandfrei funktioniert. Nach Ansicht einiger anderer kann eine Spülung von stdout erforderlich sein, um die Ergebnisse zu sehen. YMMV.

Adam Crossland
quelle
3

"Übrigens ...... Wie man es jedes Mal aktualisiert, damit es mi an einer Stelle druckt, ändere einfach die Nummer."

Es ist wirklich ein heikles Thema. Was zack vorgeschlagen hat (Ausgabe von Konsolensteuercodes), ist eine Möglichkeit, dies zu erreichen.

Sie können (n) Flüche verwenden, aber das funktioniert hauptsächlich mit * nixen.

Unter Windows (und hier geht ein interessanter Teil), der selten erwähnt wird (ich kann nicht verstehen, warum), können Sie Python-Bindungen an WinAPI verwenden ( http://sourceforge.net/projects/pywin32/ standardmäßig auch mit ActivePython) - dies ist nicht der Fall das ist hart und funktioniert gut. Hier ist ein kleines Beispiel:

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 )

Oder wenn Sie verwenden möchten print(Anweisung oder Funktion, kein Unterschied):

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 Modul ermöglicht es Ihnen, viele weitere interessante Dinge mit Windows-Konsole zu tun ... Ich bin kein großer Fan von WinAPI, aber kürzlich wurde mir klar, dass mindestens die Hälfte meiner Abneigung dagegen durch das Schreiben von WinAPI-Code in C-Python-Bindungen verursacht wurde viel einfacher zu bedienen.

Alle anderen Antworten sind natürlich großartig und pythonisch, aber ... Was wäre, wenn ich in der vorherigen Zeile drucken wollte ? Oder mehrzeiligen Text schreiben, dann löschen und die gleichen Zeilen erneut schreiben? Meine Lösung macht das möglich.

cji
quelle
2

für Python 2.7

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

für Python 3

for x in range(0, 3):
    print(x, end=" ")
Adnan Ghaffar
quelle
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.
gtrak
quelle
0

Wenn Sie nur die Zahlen drucken möchten, können Sie die Schleife vermeiden.

# 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 dauerte 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 dauerte 491.466823551ms

Mahmoud Kassem
quelle
Sollte mit Listenverständnis noch schneller sein als map.
Cji
Ja gute Beispiele. Ich mag es, aber ich muss das Ergebnis des Parsens zeigen. Zuerst zähle ich die Elemente in der Datenbank und drucke dann aus, wie viel noch übrig ist.
Pol
0

Der beste Weg, dies zu erreichen, ist die Verwendung des \rCharakters

Versuchen Sie einfach den folgenden Code:

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
vitiral
quelle
0

In Python 3 können Sie dies folgendermaßen tun:

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

Ausgänge:

1 2 3 4 5 6 7 8 9 

Tuple: Sie können mit einem Tupel das gleiche tun:

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

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

Ausgänge:

1 - 2 - 3 - 4 - 5 - 

Ein anderes Beispiel:

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

Ausgänge:

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

Sie können Ihr Tupel sogar so auspacken:

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)   

Ausgänge:

1 2
A B
3 4
Cat Dog

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

Ausgänge:

1
2


A
B


3
4


Cat
Dog
Stryker
quelle
Ich habe alle Beispiele hier ausprobiert und keines funktioniert in Python 3.8. Bitte erhalten Sie weitere Antworten.
KOTZ
Ich habe es mit Python 3.7
Stryker
Was ich meine ist, dass keine dieser Optionen die letzte Zahl überschreibt, wie sie am Ende der Frage vorgeschlagen wurde.
KOTZ
0

Ein Komma am Ende der print-Anweisung lässt die neue Zeile weg.

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

dies überschreibt aber nicht.

eruciform
quelle
0

Für diejenigen, die wie ich Probleme hatten, habe ich Folgendes entwickelt, das sowohl in Python 3.7.4 als auch in 3.5.2 zu funktionieren scheint.

Ich habe den Bereich von 100 auf 1.000.000 erweitert, da er sehr schnell läuft und die Ausgabe möglicherweise nicht angezeigt wird. Dies liegt daran, dass ein Nebeneffekt der Einstellung darin end='\r'besteht, dass die letzte Schleifeniteration die gesamte Ausgabe löscht. Eine längere Anzahl wurde benötigt, um zu demonstrieren, dass es funktioniert. Dieses Ergebnis ist möglicherweise nicht in allen Fällen wünschenswert, war aber in meinem Fall in Ordnung, und OP hat die eine oder andere Art nicht angegeben. Sie könnten dies möglicherweise mit einer if-Anweisung umgehen, die die Länge des Arrays bewertet, über das iteriert wird usw. Der Schlüssel, um es in meinem Fall zum Laufen zu bringen, bestand darin, die Klammern "{}"mit zu koppeln .format(). Ansonsten hat es nicht funktioniert.

Unten sollte funktionieren wie es ist:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)
Struktur
quelle
0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Ausgabe: 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

Alex
quelle
0

Oder noch einfacher:

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

end="\r" wird vom Anfang [0:] des ersten Drucks überschrieben.

Evan Schwartzentruber
quelle