Я відчуваю обов'язок зазначити, що метод використовує
signal(SIGPIPE, SIG_DFL)
дійсно небезпечний (як це вже пропонував Девід Беннет у коментарях) і в моєму випадку призвів до залежного від платформи смішного бізнесу в поєднанні з multiprocessing.Manager
(оскільки стандартна бібліотека покладається на те, що BrokenPipeError піднімається в декількох місцях). Щоб зробити довгу і болючу історію короткою, ось як я це виправив:
По-перше, вам потрібно зловити IOError
(Python 2) або BrokenPipeError
(Python 3). Залежно від вашої програми, ви можете спробувати вийти до цього часу або просто ігнорувати виняток:
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
Однак цього недостатньо. Python 3 все ще може надрукувати таке повідомлення:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
На жаль, позбутися цього повідомлення не просто, але я нарешті знайшов http://bugs.python.org/issue11380, де Роберт Коллінз пропонує цей обхідний шлях, який я перетворив на декоратор, яким можна обернути свою основну функцію (так, це божевільний відступ):
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())