【问题标题】:Pythonic exception handling: only catching specific errnoPythonic 异常处理:仅捕获特定的 errno
【发布时间】:2016-10-23 07:31:58
【问题描述】:

我经常在 python 中读到“请求原谅比请求许可更容易”,因此有时认为使用try except 而不是if 更好。

我经常有这样的陈述

if (not os.path.isdir(dir)):
    os.mkdir(dir).

可能的替代品是

try:
    os.mkdir(dir)
except OSError:
    pass.

但是我想更具体一点,只忽略errno.EEXIST,因为这是唯一预期会发生的错误,我不知道会发生什么。

try:
    os.mkdir(dir)
except OSError:
    if(OSError.errno != errno.EEXIST):
        raise
    else:
        pass.

似乎可以解决问题。但这真的很庞大,如果我需要大量这些代码块,会“污染”我的代码并降低可读性。在 Python 2.X 中有没有一种 Pythonic 方法可以做到这一点?处理此类案件的标准程序是什么?

编辑:

  • @Francisco Couzo 指出,使用 raise 代替引发 OSerror
  • 我使用 Python 2.7

【问题讨论】:

  • 只做raise,而不是raise OSError,这样你就不会丢失异常的上下文
  • 你可以抓住FileExistsError: except FileExistsError: pass
  • 不需要else: pass,那是多余的。

标签: python error-handling errno


【解决方案1】:

我偶然发现了可能是最优雅的解决方案:创建 ignored 上下文管理器:

import errno
from contextlib import contextmanager

@contextmanager
def ignorednr(exception, *errornrs):
    try:
        yield
    except exception as e:
        if e.errno not in errornrs:
            raise
        pass


with ignorednr(OSError, errno.EEXIST):
     os.mkdir(dir)

这样我只需要创建一次上下文管理器,从那时起语法就变得非常好和可读了。

解决方案取自https://www.youtube.com/watch?v=OSGv2VnC0go

【讨论】:

    【解决方案2】:

    如果你用不同的参数多次调用它,把它放在一个函数中:

    def catch(d, err):
        try:
            os.mkdir(d)
        except OSError as e:
            if e.errno != err:
                raise
    

    然后调用传入任何参数的函数:

     catch(, "foo", errno.EEXIST)
    

    如果您想要更多,也可以允许传递多个 errno 的选项:

    def catch(d, *errs):
        try:
            os.mkdir(d)
        except OSError as e:
            if e.errno not in errs:
                raise
    
    catch("foo", errno.EEXIST, errno.EPERM)
    

    【讨论】:

      【解决方案3】:

      这个例子是针对异常OSError : 17, 'File exists'

      import sys
      try:
          value = os.mkdir("dir")
      except:
          e = sys.exc_info()[:2]
          e = str(e)
          if "17" in e:
              raise OSError #Perform Action
          else:
              pass   
      

      只需将数字 17 更改为您的例外编号。你可以在this link得到更好的解释。

      【讨论】:

      • 我认为我的问题已经提供了更好的答案,它更短并且不使用明确的数字。我读到的数字可能因系统而异,所以errno.EEXIST 更好,也更易读。
      猜你喜欢
      • 2018-10-19
      • 2015-10-13
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      • 2017-11-25
      • 2018-05-30
      • 1970-01-01
      相关资源
      最近更新 更多