¿Cómo puedo vaciar la salida de la función de impresión?

1410

¿Cómo fuerzo a la printfunción de Python a aparecer en la pantalla?

0
1665

En Python 3, printpuede tomar un flushargumento opcional :

print("Hello, World!", flush=True)

En Python 2 tendrás que hacer

import sys
sys.stdout.flush()

después de llamar print. De forma predeterminada, printimprime en sys.stdout(consulte la documentación para obtener más información sobre los objetos de archivo ).

2
  • 1
    si lo hago, sys.stdout.flush()¿puedo evitar poner la palabra clave flush? Tengo muchas impresiones en mi archivo y no quiero cambiarlas + Quiero que mis archivos siempre se vacíen y no quiero escribirlos nunca. Solo siempre enjuagar es lo que quiero. ¿ sys.stdout.flush()Será suficiente con poner eso en la parte superior? (Estoy usando python 3 y superior) 2 de abril a las 20:01
  • 1
    No, deberías hacer sys.stdout.flush()(o usar print(..., flush=True)en Python 3) cada vez que llames print. Consulte esta respuesta para ver otra solución que pueda funcionar para usted. 22 abr a las 0:03
382

Ejecutando python -h, veo una opción de línea de comando :

-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x see man page for details on internal buffering relating to '-u'

Aquí está la documentación relevante .

1
  • 3
    Si lo está ejecutando en la plataforma Linux / Unix, puede agregar el -uen la línea de comandos del intérprete (primera línea del archivo de script), así que cambie la primera línea de (algo así como) #!/usr/bin/python3a #!/usr/bin/python3 -u- ahora cuando ejecute su script (por ejemplo, ./my_script.py) -usiempre se agregarán para ti 7 sep.20 a las 17:22
335

Desde Python 3.3, puede forzar que la print()función normal se descargue sin necesidad de usar sys.stdout.flush(); simplemente establezca el argumento de la palabra clave "flush" en verdadero. De la documentación :

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Print objects to the stream file, separated by sep and followed by end. sep, end and file, if present, must be given as keyword arguments.

All non-keyword arguments are converted to strings like str() does and written to the stream, separated by sep and followed by end. Both sep and end must be strings; they can also be None, which means to use the default values. If no objects are given, print() will just write end.

The file argument must be an object with a write(string) method; if it is not present or None, sys.stdout will be used. Whether output is buffered is usually determined by file, but if the flush keyword argument is true, the stream is forcibly flushed.

1
  • si lo hago, sys.stdout.flush()¿puedo evitar poner la palabra clave flush? Tengo muchas impresiones en mi archivo y no quiero cambiarlas + Quiero que mis archivos siempre se vacíen y no quiero escribirlos nunca. Solo siempre enjuagar es lo que quiero. ¿ sys.stdout.flush()Será suficiente con poner eso en la parte superior? (Estoy usando python 3 y superior) 2 de abril a las 20:01
238

How to flush output of Python print?

Sugiero cinco formas de hacer esto:

  • En Python 3, llame print(..., flush=True)(el argumento flush no está disponible en la función de impresión de Python 2 y no hay un análogo para la declaración de impresión).
  • Llame file.flush()al archivo de salida (podemos ajustar la función de impresión de Python 2 para hacer esto), por ejemplo,sys.stdout
  • aplique esto a cada llamada de función de impresión en el módulo con una función parcial,
    print = partial(print, flush=True)aplicada al módulo global.
  • aplicar esto al proceso con una bandera ( -u) pasada al comando del intérprete
  • aplique esto a cada proceso de Python en su entorno con PYTHONUNBUFFERED=TRUE(y desarme la variable para deshacer esto).

Python 3.3+

Con Python 3.3 o superior, puede proporcionar flush=Truecomo argumento de palabra clave a la printfunción:

print('foo', flush=True) 

Python 2 (o <3.3)

