Wie wird die Ausgabe der Druckfunktion geleert?

1216

Wie erzwinge ich die Ausgabe der Python-Druckfunktion auf dem Bildschirm?

Dies ist kein Duplikat der Deaktivierung der Ausgabepufferung. Die verknüpfte Frage versucht, eine ungepufferte Ausgabe zu erstellen, während dies allgemeiner ist. Die Top-Antworten in dieser Frage sind zu mächtig oder zu kompliziert für diese Frage (sie sind keine guten Antworten dafür), und diese Frage kann von einem relativen Neuling bei Google gefunden werden.

Walter Nissen
quelle

Antworten:

1428

printKann unter Python 3 ein optionales flushArgument annehmen

print("Hello world!", flush=True)

Auf Python 2 müssen Sie tun

import sys
sys.stdout.flush()

nach dem anruf print. Standardmäßig printdruckt sys.stdout(siehe Dokumentation für mehr über Dateiobjekte ).

CesarB
quelle
346

Beim Ausführen python -hwird eine Befehlszeilenoption angezeigt :

-u: ungepufferte binäre stdout und stderr; auch PYTHONUNBUFFERED = x Einzelheiten zur internen Pufferung in Bezug auf '-u' finden Sie in der Manpage.

Hier ist das relevante Dokument .

gimel
quelle
320

Seit Python 3.3 können Sie das Löschen der normalen print()Funktion erzwingen , ohne sie verwenden zu müssen sys.stdout.flush(). Setzen Sie einfach das Schlüsselwortargument "flush" auf true. Aus der Dokumentation :

print (* Objekte, sep = '', end = '\ n', file = sys.stdout, flush = False)

Drucken Sie Objekte in die Stream-Datei, getrennt durch sep und gefolgt von end. Sep, End und Datei, falls vorhanden, müssen als Schlüsselwortargumente angegeben werden.

Alle Nicht-Schlüsselwort-Argumente werden wie str () in Zeichenfolgen konvertiert und in den Stream geschrieben, getrennt durch sep und gefolgt von end. Sowohl Sep als auch End müssen Strings sein; Sie können auch Keine sein, was bedeutet, dass die Standardwerte verwendet werden. Wenn keine Objekte angegeben sind, schreibt print () nur end.

Das Dateiargument muss ein Objekt mit einer Schreibmethode (Zeichenfolge) sein. Wenn es nicht vorhanden oder nicht vorhanden ist, wird sys.stdout verwendet. Ob die Ausgabe gepuffert wird, wird normalerweise von der Datei bestimmt. Wenn das Schlüsselwortargument flush jedoch wahr ist, wird der Stream zwangsweise geleert.

Eugene Sajine
quelle
198

Wie lösche ich die Ausgabe von Python-Druck?

Ich schlage fünf Möglichkeiten vor, dies zu tun:

  • Rufen Sie in Python 3 auf print(..., flush=True)(das Flush-Argument ist in der Druckfunktion von Python 2 nicht verfügbar, und es gibt kein Analogon für die print-Anweisung).
  • Rufen Sie dazu file.flush()die Ausgabedatei auf (wir können dazu die Druckfunktion von Python 2 umbrechen).sys.stdout
  • Wenden Sie dies auf jeden Druckfunktionsaufruf im Modul mit einer Teilfunktion an,
    print = partial(print, flush=True)die auf das Modul global angewendet wird.
  • Wenden Sie dies auf den Prozess -uan, indem Sie ein Flag ( ) an den Interpreter-Befehl übergeben
  • Wenden Sie dies auf jeden Python-Prozess in Ihrer Umgebung mit an PYTHONUNBUFFERED=TRUE(und deaktivieren Sie die Variable, um dies rückgängig zu machen).

Python 3.3+

Mit Python 3.3 oder höher können Sie flush=Trueder printFunktion lediglich ein Schlüsselwortargument geben :

print('foo', flush=True) 

Python 2 (oder <3.3)

Sie haben das flushArgument nicht auf Python 2.7 zurückportiert. Wenn Sie also Python 2 (oder weniger als 3.3) verwenden und Code möchten, der sowohl mit 2 als auch mit 3 kompatibel ist, kann ich den folgenden Kompatibilitätscode vorschlagen. (Beachten Sie, dass sich der __future__Import an / sehr "nahe der Oberseite Ihres Moduls " befinden muss.):

from __future__ import print_function
import sys

