Comment vider la sortie de la fonction d'impression?
-
04-07-2019 - |
Question
Comment forcer la fonction d'impression de Python à s'afficher à l'écran?
Ceci n'est pas une copie de Désactiver la mise en mémoire tampon de sortie - la question liée tente de ne pas être mise en mémoire tampon sortie, alors que cela est plus général. Les réponses principales dans cette question sont trop puissantes ou impliquées pour celle-ci (ce ne sont pas de bonnes réponses pour cela), et cette question peut être trouvée sur Google par un nouveau débutant.
La solution
import sys
sys.stdout.flush()
print
imprime par défaut sur sys.stdout
.
Références
Python 2
Python 3
-
flush
-
io.IOBase
- objet de fichier - Glossaire
- <=> (<=> hérite la <=> méthode de <=>)
Autres conseils
En cours d'exécution python -h
, je vois une option de ligne de commande :
-u: stdout et stderr binaires sans mémoire tampon; aussi PYTHONUNBUFFERED = x voir la page de manuel pour plus de détails sur la mise en mémoire tampon interne relative à '-u'
Voici le le document pertinent .
Depuis Python 3.3, vous pouvez forcer le vidage de la fonction normale print()
sans qu'il soit nécessaire d'utiliser sys.stdout.flush()
; il suffit de définir le & "; flush &"; argument de mot clé à true. De la documentation :
print (* objets, sep = '', end = '\ n', fichier = sys.stdout, flush = False)
Imprimez les objets dans le fichier de flux, séparés par sep et suivis par fin. sep, end et file, le cas échéant, doivent être spécifiés en tant qu'arguments de mots clés.
Tous les arguments non-mot-clé sont convertis en chaînes comme le fait str () et écrits dans le flux, séparés par sep et suivis par fin. Les deux sep et end doivent être des chaînes; ils peuvent également être Aucun, ce qui signifie utiliser les valeurs par défaut. Si aucun objet n'est donné, print () écrira simplement end.
L'argument du fichier doit être un objet avec une méthode write (string); S'il n'est pas présent ou None, sys.stdout sera utilisé. Le type de sortie en mémoire tampon est généralement déterminé par fichier. Toutefois, si le mot clé flush est défini sur true, le flux est vidé de force.
Comment vider la sortie des impressions Python?
Je suggère cinq façons de procéder:
- Dans Python 3, appelez
print(..., flush=True)
(l'argument flush n'est pas disponible dans la fonction d'impression de Python 2 et il n'y a pas d'analogue pour l'instruction print). - Appelez
file.flush()
le fichier de sortie (pour cela, vous pouvez encapsuler la fonction d'impression de python 2), par exemple,sys.stdout
- l'appliquer à chaque appel de fonction d'impression dans le module avec une fonction partielle,
print = partial(print, flush=True)
appliqué au module global. - applique cela au processus avec un indicateur (
-u
) transmis à la commande d'interpréteur - appliquez-le à tous les processus python de votre environnement avec
PYTHONUNBUFFERED=TRUE
(et désélectionnez la variable pour annuler cela).
Python 3.3 +
Avec Python version 3.3 ou ultérieure, vous pouvez simplement fournir flush=True
en tant qu'argument de mot clé à la print
fonction:
print('foo', flush=True)
Python 2 (ou < 3.3)
Ils n'ont pas rétroporté l'argument flush
dans Python 2.7. Par conséquent, si vous utilisez Python 2 (ou une version inférieure à 3.3) et souhaitez un code compatible à la fois avec 2 et 3, puis-je vous suggérer le code de compatibilité suivant. (Notez que l’importation __future__
doit être à / very & Quot; près des haut de votre module "):
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()
Le code de compatibilité ci-dessus couvre la plupart des utilisations, mais pour un traitement beaucoup plus approfondi, voir le six
module .
Vous pouvez également appeler <=> après l'impression, par exemple, avec l'instruction print en Python 2:
import sys
print 'delayed output'
sys.stdout.flush()
Modification de la valeur par défaut dans un module en <=>
Vous pouvez modifier la valeur par défaut de la fonction d'impression à l'aide de functools.partial sur la portée globale d'un module:
import functools
print = functools.partial(print, flush=True)
si vous regardez notre nouvelle fonction partielle, du moins en Python 3:
>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)
Nous pouvons voir que cela fonctionne comme d'habitude:
>>> print('foo')
foo
Et nous pouvons en réalité remplacer le nouveau paramètre par défaut:
>>> print('foo', flush=False)
foo
Notez à nouveau que cela modifie uniquement la portée globale actuelle, car le nom d’impression de la portée globale actuelle occultera la fonction <=> intégrée (ou déréférencera la fonction de compatibilité, si vous utilisez Python 2, dans cette portée globale actuelle).
Si vous souhaitez effectuer cette opération dans une fonction plutôt que dans la portée globale d'un module, vous devez lui attribuer un nom différent, par exemple:
.def foo():
printf = functools.partial(print, flush=True)
printf('print stuff like this')
Si vous le déclarez global dans une fonction, vous le modifiez dans l'espace de noms global du module. Vous devez donc simplement le placer dans l'espace de noms global, à moins que ce comportement ne corresponde exactement à vos souhaits.
Modification de la valeur par défaut du processus
Je pense que la meilleure option ici est d'utiliser l'indicateur <=> pour obtenir une sortie non tamponnée.
$ python -u script.py
ou
$ python -um package.module
Dans les docs :
Forcez stdin, stdout et stderr à ne pas bouger. Sur les systèmes où cela compte, mettez également stdin, stdout et stderr en mode binaire.
Notez que la mise en mémoire tampon interne dans file.readlines () et les objets de fichier (pour la ligne dans sys.stdin) ne sont pas influencés par cette option. Pour contourner ce problème, vous souhaiterez utiliser file.readline () dans une boucle while: 1.
Modification de la valeur par défaut pour l'environnement d'exploitation du shell
Vous pouvez obtenir ce comportement pour tous les processus python de l'environnement ou des environnements hérités de l'environnement si vous définissez la variable d'environnement sur une chaîne non vide:
Par exemple, sous Linux ou OSX:
$ export PYTHONUNBUFFERED=TRUE
ou Windows:
C:\SET PYTHONUNBUFFERED=TRUE
depuis le docs :
PYTHONUNBUFFERED
Si ceci est défini sur une chaîne non vide, cela équivaut à spécifier l'option -u.
Annoncedendum
Voici l'aide sur la fonction d'impression de Python 2.7.12 - notez qu'il y a non <=> argument:
>>> 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.
Aussi, comme suggéré dans ce blog , vous pouvez le rouvrir. sys.stdout
en mode sans tampon:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Chaque stdout.write
et print
opération sera automatiquement vidée par la suite.
Avec Python 3.x, la fonction print()
a été étendue:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Donc, vous pouvez simplement faire:
print("Visiting toilet", flush=True)
L’utilisation du commutateur de ligne de commande -u
fonctionne, mais elle est un peu maladroite. Cela signifierait que le programme pourrait se comporter de manière incorrecte si l'utilisateur invoquait le script sans l'option stdout
. J'utilise habituellement une coutume print
, comme ceci:
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)
... Maintenant, tous vos sys.stdout
appels (qui utilisent flush
implicitement) seront automatiquement édités <=>.
Pourquoi ne pas utiliser un fichier sans tampon?
f = open('xyz.log', 'a', 0)
OU
sys.stdout = open('out.log', 'a', 0)
L'idée de Dan ne fonctionne pas très bien:
#!/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"
Le résultat:
Traceback (most recent call last):
File "./passpersist.py", line 12, in <module>
print "foo"
ValueError: I/O operation on closed file
Je pense que le problème est qu’il hérite de la classe de fichiers, ce qui n’est en fait pas nécessaire. Selon la documentation de sys.stdout:
stdout et stderr ne doivent pas & # 8217; ne pas être intégrés objets de fichier: tout objet est acceptable tant qu'il a une méthode write () qui prend un argument de chaîne.
donc changeant
class flushfile(file):
à
class flushfile(object):
ça marche très bien.
Voici ma version, qui fournit également writeelines () et fileno ():
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()
En Python 3, vous pouvez écraser la fonction d'impression avec la valeur par défaut flush = True
def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
__builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
Je l'ai fait comme ça en Python 3.4:
'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')