¿Está habilitado el almacenamiento en búfer de salida de forma predeterminada en el intérprete de Python sys.stdout?
Si la respuesta es positiva, ¿cuáles son todas las formas de desactivarla?
Sugerencias hasta el momento:
- Use el -uinterruptor de línea de comando
- Envuelva sys.stdouten un objeto que se enjuague después de cada escritura
- Establecer PYTHONUNBUFFEREDenv var
- sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
¿Hay alguna otra forma de establecer algún indicador global sys/ sys.stdoutprogramáticamente durante la ejecución?

-ues que no funcionará para el bytecode compilado o para aplicaciones con un__main__.pyarchivo como punto de entrada.Respuestas:
De la respuesta de Magnus Lycka en una lista de correo :
fuente
#!/usr/bin/env python -uno funciona !! mira aquí__getattr__solo para evitar la herencia?iter()en lugar delwhilebucle:for line in iter(pipe.readline, ''):. No lo necesita en Python 3, dondefor line in pipe:rinde lo antes posible.Prefiero poner mi respuesta en ¿Cómo vaciar la salida de la función de impresión? o en la función de impresión de Python que vacía el búfer cuando se llama? , pero como se marcaron como duplicados de este (lo que no estoy de acuerdo), lo responderé aquí.
Desde Python 3.3, print () admite el argumento de la palabra clave "flush" ( ver documentación ):
fuente
Créditos: "Sebastian", en algún lugar de la lista de correo de Python.
fuente
flush=Trueparámetro a laprint()función desde Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)(tenga en cuenta elbpara binario) yflush=Truetrabajen para mí en 3.6.4. Sin embargo, si está utilizando un subproceso para iniciar otro script, asegúrese de haber especificadopython3si tiene instancias múltiples de python instaladas.os.fdopen(sys.stdout.fileno(), 'wb', 0)terminas con un objeto de archivo binario, no unaTextIOsecuencia. Tendría que agregar unTextIOWrappera la mezcla (asegurándose de habilitarwrite_throughpara eliminar todos los búferes, o usarline_buffering=Truesolo para limpiar las nuevas líneas).Sí lo es.
Puede deshabilitarlo en la línea de comandos con el interruptor "-u".
Alternativamente, puede llamar a .flush () en sys.stdout en cada escritura (o envolverlo con un objeto que lo haga automáticamente)
fuente
Esto se relaciona con la respuesta de Cristóvão D. Sousa, pero aún no puedo comentar.
Una forma directa de utilizar el
flushargumento de palabra clave de Python 3 para tener siempre una salida sin búfer es:luego, la impresión siempre vaciará la salida directamente (excepto que
flush=Falsese indique).Tenga en cuenta, (a) que esto responde la pregunta solo parcialmente, ya que no redirige toda la salida. Pero supongo que
printes la forma más común de crear resultados enstdout/stderren python, por lo que estas 2 líneas cubren probablemente la mayoría de los casos de uso.Tenga en cuenta (b) que solo funciona en el módulo / script donde lo definió. Esto puede ser bueno al escribir un módulo, ya que no se mete con el
sys.stdout.Python 2 no proporciona el
flushargumento, pero podría emular unaprintfunción de tipo Python 3 como se describe aquí https://stackoverflow.com/a/27991478/3734258 .fuente
flushkwarg en python2.Sin guardar el viejo sys.stdout, disable_stdout_buffering () no es idempotente, y múltiples llamadas resultarán en un error como este:
Otra posibilidad es:
(Agregar a gc.garbage no es una buena idea porque es donde se ponen los ciclos no liberables, y es posible que desee verificarlos).
fuente
stdoutsigue vivosys.__stdout__como algunos han sugerido, la basura no será necesaria, ¿verdad? Sin embargo, es un truco genial.ValueError: can't have unbuffered text I/Oal llamarprint().Lo siguiente funciona en Python 2.6, 2.7 y 3.2:
fuente
OSError: [Errno 29] Illegal seekpara la líneasys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)Sí, está habilitado por defecto. Puede deshabilitarlo utilizando la opción -u en la línea de comando cuando llame a python.
fuente
También puede ejecutar Python con la utilidad stdbuf :
stdbuf -oL python <script>fuente
-oLhabilitado) todavía está almacenando en búfer: consulte f / e stackoverflow.com/questions/58416853/… , preguntando por qué laend=''salida ya no se muestra de inmediato.print(..., end='', flush=True)? OTOH, cuando varios programas escriben en la misma salida simultáneamente, la compensación tiende a pasar de ver un progreso inmediato a reducir las mezclas de salida, y el almacenamiento en línea se vuelve atractivo. Entonces, ¿tal vez es mejor no escribir explícitamenteflushy controlar el almacenamiento en búfer externamente?flush. El control de almacenamiento en búfer externo es una soluciónEn Python 3, puede parchear la función de impresión para enviar siempre flush = True:
Como se señaló en un comentario, puede simplificar esto vinculando el parámetro de vaciado a un valor, a través de
functools.partial:fuente
functools.partial?print = functools.partial(print, flush=True)funciona bien para miimport builtins; builtins.print = partial(print, flush=True)También puede usar fcntl para cambiar las marcas de archivo al vuelo.
fuente
Es posible anular solo el
writemétodo desys.stdoutuno que llameflush. La implementación del método sugerido se encuentra a continuación.El valor predeterminado del
wargumento mantendrá lawritereferencia del método original . Después de quewrite_flushse define, el originalwritepodría ser anulado.El código supone que
stdoutse importa de esta manerafrom sys import stdout.fuente
Puede crear un archivo sin búfer y asignar este archivo a sys.stdout.
No puede cambiar mágicamente la salida estándar proporcionada por el sistema; ya que es suministrado a su programa python por el sistema operativo.
fuente
Variante que funciona sin fallar (al menos en win32; python 2.7, ipython 0.12) y luego se llama posteriormente (varias veces):
fuente
sys.stdout is sys.__stdout__lugar de confiar en que el objeto de reemplazo tenga un atributo de nombre?(He publicado un comentario, pero se perdió de alguna manera. Entonces, de nuevo :)
Como noté, CPython (al menos en Linux) se comporta de manera diferente dependiendo de dónde vaya la salida. Si va a un tty, entonces la salida se vacía después de cada '
\n'Si va a una tubería / proceso, entonces se almacena en búfer y puede usar las
flush()soluciones basadas o la opción -u recomendada anteriormente.Ligeramente relacionado con el búfer de salida:
si itera sobre las líneas en la entrada con
for line in sys.stdin:...
entonces el para aplicación en CPython recogerá la entrada por un tiempo y luego ejecutar el cuerpo del bucle para un grupo de líneas de entrada. Si su script está a punto de escribir la salida para cada línea de entrada, esto podría parecer un buffer de salida, pero en realidad es un proceso por lotes, y por lo tanto, ninguna de las
flush()técnicas, etc., lo ayudará. Curiosamente, no tienes este comportamiento en pypy . Para evitar esto, puede usarwhile True: line=sys.stdin.readline()...
fuente
for line in sys.stdinvs.for line in iter(sys.stdin.readline, "")for line in sys.stdinproporciona una respuesta retrasada)Una forma de obtener resultados sin búfer sería usar en
sys.stderrlugar desys.stdouto simplemente llamarsys.stdout.flush()para forzar explícitamente a que ocurra una escritura.Puede redirigir fácilmente todo lo impreso haciendo:
O para redirigir solo para una
printdeclaración particular :Para restablecer stdout solo puedes hacer:
fuente