Поймать сломанную трубу в Python 2 и Python 3

Я пытаюсь написать некоторый код, чтобы поймать ошибку Broken Pipe. Код должен работать в Python 2.x и Python 3.x.

В Python 2.x разорванный канал представлен socket.error

socket.error: [Errno 32] Broken pipe

Это было изменено в Python 3.x - сломанная труба теперь BrokenPipeError

BrokenPipeError: [Errno 32] Broken pipe

Также немного изменился синтаксис обработки исключений (см. /questions/24940317/dejstvitelnyij-sintaksis-v-python-2x-i-3x-dlya-vozbuzhdeniya-isklyucheniya/24940325#24940325), так что мне нужно сделать что-то вроде:

try:
    do_something()
except BrokenPipeError as e: # implies Python 3.x
    resolve_for_python2()
except socket.error as e:
    if sys.version_info[0] == 2: # this is necessary, as in Python >=3.3
                                 # socket.error is an alias of OSError
                                 # https://docs.python.org/3/library/socket.html#socket.error
        resolve_for_python3()
    else:
        raise

Есть (по крайней мере) одна остающаяся проблема: в Python 2.x нет BrokenPipeErrorпоэтому, когда есть исключение в do_something() Python 2.x выдает еще одно исключение и жалуется, что не знает BrokenPipeError, Как socket.error не рекомендуется в Python 3.x аналогичная проблема может возникнуть в Python 3.x в ближайшем будущем.

Что я могу сделать, чтобы этот код работал в Python 2.x и Python 3.x?

2 ответа

Решение

Если все, что вас волнует, это ошибки сломанной трубы, то вы можете захотеть отловить socket.error и просто проверьте, действительно ли это ошибка сломанной трубы.

Вы можете сделать это с помощью исключения errno атрибут, который присутствует как в Python 2, так и в Python 3, что означает, что вам не нужна разная логика Python 2 против 3 (я бы сказал, что намерение немного яснее в этом смысле):

import socket
import errno


try:
    do_something()
except socket.error as e:
    if e.errno != errno.EPIPE:
        # Not a broken pipe
        raise
    do_something_about_the_broken_pipe()

Если вы заботитесь не только о сломанных трубах, ответ thetheyeye уместен и идиоматичен.

Вы можете попробовать использовать BrokenPipeError и если он бросает NameErrorзатем отступите к socket.error, как это

import socket
try:
    expected_error = BrokenPipeError
except NameError:
    expected_error = socket.error

А потом использовать это так

try:
    1 == 2
except expected_error as ex:
    # Handle the actual exception here
Другие вопросы по тегам