2

所以最近我一直在问一些关于 Python 中更专业和 Python 风格的问题,尽管我的问题得到了很好的答案,但我觉得我需要问一个更广泛的问题。

一般而言,当编写实用程序函数(用于库等)处理副作用(文件写入、字典定义等)而不是返回值时,返回状态码以告诉调用函数它是非常有用的通过或失败。

在 Python 中,似乎有三种方法可以标记这一点:

使用 -1 或 0(类似 C)的返回值并使用诸如

if my_function(args) < 0:
    fail condition
pass condition

或使用 True/False 的返回值

if not my_function(args):
     fail condition
pass condition

或使用异常使用'return or 'return None'(在未知错误时退出)

try:
    my_function(args)
except ExpectedOrKnownExceptionOrError:
    fail condition
pass condition

这些中哪个最好?最正确?首选?我了解所有工作,并且其中一个没有太多技术优势(除了异常处理的开销)。

4

3 回答 3

7

不要返回一些东西来指示错误。抛出异常。绝对不要捕获异常并将其转换为返回码。

于 2013-07-11T16:59:45.993 回答
2

当引发异常但未被捕获时,Python 将退出并为您提供错误(非零)代码。如果您正在定义自己的异常类型,您应该重写sys.excepthook()以提供您想要的退出代码,因为它们默认使用退出代码1

如果您出于某种奇怪的原因想要指定退出代码,请使用sys.exit()errno模块来获取标准退出代码,以便您使用适当的退出代码。您还可以使用该traceback模块来获取堆栈回溯(根据该答案,它似乎也是正确的错误代码)。就个人而言,我也不喜欢这种方法。

我推荐的方法是捕获异常;让它发生。如果你的程序在异常发生后还能继续运行,那么你应该抓住它并适当地处理它。但是,如果您的程序无法继续,您应该让异常发生。这对于在其他 Python 模块中重用您的程序特别有用,因为如果您愿意,您将能够捕获异常。

于 2013-07-11T17:24:22.660 回答
1

就像其他一切一样:这取决于。

对于本地例程(或其调用者——见下文)无法处理或无法处理的错误或条件,异常有助于“推卸责任”。特别是如果“谁”可以处理它位于调用堆栈的几个级别。我认为这是对异常的“最佳”使用。

异常的不利之处在于,一旦引发异常,就无法从上次中断的地方重新开始——即使问题已得到解决。你必须从头开始重新开始例行程序。

返回值适用于预计不会“意外”失败的常规操作。检查返回值并从那里开始。它们对于本地例程可以从中恢复的问题也很有用。例如,如果例程希望在放弃之前尝试 3 次,则返回 Pass/Fail/True/False 可能是合适的。

根据我的经验,期望调用者同时处理来自被调用者的返回值和异常会变得乏味。在我看来,检查 Try/Except 块内的返回值只会使逻辑变得笨拙……至少对于我所做的工作而言。

这并不是说您不能使用异常来代替返回值。肯定有一些情况可以提供更简洁的代码。

我的妥协是尝试限制自己在单个例程中返回值或异常。我试图限制我的来电者需要检查的事情。

当我需要两者时,我会尝试将我的使用异常限制为我的直接调用者也无法处理的问题。换句话说,我的直接调用者期望得到一个 True/False/Whatever 返回值,但也不期望处理异常。异常可能由它们的调用者处理,等等。当在同一个例程中使用两者时,我尝试将我的异常限制为真正的“异常”(即不常见的问题)。

此外,首选的 Python 习惯用法是使用 True/False 而不是 1/0。当然,除非您使用 C 语言编写,或者您在 Linux 脚本中返回 Linux 退出代码。

于 2013-07-11T23:00:56.067 回答