【问题标题】:custom exceptions in Python don't seem to follow the "its easier to ask for forgiveness"?Python中的自定义异常似乎没有遵循“更容易请求宽恕”?
【发布时间】:2020-08-02 04:22:19
【问题描述】:

我正在尝试改进我的编码,最近遇到了自定义异常和“请求宽恕比许可更容易”(EAFP)的概念,但在我看来,自定义异常仍然遵循这个概念。

例如,在下面的代码中,A 看起来很干净,但没有自定义异常。 B 看起来也很干净,但没有自定义异常,并且不遵循 EAFP 概念。 B 的替代方法是将 KeyError 替换为自定义错误。 C 有一个自定义异常,但它看起来很冗长,对我来说,它似乎更接近 LBYL。

示例 C 通常如何使用自定义异常? (使用 try/except AND if/else)

对于许多人将使用的生产级代码,示例 C 中的额外代码行是否值得?

animal_dict={'cat':'mammal', 
             'dog':'mammal', 
             'lizard':'reptile'}

# A - easier to ask for forgiveness not permission (EAFP)
try:
    animal_type = animal_dict['hamster']
except KeyError:
    print('Your animal cannot be found')


#B - look before you leap (LBYL)
if 'hamster' in animal_dict:
    animal_type = animal_dict['hamster']
else:
    raise KeyError('Your animal cannot be found')


# C - with custom exception
class AnimalNotFoundError(KeyError):
    pass

try:
    if 'hamster' in animal_dict:
        animal_type = animal_dict['hamster']
    else:
        raise AnimalNotFoundError('Invalid animal: {}'.format('hamster'))
except AnimalNotFoundError as e:
    print(e)

【问题讨论】:

  • 不过,您永远不会仅仅为了在同一个代码块中捕获而引发异常。
  • 不正确。我经常发现在单元测试中捕获 AssertionError 很方便,做一些事情(记录?检查?)然后将其重新启动。没错,我并没有含蓄地提出它,但我可能有理由在其他地方提出。
  • 对于许多人将使用的生产级代码,示例 C 中的额外代码行是否值得? 这实际上取决于代码库的复杂性以及您想要的方式处理异常。

标签: python python-3.x exception error-handling


【解决方案1】:

在这种情况下,您应该使用您的自定义异常来为通用 KeyError 异常添加详细信息。您可以在异常处理块中使用 from 关键字将您的异常与基本异常关联,如下所示:

class AnimalNotFoundError(KeyError):
    pass

try:
    # Don't look, just take
    animal_type = animal_dict['hamster']
except KeyError as ex:
    # Add some detail for the error here, and don't silently consume the error
    raise AnimalNotFoundError('Invalid animal: {}'.format('hamster')) from ex

【讨论】:

  • +1。请记住,如果您的整个代码堆栈都需要了解它们,那么许多自定义子类异常可能会很痛苦。例如,与 dbapi2 相关的 SQL 函数调用通常非常详细,但是您的客户端代码不知道库的 OperationalError 是什么,除非它专门导入它,或者除非它知道要针对哪个子类进行测试。当您的客户端代码针对通用游标触发时,情况会变得更糟,但现在不确定是 mysql 还是 postgres 库在工作。
  • 你也可以拦截 KeyError,设置 ex.myinfo = 'Invalid animal: {}'.format('hamster') 并再次引发它。这完全取决于 AnimalNotFoundError 是否打算在整个代码中具有关键意义,在这种情况下,它的声明可能属于它自己的模块。
  • @JLPeyret - 我同意,许多库的分层异常布局过于复杂,没有什么明显的好处。我尝试将这种类型的异常限制在我可以为不透明问题添加有价值的细节的情况下。
  • 我会在这里为from 再给你一个 +1,必须研究它的语义,但看起来很漂亮。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
  • 2018-01-13
  • 2011-12-24
  • 1970-01-01
  • 2011-10-01
  • 2011-05-06
  • 2019-07-03
相关资源
最近更新 更多