最近我一直在问几个关于Python中更专业和pythonic风格的问题,尽管我的问题给出了很好的答案,但我觉得我需要提出一个更广泛的问题。
通常,当编写实用程序函数(对于库等)处理更多副作用(文件写入,字典定义等)而不是返回值时,返回状态代码来告诉调用是非常有用的。它通过或失败的功能。
在Python中,似乎有三种标记方式:
使用返回值-1或0(C like)并使用诸如
之类的语句if my_function(args) < 0:
fail condition
pass condition
或使用返回值True / False
if not my_function(args):
fail condition
pass condition
或使用'return或'返回None'使用例外(出现未知错误)
try:
my_function(args)
except ExpectedOrKnownExceptionOrError:
fail condition
pass condition
哪一种最好?最正确的?首选?我理解所有的工作,并且没有太多的技术优势(除了可能是异常处理的开销)。
答案 0 :(得分:7)
不要返回指示错误的内容。抛出一个例外。绝对不要捕获异常并将其转换为返回代码。
答案 1 :(得分:1)
当引发异常并且没有被捕获时,Python will exit with an error (non-zero) code for you。如果您要定义自己的例外类型,则应override sys.excepthook()
为您提供所需的退出代码,因为默认情况下它们会使用退出代码1
。
如果您想出于某种奇怪的原因指定退出代码,请使用sys.exit()
和errno
模块获取标准退出代码,以便您使用相应的退出代码。您还可以使用traceback
模块来获取堆栈回溯(根据该答案,它似乎也是正确的错误代码)。就个人而言,我也不喜欢这种方法。
我建议的方法是不捕获异常;让它发生。如果你的程序在异常发生后可以继续运行,你应该抓住它并适当地处理它。但是,如果您的程序无法继续,您应该让例外。这对于在其他Python模块中重用您的程序特别有用,因为如果您愿意,您将能够捕获异常。
答案 2 :(得分:1)
与其他一切非常相似:这取决于。
例外情况有利于“将责任推卸”链上的错误或条件本地例程(或其调用者 - 见下文)无法处理或预期处理。特别是如果可以处理它的“谁”位于调用堆栈的几个级别。我认为这是例外的“最佳”使用。
异常的缺点是,一旦异常被提出,即使问题得到解决,也不会回到你离开的地方。你必须从头开始重新开始这个例程。
返回值适用于预期不会“意外”失败的常规操作。检查返回值并从那里开始。它们对于本地例程可以恢复的问题也很有用。例如,如果例程期望在放弃之前尝试3次,则返回Pass / Fail / True / False可能是合适的。
根据我的经验,期望调用者处理来自其被调用者的返回值和异常只是单调乏味。在我看来,检查Try / Except块内的返回值只会产生笨拙的逻辑......至少对于我的工作而言。
这并不是说您不能使用返回值的异常而不是。绝对有可能提供更清晰代码的情况。
我的妥协是试图限制自己在单个例程中返回值或异常。我试着限制我的来电者需要检查的东西。
当我需要两者时,我尝试将我的使用例外限制为我的直接调用者无法处理的问题。换句话说,我的直接调用者将期望获得True / False / Whatever返回值,但是也不期望处理异常。例外情况可能由他们的调用者等处理。当在同一例程中使用两者时,我会尝试将我的异常限制为真正的“例外”(即不常见的问题)。
此外,首选的Python习惯用法是使用True / False而不是1/0。当然,除非您使用C语言编写,否则您将在Linux脚本中返回Linux退出代码。