在 Python 2 和 Python 3 中捕获断管

Posted

技术标签:

【中文标题】在 Python 2 和 Python 3 中捕获断管【英文标题】:Catch Broken Pipe in Python 2 AND Python 3 【发布时间】:2016-01-11 09:40:44 【问题描述】:

我尝试编写一些代码来捕获 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

异常处理的语法也发生了一些变化(参见https://***.com/a/34463112/263589),所以我需要做的是:

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 中运行?

【问题讨论】:

看看python-future.org/compatible_idioms.html,他们展示了异常处理。 newbebweb.blogspot.in/2012/02/… 这里是 谢谢!但是python-future.org/compatible_idioms.html#catching-exceptions 没有解释如何捕获 Python 2 或 Python 3 中不存在但在其他版本中是强制性的异常。 @RajarshiDas 这很有趣!如果建议 Python 忽略 SIGPIPE 错误,您是否想说根本不需要捕获损坏的管道? 【参考方案1】:

如果您只关心损坏的管道错误,那么您可能想要捕获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 的回答是恰当且惯用的。

【讨论】:

谢谢!我有点担心socket.error 在 Python 3 中已被弃用。所以如果我更新我的 Python 3 解释器,在(不久的)将来可能还会出现另一个问题...... @speendo 在 Python 标准库本身中有几十个对 socket.error 的引用。当然,它已被弃用,但它不会消失。删除 socket.error 将是一个毫无意义的重大更改,这是 Python 核心开发人员公开表示他们将在未来避免的事情。如果它最终被删除(几十年后?!;)),那么识别和修复错误将是微不足道的,到那时你可能不会再支持 Python 2。【参考方案2】:

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

【讨论】:

以上是关于在 Python 2 和 Python 3 中捕获断管的主要内容,如果未能解决你的问题,请参考以下文章

仅需6道题轻松掌握Python异常捕获 | Python技能树征题

python—raise异常捕获

Python 异常处理-Python零基础入门教程

Python 2.7 和 GCP Google BigQuery:捕获文件加载错误?

python 捕获异常

捕获主目录中所有子文件夹中的所有 csv 文件 - Python 3.x