返回Exception实例而不是在Python中提升它的缺点是什么?

时间:2010-01-22 11:51:17

标签: exception python

我一直在使用python-couchdb和desktopcouch做一些工作。在我提交的其中一个补丁中,我从couchdb中包装了db.update函数。对于任何不熟悉python-couchdb的人来说,函数如下:

def update(self, documents, **options):
    """Perform a bulk update or insertion of the given documents using a
    single HTTP request.

    >>> server = Server('http://localhost:5984/')
    >>> db = server.create('python-tests')
    >>> for doc in db.update([
    ...     Document(type='Person', name='John Doe'),
    ...     Document(type='Person', name='Mary Jane'),
    ...     Document(type='City', name='Gotham City')
    ... ]):
    ...     print repr(doc) #doctest: +ELLIPSIS
    (True, '...', '...')
    (True, '...', '...')
    (True, '...', '...')

    >>> del server['python-tests']

    The return value of this method is a list containing a tuple for every
    element in the `documents` sequence. Each tuple is of the form
    ``(success, docid, rev_or_exc)``, where ``success`` is a boolean
    indicating whether the update succeeded, ``docid`` is the ID of the
    document, and ``rev_or_exc`` is either the new document revision, or
    an exception instance (e.g. `ResourceConflict`) if the update failed.

    If an object in the documents list is not a dictionary, this method
    looks for an ``items()`` method that can be used to convert the object
    to a dictionary. Effectively this means you can also use this method
    with `schema.Document` objects.

    :param documents: a sequence of dictionaries or `Document` objects, or
                      objects providing a ``items()`` method that can be
                      used to convert them to a dictionary
    :return: an iterable over the resulting documents
    :rtype: ``list``

    :since: version 0.2
    """

正如您所看到的,此函数不会引发couchdb服务器引发的异常,而是将它们返回到具有我们要更新的文档的id的元组中。

其中一位评论员前往irc的#python询问此事。在#python中,他们建议使用sentinel值而不是异常。由于您可以成像只是一种方法是不切实际的,因为有很多可能的异常可以接收。我的问题是,除了使用例外情况之外,使用例外优于哨兵价值的缺点是什么呢?

4 个答案:

答案 0 :(得分:4)

我认为在这种情况下返回异常是可以的,因为更新函数的某些部分可能会成功,而某些部分可能会失败。当您引发异常时,API用户无法控制已经成功的内容。

答案 1 :(得分:2)

提出异常是一个通知,预计可行的东西不起作用。它打破了程序流程,只有当现在发生的事情以程序不知道如何处理的方式存在缺陷时才应该这样做。

但有时你想在不破坏程序流的情况下引发一点错误标记。您可以通过返回特殊值来完成此操作,这些值很可能是例外。

Python在一个案例中内部执行此操作。当您比较foo < bar这两个值时,实际调用为foo.__lt__(bar)。如果此方法引发异常,程序流将按预期打破。但如果返回 NotImplemented,则Python将尝试bar.__ge__(foo)。因此,在这种情况下,返回异常而不是提升异常用于标记它不起作用,但是以预期的方式。

这是预期错误和意外错误之间的区别,IMO。

答案 2 :(得分:1)

拟提出的例外情况。它有助于调试,处理错误的原因,以及其他开发人员的明确和完善的实践。

我认为在查看程序的界面时,我不清楚我应该对返回的异常做什么。提高它?从实际造成它的链外部?这看起来有点令人费解。

我建议,在成功时返回docid, new_rev_doc元组并按原样传播/提升异常。您的方法也会复制success和第三个返回值的类型。

答案 3 :(得分:1)

异常导致正常的程序流程中断;然后异常进入调用堆栈直到它们被拦截,或者如果它们不是,它们可能会到达顶部。因此,他们被用来标记应由呼叫者处理的真正特殊情况。提出异常很有用,因为如果不满足必要的条件,程序将无法继续。

在不支持异常的语言(如C)中,您经常被迫检查函数的返回值以验证所有内容是否正确;否则程序可能行为不端。

顺便说一下update()有点不同:

  • 它需要多个参数;有些可能会失败,有些可能会成功,因此需要一种方法来传达每个arg的结果。
  • 先前的失败与接下来的操作无关,例如这不是永久性的错误

在这种情况下,提出异常在API中不会是有用的。另一方面,如果在执行查询时与db的连接中断,那么就会出现异常(因为它是一个永久性错误并且会影响接下来的所有操作)。

顺便说一下,如果您的业务逻辑要求所有操作成功完成,并且您在更新失败时不知道该怎么做(即您的设计说它永远不会发生),请随意在您自己的代码中引发异常