Python泛型异常不良实践概念



我有以下脚本:

import jtp_aux as aux

def logger_path(path_logger):
return aux.init_logger(path_logger)

def generic_function(a, b):
return a/b

def main():
logger = logger_path(r'log_scratch.log')
try:
print(generic_function(2, 'l'))
except Exception as e:
logger.error(e, exc_info=True)

if __name__ == "__main__":
main()

我需要捕获代码抛出的任何错误并保存到文件中,以便稍后进行分析。然而,有人告诉我,这种通用异常捕获是一种不好的做法,应该一个接一个地捕获异常,就像这样:

def main():
logger = logger_path(r'log_scratch.log')
try:
print(generic_function(2, 'l'))
except ValueError:
# Do something
except ZeroDivisionError:
# Do something

然而,我很难理解为什么如果一个意外的异常可以使程序失败而不将错误保存到日志中,那么这被认为是最佳实践。如果有任何帮助,我将不胜感激。

如果您需要捕获任何和所有异常,那么except Exception正是您想要的并且很好。如果你对所有异常都做同样的处理,那么把它做得比这更细粒度是没有意义的。

一般来说,在捕捉异常时应该尽可能详细,以确保捕捉到预期的异常,并让意外的异常冒泡出现。例如:
a = 1
b = 0
try:
c = a / B
except ...:
...

这里是只捕获预期的ZeroDivisionError还是任何错误是有区别的。通过限制自己期望ZeroDivisionErrors,这段代码将正确地失败因为输入错误的变量名导致了NameError。如果您捕获了所有异常,那么在找到错别字之前,您可能需要调试这段代码很长时间。

您的方法很好,因为您确实打算捕获所有异常。只有当您实际上只想捕获少数异常时,捕获所有异常才被认为是不好的实践。例如,在下面的代码中,如果你希望get在找不到"Hello"的情况下抛出KeyError,你应该只捕获KeyError;如果你捕获了所有的异常,你可能会错过一个不同的异常(例如ZeroDivisionError):

try:
return myObj.get("Hello")
# bad: default value returned even though "Hello" might actually exist, but something else went wrong
except Exception as e:
return "DefaultValue"
# good: default value only returned on KeyError; all other exceptions are raised normally
except KeyError as e:
return "DefaultValue"

在您的情况下,您甚至可以在记录异常之后重新引发异常,使程序返回到常规异常处理:

try:
x = 1 / 0
except Exception as e:
print("Hello") # replace with logger.error(...) in your case
raise e # exits the except block and raises the exception again

输出:

Hello
Traceback (most recent call last):
File "pygame_textinput/tests.py", line 8, in <module>
raise e
File "pygame_textinput/tests.py", line 5, in <module>
x = 1 / 0
ZeroDivisionError: division by zero

如果你这样做,你的代码看起来好像异常是从外部正常引发的,但你也记录了你得到的每个异常。这可能很重要的一个例子是,当您调用在其他地方定义的函数时,并且预计在某些条件下会引发异常。您希望按照预期引发此异常,而不是捕获并忽略它。点击这里阅读更多内容。

最新更新