¿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
-u
interruptor de línea de comando - Envuelva
sys.stdout
en un objeto que se enjuague después de cada escritura - Establecer
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
¿Hay alguna otra forma de establecer algún indicador global sys
/ sys.stdout
programáticamente durante la ejecución?
-u
es que no funcionará para el bytecode compilado o para aplicaciones con un__main__.py
archivo como punto de entrada.Respuestas:
De la respuesta de Magnus Lycka en una lista de correo :
fuente
#!/usr/bin/env python -u
no funciona !! mira aquí__getattr__
solo para evitar la herencia?iter()
en lugar delwhile
bucle: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=True
parámetro a laprint()
función desde Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)
(tenga en cuenta elb
para binario) yflush=True
trabajen para mí en 3.6.4. Sin embargo, si está utilizando un subproceso para iniciar otro script, asegúrese de haber especificadopython3
si tiene instancias múltiples de python instaladas.os.fdopen(sys.stdout.fileno(), 'wb', 0)
terminas con un objeto de archivo binario, no unaTextIO
secuencia. Tendría que agregar unTextIOWrapper
a la mezcla (asegurándose de habilitarwrite_through
para eliminar todos los búferes, o usarline_buffering=True
solo 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
flush
argumento 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=False
se indique).Tenga en cuenta, (a) que esto responde la pregunta solo parcialmente, ya que no redirige toda la salida. Pero supongo que
print
es la forma más común de crear resultados enstdout
/stderr
en 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
flush
argumento, pero podría emular unaprint
función de tipo Python 3 como se describe aquí https://stackoverflow.com/a/27991478/3734258 .fuente
flush
kwarg 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
stdout
sigue 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/O
al llamarprint()
.Lo siguiente funciona en Python 2.6, 2.7 y 3.2:
fuente
OSError: [Errno 29] Illegal seek
para 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
-oL
habilitado) 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ícitamenteflush
y 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
write
método desys.stdout
uno que llameflush
. La implementación del método sugerido se encuentra a continuación.El valor predeterminado del
w
argumento mantendrá lawrite
referencia del método original . Después de quewrite_flush
se define, el originalwrite
podría ser anulado.El código supone que
stdout
se 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.stdin
vs.for line in iter(sys.stdin.readline, "")
for line in sys.stdin
proporciona una respuesta retrasada)Una forma de obtener resultados sin búfer sería usar en
sys.stderr
lugar desys.stdout
o 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
print
declaración particular :Para restablecer stdout solo puedes hacer:
fuente