No respaldaron el flushargumento a Python 2.7 Entonces, si está usando Python 2 (o menos de 3.3) y desea un código que sea compatible con 2 y 3, puedo sugerir el siguiente código de compatibilidad. (Tenga en cuenta que la __future__importación debe estar en / muy "cerca de la parte superior de su módulo "):

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

El código de compatibilidad anterior cubrirá la mayoría de los usos, pero para un tratamiento mucho más completo, consulte el sixmódulo .

Alternativamente, puede simplemente llamar file.flush()después de imprimir, por ejemplo, con la declaración de impresión en Python 2:

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

Cambiar el valor predeterminado en un módulo a flush=True

Puede cambiar el valor predeterminado de la función de impresión utilizando functools.partial en el alcance global de un módulo:

import functools
print = functools.partial(print, flush=True)

si observa nuestra nueva función parcial, al menos en Python 3:

>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)

Podemos ver que funciona como de costumbre:

>>> print('foo')
foo

Y, de hecho, podemos anular el nuevo valor predeterminado:

>>> print('foo', flush=False)
foo

Tenga en cuenta nuevamente, esto solo cambia el alcance global actual, porque el nombre de impresión en el alcance global actual eclipsará la printfunción incorporada (o eliminará la referencia a la función de compatibilidad, si usa una en Python 2, en ese alcance global actual).

Si desea hacer esto dentro de una función en lugar de en el ámbito global de un módulo, debe darle un nombre diferente, por ejemplo:

def foo():
    printf = functools.partial(print, flush=True)
    printf('print stuff like this')

Si lo declara global en una función, lo está cambiando en el espacio de nombres global del módulo, por lo que debería ponerlo en el espacio de nombres global, a menos que ese comportamiento específico sea exactamente lo que desea.

Cambiar el valor predeterminado para el proceso

Creo que la mejor opción aquí es usar la -ubandera para obtener una salida sin búfer.

$ python -u script.py

o

$ python -um package.module

De los documentos :

Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, stdout and stderr in binary mode.

Note that there is internal buffering in file.readlines() and File Objects (for line in sys.stdin) which is not influenced by this option. To work around this, you will want to use file.readline() inside a while 1: loop.

Cambiar el valor predeterminado para el entorno operativo de shell

Puede obtener este comportamiento para todos los procesos de Python en el entorno o entornos que heredan del entorno si establece la variable de entorno en una cadena no vacía:

por ejemplo, en Linux u OSX:

$ export PYTHONUNBUFFERED=TRUE

o Windows:

C:\SET PYTHONUNBUFFERED=TRUE

de los documentos :

PYTHONUNBUFFERED

If this is set to a non-empty string it is equivalent to specifying the -u option.


Apéndice

Aquí está la ayuda sobre la función de impresión de Python 2.7.12; tenga en cuenta que no hay ningún flush argumento:

>>> 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.
6
  • Para los curiosos que migran desde versiones inferiores de Python: la __future__versión no se incluye flushporque "el argumento flush se agregó en Python 3.3 (después de que print () se transfiriera a 2.7 mediante una importación futura)" bugs.python.org/issue28458
    Oliver
    18/03/20 a las 1:46
  • Esta debería ser la respuesta aceptada. Proporciona soluciones alternativas y mucha información. 24 de enero a las 22:16
  • si lo hago, sys.stdout.flush()¿puedo evitar poner la palabra clave flush? Tengo muchas impresiones en mi archivo y no quiero cambiarlas + Quiero que mis archivos siempre se vacíen y no quiero escribirlos nunca. Solo siempre enjuagar es lo que quiero. ¿ sys.stdout.flush()Será suficiente con poner eso en la parte superior? (Estoy usando python 3 y superior) 2 de abril a las 20:01
  • No, pero puede hacer algo como import functools; print = functools.partial(print, flush=True)en la parte superior de su módulo (por ejemplo, después de las importaciones) e incluso asignarlo al nombre printen builtins.printpara la aplicabilidad en todo el proceso. 2 de abril a las 20:52
  • como import functools; print2 = functools.partial(print, flush=True); builtins.print=print2? @AaronHall 2 de abril a las 21:10
