【问题标题】:Is it better for a method to allow raising multiple types of exceptions or just one?一种方法允许引发多种类型的异常还是仅一种更好?
【发布时间】:2014-11-09 19:40:02
【问题描述】:

我的问题是关于最好的(最“pythonic”的)异常处理方式,以防一个方法可以引发两种(或更多)类型的异常,但从调用者的角度来看它们的解释是相同的。

假设我有一个命名(名称是字符串)对象的集合。我希望这个集合能够按索引或名称返回项目。

class CollectionOfNamedItems:
    def __init__(self, items):
        self._dict = {item.name: item for item in items} 
        self._items = tuple(items)

    def __getitem__(self, item):
        if isinstance(item, str):
            return = self._dict[item]  # may raise KeyError
        return self._items[item]  # may raise IndexError

# usage: collection['X'] or collection[1]

我的问题是:根据我们是按索引还是按名称访问项目,__getitem__ 方法会引发IndexErrorKeyError。这是引发异常的好方法吗?此方法的调用者必须捕获这两种类型的异常。或者在__getitem__ 中捕获KeyErrorIndexError 并引发ValueError (或其他一些?)会更好(可以说更pythonic),这样调用者就可以只捕获一种类型的异常,而不管传递的参数类型。

    def __getitem__(self, item):
        try:
            if isinstance(item, str):
                return = self._dict[item]  # may raise KeyError
            return self._items[item]  # may raise IndexError
        except (KeyError, IndexError):
            raise ValueError('invalid item')

另一方面,当我调用collection[1.5]collection[None] 时,抛出TypeError 似乎是合乎逻辑的。这是因为我觉得解释与上面的错误不同。

如果对此主题有任何意见或想法,我将不胜感激。

【问题讨论】:

标签: python exception exception-handling


【解决方案1】:

一般来说,您应该总是抛出最具体的异常。更重要的是,不要抛出旨在表示其他含义的异常类型。在您的情况下,ValueError 显然是错误的异常类型。

根据我们是按索引还是按名称访问项目,__getitem__ 方法会引发IndexErrorKeyError。这是引发异常的好方法吗?

是的,当然。如果你想同时支持索引和键访问,你应该实现“序列”和“映射”接口,并根据你的方法被调用的方式引发相应的异常。

原因是抽象:您将对象设计为作为可以通过索引访问其内容的序列/列表类型,以及作为映射/可以通过键访问其内容的字典类型。您班级的用户会选择一个这些接口,而不关心另一个。因此,他们期望不同类型的异常,并且不需要知道您的类的实现细节。

例如,如果您采用一个通用函数,该函数可以传递列表或其他行为类似于您的 CollectionOfNamedItems 的列表的对象,该函数将使用包含 合同 的“序列接口” __getitem__ 将为无效索引引发 IndexError。如果您改为提出其他类型的异常,您将违反该约定,从而限制您的类的使用

“映射接口”也是如此。

此方法的调用者必须捕获这两种类型的异常。

实际上,由于KeyErrorIndexError 都是LookupError 的子类,您的方法的调用者不区分这些情况 可以而且应该简单地捕获LookupError

try:
    item = collection[id]
except LookupError:
    # Could be KeyError or IndexError, we don't care.

【讨论】:

  • 我喜欢这个解释。谢谢。
【解决方案2】:

没有最 Pythonic 的捕获异常的方法。建议捕获最具体的异常。但是当您捕获多个异常时,请注意异常层次结构。所以你有最简单的方法来找到你的错误。有时您不想捕获最具体的异常,但您将决定您需要什么来处理特定的代码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 2020-03-19
    • 2014-04-14
    • 1970-01-01
    相关资源
    最近更新 更多