it-swarm.com.de

Deaktivieren Sie die Ausgabepufferung

Ist die Ausgabepufferung in Pythons Interpreter für sys.stdout Standardmäßig aktiviert?

Wenn die Antwort positiv ist, wie können Sie sie deaktivieren?

Bisherige Vorschläge:

  1. Verwenden Sie den Befehlszeilenschalter -u
  2. Wickeln Sie sys.stdout In ein Objekt, das nach jedem Schreiben gelöscht wird
  3. Setze PYTHONUNBUFFERED env var
  4. sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Gibt es eine andere Möglichkeit, ein globales Flag in sys/sys.stdout Während der Ausführung programmgesteuert zu setzen?

471
Eli Bendersky

Von Magnus Lycka antwortet auf einer Mailingliste :

Sie können die Pufferung für einen gesamten python Prozess mit "python -u" (oder #!/Usr/bin/env python -u usw.) oder mit Setzen der Umgebungsvariable PYTHONUNBUFFERED.

Sie können sys.stdout auch durch einen anderen Stream wie wrapper ersetzen, der nach jedem Aufruf einen Flush ausführt.

class Unbuffered(object):
   def __init__(self, stream):
       self.stream = stream
   def write(self, data):
       self.stream.write(data)
       self.stream.flush()
   def writelines(self, datas):
       self.stream.writelines(datas)
       self.stream.flush()
   def __getattr__(self, attr):
       return getattr(self.stream, attr)

import sys
sys.stdout = Unbuffered(sys.stdout)
print 'Hello'
394
Seb

Ich würde meine Antwort lieber in Wie lösche ich die Ausgabe von Python print? oder in Pythons Druckfunktion, die den Puffer löscht, wenn er aufgerufen wird? =, aber da sie als Duplikate von diesem markiert wurden (was ich nicht zustimme), werde ich es hier beantworten.

Seit Python 3.3 print () unterstützt das Schlüsselwortargument "flush" ( siehe Dokumentation ):

print('Hello World!', flush=True)
95
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Credits: "Sebastian", irgendwo auf der Python Mailingliste.

rd Party EDIT

In neueren Versionen von Python nicht unterstützt

74

Ja ist es.

Sie können es in der Befehlszeile mit der Option "-u" deaktivieren.

Alternativ können Sie bei jedem Schreiben .flush () auf sys.stdout aufrufen (oder es mit einem Objekt umschließen, das dies automatisch ausführt).

49
Brian

Dies bezieht sich auf die Antwort von Cristóvão D. Sousa, aber ich konnte noch keinen Kommentar abgeben.

Eine einfache Möglichkeit, das Schlüsselwortargument flush von Python 3 zu verwenden, um immer haben ungepufferte Ausgabe ist:

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

anschließend wird die Ausgabe beim Drucken immer direkt geleert (außer bei flush=False gegeben ist).

Beachten Sie, dass (a) dies die Frage nur teilweise beantwortet, da nicht alle Ausgaben umgeleitet werden. Aber ich denke, print ist die gebräuchlichste Methode zum Erstellen von Ausgaben in stdout/stderr in Python, sodass diese beiden Zeilen wahrscheinlich die meisten Anwendungsfälle abdecken.

Beachten Sie (b), dass es nur in dem Modul/Skript funktioniert, in dem Sie es definiert haben. Dies kann beim Schreiben eines Moduls hilfreich sein, da es nicht mit dem sys.stdout.

Python 2 liefert nicht das Argument flush, aber Sie könnten eine Python 3-type print -Funktion emulieren als hier beschrieben https://stackoverflow.com/a/27991478/3734258 .

16
tim
def disable_stdout_buffering():
    # Appending to gc.garbage is a way to stop an object from being
    # destroyed.  If the old sys.stdout is ever collected, it will
    # close() stdout, which is not good.
    gc.garbage.append(sys.stdout)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

# Then this will give output in the correct order:
disable_stdout_buffering()
print "hello"
subprocess.call(["echo", "bye"])

Ohne das alte sys.stdout zu speichern, ist disable_stdout_buffering () nicht idempotent und mehrere Aufrufe führen zu einem Fehler wie dem folgenden:

Traceback (most recent call last):
  File "test/buffering.py", line 17, in <module>
    print "hello"
IOError: [Errno 9] Bad file descriptor
close failed: [Errno 9] Bad file descriptor

Eine andere Möglichkeit ist:

def disable_stdout_buffering():
    fileno = sys.stdout.fileno()
    temp_fd = os.dup(fileno)
    sys.stdout.close()
    os.dup2(temp_fd, fileno)
    os.close(temp_fd)
    sys.stdout = os.fdopen(fileno, "w", 0)

(Das Anhängen an gc.garbage ist keine gute Idee, da hier nicht freisetzbare Zyklen abgelegt werden und Sie möglicherweise nach solchen suchen möchten.)

14
Mark Seaborn

Das Folgende funktioniert in Python 2.6, 2.7 und 3.2:

import os
import sys
buf_arg = 0
if sys.version_info[0] == 3:
    os.environ['PYTHONUNBUFFERED'] = '1'
    buf_arg = 1
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)
12
Gummbum

