Python 2和Python 3中如何捕获Broken Pipe错误

14

我试图编写一些代码来捕获“Broken Pipe”错误。该代码应在Python 2.x和Python 3.x中运行。

在Python 2.x中,一个“Broken Pipe”错误被表示为socket.error

socket.error: [Errno 32] Broken pipe

这在Python 3.x中已经改变 - 现在一个断开的管道是一个BrokenPipeError

BrokenPipeError: [Errno 32] Broken pipe

同时,异常处理的语法有些变化(请参见https://dev59.com/QpLea4cB1Zd3GeqP12qT#34463112)。因此,我需要做的是:

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。由于在 Python 3.x 中socket.error被弃用,所以在不久的将来可能会出现类似的问题。

我该怎么做才能让这段代码在 Python 2.x 和 Python 3.x 中运行?


请查看http://python-future.org/compatible_idioms.html,它们展示了异常处理。 - MKesper
1
这是一个关于Python的错误处理文章,主要讲述了在进行文件操作时出现IOError: [Errno 32] Broken pipe错误的解决方法。 - Rajarshi Das
谢谢!但是http://python-future.org/compatible_idioms.html#catching-exceptions并没有解释如何捕获在Python 2或Python 3中不存在但在另一个版本中是必需的异常。 - speendo
@RajarshiDas 这很有趣!您是在说如果建议Python忽略SIGPIPE错误,那么捕获破损的管道就不再必要了吗? - speendo
2个回答

13
如果您只关心断管错误,那么您可能希望捕获“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()

如果你关心的不仅是破管子的问题,thefourtheye的回答就很恰当和通俗易懂。


谢谢!让我有点担心的是,在Python 3中socket.error已经被弃用。因此,如果我更新我的Python 3解释器,可能会在(不久的)将来出现另一个问题... - speendo
2
@speendo 在 Python 标准库中有数十个对 socket.error 的引用。虽然它已被弃用,但并不会消失。移除 socket.error 将是一个毫无意义的破坏性变更,Python 核心开发人员已公开表示他们将在未来避免这种情况。即使它最终被删除(可能需要几十年?!),错误也很容易识别和修复,在那时你可能也不再支持 Python 2 了。 - Thomas Orozco

6
您可以尝试使用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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接