La mise en mémoire tampon de sortie est-elle activée par défaut dans l'interpréteur Python pour sys.stdout
?
Si la réponse est positive, quelles sont toutes les façons de la désactiver?
Suggestions jusqu'à présent:
- Utilisez le
-u
commutateur de ligne de commande - Enveloppez
sys.stdout
dans un objet qui se vide après chaque écriture - Définir
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Existe-t-il un autre moyen de définir un indicateur global dans sys
/ par sys.stdout
programme pendant l'exécution?
-u
est qu'il ne fonctionnera pas pour le bytecode compilé ou pour les applications avec un__main__.py
fichier comme point d'entrée.Réponses:
De Magnus Lycka répondre sur une liste de diffusion :
la source
#!/usr/bin/env python -u
ne fonctionne pas !! voir ici__getattr__
juste pour éviter l'héritage?!iter()
lieu de lawhile
boucle:for line in iter(pipe.readline, ''):
. Vous n'en avez pas besoin sur Python 3 où lesfor line in pipe:
rendements le plus tôt possible.Je préfère mettre ma réponse dans Comment vider la sortie de la fonction d'impression? ou dans la fonction d'impression de Python qui vide le tampon quand il est appelé? , mais comme ils ont été marqués comme des doublons de celui-ci (ce que je ne suis pas d'accord), je vais y répondre ici.
Depuis Python 3.3, print () supporte l'argument de mot-clé "flush" ( voir documentation ):
la source
Crédits: "Sebastian", quelque part sur la liste de diffusion Python.
la source
flush=True
paramètre pourprint()
fonctionner depuis Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)
(notez leb
pour binaire) etflush=True
travaillez pour moi en 3.6.4. Cependant, si vous utilisez un sous-processus pour démarrer un autre script, assurez-vous que vous avez spécifiépython3
, si vous avez plusieurs instances de python installées.os.fdopen(sys.stdout.fileno(), 'wb', 0)
vous vous retrouvez avec un objet fichier binaire, pas unTextIO
flux. Vous devez ajouter unTextIOWrapper
au mélange (en veillant à activerwrite_through
pour éliminer tous les tampons, ou à utiliserline_buffering=True
pour vider uniquement sur les nouvelles lignes).Oui, ça l'est.
Vous pouvez le désactiver sur la ligne de commande avec le commutateur "-u".
Alternativement, vous pouvez appeler .flush () sur sys.stdout à chaque écriture (ou l'envelopper avec un objet qui le fait automatiquement)
la source
Cela concerne la réponse de Cristóvão D. Sousa, mais je ne pourrais pas encore commenter.
Une manière simple d'utiliser l'
flush
argument mot - clé de Python 3 afin d' avoir toujours une sortie sans tampon est:par la suite, l'impression videra toujours directement la sortie (sauf indication contraire
flush=False
).Notez, (a) que cela ne répond que partiellement à la question car il ne redirige pas toute la sortie. Mais je suppose que
print
c'est la façon la plus courante de créer une sortie versstdout
/stderr
en python, donc ces 2 lignes couvrent probablement la plupart des cas d'utilisation.Notez (b) qu'il ne fonctionne que dans le module / script où vous l'avez défini. Cela peut être utile lors de l'écriture d'un module car il ne dérange pas avec le
sys.stdout
.Python 2 ne fournit pas l'
flush
argument, mais vous pouvez émuler uneprint
fonction de type Python 3 comme décrit ici https://stackoverflow.com/a/27991478/3734258 .la source
flush
kwarg en python2.Sans enregistrer l'ancien sys.stdout, disable_stdout_buffering () n'est pas idempotent, et plusieurs appels entraîneront une erreur comme celle-ci:
Une autre possibilité est:
(L'ajout à gc.garbage n'est pas une si bonne idée car c'est là que les cycles non exploitables sont mis en place, et vous voudrez peut-être les vérifier.)
la source
stdout
vit toujourssys.__stdout__
comme certains l'ont suggéré, la poubelle ne sera pas nécessaire, non? C'est un truc sympa cependant.ValueError: can't have unbuffered text I/O
lors de l'appelprint()
.Les travaux suivants dans Python 2.6, 2.7 et 3.2:
la source
OSError: [Errno 29] Illegal seek
la lignesys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
Oui, il est activé par défaut. Vous pouvez le désactiver en utilisant l'option -u sur la ligne de commande lors de l'appel de python.
la source
Vous pouvez également exécuter Python avec l' utilitaire stdbuf :
stdbuf -oL python <script>
la source
-oL
activé) est toujours en mémoire tampon - voir f / e stackoverflow.com/questions/58416853/… , demandant pourquoi laend=''
sortie n'est plus affichée immédiatement.print(..., end='', flush=True)
où cela est improtant? OTOH, lorsque plusieurs programmes écrivent simultanément sur la même sortie, le compromis a tendance à passer de la progression immédiate à la réduction des mélanges de sortie, et la mise en mémoire tampon des lignes devient attrayante. Alors peut - être qu'il est préférable de ne pas écrire explicitementflush
et le contrôle tampon externe?flush
. Le contrôle de la mise en mémoire tampon externe est une solution de contournementEn Python 3, vous pouvez patcher la fonction d'impression pour toujours envoyer flush = True:
Comme indiqué dans un commentaire, vous pouvez simplifier cela en liant le paramètre flush à une valeur, via
functools.partial
:la source
functools.partial
?print = functools.partial(print, flush=True)
fonctionne bien pour moi.import builtins; builtins.print = partial(print, flush=True)
Vous pouvez également utiliser fcntl pour modifier les indicateurs de fichier à la volée.
la source
Il est possible de remplacer uniquement la
write
méthode desys.stdout
celle qui appelleflush
. L'implémentation de méthode suggérée est ci-dessous.La valeur par défaut de l'
w
argument conservera lawrite
référence de méthode d' origine . Une foiswrite_flush
défini, l'originalwrite
peut être remplacé.Le code suppose qu'il
stdout
est importé de cette façonfrom sys import stdout
.la source
Vous pouvez créer un fichier sans tampon et affecter ce fichier à sys.stdout.
Vous ne pouvez pas modifier comme par magie la sortie standard fournie par le système; car il est fourni à votre programme python par le système d'exploitation.
la source
Variante qui fonctionne sans planter (au moins sur win32; python 2.7, ipython 0.12) puis appelée par la suite (plusieurs fois):
la source
sys.stdout is sys.__stdout__
lieu de compter sur l'objet de remplacement ayant un attribut de nom?(J'ai posté un commentaire, mais il s'est perdu d'une manière ou d'une autre. Donc, encore une fois :)
Comme je l'ai remarqué, CPython (au moins sous Linux) se comporte différemment selon où va la sortie. S'il va à un tty, la sortie est purgée après chaque '
\n'
S'il va à un tuyau / processus, alors il est tamponné et vous pouvez utiliser les
flush()
solutions basées ou l' option -u recommandée ci-dessus.Légèrement lié à la mise en mémoire tampon de sortie:
si vous parcourez les lignes en entrée avec
for line in sys.stdin:
...
puis pour la mise en œuvre en CPython recueillera l'entrée pendant un certain temps et puis exécutez le corps de la boucle pour une série de lignes d'entrée. Si votre script est sur le point d'écrire la sortie pour chaque ligne d'entrée, cela peut ressembler à une mise en mémoire tampon de sortie, mais il s'agit en fait d'un traitement par lots, et par conséquent, aucune des
flush()
techniques, etc. n'aidera cela. Fait intéressant, vous n'avez pas ce comportement dans Pypy . Pour éviter cela, vous pouvez utiliserwhile True: line=sys.stdin.readline()
...
la source
for line in sys.stdin
vsfor line in iter(sys.stdin.readline, "")
for line in sys.stdin
fournit une réponse retardée)Une façon d'obtenir une sortie non tamponnée serait d'utiliser à la
sys.stderr
place desys.stdout
ou d'appeler simplementsys.stdout.flush()
pour forcer explicitement l'écriture à se produire.Vous pouvez facilement rediriger tout ce qui est imprimé en faisant:
Ou pour rediriger juste pour une
print
instruction particulière :Pour réinitialiser stdout, vous pouvez simplement faire:
la source