if sys.version_info[:2] < (3, 3):
    old_print = print
    def print(*args, **kwargs):
        flush = kwargs.pop('flush', False)
        old_print(*args, **kwargs)
        if flush:
            file = kwargs.get('file', sys.stdout)
            # Why might file=None? IDK, but it works for print(i, file=None)
            file.flush() if file is not None else sys.stdout.flush()

Der obige Kompatibilitätscode deckt die meisten Verwendungszwecke ab. Eine ausführlichere Beschreibung finden Sie im sixModul .

Alternativ können Sie einfach file.flush()nach dem Drucken aufrufen , z. B. mit der print-Anweisung in Python 2:

import sys
print 'delayed output'
sys.stdout.flush()

Ändern der Standardeinstellung in einem Modul in flush=True

Sie können die Standardeinstellung für die Druckfunktion ändern, indem Sie functools.partial für den globalen Bereich eines Moduls verwenden:

import functools
print = functools.partial(print, flush=True)

Wenn Sie sich unsere neue Teilfunktion ansehen, zumindest in Python 3:

>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)

Wir können sehen, dass es wie gewohnt funktioniert:

>>> print('foo')
foo

Und wir können den neuen Standard tatsächlich überschreiben:

>>> print('foo', flush=False)
foo

Beachten Sie erneut, dass dies nur den aktuellen globalen Bereich ändert, da der Druckname im aktuellen globalen Bereich die integrierte printFunktion überschattet (oder die Kompatibilitätsfunktion bei Verwendung einer in Python 2 in diesem aktuellen globalen Bereich nicht referenziert).

Wenn Sie dies innerhalb einer Funktion anstatt im globalen Bereich eines Moduls tun möchten, sollten Sie ihm einen anderen Namen geben, z.

def foo():
    printf = functools.partial(print, flush=True)
    printf('print stuff like this')

Wenn Sie es in einer Funktion als global deklarieren, ändern Sie es im globalen Namespace des Moduls. Sie sollten es also einfach in den globalen Namespace einfügen, es sei denn, dieses spezifische Verhalten entspricht genau Ihren Wünschen.

Ändern der Standardeinstellung für den Prozess

Ich denke, die beste Option hier ist, das -uFlag zu verwenden, um ungepufferte Ausgabe zu erhalten.

$ python -u script.py

oder

$ python -um package.module

Aus den Dokumenten :

Erzwinge, dass stdin, stdout und stderr völlig ungepuffert sind. Versetzen Sie auf Systemen, auf denen es darauf ankommt, auch stdin, stdout und stderr in den Binärmodus.

Beachten Sie, dass file.readlines () und File Objects (für line in sys.stdin) eine interne Pufferung aufweisen, die von dieser Option nicht beeinflusst wird. Um dies zu umgehen, sollten Sie file.readline () innerhalb einer while 1: -Schleife verwenden.

Ändern der Standardeinstellung für die Shell-Betriebsumgebung

Sie können dieses Verhalten für alle Python-Prozesse in der Umgebung oder in Umgebungen erhalten, die von der Umgebung erben, wenn Sie die Umgebungsvariable auf eine nicht leere Zeichenfolge setzen:

zB unter Linux oder OSX:

$ export PYTHONUNBUFFERED=TRUE

oder Windows:

C:\SET PYTHONUNBUFFERED=TRUE

aus den Dokumenten :

PYTHONUNBUFFERED

Wenn dies auf eine nicht leere Zeichenfolge festgelegt ist, entspricht dies der Angabe der Option -u.


Nachtrag

Hier ist die Hilfe zur Druckfunktion aus Python 2.7.12 - beachten Sie, dass es kein flush Argument gibt:

>>> from __future__ import print_function
>>> help(print)
print(...)
    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.
Aaron Hall
quelle
Für die neugierige Migration von niedrigeren Python-Versionen: Die __future__Version enthält keine, flushweil "das Flush-Argument in Python 3.3 hinzugefügt wurde (nachdem print () über einen zukünftigen Import auf 2.7 zurückportiert wurde
Oliver
69

Auch wie in diesem Blog vorgeschlagen, kann man sys.stdoutim ungepufferten Modus wieder öffnen :

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Jeder stdout.writeund printBetrieb wird anschließend automatisch gespült werden.

Antony Hatchkins
quelle
2
Unter Ubuntu 12.04 in Python 2.7 gibt mir dasUnsupportedOperation: IOStream has no fileno.
drevicko
3
Hoppla, Python 3 hat es herausgefunden. Ich kann diesen Code nicht ausführen!
EKons
Ich bin verwirrt von dieser Redewendung. Gibt es danach nicht zwei dateiähnliche Objekte (das ursprüngliche sys.stdout und das neue sys.stdout), die beide glauben, das Fileno zu "besitzen"? Das ist schlecht, oder?
Don Hatch
62

