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:

  1. utilisez le -u commutateur de ligne de commande
  2. Wrap sys.stdout un objet qui, bouffées de chaleur après chaque écriture
  3. Set PYTHONUNBUFFERED env var
  4. 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?

416
demandé sur Whymarrh 2008-09-20 13:17:20

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'
355
répondu Seb 2017-05-05 05:06:58
# 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.

73
répondu Federico A. Ramponi 2008-10-08 07:41:43

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)
70
répondu Cristóvão D. Sousa 2017-05-23 12:34:51

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)

42
répondu Brian 2008-09-20 09:25:36
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.)

10
répondu Mark Seaborn 2010-09-09 15:55:37

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)
10
répondu Gummbum 2014-04-12 18:43:28

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 .

10
répondu ciem 2017-05-23 12:26:36

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.

9
répondu Nathan 2008-09-20 09:26:19

vous pouvez aussi exécuter Python avec stdbuf utility:

stdbuf -oL python <script>

5
répondu dyomas 2015-07-01 20:09:53

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)
3
répondu jimx 2009-11-15 00:01:01

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__
3
répondu stderr 2010-11-17 15:49:40

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)
3
répondu Laimis 2012-06-30 19:20:08

(j'ai posté un commentaire, mais il s'est perdu en quelque sorte. Donc, encore une fois:)

  1. 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 solutions flush() ou l'option - u recommandé ci-dessus.

  2. légèrement lié au tampon de sortie:

    Si vous itérez au-dessus des lignes dans l'entrée avec

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

...

3
répondu tzp 2013-06-11 14:47:38

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.

2
répondu S.Lott 2008-09-20 10:39:09

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 .

2
répondu Vasily E. 2017-02-25 21:00:30