library how python unix python-3.x flush broken-pipe

python - how - plotly library



BrokenPipeError en Python (3)

De acuerdo con la documentación de Python, esto se produce cuando:

tratando de escribir en una tubería mientras que el otro extremo se ha cerrado

Esto se debe al hecho de que la herramienta principal lee de stdout y luego la cierra rápidamente .

Como puede ver, puede sys.stdout.flush() simplemente agregando un sys.stdout.flush() después de cada print() . Tenga en cuenta que esto a veces no funciona en Python 3.

Alternativamente, puede canalizarlo a awk esta manera para obtener el mismo resultado que head -3 :

python3 0to3.py | awk ''NR >= 4 {exit} 1''

Espero que esto haya ayudado, ¡buena suerte!

Pregunta: ¿Hay alguna manera de usar flush=True para la función print() sin obtener el BrokenPipeError ?

Tengo un script pipe.py :

for i in range(4000): print(i)

Lo llamo así desde una línea de comandos de Unix:

python3 pipe.py | head -n3000

Y vuelve:

0 1 2

Este guión también lo hace

import sys for i in range(4000): print(i) sys.stdout.flush()

Sin embargo, cuando ejecuto este script y lo head -n3000 a la head -n3000 :

for i in range(4000): print(i, flush=True)

Entonces obtengo este error:

print(i, flush=True) BrokenPipeError: [Errno 32] Broken pipe Exception BrokenPipeError: BrokenPipeError(32, ''Broken pipe'') in <_io.TextIOWrapper name=''<stdout>'' mode=''w'' encoding=''UTF-8''> ignored

También probé la solución a continuación, pero todavía obtengo el BrokenPipeError :

import sys for i in range(4000): try: print(i, flush=True) except BrokenPipeError: sys.exit()


Como puede ver en la salida que publicó, la última excepción se plantea en la fase de destrucción: es por eso que ha ignored al final

Exception BrokenPipeError: BrokenPipeError(32, ''Broken pipe'') in <_io.TextIOWrapper name=''<stdout>'' mode=''w'' encoding=''UTF-8''> ignored

Un ejemplo simple para entender qué pasa en ese contexto es el siguiente:

>> class A(): ... def __del__(self): ... raise Exception("It will be ignored!!!") ... >>> a = A() >>> del a Exception Exception: Exception(''It will be ignored!!!'',) in <bound method A.__del__ of <__builtin__.A instance at 0x7ff1d5c06d88>> ignored >>> a = A() >>> import sys >>> sys.stderr.close() >>> del a

Cada excepción que se desencadena mientras se destruye el objeto generará un error estándar que explica la excepción producida e ignorada (esto es porque Python le informará que algo no se puede manejar correctamente en la fase de destrucción). De todos modos, ese tipo de excepciones no se pueden almacenar en caché y, por lo tanto, puedes eliminar las llamadas que pueden generarlo o cerrar stderr .

Regresa a la pregunta. Esa excepción no es un problema real (como decir que se ignora), pero si no quieres imprimirla, debes anular la función a la que se puede llamar cuando se destruirá el objeto o cerrar stderr como @SergeBallesta sugirió correctamente: en ti caso de que pueda apagar la función de write y flush y no se activará ninguna excepción en el contexto de destrucción

Ese es un ejemplo de cómo puedes hacerlo:

import sys def _void_f(*args,**kwargs): pass for i in range(4000): try: print(i,flush=True) except (BrokenPipeError, IOError): sys.stdout.write = _void_f sys.stdout.flush = _void_f sys.exit()


El BrokenPipeError es normal como dicho fantasma porque el proceso de lectura (cabeza) termina y cierra su extremo del tubo mientras el proceso de escritura (python) aún intenta escribir.

Es una condición anormal, y los scripts de Python reciben un BrokenPipeError ; más exactamente, el intérprete de Python recibe una señal SIGPIPE del sistema que capta y levanta el BrokenPipeError para permitir que el script procese el error.

Y efectivamente puede procesar el error, porque en su último ejemplo, solo ve un mensaje que dice que la excepción fue ignorada - vale, no es cierto, pero parece estar relacionado con este problema abierto en Python: los desarrolladores de Python piensan que es importante advertir al usuario de la condición anormal.

Lo que realmente sucede es que AFAIK, el intérprete de Python siempre lo señala en stderr, incluso si captas la excepción. Pero solo tiene que cerrar stderr antes de salir para deshacerse del mensaje.

Cambié ligeramente tu script a:

  • capte el error como lo hizo en su último ejemplo
  • atrapa IOError (que obtengo en Python34 en Windows64) o BrokenPipeError (en Python 33 en FreeBSD 9.0) - y muestra un mensaje para ese
  • mostrar un mensaje personalizado hecho en stderr (stdout está cerrado debido a la tubería rota)
  • cerrar stderr antes de salir para deshacerse del mensaje

Aquí está el script que utilicé:

import sys try: for i in range(4000): print(i, flush=True) except (BrokenPipeError, IOError): print (''BrokenPipeError caught'', file = sys.stderr) print (''Done'', file=sys.stderr) sys.stderr.close()

y aquí el resultado de python3.3 pipe.py | head -10 python3.3 pipe.py | head -10 :

0 1 2 3 4 5 6 7 8 9 BrokenPipeError caught Done

Si no quieres los mensajes extraños simplemente usa:

import sys try: for i in range(4000): print(i, flush=True) except (BrokenPipeError, IOError): pass sys.stderr.close()