异常处理:将其置于什么级别

2024-06-28 11:23:11 发布

您现在位置:Python中文网/ 问答频道 /正文

这是一个有点笼统和概念性的问题,不确定它是否在范围内,但我会试一试

我曾多次遇到类似以下的情况,但我一直不知道如何处理

我有几个函数,它们在某种层次结构中相互调用。我想处理函数的错误输入,但有些函数永远不会直接调用其他函数

例如,我有以下功能:

def getDataSourcesOfTypes(username, datatypes):
    if len(datatypes) < 1:
        raise ValueError("Please specify at least 1 datatype")
    http = authorizeHttp(username)
    ...snip...
    return data_sources_list

这就叫:

def authorizeHttp(username):
    if not isinstance(username, str):
        raise ValueError("Invalid username.")
    credential_json = Database.getCredential(username)
    ...snip...      

这又称之为:

def getCredential(username):
    Database.connection.row_factory = sqlite.Row  # @UndefinedVariable
    cursor = Database.connection.cursor()
    ...snip...
    result = cursor.fetchone()
    if result is None:
        raise LookupError("Username does not exist.")
    else:
       ...snip...

现在,对于username,我有几个机会抓住一个坏的机会(即不是字符串,不存在,等等)。显然,在调用最后一个函数之前,我无法捕捉到它没有出现在数据库中的错误,但是我可以早在第一个函数中捕捉到一个None

问题是:哪里是捕捉异常的最佳位置?在层次结构最下面的级别?尽快

同样,我认为这可能是一个太主观的问题,所以,但我真的很好奇什么是被认为是最佳实践


Tags: 函数if层次结构def错误usernamenotcursor
2条回答

有一些一般性的建议可以遵循

  • 在可能修复的位置捕获错误
  • 即使可能,也不要忽略异常(noexcept: pass
  • 记录它们
  • 不要使用太宽泛的情况,如except:except Exception:
  • 对不同的异常类型使用不同的异常块
  • 必要时使用elsefinally
  • 异常是一种异常行为,不要将其视为逻辑行为 应用程序的一部分

这里有一个关于异常处理的good articlePython docs也有最佳做法。和一个from the past(但仍然具有有效信息)

考虑到捕捉它们的地点。嗯,这里有不同的可能性

  1. 在代码中的任何其他地方都不能使用这些函数。
    在这种情况下,考虑这个问题的目的是“我需要通知用户出了什么问题,仅此而已”。在这种情况下,可以在可能的最高级别捕获异常

  2. 当这些函数在代码中广泛使用时,您需要一种不同的方法。在您这样做时引发异常,并在可以执行任何操作以返回正常程序执行(如果这是所需的行为)的位置捕获异常。或者,有时需要重新引发异常。例如:

    try:
         credential_json = Database.getCredential(username)
    except LookupError as le:
         log.warning(le)
         renew_token()  # (example) try to fix the problem somehow
         credential_json = Database.getCredential(username) # retry
         # note, that the next possible LookupError is not handled here.
    finally:
         check_data(credential_json)
    return credential_json
    
  3. 您正在编写可重用代码。这种情况很复杂。A. 需要深入了解您的工作流程。您的代码必须 提供自定义异常、异常处理程序,可以轻松 重写、控制返回值、提供回退等

    def function_with_handler(data, error_handler=_handler, *args, **kwargs):
        try:
            do_stuff()
        except CustomError as such_problem:
            # log.level(such_problem)
            _handler(such_problem, data, *args, **kwargs)
    

此外,有时向fail_silently = True添加一个选项实际上是一个好主意

阅读大型项目的源代码通常是一个好的做法。例如,看看Django如何处理exceptions

我会说,作为一般规则,最接近错误的真正来源,在那里它可以(可能)得到适当的处理。如果这是一个错误的输入,那么在输入的级别(可能是以链接的方式)。如果这是字典中缺少键的预期异常,那么立即捕获它。等等

但当然,还有更多

相关问题 更多 >