web-dev-qa-db-fra.com

Comment vider la sortie de la fonction d'impression?

Comment forcer la fonction d'impression de Python à s'afficher à l'écran?

Il ne s’agit pas d’un doublon de Désactiver la mise en mémoire tampon de la sortie - la question liée tente de produire une sortie non mise en mémoire tampon, 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.

1068
Walter Nissen
_import sys
sys.stdout.flush()
_

print imprime par défaut sur _sys.stdout_.

Références

Python 2

Python 3

1247
CesarB

En cours d'exécution python -h, je vois une option de ligne de commande :

-u: stdout et stderr binaires sans mémoire tampon; également PYTHONUNBUFFERED = x voir la page de manuel pour plus de détails sur la mise en mémoire tampon interne relative à '-u'

Voici le doc pertinente .

326
gimel

Depuis Python 3.3, vous pouvez forcer la fonction print() normale à se vider sans qu'il soit nécessaire d'utiliser sys.stdout.flush(); il suffit de définir l’argument du mot clé "flush" sur 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, s'ils sont présents, doivent être donnés comme 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 de 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, mais si l'argument du mot-clé flush est true, le flux est forcé.

309
Eugene Sajine

Comment vider la sortie de Python print?

Je suggère cinq façons de le faire:

  • 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'existe pas d'analogue pour l'instruction print).
  • Appelez file.flush() sur le fichier de sortie (pour cela, nous pouvons envelopper la fonction d'impression de python 2), par exemple, sys.stdout
  • appliquer cela à chaque appel de fonction d'impression dans le module avec une fonction partielle,
    print = partial(print, flush=True) appliquée au module global.
  • appliquer cela au processus avec un indicateur (-u) transmis à la commande interpréteur
  • appliquez-le à tous les processus python de votre environnement avec PYTHONUNBUFFERED=TRUE ((et désactivez la variable pour l'annuler).

Python 3.3+

Avec Python 3.3 ou version ultérieure, vous pouvez simplement fournir flush=True comme argument de mot clé à la fonction print:

print('foo', flush=True) 

Python 2 (ou <3.3)

Ainsi, ils n'ont pas rétroporté l'argument flush vers Python 2.7. Par conséquent, si vous utilisez Python 2 (ou une version inférieure à 3.3), et souhaitez un code compatible avec les versions 2 et 3, puis-je suggère le code de compatibilité suivant. (Notez que l'importation __future__ doit être à/très "proche de 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 couvrira la plupart des utilisations, mais pour un traitement beaucoup plus complet, voir le module six .

Alternativement, vous pouvez simplement appeler file.flush() après avoir imprimé, par exemple, avec l'instruction print dans Python 2:

import sys
print 'delayed output'
sys.stdout.flush()

Changer la valeur par défaut dans un module en flush=True

Vous pouvez modifier la valeur par défaut pour 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, au moins dans 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 encore une fois, cela ne change que la portée globale actuelle, car le nom d’impression sur la portée globale actuelle occultera la fonction intégrée print (ou déréférencera la fonction de compatibilité, si vous utilisez Python 2, portée).

Si vous souhaitez le faire dans une fonction plutôt que dans la portée globale d'un module, vous devez lui donner 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 spécifique ne corresponde exactement à ce que vous souhaitez.

Changer la valeur par défaut pour le processus

Je pense que la meilleure option ici est d’utiliser le drapeau -u pour obtenir une sortie non tamponnée.

$ python -u script.py

ou

$ python -um package.module

De la docs :

Forcer 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 voudrez utiliser file.readline () dans une boucle while 1:.

Modification de la valeur par défaut pour l'environnement d'exploitation 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

à partir du docs :

PYTHONUNBUFFERED

S'il est défini sur une chaîne non vide, cela équivaut à spécifier l'option -u.


Addenda

Voici l'aide sur la fonction d'impression de Python 2.7.12 - notez qu'il existe un argument noflush:

>>> 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.
157
Aaron Hall

Aussi comme suggéré dans ce blog on peut rouvrir sys.stdout en mode sans tampon:

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Chaque opération stdout.write et print sera automatiquement vidée par la suite.

69
Antony Hatchkins

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)

Entrée Python Docs

58
Noah Krasser

Utiliser le commutateur de ligne de commande -u fonctionne, mais il est un peu maladroit. Cela signifierait que le programme pourrait se comporter de manière incorrecte si l'utilisateur invoquait le script sans l'option -u. J'utilise habituellement un stdout personnalisé, 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 appels print (qui utilisent sys.stdout implicitement) seront automatiquement flushed.

36
Dan Lenski

Pourquoi ne pas essayer d'utiliser un fichier sans tampon?

f = open('xyz.log', 'a', 0)

OR

sys.stdout = open('out.log', 'a', 0)
19
Frank
import sys
print 'This will be output immediately.'
sys.stdout.flush()
15
Dynamic

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 crois 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 nécessairement être des objets de fichier intégrés: tout objet est acceptable tant qu’il dispose d’une méthode write () qui prend un argument de chaîne.

tellement changeant

class flushfile(file):

à

class flushfile(object):

ça marche très bien.

13
Kamil Kisiel

Voici ma version, qui fournit aussi 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()
8
guettli

J'ai adoré la solution de Dan! Pour python3 faire:

import io,sys
class flushfile:
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()
sys.stdout = flushfile(sys.stdout)
7
Jonas Byström

Dans Python 3, vous pouvez écraser la fonction d'impression avec la valeur par défaut définie sur flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
5
user263387

Je l'ai fait comme ça dans Python 3.4:

'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')
4
kmario23