Ja, es ist standardmäßig aktiviert. Sie können es deaktivieren, indem Sie die Option -u in der Befehlszeile verwenden, wenn Sie Python aufrufen.

11
Nathan

Sie können Python mit stdbuf auch ausführen:

stdbuf -oL python <script>

7
dyomas

Es ist möglich, nurwrite Methode von sys.stdout Mit einer zu überschreiben, die flush aufruft. Die vorgeschlagene Implementierung der Methode ist unten aufgeführt.

def write_flush(args, w=stdout.write):
    w(args)
    stdout.flush()

Der Standardwert des Arguments w behält die ursprüngliche Methodenreferenz write bei. Nachdemwrite_flush Definiert wurde, kann das ursprüngliche write überschrieben werden.

stdout.write = write_flush

Der Code geht davon aus, dass stdout auf diese Weise importiert wird from sys import stdout.

4
Vasily E.

Sie können auch fcntl verwenden, um die Dateiflaggen direkt zu ändern.

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC # or os.O_DSYNC (if you don't care the file timestamp updates)
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl)
4
jimx

(Ich habe einen Kommentar gepostet, aber er ist irgendwie verloren gegangen. Also nochmal :)

  1. Wie ich bemerkt habe, verhält sich CPython (zumindest unter Linux) anders, je nachdem, wohin die Ausgabe geht. Wenn es auf tty geht, wird die Ausgabe nach jedem '\n'
    Wenn es sich um eine Pipe/einen Prozess handelt, wird es gepuffert und Sie können die auf flush() basierenden Lösungen oder die oben empfohlene Option - verwenden.

  2. In geringem Zusammenhang mit der Ausgabepufferung:
    Wenn Sie über die Zeilen in der Eingabe mit iterieren

    for line in sys.stdin:
    ...

dann sammelt die für -Implementierung in CPython die Eingabe für eine Weile und führt dann den Schleifenkörper für eine Reihe von Eingabezeilen aus. Wenn Ihr Skript im Begriff ist, eine Ausgabe für jede Eingabezeile zu schreiben, sieht dies möglicherweise so aus, als würde die Ausgabe gepuffert, aber tatsächlich werden Batch-Vorgänge ausgeführt. Daher kann keine der Techniken flush() usw. Abhilfe schaffen. Interessanterweise haben Sie dieses Verhalten nicht in pypy. Um dies zu vermeiden, können Sie verwenden

while True: line=sys.stdin.readline()
...

3
tzp

Sie können eine ungepufferte Datei erstellen und diese Datei sys.stdout zuweisen.

import sys 
myFile= open( "a.log", "w", 0 ) 
sys.stdout= myFile

Sie können die vom System bereitgestellte Standardausgabe nicht auf magische Weise ändern. da es vom Betriebssystem an Ihr python geliefert wird.

3
S.Lott

In Python 3 können Sie die Druckfunktion mit einem Affen patchen, um immer flush = True zu senden:

_orig_print = print

def print(*args, **kwargs):
    _orig_print(*args, flush=True, **kwargs)

Wie in einem Kommentar erwähnt, können Sie dies vereinfachen, indem Sie den Flush-Parameter über functools.partial An einen Wert binden:

print = functools.partial(print, flush=True)
3
Oliver

Variante, die ohne Absturz funktioniert (zumindest auf win32; python 2.7, ipython 0.12)) und anschließend (mehrmals) aufgerufen wird:

def DisOutBuffering():
    if sys.stdout.name == '<stdout>':
        sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    if sys.stderr.name == '<stderr>':
        sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
3
Laimis

Eine Möglichkeit, eine ungepufferte Ausgabe zu erhalten, besteht darin, sys.stderr Anstelle von sys.stdout Zu verwenden oder einfach sys.stdout.flush() aufzurufen, um explizit einen Schreibvorgang zu erzwingen.

Sie können alles, was gedruckt wird, einfach umleiten, indem Sie Folgendes tun:

import sys; sys.stdout = sys.stderr
print "Hello World!"

Oder um nur für eine bestimmte print Anweisung umzuleiten:

print >>sys.stderr, "Hello World!"

Um stdout zurückzusetzen, können Sie einfach Folgendes tun:

sys.stdout = sys.__stdout__
2
stderr