Mi sento in dovere di sottolineare che il metodo utilizzato
signal(SIGPIPE, SIG_DFL)
è davvero pericoloso (come già suggerito da David Bennet nei commenti) e nel mio caso ha portato a divertenti affari dipendenti dalla piattaforma quando combinato con multiprocessing.Manager
(perché la libreria standard si basa sul fatto che BrokenPipeError viene sollevato in diversi punti). Per far breve una storia lunga e dolorosa, ecco come l'ho risolta:
Per prima cosa, devi catturare IOError
(Python 2) o BrokenPipeError
(Python 3). A seconda del programma, puoi provare a uscire in anticipo a quel punto o semplicemente ignorare l'eccezione:
from errno import EPIPE
try:
broken_pipe_exception = BrokenPipeError
except NameError:
broken_pipe_exception = IOError
try:
YOUR CODE GOES HERE
except broken_pipe_exception as exc:
if broken_pipe_exception == IOError:
if exc.errno != EPIPE:
raise
Tuttavia, questo non è sufficiente. Python 3 potrebbe ancora stampare un messaggio come questo:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
Sfortunatamente sbarazzarsi di quel messaggio non è semplice, ma alla fine ho trovato http://bugs.python.org/issue11380 dove Robert Collins suggerisce questa soluzione alternativa che ho trasformato in un decoratore con cui puoi avvolgere la tua funzione principale (sì, è un po 'folle rientro):
from functools import wraps
from sys import exit, stderr, stdout
from traceback import print_exc
def suppress_broken_pipe_msg(f):
@wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except SystemExit:
raise
except:
print_exc()
exit(1)
finally:
try:
stdout.flush()
finally:
try:
stdout.close()
finally:
try:
stderr.flush()
finally:
stderr.close()
return wrapper
@suppress_broken_pipe_msg
def main():
YOUR CODE GOES HERE
print(f1.readlines())