69

Además, como se sugiere en esta publicación de blog , se puede volver sys.stdouta abrir en modo sin búfer:

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

Cada uno stdout.writey printoperación se vacía automáticamente después.

3
  • 3
    En Ubuntu 12.04 en python 2.7 esto me da UnsupportedOperation: IOStream has no fileno. 1 de julio de 2015 a las 4:58
  • 4
    Vaya, Python 3 se enteró. ¡No me dejará ejecutar este código!
    EKons
    30/04/2016 a las 17:43
  • Estoy confundido por este idioma. Después de hacer esto, ¿no hay ahora dos objetos tipo Archivo (el sys.stdout original y el nuevo sys.stdout) que ambos piensan que "poseen" el fileno? Eso es malo, ¿verdad? 19/10/18 a las 13:41
sesenta y cinco

Con Python 3.x, la print()función se ha ampliado:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Entonces, puedes simplemente hacer:

print("Visiting toilet", flush=True)

Entrada de documentos de Python

1
39

El uso del -uconmutador de la línea de comandos funciona, pero es un poco torpe. Significaría que el programa se comportaría potencialmente de manera incorrecta si el usuario invocara el script sin la -uopción. Normalmente uso una costumbre stdout, como esta:

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)

... Ahora todas sus printllamadas (que usan sys.stdoutimplícitamente), serán editadas automáticamente flush.

2
  • 4
    Recomiendo no heredar del archivo y luego delegar a stdout agregando. def __getattr__(self,name): return object.__getattribute__(self.f, name) 23/0613 a las 19:21
  • 2
    Sin los cambios sugeridos por el comentario de @diedthreetimes, obtengo "ValueError: operación de E / S en archivo cerrado" 27/04/15 a las 22:43
19

Utilice un archivo sin búfer:

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

O

sys.stdout = open('out.log', 'a', 0)
1
  • 2
    No quiere crear un archivo sin búfer; quiere hacer que la salida estándar existente (redirigida a la consola, la terminal o lo que sea: esto no debe cambiarse) sin búfer. 28/04/15 a las 12:58
15

La idea de Dan no funciona del todo:

#!/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"

El resultado:

Traceback (most recent call last):
  File "./passpersist.py", line 12, in <module>
    print "foo"
ValueError: I/O operation on closed file

Creo que el problema es que hereda de la clase de archivo, lo que en realidad no es necesario. Según la documentación de sys.stdout:

stdout and stderr needn’t be built-in file objects: any object is acceptable as long as it has a write() method that takes a string argument.

tan cambiante

class flushfile(file):

para

class flushfile(object):

lo hace funcionar bien.

1
  • 19
    No hay voto porque esta es la solución de IS @ Dan ... (Debería comentar la publicación de Dan en lugar de copiar su solución)
    gecco
    15 de enero de 2013 a las 15:30
12

Aquí está mi versión, que también proporciona writeelines () y 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()
1
  • 1
    Solución superior. Y funciona. Probado en Python 3.4.0. Con las otras versiones, que derivan de file, obtengo un error. No hay fileclase. 22 de septiembre de 2014 a las 20:58
8

En Python 3 puede sobrescribir la función de impresión con la configuración predeterminada enflush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
1
  • 2
    esta respuesta parece un poco ligera dadas todas las otras respuestas de alta calidad. es posible que desee agregarle un poco más. 15 de mayo de 2016 a las 19:18
7

Lo hice así 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...')
1
4

Primero luché por entender cómo funcionaba la opción de descarga. Quería hacer una 'pantalla de carga' y aquí está la solución que encontré:

for i in range(100000):
    print('{:s}\r'.format(''), end='', flush=True)
    print('Loading index: {:d}/100000'.format(i+1), end='')

La primera línea elimina la impresión anterior y la segunda línea imprime un nuevo mensaje actualizado. No sé si existe una sintaxis de una línea aquí.