Mit Python 3.x wurde die print()Funktion erweitert:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Sie können also einfach Folgendes tun:

print("Visiting toilet", flush=True)

Python Docs-Eintrag

Noah Krasser
quelle
36

Die Verwendung des -uBefehlszeilenschalters funktioniert, ist jedoch etwas ungeschickt. Dies würde bedeuten, dass sich das Programm möglicherweise falsch verhält, wenn der Benutzer das Skript ohne die -uOption aufruft. Normalerweise benutze ich einen Brauch stdoutwie diesen:

class flushfile:
  def __init__(self, f):
    self.f = f

  def write(self, x):
    self.f.write(x)
    self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

... Jetzt werden alle Ihre printAnrufe (die sys.stdoutimplizit verwendet werden) automatisch flushbearbeitet.

Dan Lenski
quelle
4
Ich empfehle, nicht von der Datei zu erben und dann durch Hinzufügen an stdout zu delegieren. def __getattr__(self,name): return object.__getattribute__(self.f, name)
dreimal am
2
Ohne die Änderungen, die durch den Kommentar von @diedthreetimes vorgeschlagen wurden, erhalte ich "ValueError: E / A-Operation für geschlossene Datei"
blueFast
19

Warum nicht versuchen, eine ungepufferte Datei zu verwenden?

f = open('xyz.log', 'a', 0)

ODER

sys.stdout = open('out.log', 'a', 0)
Nakilon
quelle
1
Er möchte keine ungepufferte Datei erstellen. er möchte das vorhandene stdout (auf die Konsole, das Terminal oder was auch immer umgeleitet: dies darf nicht geändert werden) ungepuffert machen.
blueFast
13

Dans Idee funktioniert nicht ganz:

#!/usr/bin/env python
class flushfile(file):
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

print "foo"

Das Ergebnis:

Traceback (most recent call last):
  File "./passpersist.py", line 12, in <module>
    print "foo"
ValueError: I/O operation on closed file

Ich glaube, das Problem ist, dass es von der Dateiklasse erbt, was eigentlich nicht notwendig ist. Laut den Dokumenten für sys.stdout:

stdout und stderr müssen keine integrierten Dateiobjekte sein: Jedes Objekt ist akzeptabel, solange es eine write () -Methode hat, die ein Zeichenfolgenargument akzeptiert.

so verändernd

class flushfile(file):

zu

class flushfile(object):

macht es gut.

Kamil Kisiel
quelle
17
Keine Abstimmung, da dies die Lösung von IS @ Dan ist ... (Sie sollten lieber Dans Beitrag kommentieren, anstatt seine Lösung zu kopieren)
Gecco
8

Hier ist meine Version, die auch writelines () und fileno () enthält:

class FlushFile(object):
    def __init__(self, fd):
        self.fd = fd

    def write(self, x):
        ret = self.fd.write(x)
        self.fd.flush()
        return ret

    def writelines(self, lines):
        ret = self.writelines(lines)
        self.fd.flush()
        return ret

    def flush(self):
        return self.fd.flush

    def close(self):
        return self.fd.close()

    def fileno(self):
        return self.fd.fileno()
guettli
quelle
Überlegene Lösung. Und es funktioniert. Getestet auf Python 3.4.0. Bei den anderen Versionen, von denen abgeleitet wird file, erhalte ich eine Fehlermeldung. Es gibt keine fileKlasse.
Colin D Bennett
6

In Python 3 können Sie die Druckfunktion mit der Standardeinstellung überschreiben flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
user263387
quelle
2
Diese Antwort scheint angesichts all der anderen qualitativ hochwertigen Antworten ein wenig leicht zu sein. Vielleicht möchten Sie noch etwas hinzufügen.
Semikolons und Klebeband
5

Ich habe es in Python 3.4 so gemacht:

'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')
kmario23
quelle
2

Ich hatte zuerst Mühe zu verstehen, wie die Spüloption funktionierte. Ich wollte eine 'Ladeanzeige' machen und hier ist die Lösung, die ich gefunden habe:

for i in range(100000):
    print('{:s}\r'.format(''), end='', flush=True)
    print('Loading index: {:d}/100000'.format(i+1), end='')

Die erste Zeile löscht den vorherigen Druck und die zweite Zeile druckt eine neue aktualisierte Nachricht. Ich weiß nicht, ob hier eine einzeilige Syntax existiert.

Guillaume Mougeot
quelle