Désactiver le tampon de sortie
est-ce que le tampon de sortie est activé par défaut dans l'interpréteur de Python pour sys.stdout
?
si la réponse est positive, quels sont les moyens pour la désactiver?
Suggestions à ce jour:
- utilisez le
-u
commutateur de ligne de commande - Wrap
sys.stdout
un objet qui, bouffées de chaleur après chaque écriture - Set
PYTHONUNBUFFERED
env var -
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
y a-t-il une autre façon de placer un drapeau Global dans sys
/ sys.stdout
programmatiquement pendant l'exécution?
15 réponses
à Partir de Magnus Lycka réponse sur une liste de diffusion :
vous pouvez sauter le tampon pour un entier processus python utilisant " python-u" (ou#!/usr / bin / env python-u etc) ou par définition de la variable d'environnement PYTHONUNBUFFERED.
vous pourriez aussi remplacer sys.stdout avec certains autres flux comme emballage ne une chasse d'eau après chaque appel.
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'
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Crédits: "Sebastian", quelque part sur le Python liste de diffusion.
je préférerais mettre ma réponse dans comment débusquer la sortie de l'impression Python? ou dans la fonction d'impression de Python qui chasse le tampon quand il est appelé? , mais puisqu'ils ont été marqués comme des copies de celui-ci (ce que je ne suis pas d'accord), je vais répondre ici.
puisque Python 3.3 print () supporte l'argument de mot-clé "flush" ( voir documentation ):
print('Hello World!', flush=True)
Oui, c'est ça.
vous pouvez le désactiver sur la ligne de commande avec le commutateur"- u".
alternativement, vous pouvez appeler .la méthode flush() sys.stdout sur chaque écriture (ou de l'envelopper avec un objet qui le fait automatiquement)
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"])
sans sauver l'ancien système.stdout, disable_stdout_buffering () n'est pas idempotent, et plusieurs appels résulteront en une erreur comme celle-ci:
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
une autre possibilité est:
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)
(Ajout de gc.garbage est pas une bonne idée parce que c'est où unfreeable cycles se mettre, et vous pourriez vouloir vérifier pour ceux.)
les travaux suivants en Python 2.6, 2.7, et 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)
cela se rapporte à la réponse de Cristóvão D. Sousa, mais je ne pouvais pas encore commenter.
une façon simple d'utiliser l'argument de flush
mot-clé de Python 3 afin de toujours ont la sortie non tamponnée est:
import functools
print = functools.partial(print, flush=True)
ensuite, l'impression va toujours rincer la sortie directement (sauf flush=False
est donné).
Remarque, (a) que ceci répond à la question seulement en partie car il ne redirige pas toute la sortie. Mais je suppose que print
est le moyen le plus commun pour créer la sortie vers stdout
/ stderr
en python, donc ces 2 lignes couvrent probablement la plupart des cas d'utilisation.
Note (b) qu'il ne fonctionne que dans le module/script où vous l'avez défini. Cela peut être bon lors de l'écriture d'un module car il ne touche pas le sys.stdout
.
Python 2 ne fournit pas le flush
argument, mais vous pouvez émuler une fonction Python de type 3 print
comme décrit ici https://stackoverflow.com/a/27991478/3734258 .
Oui, il est activé par défaut. Vous pouvez le désactiver en utilisant l'option-u sur la ligne de commande lorsque vous appelez python.
Vous pouvez également utiliser fcntl pour modifier le fichier indicateurs de volée.
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)
une façon d'obtenir une sortie non tamponnée serait d'utiliser sys.stderr
au lieu de sys.stdout
ou simplement d'appeler sys.stdout.flush()
pour forcer explicitement une écriture à se produire.
, Vous pouvez facilement rediriger tout imprimé par:
import sys; sys.stdout = sys.stderr
print "Hello World!"
ou pour rediriger juste pour un particulier print
déclaration:
print >>sys.stderr, "Hello World!"
Pour réinitialiser la sortie standard (stdout) il vous suffit de faire:
sys.stdout = sys.__stdout__
variante qui fonctionne sans s'écraser (au moins sur win32; python 2.7, ipython 0.12) puis appelé par la suite (plusieurs fois):
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)
(j'ai posté un commentaire, mais il s'est perdu en quelque sorte. Donc, encore une fois:)
-
comme je l'ai remarqué, CPython (au moins sur Linux) se comporte différemment selon l'endroit où va la sortie. Si elle va à l'ats, alors la sortie est rincé après chaque '
\n'
S'il va à un tuyau/processus, alors il est tamponné et vous pouvez utiliser les solutionsflush()
ou l'option - u recommandé ci-dessus. -
légèrement lié au tampon de sortie:
Si vous itérez au-dessus des lignes dans l'entrée avecfor line in sys.stdin:
...
puis le pour implémentation dans CPython recueillera l'entrée pendant un certain temps, puis exécutera le corps de boucle pour un tas de lignes d'entrée. Si votre script est sur le point d'écrire la sortie pour chaque ligne d'entrée, cela pourrait ressembler à un tampon de sortie, mais c'est en fait une mise en lots, et donc , aucun des flush()
, etc. les techniques aideront.
Fait intéressant, vous n'avez pas ce comportement dans pypy .
Pour éviter cela, vous pouvez utiliser
while True:
line=sys.stdin.readline()
...
vous pouvez créer un fichier Libre et assigner ce fichier à sys.la sortie standard stdout.
import sys
myFile= open( "a.log", "w", 0 )
sys.stdout= myFile
vous ne pouvez pas changer magiquement le stdout fourni par le système, puisqu'il est fourni à votre programme python par le système D'exploitation.
il est possible de remplacer seulement write
méthode de sys.stdout
par une méthode qui appelle flush
. Méthode mise en œuvre est ci-dessous.
def write_flush(args, w=stdout.write):
w(args)
stdout.flush()
valeur par défaut de l'argument w
conservera la référence originale de la méthode write
. après write_flush
est défini, l'original write
pourrait être dépassé.
stdout.write = write_flush
le code suppose que stdout
est importé de cette façon, from sys import stdout
.